1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ash/frame/caption_buttons/frame_size_button.h" 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/metrics/user_metrics_recorder.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/screen_util.h" 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shell.h" 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/touch/touch_uma.h" 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/wm/window_state.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/window_util.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/wm/wm_event.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/wm/workspace/phantom_window_controller.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/i18n/rtl.h" 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/vector2d.h" 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/widget/widget.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The default delay between the user pressing the size button and the buttons 22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// adjacent to the size button morphing into buttons for snapping left and 23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// right. 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kSetButtonsToSnapModeDelayMs = 150; 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The amount that a user can overshoot one of the caption buttons while in 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// "snap mode" and keep the button hovered/pressed. 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kMaxOvershootX = 200; 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kMaxOvershootY = 50; 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Returns true if a mouse drag while in "snap mode" at |location_in_screen| 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// would hover/press |button| or keep it hovered/pressed. 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HitTestButton(const ash::FrameCaptionButton* button, 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const gfx::Point& location_in_screen) { 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect expanded_bounds_in_screen = button->GetBoundsInScreen(); 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (button->state() == views::Button::STATE_HOVERED || 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) button->state() == views::Button::STATE_PRESSED) { 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) expanded_bounds_in_screen.Inset(-kMaxOvershootX, -kMaxOvershootY); 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return expanded_bounds_in_screen.Contains(location_in_screen); 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace ash { 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)FrameSizeButton::FrameSizeButton( 48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) views::ButtonListener* listener, 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) views::Widget* frame, 50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FrameSizeButtonDelegate* delegate) 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) frame_(frame), 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_(delegate), 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) set_buttons_to_snap_mode_delay_ms_(kSetButtonsToSnapModeDelayMs), 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) in_snap_mode_(false), 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_(SNAP_NONE) { 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)FrameSizeButton::~FrameSizeButton() { 60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool FrameSizeButton::OnMousePressed(const ui::MouseEvent& event) { 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // The minimize and close buttons are set to snap left and right when snapping 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // is enabled. Do not enable snapping if the minimize button is not visible. 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // The close button is always visible. 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IsTriggerableEvent(event) && 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !in_snap_mode_ && 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->IsMinimizeButtonVisible()) { 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StartSetButtonsToSnapModeTimer(event); 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FrameCaptionButton::OnMousePressed(event); 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool FrameSizeButton::OnMouseDragged(const ui::MouseEvent& event) { 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateSnapType(event); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // By default a FrameCaptionButton reverts to STATE_NORMAL once the mouse 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // leaves its bounds. Skip FrameCaptionButton's handling when 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // |in_snap_mode_| == true because we want different behavior. 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!in_snap_mode_) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FrameCaptionButton::OnMouseDragged(event); 82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::OnMouseReleased(const ui::MouseEvent& event) { 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!IsTriggerableEvent(event) || !CommitSnap(event)) 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FrameCaptionButton::OnMouseReleased(event); 88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::OnMouseCaptureLost() { 91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); 92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FrameCaptionButton::OnMouseCaptureLost(); 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::OnMouseMoved(const ui::MouseEvent& event) { 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Ignore any synthetic mouse moves during a drag. 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!in_snap_mode_) 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FrameCaptionButton::OnMouseMoved(event); 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::OnGestureEvent(ui::GestureEvent* event) { 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->details().touch_points() > 1) { 103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) StartSetButtonsToSnapModeTimer(*event); 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Go through FrameCaptionButton's handling so that the button gets pressed. 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FrameCaptionButton::OnGestureEvent(event); 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateSnapType(*event); 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->SetHandled(); 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ui::ET_GESTURE_TAP || 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->type() == ui::ET_GESTURE_SCROLL_END || 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->type() == ui::ET_SCROLL_FLING_START || 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->type() == ui::ET_GESTURE_END) { 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (CommitSnap(*event)) { 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ui::ET_GESTURE_TAP) { 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TouchUMA::GetInstance()->RecordGestureAction( 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TouchUMA::GESTURE_FRAMEMAXIMIZE_TAP); 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event->SetHandled(); 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FrameCaptionButton::OnGestureEvent(event); 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::StartSetButtonsToSnapModeTimer( 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const ui::LocatedEvent& event) { 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) set_buttons_to_snap_mode_timer_event_location_ = event.location(); 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (set_buttons_to_snap_mode_delay_ms_ == 0) { 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AnimateButtonsToSnapMode(); 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else { 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) set_buttons_to_snap_mode_timer_.Start( 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FROM_HERE, 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::TimeDelta::FromMilliseconds(set_buttons_to_snap_mode_delay_ms_), 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this, 148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) &FrameSizeButton::AnimateButtonsToSnapMode); 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::AnimateButtonsToSnapMode() { 153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_YES); 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::SetButtonsToSnapMode( 157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FrameSizeButtonDelegate::Animate animate) { 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) in_snap_mode_ = true; 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // When using a right-to-left layout the close button is left of the size 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // button and the minimize button is right of the size button. 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (base::i18n::IsRTL()) { 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CAPTION_BUTTON_ICON_LEFT_SNAPPED, 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) animate); 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_LEFT_SNAPPED, 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CAPTION_BUTTON_ICON_RIGHT_SNAPPED, 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) animate); 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::UpdateSnapType(const ui::LocatedEvent& event) { 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!in_snap_mode_) { 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Set the buttons adjacent to the size button to snap left and right early 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // if the user drags past the drag threshold. 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // |set_buttons_to_snap_mode_timer_| is checked to avoid entering the snap 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // mode as a result of an unsupported drag type (e.g. only the right mouse 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // button is pressed). 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Vector2d delta( 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event.location() - set_buttons_to_snap_mode_timer_event_location_); 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!set_buttons_to_snap_mode_timer_.IsRunning() || 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) !views::View::ExceededDragThreshold(delta)) { 184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AnimateButtonsToSnapMode(); 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::Point event_location_in_screen(event.location()); 190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) views::View::ConvertPointToScreen(this, &event_location_in_screen); 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const FrameCaptionButton* to_hover = 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetButtonToHover(event_location_in_screen); 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool press_size_button = 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) to_hover || HitTestButton(this, event_location_in_screen); 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (to_hover) { 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Progress the minimize and close icon morph animations to the end if they 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // are in progress. 199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_NO); 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) delegate_->SetHoveredAndPressedButtons( 203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) to_hover, press_size_button ? this : NULL); 204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_ = SNAP_NONE; 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (to_hover) { 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (to_hover->icon()) { 208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case CAPTION_BUTTON_ICON_LEFT_SNAPPED: 209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_ = SNAP_LEFT; 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) break; 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_ = SNAP_RIGHT; 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) break; 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: 215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case CAPTION_BUTTON_ICON_MINIMIZE: 216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case CAPTION_BUTTON_ICON_CLOSE: 21703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case CAPTION_BUTTON_ICON_BACK: 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CAPTION_BUTTON_ICON_COUNT: 219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NOTREACHED(); 220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) break; 221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) aura::Window* window = frame_->GetNativeWindow(); 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!phantom_window_controller_.get()) { 227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch phantom_window_controller_.reset(new PhantomWindowController(window)); 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Rect phantom_bounds_in_parent = (snap_type_ == SNAP_LEFT) ? 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) wm::GetDefaultLeftSnappedWindowBoundsInParent(window) : 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) wm::GetDefaultRightSnappedWindowBoundsInParent(window); 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) phantom_window_controller_->Show(ScreenUtil::ConvertRectToScreen( 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window->parent(), phantom_bounds_in_parent)); 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) phantom_window_controller_.reset(); 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const FrameCaptionButton* FrameSizeButton::GetButtonToHover( 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const gfx::Point& event_location_in_screen) const { 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const FrameCaptionButton* closest_button = delegate_->GetButtonClosestTo( 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event_location_in_screen); 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if ((closest_button->icon() == CAPTION_BUTTON_ICON_LEFT_SNAPPED || 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) closest_button->icon() == CAPTION_BUTTON_ICON_RIGHT_SNAPPED) && 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HitTestButton(closest_button, event_location_in_screen)) { 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return closest_button; 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return NULL; 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 251010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool FrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { 252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // The position of |event| may be different than the position of the previous 253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // event. 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UpdateSnapType(event); 255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (in_snap_mode_ && 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) wm::WindowState* window_state = 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) wm::GetWindowState(frame_->GetNativeWindow()); 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UserMetricsRecorder* metrics = Shell::GetInstance()->metrics(); 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const wm::WMEvent snap_event( 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) snap_type_ == SNAP_LEFT ? 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) wm::WM_EVENT_SNAP_LEFT : wm::WM_EVENT_SNAP_RIGHT); 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_state->OnWMEvent(&snap_event); 265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) metrics->RecordUserMetricsAction( 266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_ == SNAP_LEFT ? 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT : 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); 269010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_NO); 270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 272010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); 273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 276010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void FrameSizeButton::SetButtonsToNormalMode( 277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FrameSizeButtonDelegate::Animate animate) { 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) in_snap_mode_ = false; 279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snap_type_ = SNAP_NONE; 280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) set_buttons_to_snap_mode_timer_.Stop(); 281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->SetButtonsToNormal(animate); 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) phantom_window_controller_.reset(); 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace ash 286