Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(504)

Unified Diff: ash/wm/maximize_bubble_controller.cc

Issue 10823025: Adding new maximize menu according to spec (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Removed radial Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ash/wm/maximize_bubble_controller.cc
diff --git a/ash/wm/maximize_bubble_controller.cc b/ash/wm/maximize_bubble_controller.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b58c9b79b5276a59f2c1b8a7be2cc73b97c3bd6a
--- /dev/null
+++ b/ash/wm/maximize_bubble_controller.cc
@@ -0,0 +1,659 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/maximize_bubble_controller.h"
+
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/wm/window_animations.h"
+#include "base/bind.h"
+#include "base/command_line.h"
msw 2012/08/02 18:56:59 nit: is this include necessary? Please only IWYU.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 I removed the radial menu and it had some tentacle
+#include "base/message_loop.h"
+#include "base/timer.h"
+#include "grit/ash_strings.h"
+#include "grit/ui_resources.h"
+#include "ui/aura/aura_switches.h"
msw 2012/08/02 18:56:59 nit: is this include necessary? Please only IWYU.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+#include "ui/base/ui_base_switches.h"
msw 2012/08/02 18:56:59 nit: is this include necessary? Please only IWYU.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+#include "ui/aura/event.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/custom_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/events/event.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace {
+
+// The command codes returned from the radial menu.
+enum RadialMenuCommands {
sky 2012/08/02 18:30:30 Remove this.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ RADIAL_MENU_NONE = 0,
+ RADIAL_MENU_RIGHT,
+ RADIAL_MENU_MINIMIZE,
+ RADIAL_MENU_LEFT
+};
+
+// Bubble constants
msw 2012/08/02 18:56:59 nit: Nix comment or extrapolate and append a perio
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+const int kMaximumBubbleWidth = 200;
+const int kArrowOffset = 10;
msw 2012/08/02 18:56:59 nit: is this used?
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+
+// The spacing between two buttons.
+const int kLayoutSpacing = 1;
+
+const int kAnimationDurationForPopupMS = 200;
msw 2012/08/02 18:56:59 nit: move down with kBubbleAppearanceDelay or vice
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+
+// The background color
+const SkColor kBubbleBackgroundColor = 0xc8141414;
+
+// The text color within the bubble
+const SkColor kBubbleTextColor = 0xffffffff;
msw 2012/08/02 18:56:59 nit: Use SK_ColorWHITE (or theme service/provider
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+
+// The line width of the bubble.
msw 2012/08/02 18:56:59 nit: s/width/height/
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+const int kLineHeight = 1;
+
+// The pixel dimensions of the arrow
msw 2012/08/02 18:56:59 nit: append a period.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+const int kArrowHeight = 10;
+const int kArrowWidth = 20;
+
+// The delay of the bubble appearance.
+const int kBubbleAppearanceDelay = 200; // msec
sky 2012/08/02 18:30:30 nit: name MS like you did on line 50 to make it cl
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+
+// The active area behind a segment in a radial menu (in segment widths):
+// In case of hover the user wants to cancel out when getting reasonably far
+// away from the menu - in this case three times the wedge radius.
+const int kHoverRadialMenuExtension = 3;
sky 2012/08/02 18:30:30 Remove the constants you aren't using in this patc
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 You are right. That slipped through
+// In contrast to a hover action as given by |kHoverRadialMenuExtension|, the
+// user does want to drag his finger / mouse much further away from the menu
+// without canceling out (e.g. when doing a 'flic/swipe'). To allow 'endless
+// distance' a 'big number' is given.
+const int kDragRadialMenuExtension = 10000;
msw 2012/08/02 18:56:59 nit: is this still used?
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Was already deleted.
+
+class MaximizeBubbleBorder : public views::BubbleBorder {
msw 2012/08/02 18:56:59 Can this work be merged with existing/needed bubbl
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 I have spent at least two to three days trying to
msw 2012/08/03 19:58:54 Take a look at Varun's work in codereview.chromium
+ public:
+ MaximizeBubbleBorder(views::View* content_view,
msw 2012/08/02 18:56:59 nit: Do not use inline definitions here and below.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ views::View* anchor)
+ : views::BubbleBorder(views::BubbleBorder::TOP_RIGHT,
+ views::BubbleBorder::NO_SHADOW),
+ anchor_(anchor),
+ content_view_(content_view) {
+ set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ }
+
+ virtual ~MaximizeBubbleBorder() {}
+
+ // Overridden from views::BubbleBorder to match the design specs.
+ virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size) const OVERRIDE {
+ gfx::Size border_size(contents_size);
+ gfx::Insets insets;
+ GetInsets(&insets);
+ border_size.Enlarge(insets.width(), insets.height());
+
+ // Position the bubble to center the box on the anchor.
msw 2012/08/02 18:56:59 Can this be accomplished via ArrowLocation and Set
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 The designer requests states that the button shoul
msw 2012/08/03 19:58:54 Ok, consider adding a TODO to support centered arr
+ int x = -insets.left() -
msw 2012/08/02 18:56:59 Can this be obtained from a view's origin point?
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 This code has slightly changes after I got the fin
msw 2012/08/03 19:58:54 Ok, this seems fine, thanks.
+ (border_size.width() - anchor_->width() - kArrowWidth) / 2;
+ // Position the bubble under the anchor, overlapping the arrow with it.
+ int y = anchor_->height() - insets.top();
+
+ gfx::Point view_topleft(x, y);
msw 2012/08/02 18:56:59 nit: is this a view origin? please rename.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ views::View::ConvertPointToScreen(anchor_, &view_topleft);
+
+ return gfx::Rect(view_topleft.x(), view_topleft.y(),
msw 2012/08/02 18:56:59 nit: use Rect(const gfx::Point& origin, const gfx:
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ border_size.width(), border_size.height());
+ }
+
+ // Overridden from views::Border
+ virtual void Paint(const views::View& view,
msw 2012/08/02 18:56:59 Again, why does this require custom code?
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 See above.
+ gfx::Canvas* canvas) const OVERRIDE {
+ gfx::Insets inset;
+ GetInsets(&inset);
+
+ // Draw the border line around everything.
+ int y = inset.top();
+ // Top
+ canvas->FillRect(gfx::Rect(inset.left(),
+ y - kLineHeight,
+ content_view_->width(),
+ kLineHeight),
+ kBubbleBackgroundColor);
+ // Bottom
+ canvas->FillRect(gfx::Rect(inset.left(),
+ y + content_view_->height(),
+ content_view_->width(),
+ kLineHeight),
+ kBubbleBackgroundColor);
+ // Left
+ canvas->FillRect(gfx::Rect(inset.left() - kLineHeight,
+ y - kLineHeight,
+ kLineHeight,
+ content_view_->height() + 2 * kLineHeight),
+ kBubbleBackgroundColor);
+ // Right
+ canvas->FillRect(gfx::Rect(inset.left() + content_view_->width(),
+ y - kLineHeight,
+ kLineHeight,
+ content_view_->height() + 2 * kLineHeight),
+ kBubbleBackgroundColor);
+
+ // Draw the arrow afterwards covering the border.
+ SkPath path;
+ path.incReserve(4);
+ // The center of the tip should be in the middle of the button.
+ int tip_x = inset.left() + content_view_->width() / 2;
+ int left_base_x = tip_x - kArrowWidth / 2;
+ int left_base_y = y;
+ int tip_y = left_base_y - kArrowHeight;
+ path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y));
+ path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
+ path.lineTo(SkIntToScalar(left_base_x + kArrowWidth),
+ SkIntToScalar(left_base_y));
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(kBubbleBackgroundColor);
+ canvas->DrawPath(path, paint);
+ }
+
+ private:
+ views::View* anchor_;
+ views::View* content_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaximizeBubbleBorder);
+};
+
+} // namespace
+
+namespace ash {
+
+// The image button gets overridden to be able to capture mouse hover events.
+class MaximizeBubbleController::BubbleMenuButton : public views::ImageButton {
msw 2012/08/02 18:56:59 This seems odd, can't each button handle mouse ent
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 You only get clicked events no hover events from C
msw 2012/08/03 19:58:54 Ah, I think I just misunderstood what you're doing
+ public:
+ explicit BubbleMenuButton(
+ MaximizeBubbleController::BubbleContentsButtonRow* button_row_listener);
+ virtual ~BubbleMenuButton() {}
+
+ // CustomButton overrides:
+ virtual void OnMouseCaptureLost() OVERRIDE;
+ virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
+
+ private:
+ // The creating class which needs to get notified in case of a hover event.
+ MaximizeBubbleController::BubbleContentsButtonRow* button_row_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleMenuButton);
+};
+
+// The class which creates and manages the bubble menu element.
+// It creates a "bubble border" and the content accordingly.
msw 2012/08/02 18:56:59 nit: nix quotes around bubble border.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Why is that? Done
msw 2012/08/03 19:58:54 I typically reserve quotes for actual quotations,
+// Note: Since the SnapSizer will show animations on top of the maximize button
+// this menu gets creates as a separate window and the SnapSizer will be
msw 2012/08/02 18:56:59 nit: "gets creates" and "will be creates"
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+// creates underneath this window.
+class MaximizeBubbleController::Bubble : public views::BubbleDelegateView {
+ public:
+ explicit Bubble(MaximizeBubbleController* owner);
+ virtual ~Bubble();
+
+ // The window of the menu under which the SnapSizer will get created.
+ aura::Window* GetMenuWindow();
+
+ // Overridden from views::BubbleDelegateView.
+ virtual gfx::Rect GetAnchorRect() const OVERRIDE;
+
+ // Overridden from View
msw 2012/08/02 18:56:59 nit: add a period for consistency.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnClickedOutsideView() OVERRIDE;
+
+ // Overridden from views::View.
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ // Overridden from views::Widget::Observer.
+ virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
+
+ // Called from the owning class to indicate that the menu should get
msw 2012/08/02 18:56:59 nit: use "controller" or owner terminology consist
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ // destroyed.
+ virtual void OwnerRequestsCloseAndDelete();
+
+ // Called from the owning class to change the menu content to the given
+ // |snap_type| so that the user knows what is selected.
+ void SetMenuState(FrameMaximizeButton::SnapType snap_type);
sky 2012/08/02 18:30:30 SetSnapType
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+
+ // Get the owning MaximizeBubbleController. This might return NULL in case
+ // of an asynchronous shutdown.
+ MaximizeBubbleController* GetOwner() {
sky 2012/08/02 18:30:30 Name this owner()
msw 2012/08/02 18:56:59 Make this MaximizeBubbleController* owner() const
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ return owner_;
+ }
+
+ private:
+ // True if the shut down has been initiated.
+ bool shutting_down_;
+
+ // Our owning class.
+ MaximizeBubbleController* owner_;
+
+ // The widget which contains our menu and the bubble border.
+ views::Widget* bubble_widget_;
+
+ // The content accessor of the menu.
+ BubbleContentsView* contents_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(Bubble);
+};
+
+// A class that creates all buttons and put them into a view.
msw 2012/08/02 18:56:59 This seems unnecessary, just do this in BubbleCont
msw 2012/08/03 19:58:54 I still think this separate class is somewhat unne
+class MaximizeBubbleController::BubbleContentsButtonRow
+ : public views::View,
+ public views::ButtonListener {
+ public:
+ explicit BubbleContentsButtonRow(MaximizeBubbleController::Bubble* bubble)
+ : bubble_(bubble),
+ left_button_(NULL),
+ minimize_button_(NULL),
+ right_button_(NULL) {
+ SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kHorizontal, 0, 0, kLayoutSpacing));
+ set_background(
+ views::Background::CreateSolidBackground(kBubbleBackgroundColor));
+
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ left_button_ = new MaximizeBubbleController::BubbleMenuButton(this);
+ left_button_->SetImage(views::CustomButton::BS_NORMAL,
sky 2012/08/02 18:30:30 Create a function for constructor that can be shar
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_LEFT_P));
+ left_button_->SetImage(views::CustomButton::BS_HOT,
+ // TODO(skuhne): Replace images as soon as they come in.
msw 2012/08/02 18:56:59 nit: consolidate redundant TODO comments.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Got the artwork in the meantime and added it accor
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_LEFT_P));
+ left_button_->SetImage(views::CustomButton::BS_PUSHED,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_LEFT_P));
+ AddChildView(left_button_);
+
+ minimize_button_ = new MaximizeBubbleController::BubbleMenuButton(this);
+ minimize_button_->SetImage(views::CustomButton::BS_NORMAL,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_P));
+ minimize_button_->SetImage(views::CustomButton::BS_HOT,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_P));
+ minimize_button_->SetImage(views::CustomButton::BS_PUSHED,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_P));
+ AddChildView(minimize_button_);
+
+ right_button_ = new MaximizeBubbleController::BubbleMenuButton(this);
+ right_button_->SetImage(views::CustomButton::BS_NORMAL,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_RIGHT_P));
+ right_button_->SetImage(views::CustomButton::BS_HOT,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_RIGHT_P));
+ right_button_->SetImage(views::CustomButton::BS_PUSHED,
+ // TODO(skuhne): Replace images as soon as they come in.
+ rb.GetImageSkiaNamed(IDR_AURA_WINDOW_SNAP_RIGHT_P));
+ AddChildView(right_button_);
+ }
+
+ virtual ~BubbleContentsButtonRow() {}
+
+ // Overridden from ButtonListener.
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE {
+ if (!bubble_->GetOwner())
sky 2012/08/02 18:30:30 Why do you need this? At a minimum add a comment (
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ return;
+ if (sender == left_button_)
+ bubble_->GetOwner()->OnButtonClicked(FrameMaximizeButton::SNAP_LEFT);
+ else if (sender == minimize_button_)
+ bubble_->GetOwner()->OnButtonClicked(FrameMaximizeButton::SNAP_MINIMIZE);
+ else if (sender == right_button_)
+ bubble_->GetOwner()->OnButtonClicked(FrameMaximizeButton::SNAP_RIGHT);
+ else {
+ NOTREACHED() << "Unknown button pressed.";
+ }
+ }
+
+ // Called from BubbleMenuButton.
+ void ButtonHovered(MaximizeBubbleController::BubbleMenuButton* sender) {
+ if (!bubble_->GetOwner())
+ return;
+ if (sender == left_button_)
+ bubble_->GetOwner()->OnButtonHover(FrameMaximizeButton::SNAP_LEFT);
+ else if (sender == minimize_button_)
+ bubble_->GetOwner()->OnButtonHover(FrameMaximizeButton::SNAP_MINIMIZE);
+ else if (sender == right_button_)
+ bubble_->GetOwner()->OnButtonHover(FrameMaximizeButton::SNAP_RIGHT);
+ else
+ bubble_->GetOwner()->OnButtonHover(FrameMaximizeButton::SNAP_NONE);
+ }
+
+ private:
+ // The owning object which gets notifications.
+ MaximizeBubbleController::Bubble* bubble_;
+
+ // The created buttons for our menu.
+ MaximizeBubbleController::BubbleMenuButton* left_button_;
+ MaximizeBubbleController::BubbleMenuButton* minimize_button_;
+ MaximizeBubbleController::BubbleMenuButton* right_button_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleContentsButtonRow);
+};
+
+// A class which creates the content of the bubble: The buttons, and the label.
+class MaximizeBubbleController::BubbleContentsView : public views::View {
+ public:
+ explicit BubbleContentsView(MaximizeBubbleController::Bubble* bubble)
+ : bubble_(bubble),
+ buttons_view_(NULL),
+ label_view_(NULL) {
+ SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, kLayoutSpacing));
+ set_background(
+ views::Background::CreateSolidBackground(kBubbleBackgroundColor));
+
+ buttons_view_ = new BubbleContentsButtonRow(bubble);
+ AddChildView(buttons_view_);
+
+ label_view_ = new views::Label();
+ SetMenuState(FrameMaximizeButton::SNAP_NONE);
+ label_view_->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
+ label_view_->SetBackgroundColor(kBubbleBackgroundColor);
+ label_view_->SetEnabledColor(kBubbleTextColor);
+ AddChildView(label_view_);
+ }
+
+ virtual ~BubbleContentsView() {}
+
+ // Set the label content to reflect the currently selected |snap_type|.
+ // This function can be executed through the frame maximize button as well as
+ // through hover operations.
+ void SetMenuState(FrameMaximizeButton::SnapType snap_type) {
sky 2012/08/02 18:30:30 SetSnapType()
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ if (!bubble_->GetOwner())
+ return;
+
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ switch (snap_type) {
+ case FrameMaximizeButton::SNAP_LEFT:
+ label_view_->SetText(rb.GetLocalizedString(IDS_ASH_SNAP_WINDOW_LEFT));
+ return;
+ case FrameMaximizeButton::SNAP_RIGHT:
+ label_view_->SetText(rb.GetLocalizedString(IDS_ASH_SNAP_WINDOW_RIGHT));
+ return;
+ case FrameMaximizeButton::SNAP_MAXIMIZE:
+ DCHECK(!bubble_->GetOwner()->is_maximized());
+ label_view_->SetText(rb.GetLocalizedString(IDS_ASH_MAXIMIZE_WINDOW));
+ return;
+ case FrameMaximizeButton::SNAP_MINIMIZE:
+ label_view_->SetText(rb.GetLocalizedString(IDS_ASH_MINIMIZE_WINDOW));
+ return;
+ case FrameMaximizeButton::SNAP_RESTORE:
+ DCHECK(bubble_->GetOwner()->is_maximized());
+ label_view_->SetText(rb.GetLocalizedString(IDS_ASH_RESTORE_WINDOW));
+ return;
+ default:
+ // If nothing is selected, we automatically select the click operation.
+ label_view_->SetText(rb.GetLocalizedString(
+ bubble_->GetOwner()->is_maximized() ? IDS_ASH_RESTORE_WINDOW :
+ IDS_ASH_MAXIMIZE_WINDOW));
+ return;
+ }
+ }
+
+ private:
+ // The owning class.
+ MaximizeBubbleController::Bubble* bubble_;
+
+ // The object which owns all the buttons.
+ BubbleContentsButtonRow* buttons_view_;
+
+ // The label object which shows the user the selected action.
+ views::Label* label_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleContentsView);
+};
+
+MaximizeBubbleController::BubbleMenuButton::BubbleMenuButton(
+ MaximizeBubbleController::BubbleContentsButtonRow* button_row)
+ : views::ImageButton(button_row),
+ button_row_(button_row) {}
+
+void MaximizeBubbleController::BubbleMenuButton::OnMouseCaptureLost(
+ ) OVERRIDE {
sky 2012/08/02 18:30:30 Don't wrap like this.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ button_row_->ButtonHovered(NULL);
+ views::ImageButton::OnMouseCaptureLost();
+}
+
+void MaximizeBubbleController::BubbleMenuButton::OnMouseEntered(
+ const views::MouseEvent& event) OVERRIDE {
+ button_row_->ButtonHovered(this);
+ views::ImageButton::OnMouseEntered(event);
+}
+
+void MaximizeBubbleController::BubbleMenuButton::OnMouseExited(
+ const views::MouseEvent& event) OVERRIDE {
+ button_row_->ButtonHovered(NULL);
+ views::ImageButton::OnMouseExited(event);
+}
+
+MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner)
+ : views::BubbleDelegateView(owner->frame_maximize_button(),
+ views::BubbleBorder::TOP_RIGHT),
+ shutting_down_(false),
+ owner_(owner),
+ bubble_widget_(NULL),
+ contents_view_(NULL) {
+ set_margins(gfx::Insets());
+
+ // The window needs to be owned by the root so that the SnapSizer does not
+ // cover it upon animation.
+ aura::Window* parent = Shell::GetContainer(
+ Shell::GetActiveRootWindow(),
+ internal::kShellWindowId_LauncherContainer);
+ set_parent_window(parent);
+
+ set_notify_enter_exit_on_child(true);
+ set_try_mirroring_arrow(false);
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
+ set_color(kBubbleBackgroundColor);
+ set_close_on_deactivate(false);
+ set_background(
+ views::Background::CreateSolidBackground(kBubbleBackgroundColor));
+
+ SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, kLayoutSpacing));
+
+ contents_view_ = new BubbleContentsView(this);
+ AddChildView(contents_view_);
+
+ // Note that the returned widget has an observer which points to our
+ // functions.
+ bubble_widget_ = views::BubbleDelegateView::CreateBubble(this);
+
+ SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ bubble_widget_->non_client_view()->frame_view()->set_background(NULL);
+
+ MaximizeBubbleBorder* bubble_border = new MaximizeBubbleBorder(
+ this,
+ anchor_view());
+ GetBubbleFrameView()->SetBubbleBorder(bubble_border);
+ GetBubbleFrameView()->set_background(NULL);
+
+ // Recalculate size with new border.
+ SizeToContents();
+
+ // Setup animation.
+ ash::SetWindowVisibilityAnimationType(
+ bubble_widget_->GetNativeWindow(),
+ ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+ ash::SetWindowVisibilityAnimationTransition(
+ bubble_widget_->GetNativeWindow(),
+ ash::ANIMATE_BOTH);
+ ash::SetWindowVisibilityAnimationDuration(
+ bubble_widget_->GetNativeWindow(),
+ base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
+
+ Show();
+ // We don't want to loose the focus on our parent window because the button
msw 2012/08/02 18:56:59 nit: s/loose/lose/ here and below.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ // would otherwise loose the highlight when the "helper bubble" is shown.
+ views::Widget* widget =
+ owner_->frame_maximize_button()->parent()->GetWidget();
+ if (widget) {
+ aura::Window* parent_window = widget->GetNativeWindow();
+ parent_window->GetFocusManager()->SetFocusedWindow(parent_window, NULL);
+ }
+}
+
+MaximizeBubbleController::Bubble::~Bubble() {
+ LOG(ERROR) << "~Bubble";
+}
+
+aura::Window* MaximizeBubbleController::Bubble::GetMenuWindow() {
+ return bubble_widget_ ? bubble_widget_->GetNativeWindow() : NULL;
+}
+
+gfx::Rect MaximizeBubbleController::Bubble::GetAnchorRect() const OVERRIDE {
+ if (!owner_)
+ return gfx::Rect();
+
+ gfx::Rect anchor_rect =
+ owner_->frame_maximize_button()->GetBoundsInScreen();
+ return anchor_rect;
+}
+
+void MaximizeBubbleController::Bubble::OnMouseExited(
+ const views::MouseEvent& event) OVERRIDE {
+ if (!owner_ || shutting_down_)
+ return;
+ // When we leave the bubble, we might be still be in gesture mode or over
+ // the maximize button. So only close if none of the other cases apply.
+ if (!owner_->frame_maximize_button()->is_snap_enabled()) {
+ gfx::Point screen_location = gfx::Screen::GetCursorScreenPoint();
+ if (!owner_->frame_maximize_button()->GetBoundsInScreen().Contains(
+ screen_location)) {
+ owner_->RequestDestructionThroughOwner();
+ }
+ }
+}
+
+void MaximizeBubbleController::Bubble::OnClickedOutsideView() OVERRIDE {
+ if (!owner_ || shutting_down_)
+ return;
+ // Don't destroy the menu when the click happened while the user is
+ // performing a dragging operation.
+ if (!owner_->frame_maximize_button()->is_snap_enabled())
+ owner_->RequestDestructionThroughOwner();
+}
+
+gfx::Size MaximizeBubbleController::Bubble::GetPreferredSize() OVERRIDE {
+ return contents_view_->GetPreferredSize();
+}
+
+void MaximizeBubbleController::Bubble::OnWidgetClosing(
+ views::Widget* widget) OVERRIDE {
+ if (bubble_widget_ != widget)
+ return;
+
+ if (owner_) {
+ // If the bubble destruction was triggered by some other external influence
+ // then ourselves, the owner needs to be informed that the menu is gone.
+ shutting_down_ = true;
+ owner_->RequestDestructionThroughOwner();
+ owner_ = NULL;
+ }
+ // Remove any existing observers.
+ bubble_widget_->RemoveObserver(this);
+ anchor_widget()->RemoveObserver(this);
+}
+
+void MaximizeBubbleController::Bubble::OwnerRequestsCloseAndDelete() {
+ // This only gets called from the owning base class once it is deleted.
+ if (shutting_down_)
+ return;
+ shutting_down_ = true;
+ owner_ = NULL;
+
+ // Close the widget asynchronously.
+ bubble_widget_->Close();
+}
+
+void MaximizeBubbleController::Bubble::SetMenuState(
+ FrameMaximizeButton::SnapType snap_type) {
+ if (contents_view_)
+ contents_view_->SetMenuState(snap_type);
+}
+
+MaximizeBubbleController::MaximizeBubbleController(
+ FrameMaximizeButton* frame_maximize_button,
+ bool is_maximized)
+ : frame_maximize_button_(frame_maximize_button),
+ bubble_(NULL),
+ is_maximized_(is_maximized) {
+ // Create the task which will create the bubble delayed.
+ base::OneShotTimer<MaximizeBubbleController>* new_timer =
+ new base::OneShotTimer<MaximizeBubbleController>();
+ new_timer->Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kBubbleAppearanceDelay),
+ this,
+ &MaximizeBubbleController::DelayedBubbleCreation);
+ timer_.reset(new_timer);
+}
+
+void MaximizeBubbleController::DelayCreation() {
+ if (timer_.get() && timer_->IsRunning())
+ timer_->Reset();
+}
+
+void MaximizeBubbleController::DelayedBubbleCreation() {
+ if (!bubble_) {
msw 2012/08/02 18:56:59 nit: remove {}
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ bubble_ = new Bubble(this);
+ }
+ timer_->Stop();
+}
+
+MaximizeBubbleController::~MaximizeBubbleController() {
sky 2012/08/02 18:30:30 Order doesn't match header.
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 Done.
+ // Note: The destructor only gets initiated through the owner.
+ timer_.reset(NULL);
+ if (bubble_) {
+ bubble_->OwnerRequestsCloseAndDelete();
+ bubble_ = NULL;
+ }
+}
+
+void MaximizeBubbleController::RequestDestructionThroughOwner() {
+ // Tell the parent to destroy us (if this didn't happen yet).
+ if (timer_.get()) {
+ timer_.reset(NULL);
+ // Informs the owner that the menu is gone and requests |this| destruction.
+ frame_maximize_button_->DestroyMaximizeMenu();
+ // Note: After this call |this| is destroyed.
+ }
+}
+
+void MaximizeBubbleController::OnButtonClicked(
+ FrameMaximizeButton::SnapType snap_type) {
+ frame_maximize_button_->ExecuteSnapAndCloseMenu(snap_type);
+}
+
+void MaximizeBubbleController::OnButtonHover(
+ FrameMaximizeButton::SnapType snap_type) {
+ frame_maximize_button_->SnapButtonHovered(snap_type);
+}
+
+void MaximizeBubbleController::SetMenuState(
+ FrameMaximizeButton::SnapType snap_type) {
+ if (bubble_)
msw 2012/08/02 18:56:59 Should this instead DCHECK(bubble_) as it should o
Mr4D (OOO till 08-26) 2012/08/02 23:10:38 The short answer is: No. The bubble lives and dies
+ bubble_->SetMenuState(snap_type);
+}
+
+aura::Window* MaximizeBubbleController::GetMenuWindow() {
+ return bubble_ ? bubble_->GetMenuWindow() : NULL;
+}
+
+} // namespace ash

Powered by Google App Engine
This is Rietveld 408576698