| 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 |