1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/caption_buttons/maximize_bubble_controller_bubble.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)#include "ash/metrics/user_metrics_recorder.h" 8d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)#include "ash/shell.h" 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shell_window_ids.h" 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/caption_buttons/bubble_contents_button_row.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/caption_buttons/frame_maximize_button.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/caption_buttons/maximize_bubble_controller.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "grit/ash_strings.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/animation/animation.h" 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/canvas.h" 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/path.h" 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/bubble/bubble_frame_view.h" 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/controls/label.h" 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/layout/box_layout.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/mouse_watcher.h" 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace ash { 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// BubbleContentsView --------------------------------------------------------- 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// A class which creates the content of the bubble: The buttons, and the label. 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class BubbleContentsView : public views::View { 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BubbleContentsView(MaximizeBubbleControllerBubble* bubble, 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SnapType initial_snap_type); 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~BubbleContentsView(); 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Set the label content to reflect the currently selected |snap_type|. 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This function can be executed through the frame maximize button as well as 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // through hover operations. 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void SetSnapType(SnapType snap_type); 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Added for unit test: Retrieve the button for an action. 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // |state| can be either SNAP_LEFT, SNAP_RIGHT or SNAP_MINIMIZE. 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::CustomButton* GetButtonForUnitTest(SnapType state); 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The owning class. 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble* bubble_; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The object which owns all the buttons. 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BubbleContentsButtonRow* buttons_view_; 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The label object which shows the user the selected action. 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::Label* label_view_; 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BubbleContentsView); 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)BubbleContentsView::BubbleContentsView( 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble* bubble, 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SnapType initial_snap_type) 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : bubble_(bubble), 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) buttons_view_(NULL), 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_(NULL) { 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetLayoutManager(new views::BoxLayout( 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::BoxLayout::kVertical, 0, 0, 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kLayoutSpacing)); 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_background(views::Background::CreateSolidBackground( 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor)); 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) buttons_view_ = new BubbleContentsButtonRow(bubble); 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AddChildView(buttons_view_); 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_ = new views::Label(); 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetSnapType(initial_snap_type); 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_->SetBackgroundColor( 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SkColor kBubbleTextColor = SK_ColorWHITE; 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_->SetEnabledColor(kBubbleTextColor); 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kLabelSpacing = 4; 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_->set_border(views::Border::CreateEmptyBorder( 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kLabelSpacing, 0, kLabelSpacing, 0)); 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AddChildView(label_view_); 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)BubbleContentsView::~BubbleContentsView() { 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Set the label content to reflect the currently selected |snap_type|. 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// This function can be executed through the frame maximize button as well as 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// through hover operations. 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BubbleContentsView::SetSnapType(SnapType snap_type) { 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!bubble_->controller()) 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int id = 0; 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (snap_type) { 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SNAP_LEFT: 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = IDS_ASH_SNAP_WINDOW_LEFT; 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SNAP_RIGHT: 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = IDS_ASH_SNAP_WINDOW_RIGHT; 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SNAP_MAXIMIZE: 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_NE(FRAME_STATE_FULL, bubble_->controller()->maximize_type()); 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = IDS_ASH_MAXIMIZE_WINDOW; 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SNAP_MINIMIZE: 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = IDS_ASH_MINIMIZE_WINDOW; 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SNAP_RESTORE: 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_NE(FRAME_STATE_NONE, bubble_->controller()->maximize_type()); 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = IDS_ASH_RESTORE_WINDOW; 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If nothing is selected, we automatically select the click operation. 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id = bubble_->controller()->maximize_type() == FRAME_STATE_FULL ? 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IDS_ASH_RESTORE_WINDOW : IDS_ASH_MAXIMIZE_WINDOW; 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) label_view_->SetText(rb.GetLocalizedString(id)); 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)views::CustomButton* BubbleContentsView::GetButtonForUnitTest(SnapType state) { 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return buttons_view_->GetButtonForUnitTest(state); 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// MaximizeBubbleBorder ------------------------------------------------------- 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace { 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kLineWidth = 1; 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kArrowHeight = 10; 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kArrowWidth = 20; 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class MaximizeBubbleBorder : public views::BubbleBorder { 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleBorder(views::View* content_view, views::View* anchor); 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~MaximizeBubbleBorder() {} 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Get the mouse active area of the window. 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void GetMask(gfx::Path* mask); 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // views::BubbleBorder: 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Size& contents_size) const OVERRIDE; 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE; 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual gfx::Size GetMinimumSize() const OVERRIDE; 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Note: Animations can continue after then main window frame was destroyed. 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // To avoid this problem, the owning screen metrics get extracted upon 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // creation. 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Size anchor_size_; 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Point anchor_screen_origin_; 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::View* content_view_; 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MaximizeBubbleBorder); 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)MaximizeBubbleBorder::MaximizeBubbleBorder(views::View* content_view, 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::View* anchor) 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : views::BubbleBorder( 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::BubbleBorder::TOP_RIGHT, views::BubbleBorder::NO_SHADOW, 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor), 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) anchor_size_(anchor->size()), 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) anchor_screen_origin_(0, 0), 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_view_(content_view) { 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::View::ConvertPointToScreen(anchor, &anchor_screen_origin_); 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleBorder::GetMask(gfx::Path* mask) { 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Insets inset = GetInsets(); 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Note: Even though the tip could be added as activatable, it is left out 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // since it would not change the action behavior in any way plus it makes 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // more sense to keep the focus on the underlying button for clicks. 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int left = inset.left() - kLineWidth; 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int right = inset.left() + content_view_->width() + kLineWidth; 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int top = inset.top() - kLineWidth; 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int bottom = inset.top() + content_view_->height() + kLineWidth; 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->moveTo(left, top); 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->lineTo(right, top); 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->lineTo(right, bottom); 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->lineTo(left, bottom); 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->lineTo(left, top); 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mask->close(); 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect MaximizeBubbleBorder::GetBounds( 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Rect& position_relative_to, 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Size& contents_size) const { 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Size border_size(contents_size); 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Insets insets = GetInsets(); 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) border_size.Enlarge(insets.width(), insets.height()); 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Position the bubble to center the box on the anchor. 201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int x = (anchor_size_.width() - border_size.width()) / 2; 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Position the bubble under the anchor, overlapping the arrow with it. 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int y = anchor_size_.height() - insets.top(); 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Point view_origin(x + anchor_screen_origin_.x(), 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) y + anchor_screen_origin_.y()); 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return gfx::Rect(view_origin, border_size); 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Insets inset = GetInsets(); 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Draw the border line around everything. 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int y = inset.top(); 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Top 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canvas->FillRect(gfx::Rect(inset.left(), 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) y - kLineWidth, 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_view_->width(), 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kLineWidth), 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Bottom 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canvas->FillRect(gfx::Rect(inset.left(), 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) y + content_view_->height(), 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_view_->width(), 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kLineWidth), 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Left 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canvas->FillRect(gfx::Rect(inset.left() - kLineWidth, 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) y - kLineWidth, 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kLineWidth, 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_view_->height() + 2 * kLineWidth), 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Right 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canvas->FillRect(gfx::Rect(inset.left() + content_view_->width(), 236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) y - kLineWidth, 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kLineWidth, 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_view_->height() + 2 * kLineWidth), 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Draw the arrow afterwards covering the border. 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SkPath path; 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) path.incReserve(4); 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The center of the tip should be in the middle of the button. 245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int tip_x = inset.left() + content_view_->width() / 2; 246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int left_base_x = tip_x - kArrowWidth / 2; 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int left_base_y = y; 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int tip_y = left_base_y - kArrowHeight; 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); 250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SkIntToScalar(left_base_y)); 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SkPaint paint; 255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) paint.setColor(MaximizeBubbleControllerBubble::kBubbleBackgroundColor); 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canvas->DrawPath(path, paint); 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Size MaximizeBubbleBorder::GetMinimumSize() const { 261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return gfx::Size(kLineWidth * 2 + kArrowWidth, 262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::max(kLineWidth, kArrowHeight) + kLineWidth); 263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// BubbleMouseWatcherHost ----------------------------------------------------- 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// The mouse watcher host which makes sure that the bubble does not get closed 269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// while the mouse cursor is over the maximize button or the balloon content. 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Note: This object gets destroyed when the MouseWatcher gets destroyed. 271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class BubbleMouseWatcherHost: public views::MouseWatcherHost { 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) explicit BubbleMouseWatcherHost(MaximizeBubbleControllerBubble* bubble); 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~BubbleMouseWatcherHost(); 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // views::MouseWatcherHost: 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual bool Contains(const gfx::Point& screen_point, 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::MouseWatcherHost::MouseEventType type) OVERRIDE; 279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble* bubble_; 281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BubbleMouseWatcherHost); 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)BubbleMouseWatcherHost::BubbleMouseWatcherHost( 286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleControllerBubble* bubble) 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : bubble_(bubble) { 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)BubbleMouseWatcherHost::~BubbleMouseWatcherHost() { 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool BubbleMouseWatcherHost::Contains( 294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Point& screen_point, 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::MouseWatcherHost::MouseEventType type) { 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bubble_->Contains(screen_point, type); 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// MaximizeBubbleControllerBubble --------------------------------------------- 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const SkColor MaximizeBubbleControllerBubble::kBubbleBackgroundColor = 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 0xFF141414; 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int MaximizeBubbleControllerBubble::kLayoutSpacing = -1; 306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)MaximizeBubbleControllerBubble::MaximizeBubbleControllerBubble( 308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MaximizeBubbleController* owner, 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int appearance_delay_ms, 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SnapType initial_snap_type) 311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : views::BubbleDelegateView(owner->frame_maximize_button(), 312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::BubbleBorder::TOP_RIGHT), 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shutting_down_(false), 314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_(owner), 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_(NULL), 316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) contents_view_(NULL), 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_border_(NULL), 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) appearance_delay_ms_(appearance_delay_ms) { 319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_margins(gfx::Insets()); 320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The window needs to be owned by the root so that the SnapSizer does not 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // cover it upon animation. 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::Window* parent = Shell::GetContainer( 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Shell::GetTargetRootWindow(), 325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) internal::kShellWindowId_ShelfContainer); 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_parent_window(parent); 327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_notify_enter_exit_on_child(true); 329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_adjust_if_offscreen(false); 330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetPaintToLayer(true); 331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_color(kBubbleBackgroundColor); 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_close_on_deactivate(false); 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_background( 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::Background::CreateSolidBackground(kBubbleBackgroundColor)); 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetLayoutManager(new views::BoxLayout( 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::BoxLayout::kVertical, 0, 0, kLayoutSpacing)); 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) contents_view_ = new BubbleContentsView(this, initial_snap_type); 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AddChildView(contents_view_); 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Note that the returned widget has an observer which points to our 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // functions. 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_ = views::BubbleDelegateView::CreateBubble(this); 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_->set_focus_on_creation(false); 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_->non_client_view()->frame_view()->set_background(NULL); 349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_border_ = new MaximizeBubbleBorder(this, GetAnchorView()); 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetBubbleFrameView()->SetBubbleBorder(bubble_border_); 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetBubbleFrameView()->set_background(NULL); 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Recalculate size with new border. 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SizeToContents(); 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!appearance_delay_ms_) 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetWidget()->Show(); 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StartFade(true); 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 362d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ash::UMA_WINDOW_MAXIMIZE_BUTTON_SHOW_BUBBLE); 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mouse_watcher_.reset(new views::MouseWatcher( 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new BubbleMouseWatcherHost(this), 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) this)); 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mouse_watcher_->Start(); 369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)MaximizeBubbleControllerBubble::~MaximizeBubbleControllerBubble() { 372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)aura::Window* MaximizeBubbleControllerBubble::GetBubbleWindow() { 375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bubble_widget_ ? bubble_widget_->GetNativeWindow() : NULL; 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect MaximizeBubbleControllerBubble::GetAnchorRect() { 379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_) 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return gfx::Rect(); 381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Rect anchor_rect = 383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_->frame_maximize_button()->GetBoundsInScreen(); 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return anchor_rect; 385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::AnimationProgressed( 388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Animation* animation) { 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // First do everything needed for the fade by calling the base function. 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BubbleDelegateView::AnimationProgressed(animation); 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // When fading in we are done. 392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!shutting_down_) 393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Upon fade out an additional shift is required. 395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kBubbleAnimationOffsetY = 5; 396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int shift = animation->CurrentValueBetween(kBubbleAnimationOffsetY, 0); 397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Rect rect = initial_position_; 398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) rect.set_y(rect.y() + shift); 400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_->GetNativeWindow()->SetBounds(rect); 401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MaximizeBubbleControllerBubble::CanActivate() const { 404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MaximizeBubbleControllerBubble::WidgetHasHitTestMask() const { 408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bubble_border_ != NULL; 409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::GetWidgetHitTestMask( 412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Path* mask) const { 413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(mask); 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(bubble_border_); 415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_border_->GetMask(mask); 416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::MouseMovedOutOfHost() { 419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_ || shutting_down_) 420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // When we leave the bubble, we might be still be in gesture mode or over 422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // the maximize button. So only close if none of the other cases apply. 423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_->frame_maximize_button()->is_snap_enabled()) { 424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Point screen_location = Shell::GetScreen()->GetCursorScreenPoint(); 425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_->frame_maximize_button()->GetBoundsInScreen().Contains( 426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) screen_location)) { 427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_->RequestDestructionThroughOwner(); 428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MaximizeBubbleControllerBubble::Contains( 433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Point& screen_point, 434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::MouseWatcherHost::MouseEventType type) { 435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_ || shutting_down_) 436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool inside_button = 438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_->frame_maximize_button()->GetBoundsInScreen().Contains( 439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) screen_point); 440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!owner_->frame_maximize_button()->is_snap_enabled() && inside_button) { 441f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetSnapType(controller()->maximize_type() == FRAME_STATE_FULL ? 442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SNAP_RESTORE : SNAP_MAXIMIZE); 443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Check if either a gesture is taking place (=> bubble stays no matter what 446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // the mouse does) or the mouse is over the maximize button or the bubble 447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // content. 448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return (owner_->frame_maximize_button()->is_snap_enabled() || 449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) inside_button || 450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) contents_view_->GetBoundsInScreen().Contains(screen_point)); 451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Size MaximizeBubbleControllerBubble::GetPreferredSize() { 454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return contents_view_->GetPreferredSize(); 455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::OnWidgetDestroying(views::Widget* widget) { 458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (bubble_widget_ == widget) { 459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mouse_watcher_->Stop(); 460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (owner_) { 462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If the bubble destruction was triggered by some other external 463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // influence then ourselves, the owner needs to be informed that the menu 464f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // is gone. 465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shutting_down_ = true; 466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_->RequestDestructionThroughOwner(); 467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_ = NULL; 468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BubbleDelegateView::OnWidgetDestroying(widget); 471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::ControllerRequestsCloseAndDelete() { 474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This only gets called from the owning base class once it is deleted. 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (shutting_down_) 476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shutting_down_ = true; 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) owner_ = NULL; 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Close the widget asynchronously after the hide animation is finished. 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) initial_position_ = bubble_widget_->GetNativeWindow()->bounds(); 482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!appearance_delay_ms_) 483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bubble_widget_->CloseNow(); 484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StartFade(false); 486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MaximizeBubbleControllerBubble::SetSnapType(SnapType snap_type) { 489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (contents_view_) 490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) contents_view_->SetSnapType(snap_type); 491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)views::CustomButton* MaximizeBubbleControllerBubble::GetButtonForUnitTest( 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SnapType state) { 495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return contents_view_->GetButtonForUnitTest(state); 496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace ash 499