1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/views/tabs/tab.h"
#include "base/gfx/size.h"
#include "chrome/views/view_container.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/path.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/chrome_menu.h"
#include "chrome/views/tooltip_manager.h"
#include "generated_resources.h"
const std::string Tab::kTabClassName = "browser/tabs/Tab";
static const SkScalar kTabCapWidth = 15;
static const SkScalar kTabTopCurveWidth = 4;
static const SkScalar kTabBottomCurveWidth = 3;
class TabContextMenuController : public ChromeViews::MenuDelegate {
public:
explicit TabContextMenuController(Tab* tab)
: tab_(tab),
last_command_(TabStripModel::CommandFirst) {
menu_.reset(new ChromeViews::MenuItemView(this));
menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab,
l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB));
menu_->AppendSeparator();
menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload,
l10n_util::GetString(IDS_TAB_CXMENU_RELOAD));
menu_->AppendMenuItemWithLabel(
TabStripModel::CommandDuplicate,
l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE));
menu_->AppendSeparator();
menu_->AppendMenuItemWithLabel(
TabStripModel::CommandCloseTab,
l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB));
menu_->AppendMenuItemWithLabel(
TabStripModel::CommandCloseOtherTabs,
l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS));
menu_->AppendMenuItemWithLabel(
TabStripModel::CommandCloseTabsToRight,
l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT));
menu_->AppendMenuItemWithLabel(
TabStripModel::CommandCloseTabsOpenedBy,
l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY));
}
virtual ~TabContextMenuController() {
tab_->delegate()->StopAllHighlighting();
}
void RunMenuAt(int x, int y) {
menu_->RunMenuAt(tab_->GetViewContainer()->GetHWND(),
gfx::Rect(x, y, 0, 0), ChromeViews::MenuItemView::TOPLEFT,
false);
}
private:
// ChromeViews::MenuDelegate implementation:
virtual bool IsCommandEnabled(int id) const {
// The MenuItemView used to contain the contents of the Context Menu itself
// has a command id of 0, and it will check to see if it's enabled for
// some reason during its construction. The TabStripModel can't handle
// command indices it doesn't know about, so we need to filter this out
// here.
if (id == 0)
return false;
return tab_->delegate()->IsCommandEnabledForTab(
static_cast<TabStripModel::ContextMenuCommand>(id),
tab_);
}
virtual void ExecuteCommand(int id) {
tab_->delegate()->ExecuteCommandForTab(
static_cast<TabStripModel::ContextMenuCommand>(id),
tab_);
}
virtual void SelectionChanged(ChromeViews::MenuItemView* menu) {
TabStripModel::ContextMenuCommand command =
static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand());
tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
last_command_ = command;
tab_->delegate()->StartHighlightTabsForCommand(command, tab_);
}
private:
// The context menu.
scoped_ptr<ChromeViews::MenuItemView> menu_;
// The Tab the context menu was brought up for.
Tab* tab_;
// The last command that was selected, so that we can start/stop highlighting
// appropriately as the user moves through the menu.
TabStripModel::ContextMenuCommand last_command_;
DISALLOW_EVIL_CONSTRUCTORS(TabContextMenuController);
};
///////////////////////////////////////////////////////////////////////////////
// Tab, public:
Tab::Tab(TabDelegate* delegate)
: TabRenderer(),
delegate_(delegate),
closing_(false) {
close_button()->SetListener(this, 0);
close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
close_button()->SetAnimationDuration(0);
SetContextMenuController(this);
}
Tab::~Tab() {
}
///////////////////////////////////////////////////////////////////////////////
// Tab, TabRenderer overrides:
bool Tab::IsSelected() const {
return delegate_->IsTabSelected(this);
}
///////////////////////////////////////////////////////////////////////////////
// Tab, ChromeViews::View overrides:
bool Tab::HitTest(const CPoint &l) const {
gfx::Path path;
MakePathForTab(&path);
ScopedHRGN rgn(path.CreateHRGN());
return !!PtInRegion(rgn, l.x, l.y);
}
bool Tab::OnMousePressed(const ChromeViews::MouseEvent& event) {
if (event.IsOnlyLeftMouseButton()) {
// Store whether or not we were selected just now... we only want to be
// able to drag foreground tabs, so we don't start dragging the tab if
// it was in the background.
bool just_selected = !IsSelected();
if (just_selected)
delegate_->SelectTab(this);
delegate_->MaybeStartDrag(this, event);
}
return true;
}
bool Tab::OnMouseDragged(const ChromeViews::MouseEvent& event) {
delegate_->ContinueDrag(event);
return true;
}
void Tab::OnMouseReleased(const ChromeViews::MouseEvent& event,
bool canceled) {
// Notify the drag helper that we're done with any potential drag operations.
// Clean up the drag helper, which is re-created on the next mouse press.
delegate_->EndDrag(canceled);
if (event.IsMiddleMouseButton())
delegate_->CloseTab(this);
}
bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) {
std::wstring title = GetTitle();
if (!title.empty()) {
// Only show the tooltip if the title is truncated.
ChromeFont font;
if (font.GetStringWidth(title) > title_bounds().width()) {
*tooltip = title;
return true;
}
}
return false;
}
bool Tab::GetTooltipTextOrigin(int x, int y, CPoint* origin) {
ChromeFont font;
origin->x = title_bounds().x() + 10;
origin->y = -ChromeViews::TooltipManager::GetTooltipHeight() - 4;
return true;
}
bool Tab::GetAccessibleRole(VARIANT* role) {
DCHECK(role);
role->vt = VT_I4;
role->lVal = ROLE_SYSTEM_PAGETAB;
return true;
}
bool Tab::GetAccessibleName(std::wstring* name) {
*name = GetTitle();
return !name->empty();
}
///////////////////////////////////////////////////////////////////////////////
// Tab, ChromeViews::ContextMenuController implementation:
void Tab::ShowContextMenu(ChromeViews::View* source, int x, int y,
bool is_mouse_gesture) {
TabContextMenuController controller(this);
controller.RunMenuAt(x, y);
}
///////////////////////////////////////////////////////////////////////////////
// ChromeViews::BaseButton::ButtonListener implementation:
void Tab::ButtonPressed(ChromeViews::BaseButton* sender) {
if (sender == close_button())
delegate_->CloseTab(this);
}
///////////////////////////////////////////////////////////////////////////////
// Tab, private:
void Tab::MakePathForTab(gfx::Path* path) const {
DCHECK(path);
SkScalar h = SkIntToScalar(GetHeight());
SkScalar w = SkIntToScalar(GetWidth());
path->moveTo(0, h);
// Left end cap.
path->lineTo(kTabBottomCurveWidth, h - kTabBottomCurveWidth);
path->lineTo(kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth);
path->lineTo(kTabCapWidth, 0);
// Connect to the right cap.
path->lineTo(w - kTabCapWidth, 0);
// Right end cap.
path->lineTo(w - kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth);
path->lineTo(w - kTabBottomCurveWidth, h - kTabBottomCurveWidth);
path->lineTo(w, h);
// Close out the path.
path->lineTo(0, h);
path->close();
}
|