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