172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/browser_actions_container.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_browser_event_router.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_host.h" 1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tabs_module.h" 1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h" 1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/view_ids.h" 1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/detachable_toolbar_view.h" 1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h" 2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/extensions/extension_popup.h" 2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/toolbar_view.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_action.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_resource.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h" 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h" 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/effects/SkGradientShader.h" 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/accessibility/accessible_view_state.h" 353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h" 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/theme_provider.h" 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h" 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h" 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/menu_button.h" 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/text_button.h" 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/menu/menu_2.h" 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/drag_utils.h" 45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "views/metrics.h" 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window.h" 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Horizontal spacing between most items in the container, as well as after the 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// last item or chevron (if visible). 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const int kItemSpacing = ToolbarView::kStandardSpacing; 533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Horizontal spacing before the chevron (if visible). 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const int kChevronSpacing = kItemSpacing - 2; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionsContainer::disable_animations_during_testing_ = false; 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BrowserActionButton 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 62513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBrowserActionButton::BrowserActionButton(const Extension* extension, 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionsContainer* panel) 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : ALLOW_THIS_IN_INITIALIZER_LIST( 653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick MenuButton(this, std::wstring(), NULL, false)), 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_(extension->browser_action()), 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_(extension), 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch showing_context_menu_(false), 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_(panel) { 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick set_border(NULL); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_alignment(TextButton::ALIGN_CENTER); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No UpdateState() here because View hierarchy not setup yet. Our parent 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // should call UpdateState() after creation. 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<ExtensionAction>(browser_action_)); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::Destroy() { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (showing_context_menu_) { 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch context_menu_menu_->CancelMenu(); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->DeleteSoon(FROM_HERE, this); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid BrowserActionButton::ViewHierarchyChanged( 91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick bool is_add, View* parent, View* child) { 92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (is_add && child == this) { 93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // The Browser Action API does not allow the default icon path to be 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // changed at runtime, so we can load this now and cache it. 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string relative_path = browser_action_->default_icon_path(); 96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (relative_path.empty()) 97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return; 98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // LoadImage is not guaranteed to be synchronous, so we might see the 100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // callback OnImageLoaded execute immediately. It (through UpdateState) 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // expects parent() to return the owner for this button, so this 102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // function is as early as we can start this request. 103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick tracker_.LoadImage(extension_, extension_->GetResource(relative_path), 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick gfx::Size(Extension::kBrowserActionIconMaxSize, 105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Extension::kBrowserActionIconMaxSize), 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ImageLoadingTracker::DONT_CACHE); 107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick MenuButton::ViewHierarchyChanged(is_add, parent, child); 110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::ButtonPressed(views::Button* sender, 1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const views::Event& event) { 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick panel_->OnBrowserActionExecuted(this, false); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionButton::OnImageLoaded(SkBitmap* image, 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const ExtensionResource& resource, 1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int index) { 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (image) 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_icon_ = *image; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call back to UpdateState() because a more specific icon might have been set 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // while the load was outstanding. 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateState(); 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::UpdateState() { 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = panel_->GetCurrentTabId(); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_id < 0) 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap icon(browser_action()->GetIcon(tab_id)); 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (icon.isNull()) 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick icon = default_icon_; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!icon.isNull()) { 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkPaint paint; 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap bg; 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg, 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap::kARGB_8888_Config); 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkCanvas bg_canvas(bg); 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2), 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkIntToScalar((bg.height() - icon.height()) / 2), &paint); 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetIcon(bg); 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap bg_h; 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h, 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap::kARGB_8888_Config); 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkCanvas bg_h_canvas(bg_h); 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bg_h_canvas.drawBitmap(icon, 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkIntToScalar((bg_h.width() - icon.width()) / 2), 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint); 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetHoverIcon(bg_h); 1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap bg_p; 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p, 1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkBitmap::kARGB_8888_Config); 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkCanvas bg_p_canvas(bg_p); 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bg_p_canvas.drawBitmap(icon, 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkIntToScalar((bg_p.width() - icon.width()) / 2), 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint); 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetPushedIcon(bg_p); 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the browser action name is empty, show the extension name instead. 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 name = UTF8ToUTF16(browser_action()->GetTitle(tab_id)); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (name.empty()) 17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen name = UTF8ToUTF16(extension()->name()); 17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SetTooltipText(UTF16ToWideHack(name)); 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent()->SchedulePaint(); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionButton::IsPopup() { 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = panel_->GetCurrentTabId(); 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGURL BrowserActionButton::GetPopupUrl() { 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = panel_->GetCurrentTabId(); 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionButton::Observe(NotificationType type, 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const NotificationSource& source, 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const NotificationDetails& details) { 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED); 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UpdateState(); 191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The browser action may have become visible/hidden so we need to make 192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // sure the state gets updated. 193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen panel_->OnBrowserActionVisibilityChanged(); 194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionButton::Activate() { 1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!IsPopup()) 1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick panel_->OnBrowserActionExecuted(this, false); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(erikkay): Run a nested modal loop while the mouse is down to 2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // enable menu-like drag-select behavior. 2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The return value of this method is returned via OnMousePressed. 2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We need to return false here since we're handing off focus to another 2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // widget/view, and true will grab it right back and try to send events 2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // to us. 2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BrowserActionButton::OnMousePressed(const views::MouseEvent& event) { 213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!event.IsRightMouseButton()) { 2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return IsPopup() ? 215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MenuButton::OnMousePressed(event) : TextButton::OnMousePressed(event); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Get the top left point of this button in screen coordinates. 2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Point point = gfx::Point(0, 0); 2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ConvertPointToScreen(this, &point); 2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Make the menu appear below the button. 2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick point.Offset(0, height()); 2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ShowContextMenu(point, true); 2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionButton::OnMouseReleased(const views::MouseEvent& event) { 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsPopup() || showing_context_menu_) { 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(erikkay) this never actually gets called (probably because of the 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // loss of focus). 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MenuButton::OnMouseReleased(event); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TextButton::OnMouseReleased(event); 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionButton::OnMouseExited(const views::MouseEvent& event) { 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsPopup() || showing_context_menu_) 241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MenuButton::OnMouseExited(event); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TextButton::OnMouseExited(event); 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BrowserActionButton::OnKeyReleased(const views::KeyEvent& event) { 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return IsPopup() ? 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MenuButton::OnKeyReleased(event) : TextButton::OnKeyReleased(event); 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::ShowContextMenu(const gfx::Point& p, 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_mouse_gesture) { 25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!extension()->ShowConfigureContextMenus()) 25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch showing_context_menu_ = true; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetButtonPushed(); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Reconstructs the menu every time because the menu's contents are dynamic. 2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick context_menu_contents_ = 2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick new ExtensionContextMenuModel(extension(), panel_->browser(), panel_); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get())); 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch context_menu_menu_->RunContextMenuAt(p); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetButtonNotPushed(); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch showing_context_menu_ = false; 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::SetButtonPushed() { 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetState(views::CustomButton::BS_PUSHED); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch menu_visible_ = true; 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionButton::SetButtonNotPushed() { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetState(views::CustomButton::BS_NORMAL); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch menu_visible_ = false; 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionButton::~BrowserActionButton() { 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BrowserActionView 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBrowserActionView::BrowserActionView(const Extension* extension, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionsContainer* panel) 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : panel_(panel) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch button_ = new BrowserActionButton(extension, panel); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch button_->SetDragController(panel_); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(button_); 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch button_->UpdateState(); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionView::~BrowserActionView() { 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveChildView(button_); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch button_->Destroy(); 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Canvas* BrowserActionView::GetIconWithBadge() { 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = panel_->GetCurrentTabId(); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (icon.isNull()) 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon = button_->default_icon(); 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Canvas* canvas = new gfx::CanvasSkia(icon.width(), icon.height(), false); 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->DrawBitmapInt(icon, 0, 0); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_id >= 0) { 3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing); 3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id); 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return canvas; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionView::Layout() { 3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We can't rely on button_->GetPreferredSize() here because that's not set 3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // correctly until the first call to 3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be 3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // called before that when the initial bounds are set (and then not after, 3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // since the bounds don't change). So instead of setting the height from the 3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // button's preferred size, we use IconHeight(), since that's how big the 3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // button should be regardless of what it's displaying. 3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick button_->SetBounds(0, ToolbarView::kVertSpacing, width(), 3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BrowserActionsContainer::IconHeight()); 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionView::GetAccessibleState(ui::AccessibleViewState* state) { 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->name = l10n_util::GetStringUTF16( 332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION); 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->role = ui::AccessibilityTypes::ROLE_GROUPING; 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionView::PaintChildren(gfx::Canvas* canvas) { 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch View::PaintChildren(canvas); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionAction* action = button()->browser_action(); 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = panel_->GetCurrentTabId(); 3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (tab_id >= 0) 3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BrowserActionsContainer 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBrowserActionsContainer::BrowserActionsContainer(Browser* browser, 3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick View* owner_view) 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : profile_(browser->profile()), 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_(browser), 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch owner_view_(owner_view), 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_(NULL), 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_button_(NULL), 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_(NULL), 3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick container_width_(0), 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chevron_(NULL), 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch overflow_menu_(NULL), 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suppress_chevron_(false), 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_amount_(0), 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_target_size_(0), 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_position_(-1), 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (profile_->GetExtensionService()) { 36721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen model_ = profile_->GetExtensionService()->toolbar_model(); 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->AddObserver(this); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen resize_animation_.reset(new ui::SlideAnimation(this)); 3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resize_area_ = new views::ResizeArea(this); 3733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AddChildView(resize_area_); 3743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); 3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->set_border(NULL); 3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->EnableCanvasFlippingForRTLUI(true); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chevron_->SetAccessibleName( 37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS_CHEVRON)); 3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetVisible(false); 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(chevron_); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionsContainer::~BrowserActionsContainer() { 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (model_) 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->RemoveObserver(this); 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopShowFolderDropMenuTimer(); 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HidePopup(); 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteBrowserActionViews(); 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static. 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::Init() { 3983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick LoadImages(); 3993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We wait to set the container width until now so that the chevron images 4013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // will be loaded. The width calculation needs to know the chevron size. 4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (model_ && 4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { 4043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Migration code to the new VisibleIconCount pref. 4053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(mpcomplete): remove this after users are upgraded to 5.0. 4063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int predefined_width = 4073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); 4083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (predefined_width != 0) 4093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick model_->SetVisibleIconCount(WidthToIconCount(predefined_width)); 4103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (model_ && model_->extensions_initialized()) 4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetContainerWidth(); 4133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 4143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserActionsContainer::GetCurrentTabId() const { 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContents* tab_contents = browser_->GetSelectedTabContents(); 4173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return tab_contents ? tab_contents->controller().session_id().id() : -1; 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionView* BrowserActionsContainer::GetBrowserActionView( 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionAction* action) { 4223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (BrowserActionViews::iterator iter = browser_action_views_.begin(); 4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick iter != browser_action_views_.end(); ++iter) { 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*iter)->button()->browser_action() == action) 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return *iter; 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::RefreshBrowserActionViews() { 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < browser_action_views_.size(); ++i) 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_[i]->button()->UpdateState(); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::CreateBrowserActionViews() { 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(browser_action_views_.empty()); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!model_) 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (ExtensionList::iterator iter = model_->begin(); iter != model_->end(); 4413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ++iter) { 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ShouldDisplayBrowserAction(*iter)) 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionView* view = new BrowserActionView(*iter, this); 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_.push_back(view); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(view); 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::DeleteBrowserActionViews() { 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!browser_action_views_.empty()) { 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < browser_action_views_.size(); ++i) 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveChildView(browser_action_views_[i]); 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteContainerPointers(browser_action_views_.begin(), 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_.end()); 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_.clear(); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::OnBrowserActionVisibilityChanged() { 4623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetVisible(!browser_action_views_.empty()); 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch owner_view_->Layout(); 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch owner_view_->SchedulePaint(); 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricksize_t BrowserActionsContainer::VisibleBrowserActions() const { 4683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t visible_actions = 0; 4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (size_t i = 0; i < browser_action_views_.size(); ++i) { 4703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (browser_action_views_[i]->IsVisible()) 4713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ++visible_actions; 4723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return visible_actions; 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::OnBrowserActionExecuted( 4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BrowserActionButton* button, 4783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool inspect_with_devtools) { 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionAction* browser_action = button->browser_action(); 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Popups just display. No notification to the extension. 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(erikkay): should there be? 4833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!button->IsPopup()) { 48472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionService* service = profile_->GetExtensionService(); 48572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen service->browser_event_router()->BrowserActionExecuted( 4863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_, browser_action->extension_id(), browser_); 4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If we're showing the same popup, just hide it and return. 4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool same_showing = popup_ && button == popup_button_; 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Always hide the current popup, even if it's not the same. 4943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Only one popup should be visible at a time. 4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HidePopup(); 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (same_showing) 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We can get the execute event for browser actions that are not visible, 5013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // since buttons can be activated from the overflow menu (chevron). In that 5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // case we show the popup as originating from the chevron. 50372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen View* reference_view = button->parent()->IsVisible() ? button : chevron_; 5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Point origin; 5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick View::ConvertPointToScreen(reference_view, &origin); 5063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Rect rect = reference_view->bounds(); 5073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rect.set_origin(origin); 5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 5093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BubbleBorder::ArrowLocation arrow_location = base::i18n::IsRTL() ? 5103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; 5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 51272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_, rect, 51372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen arrow_location, inspect_with_devtools, 51472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen this); 5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_button_ = button; 5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_button_->SetButtonPushed(); 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size BrowserActionsContainer::GetPreferredSize() { 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (browser_action_views_.empty()) 5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return gfx::Size(ToolbarView::kStandardSpacing, 0); 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We calculate the size of the view by taking the current width and 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // subtracting resize_amount_ (the latter represents how far the user is 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // resizing the view or, if animating the snapping, how far to animate it). 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // But we also clamp it to a minimum size and the maximum size, so that the 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // container can never shrink too far or take up more space than it needs. In 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). 5293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int clamped_width = std::min( 5303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::max(ContainerMinSize(), container_width_ - resize_amount_), 5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IconCountToWidth(-1, false)); 5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return gfx::Size(clamped_width, 0); 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::Layout() { 5363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (browser_action_views_.empty()) { 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetVisible(false); 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetVisible(true); 5423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing, 5433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IconHeight()); 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the icons don't all fit, show the chevron (unless suppressed). 5463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int max_x = GetPreferredSize().width(); 5473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) { 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chevron_->SetVisible(true); 5493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Size chevron_size(chevron_->GetPreferredSize()); 5503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick max_x -= 5513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing; 5523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetBounds( 5533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick width() - ToolbarView::kStandardSpacing - chevron_size.width(), 5543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height()); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chevron_->SetVisible(false); 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now draw the icons for the browser actions in the available space. 5603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int icon_width = IconWidth(false); 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < browser_action_views_.size(); ++i) { 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionView* view = browser_action_views_[i]; 5633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int x = ToolbarView::kStandardSpacing + (i * IconWidth(true)); 5643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (x + icon_width <= max_x) { 5653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick view->SetBounds(x, 0, icon_width, height()); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->SetVisible(true); 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->SetVisible(false); 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionsContainer::GetDropFormats( 5743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int* formats, 5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::set<OSExchangeData::CustomFormat>* custom_formats) { 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat()); 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionsContainer::AreDropTypesRequired() { 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionsContainer::CanDrop(const OSExchangeData& data) { 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionDragData drop_data; 5873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return drop_data.Read(data) ? drop_data.IsFromProfile(profile_) : false; 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::OnDragEntered( 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const views::DropTargetEvent& event) { 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserActionsContainer::OnDragUpdated( 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const views::DropTargetEvent& event) { 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First check if we are above the chevron (overflow) menu. 597dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (GetEventHandlerForPoint(event.location()) == chevron_) { 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (show_menu_task_factory_.empty() && !overflow_menu_) 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartShowFolderDropMenuTimer(); 60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ui::DragDropTypes::DRAG_MOVE; 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 6023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StopShowFolderDropMenuTimer(); 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Figure out where to display the indicator. This is a complex calculation: 6053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // First, we figure out how much space is to the left of the icon area, so we 6073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // can calculate the true offset into the icon area. 6083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int width_before_icons = ToolbarView::kStandardSpacing + 6093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (base::i18n::IsRTL() ? 6103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0); 6113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int offset_into_icon_area = event.x() - width_before_icons; 6123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Next, we determine which icon to place the indicator in front of. We want 6143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // to place the indicator in front of icon n when the cursor is between the 6153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // midpoints of icons (n - 1) and n. To do this we take the offset into the 6163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // icon area and transform it as follows: 6173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 6183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Real icon area: 6193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 0 a * b c 6203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // | | | | 6213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |[IC|ON] [IC|ON] [IC|ON] 6223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. 6233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Here the "*" represents the offset into the icon area, and since it's 6243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // between a and b, we want to return "1". 6253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 6263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Transformed "icon area": 6273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 0 a * b c 6283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // | | | | 6293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |[ICON] |[ICON] |[ICON] | 6303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If we shift both our offset and our divider points later by half an icon 6313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // plus one spacing unit, then it becomes very easy to calculate how many 6323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // divider points we've passed, because they're the multiples of "one icon 6333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // plus padding". 6343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + 6353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick kItemSpacing) / IconWidth(true); 6363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Because the user can drag outside the container bounds, we need to clamp to 6383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the valid range. Note that the maximum allowable value is (num icons), not 6393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // (num icons - 1), because we represent the indicator being past the last 6403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // icon as being "before the (last + 1) icon". 6413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int before_icon = std::min(std::max(before_icon_unclamped, 0), 6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static_cast<int>(VisibleBrowserActions())); 6433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now we convert back to a pixel offset into the container. We want to place 6453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the center of the drop indicator at the midpoint of the space before our 6463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // chosen icon. 6473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) - 6483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (kItemSpacing / 2)); 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ui::DragDropTypes::DRAG_MOVE; 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::OnDragExited() { 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopShowFolderDropMenuTimer(); 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_position_ = -1; 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserActionsContainer::OnPerformDrop( 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const views::DropTargetEvent& event) { 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionDragData data; 66272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!data.Read(event.data())) 66372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ui::DragDropTypes::DRAG_NONE; 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure we have the same view as we started with. 6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK_EQ(browser_action_views_[data.index()]->button()->extension()->id(), 6673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick data.id()); 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(model_); 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t i = 0; 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; i < browser_action_views_.size(); ++i) { 67272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int view_x = browser_action_views_[i]->GetMirroredBounds().x(); 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!browser_action_views_[i]->IsVisible() || 6743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (base::i18n::IsRTL() ? (view_x < drop_indicator_position_) : 6753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (view_x >= drop_indicator_position_))) { 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have reached the end of the visible icons or found one that has a 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // higher x position than the drop point. 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |i| now points to the item to the right of the drop indicator*, which is 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // correct when dragging an icon to the left. When dragging to the right, 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // however, we want the icon being dragged to get the index of the item to 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the left of the drop indicator, so we subtract one. 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * Well, it can also point to the end, but not when dragging to the left. :) 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i > data.index()) 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch --i; 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (profile_->IsOffTheRecord()) 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i = model_->IncognitoIndexToOriginal(i); 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick model_->MoveBrowserAction( 6943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick browser_action_views_[data.index()]->button()->extension(), i); 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnDragExited(); // Perform clean up after dragging. 69772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ui::DragDropTypes::DRAG_MOVE; 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionsContainer::GetAccessibleState( 701ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ui::AccessibleViewState* state) { 702ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->role = ui::AccessibilityTypes::ROLE_GROUPING; 703ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS); 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (source == chevron_) { 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch overflow_menu_ = new BrowserActionOverflowMenuController( 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, chevron_, browser_action_views_, VisibleBrowserActions()); 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch overflow_menu_->set_observer(this); 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), false); 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 715dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BrowserActionsContainer::WriteDragDataForView(View* sender, 716dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Point& press_pt, 717dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen OSExchangeData* data) { 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(data); 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < browser_action_views_.size(); ++i) { 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionButton* button = browser_action_views_[i]->button(); 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (button == sender) { 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the dragging image for the icon. 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<gfx::Canvas> canvas( 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_[i]->GetIconWithBadge()); 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_utils::SetDragImageOnDataObject(*canvas, button->size(), press_pt, 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data); 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Fill in the remaining info. 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionDragData drag_data( 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_[i]->button()->extension()->id(), i); 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_data.Write(profile_, data); 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 738dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint BrowserActionsContainer::GetDragOperationsForView(View* sender, 739dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Point& p) { 74072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return ui::DragDropTypes::DRAG_MOVE; 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 743dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool BrowserActionsContainer::CanStartDragForView(View* sender, 744dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Point& press_pt, 745dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Point& p) { 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { 7503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!done_resizing) { 7513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resize_amount_ = resize_amount; 7523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionVisibilityChanged(); 7533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 7553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 7563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Up until now we've only been modifying the resize_amount, but now it is 7573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // time to set the container size to the size we have resized to, and then 7583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // animate to the nearest icon count size if necessary (which may be 0). 7593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int max_width = IconCountToWidth(-1, false); 7603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick container_width_ = 7613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::min(std::max(0, container_width_ - resize_amount), max_width); 7623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SaveDesiredSizeAndAnimate(ui::Tween::EASE_OUT, 7633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WidthToIconCount(container_width_)); 7643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BrowserActionsContainer::AnimationProgressed( 7673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen const ui::Animation* animation) { 7683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK_EQ(resize_animation_.get(), animation); 7693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() * 7703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (container_width_ - animation_target_size_)); 7713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionVisibilityChanged(); 7723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BrowserActionsContainer::AnimationEnded(const ui::Animation* animation) { 7753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick container_width_ = animation_target_size_; 7763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick animation_target_size_ = 0; 7773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick resize_amount_ = 0; 7783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionVisibilityChanged(); 7793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick suppress_chevron_ = false; 7803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::NotifyMenuDeleted( 7833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BrowserActionOverflowMenuController* controller) { 7843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(controller == overflow_menu_); 7853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick overflow_menu_ = NULL; 7863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::InspectPopup(ExtensionAction* action) { 7893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionExecuted(GetBrowserActionView(action)->button(), true); 7903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::ExtensionPopupIsClosing(ExtensionPopup* popup) { 7933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // ExtensionPopup is ref-counted, so we don't need to delete it. 7943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK_EQ(popup_, popup); 7953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_ = NULL; 7963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_button_->SetButtonNotPushed(); 7973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_button_ = NULL; 7983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 7993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 8003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id, 8013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t new_index) { 80221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ExtensionService* service = profile_->GetExtensionService(); 8033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (service) { 804513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = service->GetExtensionById(extension_id, false); 8053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick model_->MoveBrowserAction(extension, new_index); 8063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SchedulePaint(); 8073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 8083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 8103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::HidePopup() { 8113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (popup_) 8123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick popup_->Close(); 8133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 8153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::TestExecuteBrowserAction(int index) { 8163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick BrowserActionButton* button = browser_action_views_[index]->button(); 8173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionExecuted(button, false); 8183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 8203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { 8213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick model_->SetVisibleIconCount(icons); 8223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetVisible(icons < browser_action_views_.size()); 8233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick container_width_ = IconCountToWidth(icons, chevron_->IsVisible()); 8243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Layout(); 8253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SchedulePaint(); 8263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 828ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { 829ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // TODO(sky/glen): Instead of using a drop indicator, animate the icons while 830ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // dragging (like we do for tab dragging). 831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (drop_indicator_position_ > -1) { 832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The two-pixel width drop indicator. 833ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static const int kDropIndicatorWidth = 2; 834ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gfx::Rect indicator_bounds( 835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen drop_indicator_position_ - (kDropIndicatorWidth / 2), 836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight()); 837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 838ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Color of the drop indicator. 839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static const SkColor kDropIndicatorColor = SK_ColorBLACK; 840ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(), 841ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen indicator_bounds.y(), indicator_bounds.width(), 842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen indicator_bounds.height()); 843ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 844ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 845ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 846ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionsContainer::OnThemeChanged() { 847ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LoadImages(); 848ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 849ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 850ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BrowserActionsContainer::ViewHierarchyChanged(bool is_add, 851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::View* parent, 852ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::View* child) { 853ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // No extensions (e.g., incognito). 854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!model_) 855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 856ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 857ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (is_add && child == this) { 858ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Initial toolbar button creation and placement in the widget hierarchy. 859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We do this here instead of in the constructor because AddBrowserAction 860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // calls Layout on the Toolbar, which needs this object to be constructed 861ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // before its Layout function is called. 862ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CreateBrowserActionViews(); 863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 865ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 8663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 8673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint BrowserActionsContainer::IconWidth(bool include_padding) { 8683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static bool initialized = false; 8693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static int icon_width = 0; 8703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!initialized) { 8713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick initialized = true; 8723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick icon_width = ResourceBundle::GetSharedInstance().GetBitmapNamed( 8733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_BROWSER_ACTION)->width(); 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 8753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return icon_width + (include_padding ? kItemSpacing : 0); 8763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 8793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint BrowserActionsContainer::IconHeight() { 8803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static bool initialized = false; 8813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static int icon_height = 0; 8823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!initialized) { 8833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick initialized = true; 8843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick icon_height = ResourceBundle::GetSharedInstance().GetBitmapNamed( 8853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_BROWSER_ACTION)->height(); 8863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 8873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return icon_height; 888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 890513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsContainer::BrowserActionAdded(const Extension* extension, 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(DEBUG) 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < browser_action_views_.size(); ++i) { 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(browser_action_views_[i]->button()->extension() != extension) << 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Asked to add a browser action view for an extension that already " 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "exists."; 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CloseOverflowMenu(); 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ShouldDisplayBrowserAction(extension)) 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t visible_actions = VisibleBrowserActions(); 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the new browser action to the vector and the view hierarchy. 9073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (profile_->IsOffTheRecord()) 9083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick index = model_->OriginalIndexToIncognito(index); 909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionView* view = new BrowserActionView(extension, this); 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_.insert(browser_action_views_.begin() + index, view); 91172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AddChildViewAt(view, index); 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we are still initializing the container, don't bother animating. 914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!model_->extensions_initialized()) 915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Enlarge the container if it was already at maximum size and we're not in 9183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the middle of upgrading. 919513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if ((model_->GetVisibleIconCount() < 0) && 92021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen !profile_->GetExtensionService()->IsBeingUpgraded(extension)) { 9213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick suppress_chevron_ = true; 9223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SaveDesiredSizeAndAnimate(ui::Tween::LINEAR, visible_actions + 1); 923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 9243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Just redraw the (possibly modified) visible icon set. 9253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionVisibilityChanged(); 926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 929513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsContainer::BrowserActionRemoved(const Extension* extension) { 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CloseOverflowMenu(); 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_ && popup_->host()->extension() == extension) 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HidePopup(); 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t visible_actions = VisibleBrowserActions(); 9363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (BrowserActionViews::iterator iter = browser_action_views_.begin(); 9373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick iter != browser_action_views_.end(); ++iter) { 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*iter)->button()->extension() == extension) { 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveChildView(*iter); 940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete *iter; 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_action_views_.erase(iter); 942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the extension is being upgraded we don't want the bar to shrink 944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because the icon is just going to get re-added to the same location. 94521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (profile_->GetExtensionService()->IsBeingUpgraded(extension)) 946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (browser_action_views_.size() > visible_actions) { 9493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If we have more icons than we can show, then we must not be changing 9503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the container size (since we either removed an icon from the main 9513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // area and one from the overflow list will have shifted in, or we 9523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // removed an entry directly from the overflow list). 9533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick OnBrowserActionVisibilityChanged(); 9543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 9553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Either we went from overflow to no-overflow, or we shrunk the no- 9563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // overflow container by 1. Either way the size changed, so animate. 9573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetVisible(false); 9583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SaveDesiredSizeAndAnimate(ui::Tween::EASE_OUT, 9593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick browser_action_views_.size()); 9603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 966513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsContainer::BrowserActionMoved(const Extension* extension, 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ShouldDisplayBrowserAction(extension)) 969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (profile_->IsOffTheRecord()) 972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index = model_->OriginalIndexToIncognito(index); 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size())); 975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DeleteBrowserActionViews(); 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateBrowserActionViews(); 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::ModelLoaded() { 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetContainerWidth(); 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::LoadImages() { 98772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::ThemeProvider* tp = GetThemeProvider(); 9883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW)); 9893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetHoverIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_H)); 9903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetPushedIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_P)); 9913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 9923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsContainer::SetContainerWidth() { 994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int visible_actions = model_->GetVisibleIconCount(); 995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (visible_actions < 0) // All icons should be visible. 996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visible_actions = model_->size(); 9973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size()); 9983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick container_width_ = IconCountToWidth(visible_actions, chevron_->IsVisible()); 9993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 10003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::CloseOverflowMenu() { 10023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (overflow_menu_) 10033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick overflow_menu_->CancelMenu(); 10043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 10053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::StopShowFolderDropMenuTimer() { 10073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick show_menu_task_factory_.RevokeAll(); 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::StartShowFolderDropMenuTimer() { 1011dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int delay = views::GetMenuShowDelay(); 10123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick MessageLoop::current()->PostDelayedTask(FROM_HERE, 10133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick show_menu_task_factory_.NewRunnableMethod( 10143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &BrowserActionsContainer::ShowDropFolder), 10153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick delay); 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::ShowDropFolder() { 10193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(!overflow_menu_); 10203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetDropIndicator(-1); 10213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick overflow_menu_ = new BrowserActionOverflowMenuController( 10223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick this, chevron_, browser_action_views_, VisibleBrowserActions()); 10233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick overflow_menu_->set_observer(this); 10243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true); 10253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::SetDropIndicator(int x_pos) { 10283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (drop_indicator_position_ != x_pos) { 10293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick drop_indicator_position_ = x_pos; 10303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SchedulePaint(); 10313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 10323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint BrowserActionsContainer::IconCountToWidth(int icons, 10353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool display_chevron) const { 10363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (icons < 0) 10373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick icons = browser_action_views_.size(); 10383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if ((icons == 0) && !display_chevron) 10393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return ToolbarView::kStandardSpacing; 10403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int icons_size = 10413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing); 10423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int chevron_size = display_chevron ? 10433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0; 10443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return ToolbarView::kStandardSpacing + icons_size + chevron_size + 10453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ToolbarView::kStandardSpacing; 10463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 10473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricksize_t BrowserActionsContainer::WidthToIconCount(int pixels) const { 10493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Check for widths large enough to show the entire icon set. 10503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (pixels >= IconCountToWidth(-1, false)) 10513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return browser_action_views_.size(); 10523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We need to reserve space for the resize area, chevron, and the spacing on 10543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // either side of the chevron. 10553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int available_space = pixels - ToolbarView::kStandardSpacing - 10563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->GetPreferredSize().width() - kChevronSpacing - 10573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ToolbarView::kStandardSpacing; 10583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now we add an extra between-item padding value so the space can be divided 10593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // evenly by (size of icon with padding). 10603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return static_cast<size_t>( 10613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::max(0, available_space + kItemSpacing) / IconWidth(true)); 1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserActionsContainer::ContainerMinSize() const { 10653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return ToolbarView::kStandardSpacing + kChevronSpacing + 10663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing; 10673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 10683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsContainer::SaveDesiredSizeAndAnimate( 10703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ui::Tween::Type tween_type, 10713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t num_visible_icons) { 10723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Save off the desired number of visible icons. We do this now instead of at 10733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the end of the animation so that even if the browser is shut down while 10743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // animating, the right value will be restored on next run. 10753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // NOTE: Don't save the icon count in incognito because there may be fewer 10763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // icons in that mode. The result is that the container in a normal window is 10773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // always at least as wide as in an incognito window. 10783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!profile_->IsOffTheRecord()) 10793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick model_->SetVisibleIconCount(num_visible_icons); 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int target_size = IconCountToWidth(num_visible_icons, 10823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick num_visible_icons < browser_action_views_.size()); 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!disable_animations_during_testing_) { 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Animate! We have to set the animation_target_size_ after calling Reset(), 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because that could end up calling AnimationEnded which clears the value. 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_animation_->Reset(); 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_animation_->SetTweenType(tween_type); 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_target_size_ = target_size; 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_animation_->Show(); 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_target_size_ = target_size; 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AnimationEnded(resize_animation_.get()); 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1096513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool BrowserActionsContainer::ShouldDisplayBrowserAction( 1097513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension) { 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only display incognito-enabled extensions while in incognito mode. 1099ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return 1100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (!profile_->IsOffTheRecord() || 1101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen profile_->GetExtensionService()->IsIncognitoEnabled(extension->id())); 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1103