Index: ash/wm/workspace/frame_maximize_button.cc |
diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc |
index 213f4d21228762557d251138335c7d1dfec32277..152f525c6b1f3b49f9bb8d138de17062b6cd7601 100644 |
--- a/ash/wm/workspace/frame_maximize_button.cc |
+++ b/ash/wm/workspace/frame_maximize_button.cc |
@@ -8,6 +8,7 @@ |
#include "ash/screen_ash.h" |
#include "ash/shell.h" |
#include "ash/wm/property_util.h" |
+#include "ash/wm/maximize_bubble_controller.h" |
#include "ash/wm/workspace/phantom_window_controller.h" |
#include "ash/wm/workspace/snap_sizer.h" |
#include "grit/ash_strings.h" |
@@ -74,7 +75,7 @@ bool FrameMaximizeButton::EscapeEventFilter::PreHandleKeyEvent( |
aura::KeyEvent* event) { |
if (event->type() == ui::ET_KEY_PRESSED && |
event->key_code() == ui::VKEY_ESCAPE) { |
- button_->Cancel(); |
+ button_->Cancel(false); |
} |
return false; |
} |
@@ -105,15 +106,31 @@ FrameMaximizeButton::FrameMaximizeButton(views::ButtonListener* listener, |
frame_(frame), |
is_snap_enabled_(false), |
exceeded_drag_threshold_(false), |
- snap_type_(SNAP_NONE) { |
+ window_(NULL), |
+ snap_type_(workspace::SNAP_NONE) { |
// TODO(sky): nuke this. It's temporary while we don't have good images. |
SetImageAlignment(ALIGN_LEFT, ALIGN_BOTTOM); |
- SetTooltipText(l10n_util::GetStringUTF16(IDS_FRAME_MAXIMIZE_BUTTON_TOOLTIP)); |
} |
FrameMaximizeButton::~FrameMaximizeButton() { |
} |
+void FrameMaximizeButton::OnWindowBoundsChanged( |
+ aura::Window* window, |
+ const gfx::Rect& old_bounds, |
+ const gfx::Rect& new_bounds) { |
+ Cancel(false); |
+} |
+ |
+void FrameMaximizeButton::OnWindowDestroying(aura::Window* window) { |
+ maximizer_.reset(); |
+ if (window_) { |
+ CHECK_EQ(window_, window); |
+ window_->RemoveObserver(this); |
+ window_ = NULL; |
+ } |
+} |
+ |
bool FrameMaximizeButton::OnMousePressed(const views::MouseEvent& event) { |
is_snap_enabled_ = event.IsLeftMouseButton(); |
if (is_snap_enabled_) |
@@ -124,10 +141,30 @@ bool FrameMaximizeButton::OnMousePressed(const views::MouseEvent& event) { |
void FrameMaximizeButton::OnMouseEntered(const views::MouseEvent& event) { |
ImageButton::OnMouseEntered(event); |
+ if (!maximizer_.get()) { |
+ DCHECK(parent()->GetWidget()); |
+ if (!window_ && parent()) { |
+ window_ = parent()->GetWidget()->GetNativeWindow(); |
+ window_->AddObserver(this); |
+ } |
+ maximizer_.reset(new MaximizeBubbleController( |
+ this, |
+ frame_->GetWidget()->IsMaximized())); |
+ } |
} |
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()->bounds().Contains(screen_location)) { |
+ maximizer_.reset(); |
+ // Make sure that all remaining snap hover states get removed. |
+ SnapButtonHovered(workspace::SNAP_NONE); |
+ } |
+ } |
} |
bool FrameMaximizeButton::OnMouseDragged(const views::MouseEvent& event) { |
@@ -139,10 +176,11 @@ bool FrameMaximizeButton::OnMouseDragged(const views::MouseEvent& event) { |
void FrameMaximizeButton::OnMouseReleased(const views::MouseEvent& event) { |
if (!ProcessEndEvent(event)) |
ImageButton::OnMouseReleased(event); |
+ maximizer_.reset(); |
} |
void FrameMaximizeButton::OnMouseCaptureLost() { |
- Cancel(); |
+ Cancel(false); |
ImageButton::OnMouseCaptureLost(); |
} |
@@ -180,59 +218,68 @@ ui::GestureStatus FrameMaximizeButton::OnGestureEvent( |
return ImageButton::OnGestureEvent(event); |
} |
-gfx::ImageSkia FrameMaximizeButton::GetImageToPaint() { |
- if (is_snap_enabled_) { |
- int id = 0; |
- if (frame_->GetWidget()->IsMaximized()) { |
- switch (snap_type_) { |
- case SNAP_LEFT: |
- id = IDR_AURA_WINDOW_MAXIMIZED_SNAP_LEFT_P; |
- break; |
- case SNAP_RIGHT: |
- id = IDR_AURA_WINDOW_MAXIMIZED_SNAP_RIGHT_P; |
- break; |
- case SNAP_MAXIMIZE: |
- case SNAP_RESTORE: |
- case SNAP_NONE: |
- id = IDR_AURA_WINDOW_MAXIMIZED_SNAP_P; |
- break; |
- case SNAP_MINIMIZE: |
- id = IDR_AURA_WINDOW_MAXIMIZED_SNAP_MINIMIZE_P; |
- break; |
- default: |
- NOTREACHED(); |
- } |
- } else { |
- switch (snap_type_) { |
- case SNAP_LEFT: |
- id = IDR_AURA_WINDOW_SNAP_LEFT_P; |
- break; |
- case SNAP_RIGHT: |
- id = IDR_AURA_WINDOW_SNAP_RIGHT_P; |
- break; |
- case SNAP_MAXIMIZE: |
- case SNAP_RESTORE: |
- case SNAP_NONE: |
- id = IDR_AURA_WINDOW_SNAP_P; |
- break; |
- case SNAP_MINIMIZE: |
- id = IDR_AURA_WINDOW_SNAP_MINIMIZE_P; |
- break; |
- default: |
- NOTREACHED(); |
- } |
- } |
- return *ResourceBundle::GetSharedInstance().GetImageNamed(id).ToImageSkia(); |
+void FrameMaximizeButton::SnapButtonHovered(workspace::SnapType type) { |
+ // Make sure to only show hover operations when no button is pressed and |
+ // a similar snap operation in progress does not get re-applied. |
+ if (is_snap_enabled_ || (type == snap_type_ && snap_sizer_.get())) |
+ return; |
+ // Prime the mouse location with the center of the (local) button. |
+ press_location_ = gfx::Point(width() / 2, height() / 2); |
+ // Then get an adjusted mouse position to initiate the effect. |
+ gfx::Point location = press_location_; |
+ switch (type) { |
+ case workspace::SNAP_LEFT: |
+ location.set_x(location.x() - width()); |
+ break; |
+ case workspace::SNAP_RIGHT: |
+ location.set_x(location.x() + width()); |
+ break; |
+ case workspace::SNAP_MINIMIZE: |
+ location.set_y(location.y() + height()); |
+ break; |
+ case workspace::SNAP_MAXIMIZE: |
+ case workspace::SNAP_RESTORE: |
+ break; |
+ case workspace::SNAP_NONE: |
+ Cancel(true); |
+ return; |
+ default: |
+ // We should not come here. |
+ NOTREACHED(); |
} |
- // Hot and pressed states handled by regular ImageButton. |
- return ImageButton::GetImageToPaint(); |
+ UpdateSnap(location); |
+} |
+ |
+void FrameMaximizeButton::ExecuteSnapAndCloseMenu( |
+ workspace::SnapType snap_type) { |
+ DCHECK_NE(snap_type_, workspace::SNAP_NONE); |
+ snap_type_ = snap_type; |
+ Snap(); |
+ // Remove any pending snap previews. |
+ SnapButtonHovered(workspace::SNAP_NONE); |
+ // At this point the operation has been performed and the menu should be |
+ // closed - if not, it'll get now closed. |
+ maximizer_.reset(); |
+} |
+ |
+void FrameMaximizeButton::DestroyMaximizeMenu() { |
+ maximizer_.reset(); |
} |
void FrameMaximizeButton::ProcessStartEvent(const views::LocatedEvent& event) { |
DCHECK(is_snap_enabled_); |
+ // Prepare the help menu. |
+ if (!maximizer_.get()) { |
+ maximizer_.reset(new MaximizeBubbleController( |
+ this, |
+ frame_->GetWidget()->IsMaximized())); |
+ } else { |
+ // If the menu did not show up yet, we delay it even a bit more. |
+ maximizer_->DelayCreation(); |
+ } |
snap_sizer_.reset(NULL); |
InstallEventFilter(); |
- snap_type_ = SNAP_NONE; |
+ snap_type_ = workspace::SNAP_NONE; |
press_location_ = event.location(); |
exceeded_drag_threshold_ = false; |
update_timer_.Start( |
@@ -260,7 +307,12 @@ bool FrameMaximizeButton::ProcessEndEvent(const views::LocatedEvent& event) { |
bool should_snap = is_snap_enabled_; |
is_snap_enabled_ = false; |
- if (!should_snap || snap_type_ == SNAP_NONE) |
+ // Remove our help menu if the mouse cursor is not still over it. |
+ gfx::Point screen_location = gfx::Screen::GetCursorScreenPoint(); |
+ if (!GetBoundsInScreen().Contains(screen_location)) |
+ maximizer_.reset(); |
+ |
+ if (!should_snap || snap_type_ == workspace::SNAP_NONE) |
return false; |
SetState(BS_NORMAL); |
@@ -272,11 +324,15 @@ bool FrameMaximizeButton::ProcessEndEvent(const views::LocatedEvent& event) { |
return true; |
} |
-void FrameMaximizeButton::Cancel() { |
- UninstallEventFilter(); |
- is_snap_enabled_ = false; |
+void FrameMaximizeButton::Cancel(bool keep_menu_open) { |
+ if (!keep_menu_open) { |
+ maximizer_.reset(); |
+ UninstallEventFilter(); |
+ is_snap_enabled_ = false; |
+ } |
phantom_window_.reset(); |
snap_sizer_.reset(); |
+ snap_type_ = workspace::SNAP_NONE; |
update_timer_.Stop(); |
SchedulePaint(); |
} |
@@ -301,7 +357,7 @@ void FrameMaximizeButton::UpdateSnapFromEventLocation() { |
} |
void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) { |
- SnapType type = SnapTypeForLocation(location); |
+ workspace::SnapType type = SnapTypeForLocation(location); |
if (type == snap_type_) { |
if (snap_sizer_.get()) { |
snap_sizer_->Update(LocationForSnapSizer(location)); |
@@ -316,13 +372,14 @@ void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) { |
snap_sizer_.reset(); |
SchedulePaint(); |
- if (snap_type_ == SNAP_NONE) { |
+ if (snap_type_ == workspace::SNAP_NONE) { |
phantom_window_.reset(); |
return; |
} |
- if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { |
- SnapSizer::Edge snap_edge = snap_type_ == SNAP_LEFT ? |
+ if (snap_type_ == workspace::SNAP_LEFT || |
+ snap_type_ == workspace::SNAP_RIGHT) { |
+ SnapSizer::Edge snap_edge = snap_type_ == workspace::SNAP_LEFT ? |
SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE; |
int grid_size = Shell::GetInstance()->GetGridSize(); |
snap_sizer_.reset(new SnapSizer(frame_->GetWidget()->GetNativeWindow(), |
@@ -333,37 +390,44 @@ void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) { |
phantom_window_.reset(new internal::PhantomWindowController( |
frame_->GetWidget()->GetNativeWindow())); |
} |
+ if (maximizer_.get()) { |
+ phantom_window_->set_phantom_below_window(maximizer_->GetBubbleWindow()); |
+ maximizer_->SetSnapType(snap_type_); |
+ } |
phantom_window_->Show(ScreenBoundsForType(snap_type_)); |
} |
-FrameMaximizeButton::SnapType FrameMaximizeButton::SnapTypeForLocation( |
+workspace::SnapType FrameMaximizeButton::SnapTypeForLocation( |
const gfx::Point& location) const { |
int delta_x = location.x() - press_location_.x(); |
int delta_y = location.y() - press_location_.y(); |
if (!views::View::ExceededDragThreshold(delta_x, delta_y)) |
- return !frame_->GetWidget()->IsMaximized() ? SNAP_MAXIMIZE : SNAP_RESTORE; |
+ return !frame_->GetWidget()->IsMaximized() ? workspace::SNAP_MAXIMIZE : |
+ workspace::SNAP_RESTORE; |
else if (delta_x < 0 && delta_y > delta_x && delta_y < -delta_x) |
- return SNAP_LEFT; |
+ return workspace::SNAP_LEFT; |
else if (delta_x > 0 && delta_y > -delta_x && delta_y < delta_x) |
- return SNAP_RIGHT; |
+ return workspace::SNAP_RIGHT; |
else if (delta_y > 0) |
- return SNAP_MINIMIZE; |
- return !frame_->GetWidget()->IsMaximized() ? SNAP_MAXIMIZE : SNAP_RESTORE; |
+ return workspace::SNAP_MINIMIZE; |
+ return !frame_->GetWidget()->IsMaximized() ? workspace::SNAP_MAXIMIZE : |
+ workspace::SNAP_RESTORE; |
} |
-gfx::Rect FrameMaximizeButton::ScreenBoundsForType(SnapType type) const { |
+gfx::Rect FrameMaximizeButton::ScreenBoundsForType( |
+ workspace::SnapType type) const { |
aura::Window* window = frame_->GetWidget()->GetNativeWindow(); |
switch (type) { |
- case SNAP_LEFT: |
- case SNAP_RIGHT: |
+ case workspace::SNAP_LEFT: |
+ case workspace::SNAP_RIGHT: |
return ScreenAsh::ConvertRectToScreen( |
frame_->GetWidget()->GetNativeView()->parent(), |
snap_sizer_->target_bounds()); |
- case SNAP_MAXIMIZE: |
+ case workspace::SNAP_MAXIMIZE: |
return ScreenAsh::ConvertRectToScreen( |
window->parent(), |
ScreenAsh::GetMaximizedWindowBoundsInParent(window)); |
- case SNAP_MINIMIZE: { |
+ case workspace::SNAP_MINIMIZE: { |
Launcher* launcher = Shell::GetInstance()->launcher(); |
gfx::Rect item_rect(launcher->GetScreenBoundsOfItemIconForWindow(window)); |
if (!item_rect.IsEmpty()) { |
@@ -374,12 +438,12 @@ gfx::Rect FrameMaximizeButton::ScreenBoundsForType(SnapType type) const { |
} |
return launcher->widget()->GetWindowBoundsInScreen(); |
} |
- case SNAP_RESTORE: { |
+ case workspace::SNAP_RESTORE: { |
const gfx::Rect* restore = GetRestoreBoundsInScreen(window); |
return restore ? |
*restore : frame_->GetWidget()->GetWindowBoundsInScreen(); |
} |
- case SNAP_NONE: |
+ case workspace::SNAP_NONE: |
NOTREACHED(); |
} |
return gfx::Rect(); |
@@ -394,8 +458,8 @@ gfx::Point FrameMaximizeButton::LocationForSnapSizer( |
void FrameMaximizeButton::Snap() { |
switch (snap_type_) { |
- case SNAP_LEFT: |
- case SNAP_RIGHT: |
+ case workspace::SNAP_LEFT: |
+ case workspace::SNAP_RIGHT: |
if (frame_->GetWidget()->IsMaximized()) { |
ash::SetRestoreBoundsInScreen(frame_->GetWidget()->GetNativeWindow(), |
ScreenBoundsForType(snap_type_)); |
@@ -404,16 +468,16 @@ void FrameMaximizeButton::Snap() { |
frame_->GetWidget()->SetBounds(ScreenBoundsForType(snap_type_)); |
} |
break; |
- case SNAP_MAXIMIZE: |
+ case workspace::SNAP_MAXIMIZE: |
frame_->GetWidget()->Maximize(); |
break; |
- case SNAP_MINIMIZE: |
+ case workspace::SNAP_MINIMIZE: |
frame_->GetWidget()->Minimize(); |
break; |
- case SNAP_RESTORE: |
+ case workspace::SNAP_RESTORE: |
frame_->GetWidget()->Restore(); |
break; |
- case SNAP_NONE: |
+ case workspace::SNAP_NONE: |
NOTREACHED(); |
} |
} |