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