OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/wm/caption_buttons/alternate_frame_size_button.h" | 5 #include "ash/wm/caption_buttons/alternate_frame_size_button.h" |
6 | 6 |
7 #include "ash/metrics/user_metrics_recorder.h" | 7 #include "ash/metrics/user_metrics_recorder.h" |
8 #include "ash/screen_util.h" | 8 #include "ash/screen_util.h" |
9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
10 #include "ash/touch/touch_uma.h" | 10 #include "ash/touch/touch_uma.h" |
11 #include "ash/wm/window_state.h" | 11 #include "ash/wm/window_state.h" |
12 #include "ash/wm/workspace/phantom_window_controller.h" | 12 #include "ash/wm/workspace/phantom_window_controller.h" |
13 #include "ash/wm/workspace/snap_sizer.h" | 13 #include "ash/wm/workspace/snap_sizer.h" |
14 #include "ui/gfx/vector2d.h" | 14 #include "ui/gfx/vector2d.h" |
15 #include "ui/views/widget/widget.h" | 15 #include "ui/views/widget/widget.h" |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // The default delay between the user pressing the size button and the buttons | 19 // The default delay between the user pressing the size button and the buttons |
20 // adjacent to the size button morphing into buttons for snapping left and | 20 // adjacent to the size button morphing into buttons for snapping left and |
21 // right. | 21 // right. |
22 const int kSetButtonsToSnapModeDelayMs = 150; | 22 const int kSetButtonsToSnapModeDelayMs = 150; |
23 | 23 |
24 // The amount that a user can overshoot the snap left / snap right button and | 24 // The amount that a user can overshoot one of the caption buttons while in |
25 // keep the snap left / snap right button pressed. | 25 // "snap mode" and keep the button hovered/pressed. |
26 const int kPressedHitBoundsExpandX = 200; | 26 const int kMaxOvershootX = 200; |
27 const int kPressedHitBoundsExpandY = 50; | 27 const int kMaxOvershootY = 50; |
| 28 |
| 29 // Returns true if a mouse drag while in "snap mode" at |location_in_screen| |
| 30 // would hover/press |button| or keep it hovered/pressed. |
| 31 bool HitTestButton(const ash::FrameCaptionButton* button, |
| 32 const gfx::Point& location_in_screen) { |
| 33 gfx::Rect expanded_bounds_in_screen = button->GetBoundsInScreen(); |
| 34 if (button->state() == views::Button::STATE_HOVERED || |
| 35 button->state() == views::Button::STATE_PRESSED) { |
| 36 expanded_bounds_in_screen.Inset(-kMaxOvershootX, -kMaxOvershootY); |
| 37 } |
| 38 return expanded_bounds_in_screen.Contains(location_in_screen); |
| 39 } |
28 | 40 |
29 } // namespace | 41 } // namespace |
30 | 42 |
31 namespace ash { | 43 namespace ash { |
32 | 44 |
33 AlternateFrameSizeButton::AlternateFrameSizeButton( | 45 AlternateFrameSizeButton::AlternateFrameSizeButton( |
34 views::ButtonListener* listener, | 46 views::ButtonListener* listener, |
35 views::Widget* frame, | 47 views::Widget* frame, |
36 AlternateFrameSizeButtonDelegate* delegate) | 48 AlternateFrameSizeButtonDelegate* delegate) |
37 : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), | 49 : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), |
(...skipping 14 matching lines...) Expand all Loading... |
52 if (IsTriggerableEvent(event) && | 64 if (IsTriggerableEvent(event) && |
53 !in_snap_mode_ && | 65 !in_snap_mode_ && |
54 delegate_->IsMinimizeButtonVisible()) { | 66 delegate_->IsMinimizeButtonVisible()) { |
55 StartSetButtonsToSnapModeTimer(event); | 67 StartSetButtonsToSnapModeTimer(event); |
56 } | 68 } |
57 FrameCaptionButton::OnMousePressed(event); | 69 FrameCaptionButton::OnMousePressed(event); |
58 return true; | 70 return true; |
59 } | 71 } |
60 | 72 |
61 bool AlternateFrameSizeButton::OnMouseDragged(const ui::MouseEvent& event) { | 73 bool AlternateFrameSizeButton::OnMouseDragged(const ui::MouseEvent& event) { |
62 UpdatePressedButton(event); | 74 UpdateSnapType(event); |
63 FrameCaptionButton::OnMouseDragged(event); | 75 // By default a FrameCaptionButton reverts to STATE_NORMAL once the mouse |
| 76 // leaves its bounds. Skip FrameCaptionButton's handling when |
| 77 // |in_snap_mode_| == true because we want different behavior. |
| 78 if (!in_snap_mode_) |
| 79 FrameCaptionButton::OnMouseDragged(event); |
64 return true; | 80 return true; |
65 } | 81 } |
66 | 82 |
67 void AlternateFrameSizeButton::OnMouseReleased(const ui::MouseEvent& event) { | 83 void AlternateFrameSizeButton::OnMouseReleased(const ui::MouseEvent& event) { |
68 if (!IsTriggerableEvent(event) || !CommitSnap(event)) | 84 if (!IsTriggerableEvent(event) || !CommitSnap(event)) |
69 FrameCaptionButton::OnMouseReleased(event); | 85 FrameCaptionButton::OnMouseReleased(event); |
70 } | 86 } |
71 | 87 |
72 void AlternateFrameSizeButton::OnMouseCaptureLost() { | 88 void AlternateFrameSizeButton::OnMouseCaptureLost() { |
73 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); | 89 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); |
74 FrameCaptionButton::OnMouseCaptureLost(); | 90 FrameCaptionButton::OnMouseCaptureLost(); |
75 } | 91 } |
76 | 92 |
| 93 void AlternateFrameSizeButton::OnMouseMoved(const ui::MouseEvent& event) { |
| 94 // Ignore any synthetic mouse moves during a drag. |
| 95 if (!in_snap_mode_) |
| 96 FrameCaptionButton::OnMouseMoved(event); |
| 97 } |
| 98 |
77 void AlternateFrameSizeButton::OnGestureEvent(ui::GestureEvent* event) { | 99 void AlternateFrameSizeButton::OnGestureEvent(ui::GestureEvent* event) { |
78 if (event->details().touch_points() > 1) { | 100 if (event->details().touch_points() > 1) { |
79 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); | 101 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); |
80 return; | 102 return; |
81 } | 103 } |
82 | 104 |
83 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | 105 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { |
84 StartSetButtonsToSnapModeTimer(*event); | 106 StartSetButtonsToSnapModeTimer(*event); |
85 // Go through FrameCaptionButton's handling so that the button gets pressed. | 107 // Go through FrameCaptionButton's handling so that the button gets pressed. |
86 FrameCaptionButton::OnGestureEvent(event); | 108 FrameCaptionButton::OnGestureEvent(event); |
87 return; | 109 return; |
88 } | 110 } |
89 | 111 |
90 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || | 112 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || |
91 event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { | 113 event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { |
92 UpdatePressedButton(*event); | 114 UpdateSnapType(*event); |
93 event->SetHandled(); | 115 event->SetHandled(); |
94 return; | 116 return; |
95 } | 117 } |
96 | 118 |
97 if (event->type() == ui::ET_GESTURE_TAP || | 119 if (event->type() == ui::ET_GESTURE_TAP || |
98 event->type() == ui::ET_GESTURE_SCROLL_END || | 120 event->type() == ui::ET_GESTURE_SCROLL_END || |
99 event->type() == ui::ET_SCROLL_FLING_START || | 121 event->type() == ui::ET_SCROLL_FLING_START || |
100 event->type() == ui::ET_GESTURE_END) { | 122 event->type() == ui::ET_GESTURE_END) { |
101 if (CommitSnap(*event)) { | 123 if (CommitSnap(*event)) { |
102 if (event->type() == ui::ET_GESTURE_TAP) { | 124 if (event->type() == ui::ET_GESTURE_TAP) { |
(...skipping 24 matching lines...) Expand all Loading... |
127 | 149 |
128 void AlternateFrameSizeButton::SetButtonsToSnapMode() { | 150 void AlternateFrameSizeButton::SetButtonsToSnapMode() { |
129 if (in_snap_mode_) | 151 if (in_snap_mode_) |
130 return; | 152 return; |
131 in_snap_mode_ = true; | 153 in_snap_mode_ = true; |
132 delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_LEFT_SNAPPED, | 154 delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_LEFT_SNAPPED, |
133 CAPTION_BUTTON_ICON_RIGHT_SNAPPED, | 155 CAPTION_BUTTON_ICON_RIGHT_SNAPPED, |
134 AlternateFrameSizeButtonDelegate::ANIMATE_YES); | 156 AlternateFrameSizeButtonDelegate::ANIMATE_YES); |
135 } | 157 } |
136 | 158 |
137 void AlternateFrameSizeButton::UpdatePressedButton( | 159 void AlternateFrameSizeButton::UpdateSnapType(const ui::LocatedEvent& event) { |
138 const ui::LocatedEvent& event) { | |
139 if (!in_snap_mode_) { | 160 if (!in_snap_mode_) { |
140 // Set the buttons adjacent to the size button to snap left and right early | 161 // Set the buttons adjacent to the size button to snap left and right early |
141 // if the user drags past the drag threshold. | 162 // if the user drags past the drag threshold. |
142 // |set_buttons_to_snap_mode_timer_| is checked to avoid entering the snap | 163 // |set_buttons_to_snap_mode_timer_| is checked to avoid entering the snap |
143 // mode as a result of an unsupported drag type (e.g. only the right mouse | 164 // mode as a result of an unsupported drag type (e.g. only the right mouse |
144 // button is pressed). | 165 // button is pressed). |
145 gfx::Vector2d delta( | 166 gfx::Vector2d delta( |
146 event.location() - set_buttons_to_snap_mode_timer_event_location_); | 167 event.location() - set_buttons_to_snap_mode_timer_event_location_); |
147 if (!set_buttons_to_snap_mode_timer_.IsRunning() || | 168 if (!set_buttons_to_snap_mode_timer_.IsRunning() || |
148 !views::View::ExceededDragThreshold(delta)) { | 169 !views::View::ExceededDragThreshold(delta)) { |
149 return; | 170 return; |
150 } | 171 } |
151 SetButtonsToSnapMode(); | 172 SetButtonsToSnapMode(); |
152 } | 173 } |
153 | 174 |
154 gfx::Point event_location_in_screen(event.location()); | 175 gfx::Point event_location_in_screen(event.location()); |
155 views::View::ConvertPointToScreen(this, &event_location_in_screen); | 176 views::View::ConvertPointToScreen(this, &event_location_in_screen); |
| 177 const FrameCaptionButton* to_hover = |
| 178 GetButtonToHover(event_location_in_screen); |
| 179 bool press_size_button = |
| 180 to_hover || HitTestButton(this, event_location_in_screen); |
| 181 delegate_->SetHoveredAndPressedButtons( |
| 182 to_hover, press_size_button ? this : NULL); |
156 | 183 |
157 gfx::Insets pressed_button_hittest_insets(-kPressedHitBoundsExpandY, | |
158 -kPressedHitBoundsExpandX, | |
159 -kPressedHitBoundsExpandY, | |
160 -kPressedHitBoundsExpandX); | |
161 const FrameCaptionButton* pressed_button = delegate_->PressButtonAt( | |
162 event_location_in_screen, pressed_button_hittest_insets); | |
163 snap_type_ = SNAP_NONE; | 184 snap_type_ = SNAP_NONE; |
164 if (pressed_button) { | 185 if (to_hover) { |
165 switch (pressed_button->icon()) { | 186 switch (to_hover->icon()) { |
166 case CAPTION_BUTTON_ICON_LEFT_SNAPPED: | 187 case CAPTION_BUTTON_ICON_LEFT_SNAPPED: |
167 snap_type_ = SNAP_LEFT; | 188 snap_type_ = SNAP_LEFT; |
168 break; | 189 break; |
169 case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: | 190 case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: |
170 snap_type_ = SNAP_RIGHT; | 191 snap_type_ = SNAP_RIGHT; |
171 break; | 192 break; |
172 case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: | 193 case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: |
173 // snap_type_ = SNAP_NONE | |
174 break; | |
175 case CAPTION_BUTTON_ICON_MINIMIZE: | 194 case CAPTION_BUTTON_ICON_MINIMIZE: |
176 case CAPTION_BUTTON_ICON_CLOSE: | 195 case CAPTION_BUTTON_ICON_CLOSE: |
177 NOTREACHED(); | 196 NOTREACHED(); |
178 break; | 197 break; |
179 } | 198 } |
180 } | 199 } |
181 | 200 |
182 if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { | 201 if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { |
183 if (!phantom_window_controller_.get()) { | 202 if (!phantom_window_controller_.get()) { |
184 phantom_window_controller_.reset( | 203 phantom_window_controller_.reset( |
185 new internal::PhantomWindowController(frame_->GetNativeWindow())); | 204 new internal::PhantomWindowController(frame_->GetNativeWindow())); |
186 } | 205 } |
187 | 206 |
188 using internal::SnapSizer; | 207 using internal::SnapSizer; |
189 SnapSizer snap_sizer(wm::GetWindowState(frame_->GetNativeWindow()), | 208 SnapSizer snap_sizer(wm::GetWindowState(frame_->GetNativeWindow()), |
190 gfx::Point(), | 209 gfx::Point(), |
191 snap_type_ == SNAP_LEFT ? | 210 snap_type_ == SNAP_LEFT ? |
192 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE, | 211 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE, |
193 SnapSizer::OTHER_INPUT); | 212 SnapSizer::OTHER_INPUT); |
194 phantom_window_controller_->Show(ScreenUtil::ConvertRectToScreen( | 213 phantom_window_controller_->Show(ScreenUtil::ConvertRectToScreen( |
195 frame_->GetNativeView()->parent(), | 214 frame_->GetNativeView()->parent(), |
196 snap_sizer.target_bounds())); | 215 snap_sizer.target_bounds())); |
197 } else { | 216 } else { |
198 phantom_window_controller_.reset(); | 217 phantom_window_controller_.reset(); |
199 } | 218 } |
200 } | 219 } |
201 | 220 |
| 221 const FrameCaptionButton* AlternateFrameSizeButton::GetButtonToHover( |
| 222 const gfx::Point& event_location_in_screen) const { |
| 223 const FrameCaptionButton* closest_button = delegate_->GetButtonClosestTo( |
| 224 event_location_in_screen); |
| 225 if ((closest_button->icon() == CAPTION_BUTTON_ICON_LEFT_SNAPPED || |
| 226 closest_button->icon() == CAPTION_BUTTON_ICON_RIGHT_SNAPPED) && |
| 227 HitTestButton(closest_button, event_location_in_screen)) { |
| 228 return closest_button; |
| 229 } |
| 230 return NULL; |
| 231 } |
| 232 |
202 bool AlternateFrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { | 233 bool AlternateFrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { |
203 // The position of |event| may be different than the position of the previous | 234 // The position of |event| may be different than the position of the previous |
204 // event. | 235 // event. |
205 UpdatePressedButton(event); | 236 UpdateSnapType(event); |
206 | 237 |
207 if (in_snap_mode_ && | 238 if (in_snap_mode_ && |
208 (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { | 239 (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { |
209 using internal::SnapSizer; | 240 using internal::SnapSizer; |
210 SnapSizer::SnapWindow(ash::wm::GetWindowState(frame_->GetNativeWindow()), | 241 SnapSizer::SnapWindow(ash::wm::GetWindowState(frame_->GetNativeWindow()), |
211 snap_type_ == SNAP_LEFT ? | 242 snap_type_ == SNAP_LEFT ? |
212 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE); | 243 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE); |
213 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( | 244 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( |
214 snap_type_ == SNAP_LEFT ? | 245 snap_type_ == SNAP_LEFT ? |
215 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT : | 246 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT : |
216 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); | 247 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); |
217 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_NO); | 248 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_NO); |
218 return true; | 249 return true; |
219 } | 250 } |
220 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); | 251 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); |
221 return false; | 252 return false; |
222 } | 253 } |
223 | 254 |
224 void AlternateFrameSizeButton::SetButtonsToNormalMode( | 255 void AlternateFrameSizeButton::SetButtonsToNormalMode( |
225 AlternateFrameSizeButtonDelegate::Animate animate) { | 256 AlternateFrameSizeButtonDelegate::Animate animate) { |
226 in_snap_mode_ = false; | 257 in_snap_mode_ = false; |
227 snap_type_ = SNAP_NONE; | 258 snap_type_ = SNAP_NONE; |
228 set_buttons_to_snap_mode_timer_.Stop(); | 259 set_buttons_to_snap_mode_timer_.Stop(); |
229 delegate_->SetButtonsToNormal(animate); | 260 delegate_->SetButtonsToNormal(animate); |
230 phantom_window_controller_.reset(); | 261 phantom_window_controller_.reset(); |
231 } | 262 } |
232 | 263 |
233 } // namespace ash | 264 } // namespace ash |
OLD | NEW |