summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-09 13:21:15 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-09 13:21:15 +0000
commit4aadc39eb6796f3ed92ec34fa6c39c2b8021d849 (patch)
tree767cb8461dc77e119b76f9aefa5025d4934110d0 /ash
parentb58f23cc40de3b07cc3cfa18f96bf07cb5633ed4 (diff)
downloadchromium_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.cc134
-rw-r--r--ash/wm/workspace/frame_maximize_button.cc57
-rw-r--r--ash/wm/workspace/frame_maximize_button.h5
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_;