OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/views/browser_actions_container.h" | 5 #include "chrome/browser/views/browser_actions_container.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "app/resource_bundle.h" | 8 #include "app/resource_bundle.h" |
9 #include "app/slide_animation.h" | 9 #include "app/slide_animation.h" |
10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "chrome/browser/browser.h" | 12 #include "chrome/browser/browser.h" |
13 #include "chrome/browser/browser_theme_provider.h" | 13 #include "chrome/browser/browser_theme_provider.h" |
14 #include "chrome/browser/browser_window.h" | 14 #include "chrome/browser/browser_window.h" |
15 #include "chrome/browser/extensions/extension_browser_event_router.h" | 15 #include "chrome/browser/extensions/extension_browser_event_router.h" |
16 #include "chrome/browser/extensions/extension_host.h" | 16 #include "chrome/browser/extensions/extension_host.h" |
17 #include "chrome/browser/extensions/extensions_service.h" | 17 #include "chrome/browser/extensions/extensions_service.h" |
18 #include "chrome/browser/extensions/extension_tabs_module.h" | 18 #include "chrome/browser/extensions/extension_tabs_module.h" |
19 #include "chrome/browser/renderer_host/render_widget_host_view.h" | 19 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
20 #include "chrome/browser/renderer_host/render_view_host.h" | 20 #include "chrome/browser/renderer_host/render_view_host.h" |
21 #include "chrome/browser/profile.h" | 21 #include "chrome/browser/profile.h" |
22 #include "chrome/browser/tab_contents/tab_contents.h" | 22 #include "chrome/browser/tab_contents/tab_contents.h" |
23 #include "chrome/browser/view_ids.h" | 23 #include "chrome/browser/view_ids.h" |
24 #include "chrome/browser/views/detachable_toolbar_view.h" | 24 #include "chrome/browser/views/detachable_toolbar_view.h" |
25 #include "chrome/browser/views/extensions/browser_action_drag_data.h" | 25 #include "chrome/browser/views/extensions/browser_action_drag_data.h" |
26 #include "chrome/browser/views/extensions/extension_popup.h" | 26 #include "chrome/browser/views/extensions/extension_popup.h" |
| 27 #include "chrome/browser/views/toolbar_view.h" |
27 #include "chrome/common/extensions/extension_action.h" | 28 #include "chrome/common/extensions/extension_action.h" |
28 #include "chrome/common/extensions/extension_resource.h" | 29 #include "chrome/common/extensions/extension_resource.h" |
29 #include "chrome/common/notification_source.h" | 30 #include "chrome/common/notification_source.h" |
30 #include "chrome/common/notification_type.h" | 31 #include "chrome/common/notification_type.h" |
31 #include "chrome/common/pref_names.h" | 32 #include "chrome/common/pref_names.h" |
32 #include "gfx/canvas.h" | 33 #include "gfx/canvas.h" |
33 #include "gfx/canvas_skia.h" | 34 #include "gfx/canvas_skia.h" |
34 #include "grit/app_resources.h" | 35 #include "grit/app_resources.h" |
35 #include "grit/generated_resources.h" | 36 #include "grit/generated_resources.h" |
36 #include "third_party/skia/include/core/SkBitmap.h" | 37 #include "third_party/skia/include/core/SkBitmap.h" |
37 #include "third_party/skia/include/core/SkTypeface.h" | 38 #include "third_party/skia/include/core/SkTypeface.h" |
38 #include "third_party/skia/include/effects/SkGradientShader.h" | 39 #include "third_party/skia/include/effects/SkGradientShader.h" |
39 #include "views/controls/button/menu_button.h" | 40 #include "views/controls/button/menu_button.h" |
40 #include "views/controls/button/text_button.h" | 41 #include "views/controls/button/text_button.h" |
41 #include "views/controls/menu/menu_2.h" | 42 #include "views/controls/menu/menu_2.h" |
42 #include "views/drag_utils.h" | 43 #include "views/drag_utils.h" |
43 #include "views/window/window.h" | 44 #include "views/window/window.h" |
44 | 45 |
45 #include "grit/theme_resources.h" | 46 #include "grit/theme_resources.h" |
46 | 47 |
47 namespace { | 48 // Horizontal spacing between most items in the container, as well as after the |
| 49 // last item or chevron (if visible). |
| 50 static const int kItemSpacing = ToolbarView::kStandardSpacing; |
| 51 // Horizontal spacing before the chevron (if visible). |
| 52 static const int kChevronSpacing = kItemSpacing - 2; |
48 | 53 |
49 // The size (both dimensions) of the buttons for page actions. | 54 // static |
50 static const int kButtonSize = 29; | |
51 | |
52 // The padding between the browser actions and the OmniBox/page menu. | |
53 static const int kHorizontalPadding = 4; | |
54 static const int kHorizontalPaddingRtl = 8; | |
55 | |
56 // The padding between browser action buttons. Visually, the actual number of | |
57 // empty (non-drawing) pixels is this value + 2 when adjacent browser icons | |
58 // use their maximum allowed size. | |
59 static const int kBrowserActionButtonPadding = 3; | |
60 | |
61 // This is the same value from toolbar.cc. We position the browser actions | |
62 // container flush with the edges of the toolbar as a special case so that we | |
63 // can draw the badge outside the visual bounds of the container. | |
64 static const int kControlVertOffset = 6; | |
65 | |
66 // The margin between the divider and the chrome menu buttons. | |
67 static const int kDividerHorizontalMargin = 2; | |
68 | |
69 // The padding above and below the divider. | |
70 static const int kDividerVerticalPadding = 9; | |
71 | |
72 // The margin above the chevron. | |
73 static const int kChevronTopMargin = 9; | |
74 | |
75 // The margin to the right of the chevron. | |
76 static const int kChevronRightMargin = 4; | |
77 | |
78 // Width for the resize area. | |
79 static const int kResizeAreaWidth = 4; | |
80 | |
81 // The x offset for the drop indicator (how much we shift it by). | |
82 static const int kDropIndicatorOffsetLtr = 3; | |
83 static const int kDropIndicatorOffsetRtl = 9; | |
84 | |
85 } // namespace. | |
86 | |
87 // Static. | |
88 bool BrowserActionsContainer::disable_animations_during_testing_ = false; | 55 bool BrowserActionsContainer::disable_animations_during_testing_ = false; |
89 | 56 |
90 //////////////////////////////////////////////////////////////////////////////// | 57 //////////////////////////////////////////////////////////////////////////////// |
91 // BrowserActionButton | 58 // BrowserActionButton |
92 | 59 |
93 BrowserActionButton::BrowserActionButton(Extension* extension, | 60 BrowserActionButton::BrowserActionButton(Extension* extension, |
94 BrowserActionsContainer* panel) | 61 BrowserActionsContainer* panel) |
95 : ALLOW_THIS_IN_INITIALIZER_LIST( | 62 : ALLOW_THIS_IN_INITIALIZER_LIST( |
96 MenuButton(this, std::wstring(), NULL, false)), | 63 MenuButton(this, std::wstring(), NULL, false)), |
97 browser_action_(extension->browser_action()), | 64 browser_action_(extension->browser_action()), |
98 extension_(extension), | 65 extension_(extension), |
99 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), | 66 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), |
100 showing_context_menu_(false), | 67 showing_context_menu_(false), |
101 panel_(panel) { | 68 panel_(panel) { |
| 69 set_border(NULL); |
102 set_alignment(TextButton::ALIGN_CENTER); | 70 set_alignment(TextButton::ALIGN_CENTER); |
103 | 71 |
104 // No UpdateState() here because View hierarchy not setup yet. Our parent | 72 // No UpdateState() here because View hierarchy not setup yet. Our parent |
105 // should call UpdateState() after creation. | 73 // should call UpdateState() after creation. |
106 | 74 |
107 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, | 75 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, |
108 Source<ExtensionAction>(browser_action_)); | 76 Source<ExtensionAction>(browser_action_)); |
109 | 77 |
110 // The Browser Action API does not allow the default icon path to be changed | 78 // The Browser Action API does not allow the default icon path to be changed |
111 // at runtime, so we can load this now and cache it. | 79 // at runtime, so we can load this now and cache it. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 // Call back to UpdateState() because a more specific icon might have been set | 115 // Call back to UpdateState() because a more specific icon might have been set |
148 // while the load was outstanding. | 116 // while the load was outstanding. |
149 UpdateState(); | 117 UpdateState(); |
150 } | 118 } |
151 | 119 |
152 void BrowserActionButton::UpdateState() { | 120 void BrowserActionButton::UpdateState() { |
153 int tab_id = panel_->GetCurrentTabId(); | 121 int tab_id = panel_->GetCurrentTabId(); |
154 if (tab_id < 0) | 122 if (tab_id < 0) |
155 return; | 123 return; |
156 | 124 |
157 SkBitmap image = browser_action()->GetIcon(tab_id); | 125 SkBitmap icon(browser_action()->GetIcon(tab_id)); |
158 if (!image.isNull()) | 126 if (icon.isNull()) |
159 SetIcon(image); | 127 icon = default_icon_; |
160 else if (!default_icon_.isNull()) | 128 if (!icon.isNull()) { |
161 SetIcon(default_icon_); | 129 SkPaint paint; |
| 130 paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); |
| 131 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 132 |
| 133 SkBitmap bg; |
| 134 rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg, |
| 135 SkBitmap::kARGB_8888_Config); |
| 136 SkCanvas bg_canvas(bg); |
| 137 bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2), |
| 138 SkIntToScalar((bg.height() - icon.height()) / 2), &paint); |
| 139 SetIcon(bg); |
| 140 |
| 141 SkBitmap bg_h; |
| 142 rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h, |
| 143 SkBitmap::kARGB_8888_Config); |
| 144 SkCanvas bg_h_canvas(bg_h); |
| 145 bg_h_canvas.drawBitmap(icon, |
| 146 SkIntToScalar((bg_h.width() - icon.width()) / 2), |
| 147 SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint); |
| 148 SetHoverIcon(bg_h); |
| 149 |
| 150 SkBitmap bg_p; |
| 151 rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p, |
| 152 SkBitmap::kARGB_8888_Config); |
| 153 SkCanvas bg_p_canvas(bg_p); |
| 154 bg_p_canvas.drawBitmap(icon, |
| 155 SkIntToScalar((bg_p.width() - icon.width()) / 2), |
| 156 SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint); |
| 157 SetPushedIcon(bg_p); |
| 158 } |
162 | 159 |
163 // If the browser action name is empty, show the extension name instead. | 160 // If the browser action name is empty, show the extension name instead. |
164 std::wstring name = UTF8ToWide(browser_action()->GetTitle(tab_id)); | 161 std::wstring name = UTF8ToWide(browser_action()->GetTitle(tab_id)); |
165 if (name.empty()) | 162 if (name.empty()) |
166 name = UTF8ToWide(extension()->name()); | 163 name = UTF8ToWide(extension()->name()); |
167 SetTooltipText(name); | 164 SetTooltipText(name); |
168 SetAccessibleName(name); | 165 SetAccessibleName(name); |
169 GetParent()->SchedulePaint(); | 166 GetParent()->SchedulePaint(); |
170 } | 167 } |
171 | 168 |
(...skipping 16 matching lines...) Expand all Loading... |
188 GURL BrowserActionButton::GetPopupUrl() { | 185 GURL BrowserActionButton::GetPopupUrl() { |
189 int tab_id = panel_->GetCurrentTabId(); | 186 int tab_id = panel_->GetCurrentTabId(); |
190 DCHECK_GE(tab_id, 0); | 187 DCHECK_GE(tab_id, 0); |
191 return browser_action_->GetPopupUrl(tab_id); | 188 return browser_action_->GetPopupUrl(tab_id); |
192 } | 189 } |
193 | 190 |
194 bool BrowserActionButton::Activate() { | 191 bool BrowserActionButton::Activate() { |
195 if (!IsPopup()) | 192 if (!IsPopup()) |
196 return true; | 193 return true; |
197 | 194 |
198 panel_->OnBrowserActionExecuted(this, false); // |inspect_with_devtools|. | 195 panel_->OnBrowserActionExecuted(this, false); |
199 | 196 |
200 // TODO(erikkay): Run a nested modal loop while the mouse is down to | 197 // TODO(erikkay): Run a nested modal loop while the mouse is down to |
201 // enable menu-like drag-select behavior. | 198 // enable menu-like drag-select behavior. |
202 | 199 |
203 // The return value of this method is returned via OnMousePressed. | 200 // The return value of this method is returned via OnMousePressed. |
204 // We need to return false here since we're handing off focus to another | 201 // We need to return false here since we're handing off focus to another |
205 // widget/view, and true will grab it right back and try to send events | 202 // widget/view, and true will grab it right back and try to send events |
206 // to us. | 203 // to us. |
207 return false; | 204 return false; |
208 } | 205 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 int tab_id = panel_->GetCurrentTabId(); | 296 int tab_id = panel_->GetCurrentTabId(); |
300 | 297 |
301 SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id); | 298 SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id); |
302 if (icon.isNull()) | 299 if (icon.isNull()) |
303 icon = button_->default_icon(); | 300 icon = button_->default_icon(); |
304 | 301 |
305 gfx::Canvas* canvas = new gfx::CanvasSkia(icon.width(), icon.height(), false); | 302 gfx::Canvas* canvas = new gfx::CanvasSkia(icon.width(), icon.height(), false); |
306 canvas->DrawBitmapInt(icon, 0, 0); | 303 canvas->DrawBitmapInt(icon, 0, 0); |
307 | 304 |
308 if (tab_id >= 0) { | 305 if (tab_id >= 0) { |
309 gfx::Rect bounds(icon.width(), icon.height() + kControlVertOffset); | 306 gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing); |
310 button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id); | 307 button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id); |
311 } | 308 } |
312 | 309 |
313 return canvas; | 310 return canvas; |
314 } | 311 } |
315 | 312 |
316 bool BrowserActionView::GetAccessibleRole(AccessibilityTypes::Role* role) { | 313 bool BrowserActionView::GetAccessibleRole(AccessibilityTypes::Role* role) { |
317 DCHECK(role); | 314 DCHECK(role); |
318 *role = AccessibilityTypes::ROLE_GROUPING; | 315 *role = AccessibilityTypes::ROLE_GROUPING; |
319 return true; | 316 return true; |
320 } | 317 } |
321 | 318 |
322 void BrowserActionView::Layout() { | 319 void BrowserActionView::Layout() { |
323 button_->SetBounds(0, kControlVertOffset, width(), kButtonSize); | 320 // We can't rely on button_->GetPreferredSize() here because that's not set |
| 321 // correctly until the first call to |
| 322 // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be |
| 323 // called before that when the initial bounds are set (and then not after, |
| 324 // since the bounds don't change). So instead of setting the height from the |
| 325 // button's preferred size, we use IconHeight(), since that's how big the |
| 326 // button should be regardless of what it's displaying. |
| 327 button_->SetBounds(0, ToolbarView::kVertSpacing, width(), |
| 328 BrowserActionsContainer::IconHeight()); |
324 } | 329 } |
325 | 330 |
326 void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { | 331 void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { |
327 View::PaintChildren(canvas); | 332 View::PaintChildren(canvas); |
328 ExtensionAction* action = button()->browser_action(); | 333 ExtensionAction* action = button()->browser_action(); |
329 int tab_id = panel_->GetCurrentTabId(); | 334 int tab_id = panel_->GetCurrentTabId(); |
330 if (tab_id >= 0) | 335 if (tab_id >= 0) |
331 action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); | 336 action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); |
332 } | 337 } |
333 | 338 |
334 //////////////////////////////////////////////////////////////////////////////// | 339 //////////////////////////////////////////////////////////////////////////////// |
335 // BrowserActionsContainer | 340 // BrowserActionsContainer |
336 | 341 |
337 BrowserActionsContainer::BrowserActionsContainer(Browser* browser, | 342 BrowserActionsContainer::BrowserActionsContainer(Browser* browser, |
338 View* owner_view) | 343 View* owner_view) |
339 : profile_(browser->profile()), | 344 : profile_(browser->profile()), |
340 browser_(browser), | 345 browser_(browser), |
341 owner_view_(owner_view), | 346 owner_view_(owner_view), |
342 popup_(NULL), | 347 popup_(NULL), |
343 popup_button_(NULL), | 348 popup_button_(NULL), |
344 model_(NULL), | 349 model_(NULL), |
| 350 container_width_(0), |
345 chevron_(NULL), | 351 chevron_(NULL), |
346 overflow_menu_(NULL), | 352 overflow_menu_(NULL), |
347 suppress_chevron_(false), | 353 suppress_chevron_(false), |
348 resize_amount_(0), | 354 resize_amount_(0), |
349 animation_target_size_(0), | 355 animation_target_size_(0), |
350 drop_indicator_position_(-1), | 356 drop_indicator_position_(-1), |
351 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | 357 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
352 ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { | 358 ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { |
353 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); | 359 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
354 | 360 |
355 if (profile_->GetExtensionsService()) { | 361 if (profile_->GetExtensionsService()) { |
356 model_ = profile_->GetExtensionsService()->toolbar_model(); | 362 model_ = profile_->GetExtensionsService()->toolbar_model(); |
357 model_->AddObserver(this); | 363 model_->AddObserver(this); |
358 } | 364 } |
359 | 365 |
360 resize_animation_.reset(new SlideAnimation(this)); | 366 resize_animation_.reset(new SlideAnimation(this)); |
361 resize_area_ = new views::ResizeArea(this); | 367 resize_area_ = new views::ResizeArea(this); |
362 resize_area_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SEPARATOR)); | 368 resize_area_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SEPARATOR)); |
363 AddChildView(resize_area_); | 369 AddChildView(resize_area_); |
364 | 370 |
365 // TODO(glen): Come up with a new bitmap for the chevron. | |
366 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
367 SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); | |
368 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); | 371 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); |
369 chevron_->SetVisible(false); | 372 chevron_->set_border(NULL); |
370 chevron_->SetIcon(*chevron_image); | 373 chevron_->EnableCanvasFlippingForRTLUI(true); |
371 chevron_->SetAccessibleName( | 374 chevron_->SetAccessibleName( |
372 l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_CHEVRON)); | 375 l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_CHEVRON)); |
373 // Chevron contains >> that should point left in LTR locales. | 376 chevron_->SetVisible(false); |
374 chevron_->EnableCanvasFlippingForRTLUI(true); | |
375 AddChildView(chevron_); | 377 AddChildView(chevron_); |
376 | 378 |
377 if (model_ && | |
378 !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { | |
379 // Migration code to the new VisibleIconCount pref. | |
380 // TODO(mpcomplete): remove this after users are upgraded to 5.0. | |
381 int predefined_width = | |
382 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); | |
383 if (predefined_width != 0) { | |
384 model_->SetVisibleIconCount((predefined_width - WidthOfNonIconArea()) / | |
385 (kButtonSize + kBrowserActionButtonPadding)); | |
386 } | |
387 } | |
388 if (model_ && model_->extensions_initialized()) | |
389 SetContainerWidth(); | |
390 | |
391 SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS)); | 379 SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS)); |
392 } | 380 } |
393 | 381 |
394 BrowserActionsContainer::~BrowserActionsContainer() { | 382 BrowserActionsContainer::~BrowserActionsContainer() { |
395 if (model_) | 383 if (model_) |
396 model_->RemoveObserver(this); | 384 model_->RemoveObserver(this); |
397 StopShowFolderDropMenuTimer(); | 385 StopShowFolderDropMenuTimer(); |
398 HidePopup(); | 386 HidePopup(); |
399 DeleteBrowserActionViews(); | 387 DeleteBrowserActionViews(); |
400 } | 388 } |
401 | 389 |
402 // Static. | 390 // Static. |
403 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { | 391 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { |
404 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); | 392 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); |
405 } | 393 } |
406 | 394 |
| 395 void BrowserActionsContainer::Init() { |
| 396 LoadImages(); |
| 397 |
| 398 // We wait to set the container width until now so that the chevron images |
| 399 // will be loaded. The width calculation needs to know the chevron size. |
| 400 if (model_ && |
| 401 !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { |
| 402 // Migration code to the new VisibleIconCount pref. |
| 403 // TODO(mpcomplete): remove this after users are upgraded to 5.0. |
| 404 int predefined_width = |
| 405 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); |
| 406 if (predefined_width != 0) |
| 407 model_->SetVisibleIconCount(WidthToIconCount(predefined_width)); |
| 408 } |
| 409 if (model_ && model_->extensions_initialized()) |
| 410 SetContainerWidth(); |
| 411 } |
| 412 |
407 int BrowserActionsContainer::GetCurrentTabId() const { | 413 int BrowserActionsContainer::GetCurrentTabId() const { |
408 TabContents* tab_contents = browser_->GetSelectedTabContents(); | 414 TabContents* tab_contents = browser_->GetSelectedTabContents(); |
409 return tab_contents ? tab_contents->controller().session_id().id() : -1; | 415 return tab_contents ? tab_contents->controller().session_id().id() : -1; |
410 } | 416 } |
411 | 417 |
412 BrowserActionView* BrowserActionsContainer::GetBrowserActionView( | 418 BrowserActionView* BrowserActionsContainer::GetBrowserActionView( |
413 ExtensionAction* action) { | 419 ExtensionAction* action) { |
414 for (BrowserActionViews::iterator iter = browser_action_views_.begin(); | 420 for (BrowserActionViews::iterator iter = browser_action_views_.begin(); |
415 iter != browser_action_views_.end(); ++iter) { | 421 iter != browser_action_views_.end(); ++iter) { |
416 if ((*iter)->button()->browser_action() == action) | 422 if ((*iter)->button()->browser_action() == action) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 | 509 |
504 popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_, | 510 popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_, |
505 browser_->profile(), frame_window, rect, arrow_location, true, | 511 browser_->profile(), frame_window, rect, arrow_location, true, |
506 inspect_with_devtools, ExtensionPopup::BUBBLE_CHROME, this); | 512 inspect_with_devtools, ExtensionPopup::BUBBLE_CHROME, this); |
507 popup_button_ = button; | 513 popup_button_ = button; |
508 popup_button_->SetButtonPushed(); | 514 popup_button_->SetButtonPushed(); |
509 } | 515 } |
510 | 516 |
511 gfx::Size BrowserActionsContainer::GetPreferredSize() { | 517 gfx::Size BrowserActionsContainer::GetPreferredSize() { |
512 if (browser_action_views_.empty()) | 518 if (browser_action_views_.empty()) |
513 return gfx::Size(0, 0); | 519 return gfx::Size(ToolbarView::kStandardSpacing, 0); |
514 | 520 |
515 // We calculate the size of the view by taking the current width and | 521 // We calculate the size of the view by taking the current width and |
516 // subtracting resize_amount_ (the latter represents how far the user is | 522 // subtracting resize_amount_ (the latter represents how far the user is |
517 // resizing the view or, if animating the snapping, how far to animate it). | 523 // resizing the view or, if animating the snapping, how far to animate it). |
518 // But we also clamp it to a minimum size and the maximum size, so that the | 524 // But we also clamp it to a minimum size and the maximum size, so that the |
519 // container can never shrink too far or take up more space than it needs. In | 525 // container can never shrink too far or take up more space than it needs. In |
520 // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). | 526 // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). |
521 int clamped_width = std::min( | 527 int clamped_width = std::min( |
522 std::max(ContainerMinSize(), container_width_ - resize_amount_), | 528 std::max(ContainerMinSize(), container_width_ - resize_amount_), |
523 ClampToNearestIconCount(-1, false)); | 529 IconCountToWidth(-1, false)); |
524 return gfx::Size(clamped_width, kButtonSize); | 530 return gfx::Size(clamped_width, 0); |
525 } | 531 } |
526 | 532 |
527 void BrowserActionsContainer::Layout() { | 533 void BrowserActionsContainer::Layout() { |
528 if (browser_action_views_.empty()) { | 534 if (browser_action_views_.empty()) { |
529 SetVisible(false); | 535 SetVisible(false); |
530 chevron_->SetVisible(false); | |
531 return; | 536 return; |
532 } | 537 } |
533 | 538 |
534 SetVisible(true); | 539 SetVisible(true); |
| 540 resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing, |
| 541 IconHeight()); |
535 | 542 |
536 resize_area_->SetBounds(0, 0, kResizeAreaWidth, height()); | 543 // If the icons don't all fit, show the chevron (unless suppressed). |
537 int x = kResizeAreaWidth; | 544 int max_x = GetPreferredSize().width(); |
538 | 545 if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) { |
539 x += base::i18n::IsRTL() ? kHorizontalPaddingRtl : kHorizontalPadding; | |
540 | |
541 // Calculate if all icons fit without showing the chevron. We need to know | |
542 // this beforehand, because showing the chevron will decrease the space that | |
543 // we have to draw the visible ones (ie. if one icon is visible and another | |
544 // doesn't have enough room). | |
545 int last_x_of_icons = x + | |
546 (browser_action_views_.size() * kButtonSize) + | |
547 ((browser_action_views_.size() - 1) * | |
548 kBrowserActionButtonPadding); | |
549 | |
550 gfx::Size sz = GetPreferredSize(); | |
551 int max_x = sz.width() - kDividerHorizontalMargin - kChevronRightMargin; | |
552 | |
553 // If they don't all fit, show the chevron (unless suppressed). | |
554 if (last_x_of_icons >= max_x && !suppress_chevron_) { | |
555 chevron_->SetVisible(true); | 546 chevron_->SetVisible(true); |
556 gfx::Size chevron_size(chevron_->GetPreferredSize()); | 547 gfx::Size chevron_size(chevron_->GetPreferredSize()); |
557 max_x -= chevron_size.width(); | 548 max_x -= |
558 chevron_->SetBounds(width() - chevron_size.width() - kChevronRightMargin, | 549 ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing; |
559 kChevronTopMargin, | 550 chevron_->SetBounds( |
560 chevron_size.width(), chevron_size.height()); | 551 width() - ToolbarView::kStandardSpacing - chevron_size.width(), |
| 552 ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height()); |
561 } else { | 553 } else { |
562 chevron_->SetVisible(false); | 554 chevron_->SetVisible(false); |
563 } | 555 } |
564 | 556 |
565 // Now draw the icons for the browser actions in the available space. | 557 // Now draw the icons for the browser actions in the available space. |
| 558 int icon_width = IconWidth(false); |
566 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | 559 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
567 BrowserActionView* view = browser_action_views_[i]; | 560 BrowserActionView* view = browser_action_views_[i]; |
568 // Add padding between buttons if multiple buttons. | 561 int x = ToolbarView::kStandardSpacing + (i * IconWidth(true)); |
569 int padding = (i > 0) ? kBrowserActionButtonPadding : 0; | 562 if (x + icon_width <= max_x) { |
570 if (x + kButtonSize + padding < max_x) { | 563 view->SetBounds(x, 0, icon_width, height()); |
571 x += padding; | |
572 view->SetBounds(x, 0, kButtonSize, height()); | |
573 view->SetVisible(true); | 564 view->SetVisible(true); |
574 x += kButtonSize; | |
575 } else { | 565 } else { |
576 view->SetVisible(false); | 566 view->SetVisible(false); |
577 } | 567 } |
578 } | 568 } |
579 } | 569 } |
580 | 570 |
581 void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { | 571 void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { |
582 // The one-pixel themed vertical divider to the right of the browser actions. | |
583 int x = base::i18n::IsRTL() ? | |
584 kDividerHorizontalMargin : (width() - kDividerHorizontalMargin); | |
585 DetachableToolbarView::PaintVerticalDivider( | |
586 canvas, x, height(), kDividerVerticalPadding, | |
587 DetachableToolbarView::kEdgeDividerColor, | |
588 DetachableToolbarView::kMiddleDividerColor, | |
589 GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); | |
590 | |
591 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while | 572 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while |
592 // dragging (like we do for tab dragging). | 573 // dragging (like we do for tab dragging). |
593 if (drop_indicator_position_ > -1) { | 574 if (drop_indicator_position_ > -1) { |
594 // The two-pixel width drop indicator. | 575 // The two-pixel width drop indicator. |
595 static const int kDropIndicatorWidth = 2; | 576 static const int kDropIndicatorWidth = 2; |
596 gfx::Rect indicator_bounds( | 577 gfx::Rect indicator_bounds( |
597 drop_indicator_position_ - (kDropIndicatorWidth / 2), | 578 drop_indicator_position_ - (kDropIndicatorWidth / 2), |
598 kDividerVerticalPadding, kDropIndicatorWidth, | 579 ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight()); |
599 height() - (2 * kDividerVerticalPadding)); | |
600 | 580 |
601 // Color of the drop indicator. | 581 // Color of the drop indicator. |
602 static const SkColor kDropIndicatorColor = SK_ColorBLACK; | 582 static const SkColor kDropIndicatorColor = SK_ColorBLACK; |
603 canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(), | 583 canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(), |
604 indicator_bounds.y(), indicator_bounds.width(), | 584 indicator_bounds.y(), indicator_bounds.width(), |
605 indicator_bounds.height()); | 585 indicator_bounds.height()); |
606 } | 586 } |
607 } | 587 } |
608 | 588 |
609 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, | 589 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 int BrowserActionsContainer::OnDragUpdated( | 626 int BrowserActionsContainer::OnDragUpdated( |
647 const views::DropTargetEvent& event) { | 627 const views::DropTargetEvent& event) { |
648 // First check if we are above the chevron (overflow) menu. | 628 // First check if we are above the chevron (overflow) menu. |
649 if (GetViewForPoint(event.location()) == chevron_) { | 629 if (GetViewForPoint(event.location()) == chevron_) { |
650 if (show_menu_task_factory_.empty() && !overflow_menu_) | 630 if (show_menu_task_factory_.empty() && !overflow_menu_) |
651 StartShowFolderDropMenuTimer(); | 631 StartShowFolderDropMenuTimer(); |
652 return DragDropTypes::DRAG_MOVE; | 632 return DragDropTypes::DRAG_MOVE; |
653 } | 633 } |
654 StopShowFolderDropMenuTimer(); | 634 StopShowFolderDropMenuTimer(); |
655 | 635 |
656 // Modifying the x value before clamping affects how far you have to drag to | 636 // Figure out where to display the indicator. This is a complex calculation: |
657 // get the drop indicator to shift to another position. Modifying after | |
658 // clamping affects where the drop indicator is drawn. | |
659 | 637 |
660 // We add half a button size so that when you drag a button to the right and | 638 // First, we figure out how much space is to the left of the icon area, so we |
661 // you are half-way dragging across a button the drop indicator moves from the | 639 // can calculate the true offset into the icon area. |
662 // left of that button to the right of that button. | 640 int width_before_icons = ToolbarView::kStandardSpacing + |
663 int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding); | 641 (base::i18n::IsRTL() ? |
664 if (chevron_->IsVisible()) | 642 (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0); |
665 x += chevron_->bounds().width(); | 643 int offset_into_icon_area = event.x() - width_before_icons; |
666 x = ClampToNearestIconCount(x, false); | |
667 | 644 |
668 if (!base::i18n::IsRTL() && chevron_->IsVisible()) { | 645 // Next, we determine which icon to place the indicator in front of. We want |
669 // The clamping function includes the chevron width. In LTR locales, the | 646 // to place the indicator in front of icon n when the cursor is between the |
670 // chevron is on the right and we never want to account for its width. In | 647 // midpoints of icons (n - 1) and n. To do this we take the offset into the |
671 // RTL it is on the left and we always want to count the width. | 648 // icon area and transform it as follows: |
672 x -= chevron_->width(); | 649 // |
673 } | 650 // Real icon area: |
| 651 // 0 a * b c |
| 652 // | | | | |
| 653 // |[IC|ON] [IC|ON] [IC|ON] |
| 654 // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. |
| 655 // Here the "*" represents the offset into the icon area, and since it's |
| 656 // between a and b, we want to return "1". |
| 657 // |
| 658 // Transformed "icon area": |
| 659 // 0 a * b c |
| 660 // | | | | |
| 661 // |[ICON] |[ICON] |[ICON] | |
| 662 // If we shift both our offset and our divider points later by half an icon |
| 663 // plus one spacing unit, then it becomes very easy to calculate how many |
| 664 // divider points we've passed, because they're the multiples of "one icon |
| 665 // plus padding". |
| 666 int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + |
| 667 kItemSpacing) / IconWidth(true); |
674 | 668 |
675 // Clamping gives us a value where the next button will be drawn, but we want | 669 // Because the user can drag outside the container bounds, we need to clamp to |
676 // to subtract the padding (and then some) to make it appear in-between the | 670 // the valid range. Note that the maximum allowable value is (num icons), not |
677 // buttons. | 671 // (num icons - 1), because we represent the indicator being past the last |
678 SetDropIndicator(x - kBrowserActionButtonPadding - (base::i18n::IsRTL() ? | 672 // icon as being "before the (last + 1) icon". |
679 kDropIndicatorOffsetRtl : kDropIndicatorOffsetLtr)); | 673 int before_icon = std::min(std::max(before_icon_unclamped, 0), |
| 674 static_cast<int>(VisibleBrowserActions())); |
| 675 |
| 676 // Now we convert back to a pixel offset into the container. We want to place |
| 677 // the center of the drop indicator at the midpoint of the space before our |
| 678 // chosen icon. |
| 679 SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) - |
| 680 (kItemSpacing / 2)); |
| 681 |
680 return DragDropTypes::DRAG_MOVE; | 682 return DragDropTypes::DRAG_MOVE; |
681 } | 683 } |
682 | 684 |
683 void BrowserActionsContainer::OnDragExited() { | 685 void BrowserActionsContainer::OnDragExited() { |
684 StopShowFolderDropMenuTimer(); | 686 StopShowFolderDropMenuTimer(); |
685 drop_indicator_position_ = -1; | 687 drop_indicator_position_ = -1; |
686 SchedulePaint(); | 688 SchedulePaint(); |
687 } | 689 } |
688 | 690 |
689 int BrowserActionsContainer::OnPerformDrop( | 691 int BrowserActionsContainer::OnPerformDrop( |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 if (profile_->IsOffTheRecord()) | 723 if (profile_->IsOffTheRecord()) |
722 i = model_->IncognitoIndexToOriginal(i); | 724 i = model_->IncognitoIndexToOriginal(i); |
723 | 725 |
724 model_->MoveBrowserAction( | 726 model_->MoveBrowserAction( |
725 browser_action_views_[data.index()]->button()->extension(), i); | 727 browser_action_views_[data.index()]->button()->extension(), i); |
726 | 728 |
727 OnDragExited(); // Perform clean up after dragging. | 729 OnDragExited(); // Perform clean up after dragging. |
728 return DragDropTypes::DRAG_MOVE; | 730 return DragDropTypes::DRAG_MOVE; |
729 } | 731 } |
730 | 732 |
| 733 void BrowserActionsContainer::OnThemeChanged() { |
| 734 LoadImages(); |
| 735 } |
| 736 |
731 bool BrowserActionsContainer::GetAccessibleRole( | 737 bool BrowserActionsContainer::GetAccessibleRole( |
732 AccessibilityTypes::Role* role) { | 738 AccessibilityTypes::Role* role) { |
733 DCHECK(role); | 739 DCHECK(role); |
734 *role = AccessibilityTypes::ROLE_GROUPING; | 740 *role = AccessibilityTypes::ROLE_GROUPING; |
735 return true; | 741 return true; |
736 } | 742 } |
737 | 743 |
738 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { | 744 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { |
739 if (source == chevron_) { | 745 if (source == chevron_) { |
740 overflow_menu_ = new BrowserActionOverflowMenuController( | 746 overflow_menu_ = new BrowserActionOverflowMenuController( |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 return DragDropTypes::DRAG_MOVE; | 778 return DragDropTypes::DRAG_MOVE; |
773 } | 779 } |
774 | 780 |
775 bool BrowserActionsContainer::CanStartDrag(View* sender, | 781 bool BrowserActionsContainer::CanStartDrag(View* sender, |
776 const gfx::Point& press_pt, | 782 const gfx::Point& press_pt, |
777 const gfx::Point& p) { | 783 const gfx::Point& p) { |
778 return true; | 784 return true; |
779 } | 785 } |
780 | 786 |
781 void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { | 787 void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { |
782 if (!done_resizing) { | 788 if (done_resizing) { |
| 789 // Up until now we've only been modifying the resize_amount, but now it is |
| 790 // time to set the container size to the size we have resized to, and then |
| 791 // animate to the nearest icon count size if necessary (which may be 0). |
| 792 int max_width = IconCountToWidth(-1, false); |
| 793 container_width_ = |
| 794 std::min(std::max(0, container_width_ - resize_amount), max_width); |
| 795 if (container_width_ < max_width) { |
| 796 animation_target_size_ = |
| 797 IconCountToWidth(WidthToIconCount(container_width_), true); |
| 798 resize_animation_->Reset(); |
| 799 resize_animation_->SetTweenType(Tween::EASE_OUT); |
| 800 resize_animation_->Show(); |
| 801 return; |
| 802 } |
| 803 } else { |
783 resize_amount_ = resize_amount; | 804 resize_amount_ = resize_amount; |
784 OnBrowserActionVisibilityChanged(); | |
785 } else { | |
786 // For details on why we do the following see the class comments in the | |
787 // header. | |
788 | |
789 // Clamp lower limit to 0 and upper limit to the amount that allows enough | |
790 // room for all icons to show. | |
791 int new_width = std::max(0, container_width_ - resize_amount); | |
792 int max_width = ClampToNearestIconCount(-1, false); | |
793 new_width = std::min(new_width, max_width); | |
794 | |
795 // Up until now we've only been modifying the resize_amount, but now it is | |
796 // time to set the container size to the size we have resized to, but then | |
797 // animate to the nearest icon count size (or down to min size if no icon). | |
798 container_width_ = new_width; | |
799 animation_target_size_ = ClampToNearestIconCount(new_width, true); | |
800 resize_animation_->Reset(); | |
801 resize_animation_->SetTweenType(Tween::EASE_OUT); | |
802 resize_animation_->Show(); | |
803 } | 805 } |
| 806 OnBrowserActionVisibilityChanged(); |
804 } | 807 } |
805 | 808 |
806 void BrowserActionsContainer::AnimationProgressed(const Animation* animation) { | 809 void BrowserActionsContainer::AnimationProgressed(const Animation* animation) { |
807 DCHECK_EQ(resize_animation_.get(), animation); | 810 DCHECK_EQ(resize_animation_.get(), animation); |
808 resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() * | 811 resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() * |
809 (container_width_ - animation_target_size_)); | 812 (container_width_ - animation_target_size_)); |
810 OnBrowserActionVisibilityChanged(); | 813 OnBrowserActionVisibilityChanged(); |
811 } | 814 } |
812 | 815 |
813 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { | 816 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
852 } | 855 } |
853 } | 856 } |
854 | 857 |
855 void BrowserActionsContainer::HidePopup() { | 858 void BrowserActionsContainer::HidePopup() { |
856 if (popup_) | 859 if (popup_) |
857 popup_->Close(); | 860 popup_->Close(); |
858 } | 861 } |
859 | 862 |
860 void BrowserActionsContainer::TestExecuteBrowserAction(int index) { | 863 void BrowserActionsContainer::TestExecuteBrowserAction(int index) { |
861 BrowserActionButton* button = browser_action_views_[index]->button(); | 864 BrowserActionButton* button = browser_action_views_[index]->button(); |
862 OnBrowserActionExecuted(button, false); // |inspect_with_devtools|. | 865 OnBrowserActionExecuted(button, false); |
863 } | 866 } |
864 | 867 |
865 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { | 868 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { |
| 869 model_->SetVisibleIconCount(icons); |
866 chevron_->SetVisible(icons < browser_action_views_.size()); | 870 chevron_->SetVisible(icons < browser_action_views_.size()); |
867 container_width_ = IconCountToWidth(icons); | 871 container_width_ = IconCountToWidth(icons, chevron_->IsVisible()); |
868 Layout(); | 872 Layout(); |
869 SchedulePaint(); | 873 SchedulePaint(); |
870 } | 874 } |
871 | 875 |
| 876 // static |
| 877 int BrowserActionsContainer::IconWidth(bool include_padding) { |
| 878 static bool initialized = false; |
| 879 static int icon_width = 0; |
| 880 if (!initialized) { |
| 881 initialized = true; |
| 882 icon_width = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 883 IDR_BROWSER_ACTION)->width(); |
| 884 } |
| 885 return icon_width + (include_padding ? kItemSpacing : 0); |
| 886 } |
| 887 |
| 888 // static |
| 889 int BrowserActionsContainer::IconHeight() { |
| 890 static bool initialized = false; |
| 891 static int icon_height = 0; |
| 892 if (!initialized) { |
| 893 initialized = true; |
| 894 icon_height = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 895 IDR_BROWSER_ACTION)->height(); |
| 896 } |
| 897 return icon_height; |
| 898 } |
| 899 |
872 void BrowserActionsContainer::BrowserActionAdded(Extension* extension, | 900 void BrowserActionsContainer::BrowserActionAdded(Extension* extension, |
873 int index) { | 901 int index) { |
874 #if defined(DEBUG) | 902 #if defined(DEBUG) |
875 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | 903 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
876 DCHECK(browser_action_views_[i]->button()->extension() != extension) << | 904 DCHECK(browser_action_views_[i]->button()->extension() != extension) << |
877 "Asked to add a browser action view for an extension that already " | 905 "Asked to add a browser action view for an extension that already " |
878 "exists."; | 906 "exists."; |
879 } | 907 } |
880 #endif | 908 #endif |
881 CloseOverflowMenu(); | 909 CloseOverflowMenu(); |
882 | 910 |
883 if (!ShouldDisplayBrowserAction(extension)) | 911 if (!ShouldDisplayBrowserAction(extension)) |
884 return; | 912 return; |
885 | 913 |
886 size_t visible_actions = VisibleBrowserActions(); | 914 size_t visible_actions = VisibleBrowserActions(); |
887 | 915 |
888 // Add the new browser action to the vector and the view hierarchy. | 916 // Add the new browser action to the vector and the view hierarchy. |
889 if (profile_->IsOffTheRecord()) | 917 if (profile_->IsOffTheRecord()) |
890 index = model_->OriginalIndexToIncognito(index); | 918 index = model_->OriginalIndexToIncognito(index); |
891 | |
892 BrowserActionView* view = new BrowserActionView(extension, this); | 919 BrowserActionView* view = new BrowserActionView(extension, this); |
893 browser_action_views_.insert(browser_action_views_.begin() + index, view); | 920 browser_action_views_.insert(browser_action_views_.begin() + index, view); |
894 AddChildView(index, view); | 921 AddChildView(index, view); |
895 | 922 |
896 // If we are still initializing the container, don't bother animating. | 923 // If we are still initializing the container, don't bother animating. |
897 if (!model_->extensions_initialized()) | 924 if (!model_->extensions_initialized()) |
898 return; | 925 return; |
899 | 926 |
900 // For details on why we do the following see the class comments in the | 927 // Enlarge the container if it was already at maximum size and we're not in |
901 // header. | 928 // the middle of upgrading. |
902 | 929 if ((model_->GetVisibleIconCount() < 0) && !extension->being_upgraded()) { |
903 // Determine if we need to increase (we only do that if the container was | 930 int target_size = IconCountToWidth(visible_actions + 1, false); |
904 // showing all icons before the addition of this icon). | 931 suppress_chevron_ = true; |
905 if (model_->GetVisibleIconCount() >= 0 || extension->being_upgraded()) { | 932 Animate(Tween::LINEAR, target_size); |
906 // Some icons were hidden, don't increase the size of the container. | 933 } else { |
| 934 // Just redraw the (possibly modified) visible icon set. |
907 OnBrowserActionVisibilityChanged(); | 935 OnBrowserActionVisibilityChanged(); |
908 } else { | |
909 // Container was at max, increase the size of it by one icon. | |
910 int target_size = IconCountToWidth(visible_actions + 1); | |
911 | |
912 // We don't want the chevron to appear while we animate. See documentation | |
913 // in the header for why we do this. | |
914 suppress_chevron_ = !chevron_->IsVisible(); | |
915 | |
916 Animate(Tween::LINEAR, target_size); | |
917 } | 936 } |
918 } | 937 } |
919 | 938 |
920 void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { | 939 void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { |
921 CloseOverflowMenu(); | 940 CloseOverflowMenu(); |
922 | 941 |
923 if (popup_ && popup_->host()->extension() == extension) | 942 if (popup_ && popup_->host()->extension() == extension) |
924 HidePopup(); | 943 HidePopup(); |
925 | 944 |
926 size_t visible_actions = VisibleBrowserActions(); | 945 size_t visible_actions = VisibleBrowserActions(); |
927 for (BrowserActionViews::iterator iter = browser_action_views_.begin(); | 946 for (BrowserActionViews::iterator iter = browser_action_views_.begin(); |
928 iter != browser_action_views_.end(); ++iter) { | 947 iter != browser_action_views_.end(); ++iter) { |
929 if ((*iter)->button()->extension() == extension) { | 948 if ((*iter)->button()->extension() == extension) { |
930 RemoveChildView(*iter); | 949 RemoveChildView(*iter); |
931 delete *iter; | 950 delete *iter; |
932 browser_action_views_.erase(iter); | 951 browser_action_views_.erase(iter); |
933 | 952 |
934 // If the extension is being upgraded we don't want the bar to shrink | 953 // If the extension is being upgraded we don't want the bar to shrink |
935 // because the icon is just going to get re-added to the same location. | 954 // because the icon is just going to get re-added to the same location. |
936 if (extension->being_upgraded()) | 955 if (extension->being_upgraded()) |
937 return; | 956 return; |
938 | 957 |
939 // For details on why we do the following see the class comments in the | 958 if (browser_action_views_.size() > visible_actions) { |
940 // header. | 959 // If we have more icons than we can show, then we must not be changing |
941 | 960 // the container size (since we either removed an icon from the main |
942 // Calculate the target size we'll animate to (end state). This might be | 961 // area and one from the overflow list will have shifted in, or we |
943 // the same size (if the icon we are removing is in the overflow bucket | 962 // removed an entry directly from the overflow list). |
944 // and there are other icons there). We don't decrement visible_actions | 963 OnBrowserActionVisibilityChanged(); |
945 // because we want the container to stay the same size (clamping will take | 964 } else { |
946 // care of shrinking the container if there aren't enough icons to show). | 965 // Either we went from overflow to no-overflow, or we shrunk the no- |
947 int target_size = | 966 // overflow container by 1. Either way the size changed, so animate. |
948 ClampToNearestIconCount(IconCountToWidth(visible_actions), true); | 967 chevron_->SetVisible(false); |
949 | 968 Animate(Tween::EASE_OUT, IconCountToWidth(-1, false)); |
950 Animate(Tween::EASE_OUT, target_size); | 969 } |
951 return; | 970 return; |
952 } | 971 } |
953 } | 972 } |
954 } | 973 } |
955 | 974 |
956 void BrowserActionsContainer::BrowserActionMoved(Extension* extension, | 975 void BrowserActionsContainer::BrowserActionMoved(Extension* extension, |
957 int index) { | 976 int index) { |
958 if (!ShouldDisplayBrowserAction(extension)) | 977 if (!ShouldDisplayBrowserAction(extension)) |
959 return; | 978 return; |
960 | 979 |
961 if (profile_->IsOffTheRecord()) | 980 if (profile_->IsOffTheRecord()) |
962 index = model_->OriginalIndexToIncognito(index); | 981 index = model_->OriginalIndexToIncognito(index); |
963 | 982 |
964 DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size())); | 983 DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size())); |
965 | 984 |
966 DeleteBrowserActionViews(); | 985 DeleteBrowserActionViews(); |
967 CreateBrowserActionViews(); | 986 CreateBrowserActionViews(); |
968 Layout(); | 987 Layout(); |
969 SchedulePaint(); | 988 SchedulePaint(); |
970 } | 989 } |
971 | 990 |
972 void BrowserActionsContainer::ModelLoaded() { | 991 void BrowserActionsContainer::ModelLoaded() { |
973 SetContainerWidth(); | 992 SetContainerWidth(); |
974 } | 993 } |
975 | 994 |
| 995 void BrowserActionsContainer::LoadImages() { |
| 996 ThemeProvider* tp = GetThemeProvider(); |
| 997 chevron_->SetIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW)); |
| 998 chevron_->SetHoverIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_H)); |
| 999 chevron_->SetPushedIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_P)); |
| 1000 } |
| 1001 |
976 void BrowserActionsContainer::SetContainerWidth() { | 1002 void BrowserActionsContainer::SetContainerWidth() { |
977 int visible_actions = model_->GetVisibleIconCount(); | 1003 int visible_actions = model_->GetVisibleIconCount(); |
978 if (visible_actions < 0) // All icons should be visible. | 1004 if (visible_actions < 0) // All icons should be visible. |
979 visible_actions = model_->size(); | 1005 visible_actions = model_->size(); |
980 chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size()); | 1006 chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size()); |
981 container_width_ = IconCountToWidth(visible_actions); | 1007 container_width_ = IconCountToWidth(visible_actions, chevron_->IsVisible()); |
982 } | 1008 } |
983 | 1009 |
984 void BrowserActionsContainer::CloseOverflowMenu() { | 1010 void BrowserActionsContainer::CloseOverflowMenu() { |
985 if (overflow_menu_) | 1011 if (overflow_menu_) |
986 overflow_menu_->CancelMenu(); | 1012 overflow_menu_->CancelMenu(); |
987 } | 1013 } |
988 | 1014 |
989 void BrowserActionsContainer::StopShowFolderDropMenuTimer() { | 1015 void BrowserActionsContainer::StopShowFolderDropMenuTimer() { |
990 show_menu_task_factory_.RevokeAll(); | 1016 show_menu_task_factory_.RevokeAll(); |
991 } | 1017 } |
(...skipping 15 matching lines...) Expand all Loading... |
1007 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true); | 1033 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true); |
1008 } | 1034 } |
1009 | 1035 |
1010 void BrowserActionsContainer::SetDropIndicator(int x_pos) { | 1036 void BrowserActionsContainer::SetDropIndicator(int x_pos) { |
1011 if (drop_indicator_position_ != x_pos) { | 1037 if (drop_indicator_position_ != x_pos) { |
1012 drop_indicator_position_ = x_pos; | 1038 drop_indicator_position_ = x_pos; |
1013 SchedulePaint(); | 1039 SchedulePaint(); |
1014 } | 1040 } |
1015 } | 1041 } |
1016 | 1042 |
1017 int BrowserActionsContainer::ClampToNearestIconCount( | 1043 int BrowserActionsContainer::IconCountToWidth(int icons, |
1018 int pixelWidth, | 1044 bool display_chevron) const { |
1019 bool allow_shrink_to_minimum) const { | 1045 if (icons < 0) |
1020 // Calculate the width of one icon. | 1046 icons = browser_action_views_.size(); |
1021 int icon_width = (kButtonSize + kBrowserActionButtonPadding); | 1047 if ((icons == 0) && !display_chevron) |
1022 | 1048 return ToolbarView::kStandardSpacing; |
1023 // Calculate pixel count for the area not used by the icons. | 1049 int icons_size = |
1024 int extras = WidthOfNonIconArea(); | 1050 (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing); |
1025 | 1051 int chevron_size = display_chevron ? |
1026 size_t icon_count = 0u; | 1052 (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0; |
1027 if (pixelWidth >= 0) { | 1053 return ToolbarView::kStandardSpacing + icons_size + chevron_size + |
1028 // Caller wants to know how many icons fit within a given space so we start | 1054 ToolbarView::kStandardSpacing; |
1029 // by subtracting the padding, resize area and dividers. | |
1030 int icon_area = pixelWidth - extras; | |
1031 icon_area = std::max(0, icon_area); | |
1032 | |
1033 // Make sure we never throw an icon into the chevron menu just because | |
1034 // there isn't enough enough space for the invisible padding around buttons. | |
1035 icon_area += kBrowserActionButtonPadding - 1; | |
1036 | |
1037 // Count the number of icons that fit within that area. | |
1038 icon_count = icon_area / icon_width; | |
1039 | |
1040 if (icon_count == 0 && allow_shrink_to_minimum) { | |
1041 extras = ContainerMinSize(); // Allow very narrow width if no icons. | |
1042 } else if (icon_count > browser_action_views_.size()) { | |
1043 // No use allowing more than what we have. | |
1044 icon_count = browser_action_views_.size(); | |
1045 } | |
1046 } else { | |
1047 // A negative |pixels| count indicates caller wants to know the max width | |
1048 // that fits all icons; | |
1049 icon_count = browser_action_views_.size(); | |
1050 } | |
1051 | |
1052 return extras + (icon_count * icon_width); | |
1053 } | 1055 } |
1054 | 1056 |
1055 int BrowserActionsContainer::WidthOfNonIconArea() const { | 1057 int BrowserActionsContainer::WidthToIconCount(int pixels) const { |
1056 int chevron_size = (chevron_->IsVisible()) ? | 1058 // We need to reserve space for the resize area, chevron, and the spacing on |
1057 chevron_->GetPreferredSize().width() : 0; | 1059 // either side of the chevron. |
1058 int padding = base::i18n::IsRTL() ? | 1060 int available_space = pixels - ToolbarView::kStandardSpacing - |
1059 kHorizontalPaddingRtl : kHorizontalPadding; | 1061 chevron_->GetPreferredSize().width() - kChevronSpacing - |
1060 return kResizeAreaWidth + padding + chevron_size + kChevronRightMargin + | 1062 ToolbarView::kStandardSpacing; |
1061 kDividerHorizontalMargin; | 1063 // Now we add an extra between-item padding value so the space can be divided |
1062 } | 1064 // evenly by (size of icon with padding). |
1063 | 1065 return std::max(0, available_space + kItemSpacing) / IconWidth(true); |
1064 int BrowserActionsContainer::IconCountToWidth(int icons) const { | |
1065 DCHECK_GE(icons, 0); | |
1066 if (icons == 0) | |
1067 return ContainerMinSize(); | |
1068 | |
1069 int icon_width = kButtonSize + kBrowserActionButtonPadding; | |
1070 | |
1071 return WidthOfNonIconArea() + (icons * icon_width); | |
1072 } | 1066 } |
1073 | 1067 |
1074 int BrowserActionsContainer::ContainerMinSize() const { | 1068 int BrowserActionsContainer::ContainerMinSize() const { |
1075 return kResizeAreaWidth + chevron_->width() + kChevronRightMargin; | 1069 return ToolbarView::kStandardSpacing + kChevronSpacing + |
| 1070 chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing; |
1076 } | 1071 } |
1077 | 1072 |
1078 void BrowserActionsContainer::Animate(Tween::Type tween_type, int target_size) { | 1073 void BrowserActionsContainer::Animate(Tween::Type tween_type, int target_size) { |
1079 if (!disable_animations_during_testing_) { | 1074 if (!disable_animations_during_testing_) { |
1080 // Animate! We have to set the animation_target_size_ after calling Reset(), | 1075 // Animate! We have to set the animation_target_size_ after calling Reset(), |
1081 // because that could end up calling AnimationEnded which clears the value. | 1076 // because that could end up calling AnimationEnded which clears the value. |
1082 resize_animation_->Reset(); | 1077 resize_animation_->Reset(); |
1083 resize_animation_->SetTweenType(tween_type); | 1078 resize_animation_->SetTweenType(tween_type); |
1084 animation_target_size_ = target_size; | 1079 animation_target_size_ = target_size; |
1085 resize_animation_->Show(); | 1080 resize_animation_->Show(); |
1086 } else { | 1081 } else { |
1087 animation_target_size_ = target_size; | 1082 animation_target_size_ = target_size; |
1088 AnimationEnded(resize_animation_.get()); | 1083 AnimationEnded(resize_animation_.get()); |
1089 } | 1084 } |
1090 } | 1085 } |
1091 | 1086 |
1092 bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) { | 1087 bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) { |
1093 // Only display incognito-enabled extensions while in incognito mode. | 1088 // Only display incognito-enabled extensions while in incognito mode. |
1094 return (!profile_->IsOffTheRecord() || | 1089 return (!profile_->IsOffTheRecord() || |
1095 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); | 1090 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); |
1096 } | 1091 } |
OLD | NEW |