diff options
author | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-09 13:21:15 +0000 |
---|---|---|
committer | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-09 13:21:15 +0000 |
commit | 4aadc39eb6796f3ed92ec34fa6c39c2b8021d849 (patch) | |
tree | 767cb8461dc77e119b76f9aefa5025d4934110d0 /ash | |
parent | b58f23cc40de3b07cc3cfa18f96bf07cb5633ed4 (diff) | |
download | chromium_src-4aadc39eb6796f3ed92ec34fa6c39c2b8021d849.zip chromium_src-4aadc39eb6796f3ed92ec34fa6c39c2b8021d849.tar.gz chromium_src-4aadc39eb6796f3ed92ec34fa6c39c2b8021d849.tar.bz2 |
Fixing many problems around the maximize bubble
- Text for default action was not properly presented before
- Crash on minimize of file dialog
- Clicking in tip area of button did not do anything
- Added padding for text
- Launcher did show gray background upon maximize/minimize
- Added requested animations
BUG=140834, 140958, 140840
TEST=Visual
Review URL: https://chromiumcodereview.appspot.com/10829226
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150788 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/wm/maximize_bubble_controller.cc | 134 | ||||
-rw-r--r-- | ash/wm/workspace/frame_maximize_button.cc | 57 | ||||
-rw-r--r-- | ash/wm/workspace/frame_maximize_button.h | 5 |
3 files changed, 138 insertions, 58 deletions
diff --git a/ash/wm/maximize_bubble_controller.cc b/ash/wm/maximize_bubble_controller.cc index 2746aec..61c5f32 100644 --- a/ash/wm/maximize_bubble_controller.cc +++ b/ash/wm/maximize_bubble_controller.cc @@ -11,11 +11,14 @@ #include "base/timer.h" #include "grit/ash_strings.h" #include "grit/ui_resources.h" +#include "third_party/skia/include/core/SkPath.h" #include "ui/aura/focus_manager.h" #include "ui/aura/window.h" +#include "ui/base/animation/animation.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/path.h" #include "ui/gfx/screen.h" #include "ui/views/bubble/bubble_delegate.h" #include "ui/views/bubble/bubble_frame_view.h" @@ -41,13 +44,18 @@ const SkColor kBubbleTextColor = SK_ColorWHITE; // The line width of the bubble. const int kLineWidth = 1; +// The spacing for the top and bottom of the info label. +const int kLabelSpacing = 4; + // The pixel dimensions of the arrow. const int kArrowHeight = 10; const int kArrowWidth = 20; // The delay of the bubble appearance. const int kBubbleAppearanceDelayMS = 200; -const int kAnimationDurationForPopupMS = 200; + +// The animation offset in y for the bubble when appearing. +const int kBubbleAnimationOffsetY = 5; class MaximizeBubbleBorder : public views::BubbleBorder { public: @@ -55,6 +63,9 @@ class MaximizeBubbleBorder : public views::BubbleBorder { virtual ~MaximizeBubbleBorder() {} + // Get the mouse active area of the window. + void GetMask(gfx::Path* mask); + // 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; @@ -62,8 +73,13 @@ class MaximizeBubbleBorder : public views::BubbleBorder { // Overridden from views::Border. virtual void Paint(const views::View& view, gfx::Canvas* canvas) const OVERRIDE; + private: - views::View* anchor_; + // Note: Animations can continue after then main window frame was destroyed. + // To avoid this problem, the owning screen metrics get extracted upon + // creation. + gfx::Size anchor_size_; + gfx::Point anchor_screen_origin_; views::View* content_view_; DISALLOW_COPY_AND_ASSIGN(MaximizeBubbleBorder); @@ -73,11 +89,31 @@ MaximizeBubbleBorder::MaximizeBubbleBorder(views::View* content_view, views::View* anchor) : views::BubbleBorder(views::BubbleBorder::TOP_RIGHT, views::BubbleBorder::NO_SHADOW), - anchor_(anchor), + anchor_size_(anchor->size()), + anchor_screen_origin_(0,0), content_view_(content_view) { + views::View::ConvertPointToScreen(anchor, &anchor_screen_origin_); set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); } +void MaximizeBubbleBorder::GetMask(gfx::Path* mask) { + gfx::Insets inset; + GetInsets(&inset); + // Note: Even though the tip could be added as activatable, it is left out + // since it would not change the action behavior in any way plus it makes + // more sense to keep the focus on the underlying button for clicks. + int left = inset.left() - kLineWidth; + int right = inset.left() + content_view_->width() + kLineWidth; + int top = inset.top() - kLineWidth; + int bottom = inset.top() + content_view_->height() + kLineWidth; + mask->moveTo(left, top); + mask->lineTo(right, top); + mask->lineTo(right, bottom); + mask->lineTo(left, bottom); + mask->lineTo(left, top); + mask->close(); +} + gfx::Rect MaximizeBubbleBorder::GetBounds( const gfx::Rect& position_relative_to, const gfx::Size& contents_size) const { @@ -87,12 +123,12 @@ gfx::Rect MaximizeBubbleBorder::GetBounds( border_size.Enlarge(insets.width(), insets.height()); // Position the bubble to center the box on the anchor. - int x = (-border_size.width() + anchor_->width()) / 2; + int x = (-border_size.width() + anchor_size_.width()) / 2; // Position the bubble under the anchor, overlapping the arrow with it. - int y = anchor_->height() - insets.top(); + int y = anchor_size_.height() - insets.top(); - gfx::Point view_origin(x, y); - views::View::ConvertPointToScreen(anchor_, &view_origin); + gfx::Point view_origin(x + anchor_screen_origin_.x(), + y + anchor_screen_origin_.y()); return gfx::Rect(view_origin, border_size); } @@ -190,6 +226,11 @@ class MaximizeBubbleController::Bubble : public views::BubbleDelegateView, // Overridden from views::BubbleDelegateView. virtual gfx::Rect GetAnchorRect() OVERRIDE; + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; + + // Overridden from views::WidgetDelegateView. + virtual bool HasHitTestMask() const OVERRIDE; + virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE; // Implementation of MouseWatcherListener. virtual void MouseMovedOutOfHost(); @@ -229,6 +270,12 @@ class MaximizeBubbleController::Bubble : public views::BubbleDelegateView, // The content accessor of the menu. BubbleContentsView* contents_view_; + // The bubble border. + MaximizeBubbleBorder* bubble_border_; + + // The rectangle before the animation starts. + gfx::Rect initial_position_; + // The mouse watcher which takes care of out of window hover events. scoped_ptr<views::MouseWatcher> mouse_watcher_; @@ -315,7 +362,8 @@ MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner) shutting_down_(false), owner_(owner), bubble_widget_(NULL), - contents_view_(NULL) { + contents_view_(NULL), + bubble_border_(NULL) { set_margins(gfx::Insets()); // The window needs to be owned by the root so that the SnapSizer does not @@ -347,35 +395,15 @@ MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner) 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); + 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 lose the focus on our parent window because the button - // would otherwise lose 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); - } + StartFade(true); + mouse_watcher_.reset(new views::MouseWatcher( new BubbleMouseWatcherHost(this), this)); @@ -401,6 +429,31 @@ gfx::Rect MaximizeBubbleController::Bubble::GetAnchorRect() { return anchor_rect; } +void MaximizeBubbleController::Bubble::AnimationProgressed( + const ui::Animation* animation) { + // First do everything needed for the fade by calling the base function. + BubbleDelegateView::AnimationProgressed(animation); + // When fading in we are done. + if (!shutting_down_) + return; + // Upon fade out an additional shift is required. + int shift = animation->CurrentValueBetween(kBubbleAnimationOffsetY, 0); + gfx::Rect rect = initial_position_; + + rect.set_y(rect.y() + shift); + bubble_widget_->GetNativeWindow()->SetBounds(rect); +} + +bool MaximizeBubbleController::Bubble::HasHitTestMask() const { + return bubble_border_ != NULL; +} + +void MaximizeBubbleController::Bubble::GetHitTestMask(gfx::Path* mask) const { + DCHECK(mask); + DCHECK(bubble_border_); + bubble_border_->GetMask(mask); +} + void MaximizeBubbleController::Bubble::MouseMovedOutOfHost() { if (!owner_ || shutting_down_) return; @@ -420,12 +473,18 @@ bool MaximizeBubbleController::Bubble::Contains( views::MouseWatcherHost::MouseEventType type) { if (!owner_ || shutting_down_) return false; + bool inside_button = + owner_->frame_maximize_button()->GetBoundsInScreen().Contains( + screen_point); + if (!owner_->frame_maximize_button()->is_snap_enabled() && inside_button) { + SetSnapType(controller()->is_maximized() ? SNAP_RESTORE : SNAP_MAXIMIZE); + return true; + } // Check if either a gesture is taking place (=> bubble stays no matter what // the mouse does) or the mouse is over the maximize button or the bubble // content. return (owner_->frame_maximize_button()->is_snap_enabled() || - owner_->frame_maximize_button()->GetBoundsInScreen().Contains( - screen_point) || + inside_button || contents_view_->GetBoundsInScreen().Contains(screen_point)); } @@ -458,8 +517,9 @@ void MaximizeBubbleController::Bubble::ControllerRequestsCloseAndDelete() { shutting_down_ = true; owner_ = NULL; - // Close the widget asynchronously. - bubble_widget_->Close(); + // Close the widget asynchronously after the hide animation is finished. + initial_position_ = bubble_widget_->GetNativeWindow()->bounds(); + StartFade(false); } void MaximizeBubbleController::Bubble::SetSnapType(SnapType snap_type) { @@ -544,6 +604,8 @@ BubbleContentsView::BubbleContentsView( label_view_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); label_view_->SetBackgroundColor(kBubbleBackgroundColor); label_view_->SetEnabledColor(kBubbleTextColor); + label_view_->set_border(views::Border::CreateEmptyBorder( + kLabelSpacing, 0, kLabelSpacing, 0)); AddChildView(label_view_); } diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc index 9a584c8..21c8159 100644 --- a/ash/wm/workspace/frame_maximize_button.cc +++ b/ash/wm/workspace/frame_maximize_button.cc @@ -113,6 +113,9 @@ FrameMaximizeButton::FrameMaximizeButton(views::ButtonListener* listener, } FrameMaximizeButton::~FrameMaximizeButton() { + // Before the window gets destroyed, the maximizer dialog needs to be shut + // down since it would otherwise call into a deleted object. + maximizer_.reset(); if (window_) OnWindowDestroying(window_); } @@ -151,13 +154,14 @@ void FrameMaximizeButton::SnapButtonHovered(SnapType type) { void FrameMaximizeButton::ExecuteSnapAndCloseMenu(SnapType snap_type) { DCHECK_NE(snap_type_, SNAP_NONE); - snap_type_ = snap_type; - Snap(); - // Remove any pending snap previews. - SnapButtonHovered(SNAP_NONE); - // At this point the operation has been performed and the menu should be - // closed - if not, it'll get now closed. + Cancel(true); + // Tell our menu to close. maximizer_.reset(); + snap_type_ = snap_type; + // Since Snap might destroy |this|, but the snap_sizer needs to be destroyed, + // The ownership of the snap_sizer is taken now. + scoped_ptr<SnapSizer> snap_sizer(snap_sizer_.release()); + Snap(*snap_sizer.get()); } void FrameMaximizeButton::DestroyMaximizeMenu() { @@ -206,13 +210,19 @@ void FrameMaximizeButton::OnMouseExited(const views::MouseEvent& event) { ImageButton::OnMouseExited(event); // Remove the bubble menu when the button is not pressed and the mouse is not // within the bubble. - if (!is_snap_enabled_ && maximizer_.get() && maximizer_->GetBubbleWindow()) { - gfx::Point screen_location = gfx::Screen::GetCursorScreenPoint(); - if (!maximizer_->GetBubbleWindow()->GetBoundsInScreen().Contains( - screen_location)) { + if (!is_snap_enabled_ && maximizer_.get()) { + if (maximizer_->GetBubbleWindow()) { + gfx::Point screen_location = gfx::Screen::GetCursorScreenPoint(); + if (!maximizer_->GetBubbleWindow()->GetBoundsInScreen().Contains( + screen_location)) { + maximizer_.reset(); + // Make sure that all remaining snap hover states get removed. + SnapButtonHovered(SNAP_NONE); + } + } else { + // The maximize dialog does not show up immediately after creating the + // |mazimizer_|. Destroy the dialog therefore before it shows up. maximizer_.reset(); - // Make sure that all remaining snap hover states get removed. - SnapButtonHovered(SNAP_NONE); } } } @@ -321,7 +331,10 @@ bool FrameMaximizeButton::ProcessEndEvent(const views::LocatedEvent& event) { // BS_NORMAL during a drag. SchedulePaint(); phantom_window_.reset(); - Snap(); + // Since Snap might destroy |this|, but the snap_sizer needs to be destroyed, + // The ownership of the snap_sizer is taken now. + scoped_ptr<SnapSizer> snap_sizer(snap_sizer_.release()); + Snap(*snap_sizer.get()); return true; } @@ -330,9 +343,9 @@ void FrameMaximizeButton::Cancel(bool keep_menu_open) { maximizer_.reset(); UninstallEventFilter(); is_snap_enabled_ = false; + snap_sizer_.reset(); } phantom_window_.reset(); - snap_sizer_.reset(); snap_type_ = SNAP_NONE; update_timer_.Stop(); SchedulePaint(); @@ -394,7 +407,7 @@ void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) { phantom_window_->set_phantom_below_window(maximizer_->GetBubbleWindow()); maximizer_->SetSnapType(snap_type_); } - phantom_window_->Show(ScreenBoundsForType(snap_type_)); + phantom_window_->Show(ScreenBoundsForType(snap_type_, *snap_sizer_.get())); } SnapType FrameMaximizeButton::SnapTypeForLocation( @@ -412,14 +425,16 @@ SnapType FrameMaximizeButton::SnapTypeForLocation( return !frame_->GetWidget()->IsMaximized() ? SNAP_MAXIMIZE : SNAP_RESTORE; } -gfx::Rect FrameMaximizeButton::ScreenBoundsForType(SnapType type) const { +gfx::Rect FrameMaximizeButton::ScreenBoundsForType( + SnapType type, + const SnapSizer& snap_sizer) const { aura::Window* window = frame_->GetWidget()->GetNativeWindow(); switch (type) { case SNAP_LEFT: case SNAP_RIGHT: return ScreenAsh::ConvertRectToScreen( frame_->GetWidget()->GetNativeView()->parent(), - snap_sizer_->target_bounds()); + snap_sizer.target_bounds()); case SNAP_MAXIMIZE: return ScreenAsh::ConvertRectToScreen( window->parent(), @@ -453,16 +468,18 @@ gfx::Point FrameMaximizeButton::LocationForSnapSizer( return result; } -void FrameMaximizeButton::Snap() { +void FrameMaximizeButton::Snap(const SnapSizer& snap_sizer) { switch (snap_type_) { case SNAP_LEFT: case SNAP_RIGHT: if (frame_->GetWidget()->IsMaximized()) { ash::SetRestoreBoundsInScreen(frame_->GetWidget()->GetNativeWindow(), - ScreenBoundsForType(snap_type_)); + ScreenBoundsForType(snap_type_, + snap_sizer)); frame_->GetWidget()->Restore(); } else { - frame_->GetWidget()->SetBounds(ScreenBoundsForType(snap_type_)); + frame_->GetWidget()->SetBounds(ScreenBoundsForType(snap_type_, + snap_sizer)); } break; case SNAP_MAXIMIZE: diff --git a/ash/wm/workspace/frame_maximize_button.h b/ash/wm/workspace/frame_maximize_button.h index 2b0eec7..4c55da1 100644 --- a/ash/wm/workspace/frame_maximize_button.h +++ b/ash/wm/workspace/frame_maximize_button.h @@ -96,14 +96,15 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton, SnapType SnapTypeForLocation(const gfx::Point& location) const; // Returns the bounds of the resulting window for the specified type. - gfx::Rect ScreenBoundsForType(SnapType type) const; + gfx::Rect ScreenBoundsForType(SnapType type, + const internal::SnapSizer& snap_sizer) const; // Converts location to screen coordinates and returns it. These are the // coordinates used by the SnapSizer. gfx::Point LocationForSnapSizer(const gfx::Point& location) const; // Snaps the window to the current snap position. - void Snap(); + void Snap(const internal::SnapSizer& snap_sizer); // Frame that the maximize button acts on. views::NonClientFrameView* frame_; |