| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "mash/wm/move_loop.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "components/mus/public/cpp/window.h" | |
| 9 #include "components/mus/public/interfaces/input_event_constants.mojom.h" | |
| 10 #include "mash/wm/property_util.h" | |
| 11 #include "ui/gfx/geometry/point_conversions.h" | |
| 12 #include "ui/gfx/geometry/rect.h" | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 gfx::Point EventLocationToPoint(const mus::mojom::Event& event) { | |
| 17 return gfx::ToFlooredPoint(gfx::PointF(event.pointer_data->location->x, | |
| 18 event.pointer_data->location->y)); | |
| 19 } | |
| 20 | |
| 21 gfx::Point EventScreenLocationToPoint(const mus::mojom::Event& event) { | |
| 22 return gfx::ToFlooredPoint( | |
| 23 gfx::PointF(event.pointer_data->location->screen_x, | |
| 24 event.pointer_data->location->screen_y)); | |
| 25 } | |
| 26 | |
| 27 mus::mojom::EventFlags MouseOnlyEventFlags(mus::mojom::EventFlags flags) { | |
| 28 return static_cast<mus::mojom::EventFlags>( | |
| 29 flags & (mus::mojom::EVENT_FLAGS_LEFT_MOUSE_BUTTON | | |
| 30 mus::mojom::EVENT_FLAGS_MIDDLE_MOUSE_BUTTON | | |
| 31 mus::mojom::EVENT_FLAGS_RIGHT_MOUSE_BUTTON)); | |
| 32 } | |
| 33 | |
| 34 gfx::Rect ClientAreaBounds(const mus::Window* window) { | |
| 35 gfx::Rect client_area(window->bounds().size()); | |
| 36 client_area.Inset(window->client_area()); | |
| 37 return client_area; | |
| 38 } | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 42 MoveLoop::~MoveLoop() { | |
| 43 if (target_) | |
| 44 target_->RemoveObserver(this); | |
| 45 } | |
| 46 | |
| 47 // static | |
| 48 scoped_ptr<MoveLoop> MoveLoop::Create(mus::Window* target, | |
| 49 const mus::mojom::Event& event) { | |
| 50 DCHECK_EQ(event.action, mus::mojom::EVENT_TYPE_POINTER_DOWN); | |
| 51 const gfx::Point location(EventLocationToPoint(event)); | |
| 52 if (!gfx::Rect(target->bounds().size()).Contains(location) || | |
| 53 ClientAreaBounds(target).Contains(location)) { | |
| 54 return nullptr; | |
| 55 } | |
| 56 | |
| 57 // Start a move on left mouse, or any other type of pointer. | |
| 58 if (event.pointer_data->kind == mus::mojom::POINTER_KIND_MOUSE && | |
| 59 MouseOnlyEventFlags(event.flags) != | |
| 60 mus::mojom::EVENT_FLAGS_LEFT_MOUSE_BUTTON) { | |
| 61 return nullptr; | |
| 62 } | |
| 63 | |
| 64 Type type; | |
| 65 HorizontalLocation h_loc; | |
| 66 VerticalLocation v_loc; | |
| 67 DetermineType(target, location, &type, &h_loc, &v_loc); | |
| 68 | |
| 69 return make_scoped_ptr(new MoveLoop(target, event, type, h_loc, v_loc)); | |
| 70 } | |
| 71 | |
| 72 MoveLoop::MoveResult MoveLoop::Move(const mus::mojom::Event& event) { | |
| 73 switch (event.action) { | |
| 74 case mus::mojom::EVENT_TYPE_POINTER_CANCEL: | |
| 75 if (event.pointer_data->pointer_id == pointer_id_) { | |
| 76 if (target_) | |
| 77 Revert(); | |
| 78 return MoveResult::DONE; | |
| 79 } | |
| 80 return MoveResult::CONTINUE; | |
| 81 | |
| 82 case mus::mojom::EVENT_TYPE_POINTER_MOVE: | |
| 83 if (target_ && event.pointer_data->pointer_id == pointer_id_) | |
| 84 MoveImpl(event); | |
| 85 return MoveResult::CONTINUE; | |
| 86 | |
| 87 case mus::mojom::EVENT_TYPE_POINTER_UP: | |
| 88 if (event.pointer_data->pointer_id == pointer_id_) { | |
| 89 // TODO(sky): need to support changed_flags. | |
| 90 if (target_) | |
| 91 MoveImpl(event); | |
| 92 return MoveResult::DONE; | |
| 93 } | |
| 94 return MoveResult::CONTINUE; | |
| 95 | |
| 96 default: | |
| 97 break; | |
| 98 } | |
| 99 | |
| 100 return MoveResult::CONTINUE; | |
| 101 } | |
| 102 | |
| 103 MoveLoop::MoveLoop(mus::Window* target, | |
| 104 const mus::mojom::Event& event, | |
| 105 Type type, | |
| 106 HorizontalLocation h_loc, | |
| 107 VerticalLocation v_loc) | |
| 108 : target_(target), | |
| 109 type_(type), | |
| 110 h_loc_(h_loc), | |
| 111 v_loc_(v_loc), | |
| 112 pointer_id_(event.pointer_data->pointer_id), | |
| 113 initial_event_screen_location_(EventScreenLocationToPoint(event)), | |
| 114 initial_window_bounds_(target->bounds()), | |
| 115 initial_user_set_bounds_(GetWindowUserSetBounds(target)), | |
| 116 changing_bounds_(false) { | |
| 117 target->AddObserver(this); | |
| 118 } | |
| 119 | |
| 120 // static | |
| 121 void MoveLoop::DetermineType(mus::Window* target, | |
| 122 const gfx::Point& location, | |
| 123 Type* type, | |
| 124 HorizontalLocation* h_loc, | |
| 125 VerticalLocation* v_loc) { | |
| 126 *h_loc = HorizontalLocation::OTHER; | |
| 127 *v_loc = VerticalLocation::OTHER; | |
| 128 const int resize_size = static_cast<int>( | |
| 129 kResizeSize * | |
| 130 std::max(1.f, target->viewport_metrics().device_pixel_ratio)); | |
| 131 | |
| 132 const gfx::Rect client_area(ClientAreaBounds(target)); | |
| 133 if (location.x() < client_area.x()) | |
| 134 *h_loc = HorizontalLocation::LEFT; | |
| 135 else if (location.x() >= client_area.right()) | |
| 136 *h_loc = HorizontalLocation::RIGHT; | |
| 137 else | |
| 138 *h_loc = HorizontalLocation::OTHER; | |
| 139 | |
| 140 if (location.y() < resize_size) | |
| 141 *v_loc = VerticalLocation::TOP; | |
| 142 else if (location.y() >= client_area.bottom()) | |
| 143 *v_loc = VerticalLocation::BOTTOM; | |
| 144 else | |
| 145 *v_loc = VerticalLocation::OTHER; | |
| 146 | |
| 147 if (*v_loc == VerticalLocation::OTHER && location.y() >= resize_size && | |
| 148 *h_loc == HorizontalLocation::OTHER) { | |
| 149 *type = Type::MOVE; | |
| 150 return; | |
| 151 } | |
| 152 *type = Type::RESIZE; | |
| 153 DCHECK(*h_loc != HorizontalLocation::OTHER || | |
| 154 *v_loc != VerticalLocation::OTHER); | |
| 155 } | |
| 156 | |
| 157 void MoveLoop::MoveImpl(const mus::mojom::Event& event) { | |
| 158 const gfx::Vector2d delta = | |
| 159 EventScreenLocationToPoint(event) - initial_event_screen_location_; | |
| 160 const gfx::Rect new_bounds(DetermineBoundsFromDelta(delta)); | |
| 161 base::AutoReset<bool> resetter(&changing_bounds_, true); | |
| 162 target_->SetBounds(new_bounds); | |
| 163 SetWindowUserSetBounds(target_, new_bounds); | |
| 164 } | |
| 165 | |
| 166 void MoveLoop::Cancel() { | |
| 167 target_->RemoveObserver(this); | |
| 168 target_ = nullptr; | |
| 169 } | |
| 170 | |
| 171 void MoveLoop::Revert() { | |
| 172 base::AutoReset<bool> resetter(&changing_bounds_, true); | |
| 173 target_->SetBounds(initial_window_bounds_); | |
| 174 SetWindowUserSetBounds(target_, initial_user_set_bounds_); | |
| 175 } | |
| 176 | |
| 177 gfx::Rect MoveLoop::DetermineBoundsFromDelta(const gfx::Vector2d& delta) { | |
| 178 if (type_ == Type::MOVE) { | |
| 179 return gfx::Rect(initial_window_bounds_.origin() + delta, | |
| 180 initial_window_bounds_.size()); | |
| 181 } | |
| 182 | |
| 183 // TODO(sky): support better min sizes, make sure doesn't get bigger than | |
| 184 // screen and max. Also make sure keep some portion on screen. | |
| 185 gfx::Rect bounds(initial_window_bounds_); | |
| 186 if (h_loc_ == HorizontalLocation::LEFT) { | |
| 187 const int x = std::min(bounds.right() - 1, bounds.x() + delta.x()); | |
| 188 const int width = bounds.right() - x; | |
| 189 bounds.set_x(x); | |
| 190 bounds.set_width(width); | |
| 191 } else if (h_loc_ == HorizontalLocation::RIGHT) { | |
| 192 bounds.set_width(std::max(1, bounds.width() + delta.x())); | |
| 193 } | |
| 194 | |
| 195 if (v_loc_ == VerticalLocation::TOP) { | |
| 196 const int y = std::min(bounds.bottom() - 1, bounds.y() + delta.y()); | |
| 197 const int height = bounds.bottom() - y; | |
| 198 bounds.set_y(y); | |
| 199 bounds.set_height(height); | |
| 200 } else if (v_loc_ == VerticalLocation::BOTTOM) { | |
| 201 bounds.set_height(std::max(1, bounds.height() + delta.y())); | |
| 202 } | |
| 203 | |
| 204 return bounds; | |
| 205 } | |
| 206 | |
| 207 void MoveLoop::OnTreeChanged(const TreeChangeParams& params) { | |
| 208 if (params.target == target_) | |
| 209 Cancel(); | |
| 210 } | |
| 211 | |
| 212 void MoveLoop::OnWindowBoundsChanged(mus::Window* window, | |
| 213 const gfx::Rect& old_bounds, | |
| 214 const gfx::Rect& new_bounds) { | |
| 215 DCHECK_EQ(window, target_); | |
| 216 if (!changing_bounds_) | |
| 217 Cancel(); | |
| 218 } | |
| 219 | |
| 220 void MoveLoop::OnWindowVisibilityChanged(mus::Window* window) { | |
| 221 DCHECK_EQ(window, target_); | |
| 222 Cancel(); | |
| 223 } | |
| OLD | NEW |