| 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 case CAPTION_BUTTON_ICON_COUNT: | 196 case CAPTION_BUTTON_ICON_COUNT: |
| 178 NOTREACHED(); | 197 NOTREACHED(); |
| 179 break; | 198 break; |
| 180 } | 199 } |
| 181 } | 200 } |
| 182 | 201 |
| 183 if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { | 202 if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { |
| 184 if (!phantom_window_controller_.get()) { | 203 if (!phantom_window_controller_.get()) { |
| 185 phantom_window_controller_.reset( | 204 phantom_window_controller_.reset( |
| 186 new internal::PhantomWindowController(frame_->GetNativeWindow())); | 205 new internal::PhantomWindowController(frame_->GetNativeWindow())); |
| 187 } | 206 } |
| 188 | 207 |
| 189 using internal::SnapSizer; | 208 using internal::SnapSizer; |
| 190 SnapSizer snap_sizer(wm::GetWindowState(frame_->GetNativeWindow()), | 209 SnapSizer snap_sizer(wm::GetWindowState(frame_->GetNativeWindow()), |
| 191 gfx::Point(), | 210 gfx::Point(), |
| 192 snap_type_ == SNAP_LEFT ? | 211 snap_type_ == SNAP_LEFT ? |
| 193 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE, | 212 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE, |
| 194 SnapSizer::OTHER_INPUT); | 213 SnapSizer::OTHER_INPUT); |
| 195 phantom_window_controller_->Show(ScreenUtil::ConvertRectToScreen( | 214 phantom_window_controller_->Show(ScreenUtil::ConvertRectToScreen( |
| 196 frame_->GetNativeView()->parent(), | 215 frame_->GetNativeView()->parent(), |
| 197 snap_sizer.target_bounds())); | 216 snap_sizer.target_bounds())); |
| 198 } else { | 217 } else { |
| 199 phantom_window_controller_.reset(); | 218 phantom_window_controller_.reset(); |
| 200 } | 219 } |
| 201 } | 220 } |
| 202 | 221 |
| 222 const FrameCaptionButton* AlternateFrameSizeButton::GetButtonToHover( |
| 223 const gfx::Point& event_location_in_screen) const { |
| 224 const FrameCaptionButton* closest_button = delegate_->GetButtonClosestTo( |
| 225 event_location_in_screen); |
| 226 if ((closest_button->icon() == CAPTION_BUTTON_ICON_LEFT_SNAPPED || |
| 227 closest_button->icon() == CAPTION_BUTTON_ICON_RIGHT_SNAPPED) && |
| 228 HitTestButton(closest_button, event_location_in_screen)) { |
| 229 return closest_button; |
| 230 } |
| 231 return NULL; |
| 232 } |
| 233 |
| 203 bool AlternateFrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { | 234 bool AlternateFrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { |
| 204 // The position of |event| may be different than the position of the previous | 235 // The position of |event| may be different than the position of the previous |
| 205 // event. | 236 // event. |
| 206 UpdatePressedButton(event); | 237 UpdateSnapType(event); |
| 207 | 238 |
| 208 if (in_snap_mode_ && | 239 if (in_snap_mode_ && |
| 209 (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { | 240 (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { |
| 210 using internal::SnapSizer; | 241 using internal::SnapSizer; |
| 211 SnapSizer::SnapWindow(ash::wm::GetWindowState(frame_->GetNativeWindow()), | 242 SnapSizer::SnapWindow(ash::wm::GetWindowState(frame_->GetNativeWindow()), |
| 212 snap_type_ == SNAP_LEFT ? | 243 snap_type_ == SNAP_LEFT ? |
| 213 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE); | 244 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE); |
| 214 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( | 245 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( |
| 215 snap_type_ == SNAP_LEFT ? | 246 snap_type_ == SNAP_LEFT ? |
| 216 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT : | 247 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT : |
| 217 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); | 248 ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); |
| 218 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_NO); | 249 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_NO); |
| 219 return true; | 250 return true; |
| 220 } | 251 } |
| 221 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); | 252 SetButtonsToNormalMode(AlternateFrameSizeButtonDelegate::ANIMATE_YES); |
| 222 return false; | 253 return false; |
| 223 } | 254 } |
| 224 | 255 |
| 225 void AlternateFrameSizeButton::SetButtonsToNormalMode( | 256 void AlternateFrameSizeButton::SetButtonsToNormalMode( |
| 226 AlternateFrameSizeButtonDelegate::Animate animate) { | 257 AlternateFrameSizeButtonDelegate::Animate animate) { |
| 227 in_snap_mode_ = false; | 258 in_snap_mode_ = false; |
| 228 snap_type_ = SNAP_NONE; | 259 snap_type_ = SNAP_NONE; |
| 229 set_buttons_to_snap_mode_timer_.Stop(); | 260 set_buttons_to_snap_mode_timer_.Stop(); |
| 230 delegate_->SetButtonsToNormal(animate); | 261 delegate_->SetButtonsToNormal(animate); |
| 231 phantom_window_controller_.reset(); | 262 phantom_window_controller_.reset(); |
| 232 } | 263 } |
| 233 | 264 |
| 234 } // namespace ash | 265 } // namespace ash |
| OLD | NEW |