Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: chrome/browser/chromeos/ui/autoclick_ring_handler.cc

Issue 2016073004: Show a visual indicator for the progress of auto-click. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Moved ring rendering code to chrome/browser/chromeos/ui Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 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 "chrome/browser/chromeos/ui/autoclick_ring_handler.h"
6
7 #include <memory>
8
9 #include "ash/common/shell_window_ids.h"
10 #include "ash/common/wm/root_window_finder.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/shell.h"
13 #include "ash/wm/aura/wm_window_aura.h"
14 #include "third_party/skia/include/core/SkColor.h"
15 #include "third_party/skia/include/core/SkPaint.h"
16 #include "third_party/skia/include/core/SkPath.h"
17 #include "third_party/skia/include/core/SkRect.h"
18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/window.h"
21 #include "ui/aura/window_event_dispatcher.h"
22 #include "ui/compositor/layer.h"
23 #include "ui/gfx/canvas.h"
24 #include "ui/gfx/transform.h"
25 #include "ui/views/view.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/wm/core/coordinate_conversion.h"
28
29 namespace chromeos {
30 namespace {
31
32 const int kAutoclickRingOuterRadius = 30;
33 const int kAutoclickRingInnerRadius = 20;
34
35 // Angles from x-axis at which the outer and inner circles start.
36 // const int kAutoclickRingOuterStartAngle = 0;
37 const int kAutoclickRingInnerStartAngle = -90;
38
39 const int kAutoclickRingGlowWidth = 20;
40 // The following is half width to avoid division by 2.
41 const int kAutoclickRingArcWidth = 2;
42
43 // Start and end values for various animations.
44 const double kAutoclickRingScaleStartValue = 1.0;
45 const double kAutoclickRingScaleEndValue = 0.5;
46 const double kAutoclickRingShrinkScaleEndValue = 0.5;
47 const double kAutoclickRingOpacityStartValue = 0.1;
48 const double kAutoclickRingOpacityEndValue = 0.5;
49 const int kAutoclickRingAngleStartValue = -90;
50 // The sweep angle is a bit greater than 360 to make sure the circle
51 // completes at the end of the animation.
52 const int kAutoclickRingAngleEndValue = 360;
53
54 // Visual constants.
55 const SkColor kAutoclickRingArcColor = SkColorSetARGB(255, 0, 255, 0);
56 const SkColor kAutoclickRingCircleColor = SkColorSetARGB(255, 0, 0, 255);
57 const int kAutoclickRingFrameRateHz = 60;
58
59 views::Widget* CreateAutoclickRingWidget(aura::Window* root_window) {
60 views::Widget* widget = new views::Widget;
61 views::Widget::InitParams params;
62 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
63 params.keep_on_top = true;
64 params.accept_events = false;
65 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
66 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
67 params.context = root_window;
68 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
69 widget->Init(params);
70 widget->SetOpacity(1.f);
71 ash::GetRootWindowController(root_window)
72 ->GetContainer(ash::kShellWindowId_OverlayContainer)
73 ->AddChild(widget->GetNativeWindow());
74 return widget;
75 }
76
77 void PaintAutoclickRingCircle(gfx::Canvas* canvas,
78 gfx::Point& center,
79 int radius) {
80 SkPaint paint;
81 paint.setStyle(SkPaint::kStroke_Style);
82 paint.setStrokeWidth(2 * kAutoclickRingArcWidth);
83 paint.setColor(kAutoclickRingCircleColor);
84 paint.setAntiAlias(true);
85
86 canvas->DrawCircle(center, radius, paint);
87 }
88 void PaintAutoclickRingArc(gfx::Canvas* canvas,
89 gfx::Point& center,
90 int radius,
91 int start_angle,
92 int end_angle) {
93 SkPaint paint;
94 paint.setStyle(SkPaint::kStroke_Style);
95 paint.setStrokeWidth(2 * kAutoclickRingArcWidth);
96 paint.setColor(kAutoclickRingArcColor);
97 paint.setAntiAlias(true);
98
99 SkPath arc_path;
100 arc_path.addArc(SkRect::MakeXYWH(center.x() - radius, center.y() - radius,
101 2 * radius, 2 * radius),
102 start_angle, end_angle - start_angle);
103 canvas->DrawPath(arc_path, paint);
104 }
105 } // namespace
106
107 // View of the LongPressAutoclickRingHandler. Draws the actual contents and
108 // updates as the animation proceeds. It also maintains the views::Widget that
109 // the animation is shown in.
110 class LongPressAutoclickRingHandler::LongPressAutoclickRingView
111 : public views::View {
112 public:
113 LongPressAutoclickRingView(const gfx::Point& event_location,
114 aura::Window* root_window)
115 : views::View(),
116 widget_(CreateAutoclickRingWidget(root_window)),
117 current_angle_(kAutoclickRingAngleStartValue),
118 current_scale_(kAutoclickRingScaleStartValue) {
119 widget_->SetContentsView(this);
120 widget_->SetAlwaysOnTop(true);
121
122 // We are owned by the LongPressAutoclickRing.
123 set_owned_by_client();
124 SetNewLocation(event_location, root_window);
125 }
126
127 ~LongPressAutoclickRingView() override {}
128
129 void SetNewLocation(const gfx::Point& new_event_location,
130 aura::Window* root_window) {
131 gfx::Point point = new_event_location;
132 aura::client::GetScreenPositionClient(root_window)
133 ->ConvertPointToScreen(root_window, &point);
134 widget_->SetBounds(gfx::Rect(
135 point.x() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
136 point.y() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
137 GetPreferredSize().width(), GetPreferredSize().height()));
138 widget_->Show();
139 widget_->GetNativeView()->layer()->SetOpacity(
140 kAutoclickRingOpacityStartValue);
141 }
142
143 void UpdateWithGrowAnimation(gfx::Animation* animation) {
144 // Update the portion of the circle filled so far and re-draw.
145 current_angle_ = animation->CurrentValueBetween(
146 kAutoclickRingInnerStartAngle, kAutoclickRingAngleEndValue);
147 current_scale_ = animation->CurrentValueBetween(
148 kAutoclickRingScaleStartValue, kAutoclickRingScaleEndValue);
149 widget_->GetNativeView()->layer()->SetOpacity(
150 animation->CurrentValueBetween(kAutoclickRingOpacityStartValue,
151 kAutoclickRingOpacityEndValue));
152 SchedulePaint();
153 }
154
155 void UpdateWithShrinkAnimation(gfx::Animation* animation) {
156 current_scale_ = animation->CurrentValueBetween(
157 kAutoclickRingScaleEndValue, kAutoclickRingShrinkScaleEndValue);
158 widget_->GetNativeView()->layer()->SetOpacity(
159 animation->CurrentValueBetween(kAutoclickRingOpacityEndValue,
160 kAutoclickRingOpacityStartValue));
161 SchedulePaint();
162 }
163
164 private:
165 // Overridden from views::View.
166 gfx::Size GetPreferredSize() const override {
167 return gfx::Size(2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
168 2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth));
169 }
170
171 void OnPaint(gfx::Canvas* canvas) override {
172 gfx::Point center(GetPreferredSize().width() / 2,
173 GetPreferredSize().height() / 2);
174 canvas->Save();
175
176 gfx::Transform scale;
177 scale.Scale(current_scale_, current_scale_);
178 // We want to scale from the center.
179 canvas->Translate(center.OffsetFromOrigin());
180 canvas->Transform(scale);
181 canvas->Translate(-center.OffsetFromOrigin());
182
183 // Paint inner circle.
184 PaintAutoclickRingArc(canvas, center, kAutoclickRingInnerRadius,
185 kAutoclickRingInnerStartAngle, current_angle_);
186 // Paint outer circle.
187 PaintAutoclickRingCircle(canvas, center, kAutoclickRingOuterRadius);
188
189 canvas->Restore();
190 }
191
192 std::unique_ptr<views::Widget> widget_;
193 int current_angle_;
194 double current_scale_;
195
196 DISALLOW_COPY_AND_ASSIGN(LongPressAutoclickRingView);
197 };
198
199 ////////////////////////////////////////////////////////////////////////////////
200 // LongPressAutoclickRingHandler, public
201
202 LongPressAutoclickRingHandler::LongPressAutoclickRingHandler()
203 : gfx::LinearAnimation(kAutoclickRingFrameRateHz, nullptr),
204 tap_down_target_(nullptr),
205 current_animation_type_(NONE) {}
206 LongPressAutoclickRingHandler::~LongPressAutoclickRingHandler() {
207 StopAutoclickRing();
208 }
209
210 void LongPressAutoclickRingHandler::StartGesture(int delay_ms,
211 gfx::Point center) {
212 aura::Window* target = GetTargetWindow();
213 if (tap_down_target_ && tap_down_target_ != target)
214 return;
215 StopAutoclickRing();
216 SetTapDownTarget();
217 tap_down_location_ = center;
218 current_animation_type_ = GROW_ANIMATION;
219 StartAnimation(delay_ms);
220 }
221
222 void LongPressAutoclickRingHandler::StopGesture() {
223 aura::Window* target = GetTargetWindow();
224 if (tap_down_target_ && tap_down_target_ != target)
225 return;
226 StopAutoclickRing();
227 }
228
229 void LongPressAutoclickRingHandler::SetGestureCenter(gfx::Point center) {
230 tap_down_location_ = center;
231 }
232 ////////////////////////////////////////////////////////////////////////////////
jdufault 2016/06/03 22:02:44 Newline between the end of the function and the st
233 // LongPressAutoclickRingHandler, private
234 aura::Window* LongPressAutoclickRingHandler::GetTargetWindow() {
235 aura::Window* target = ash::wm::WmWindowAura::GetAuraWindow(
236 ash::wm::GetRootWindowAt(tap_down_location_));
237 DCHECK(target) << "Root window not found while rendering autoclick circle;";
238 return target;
239 }
240
241 void LongPressAutoclickRingHandler::SetTapDownTarget() {
242 aura::Window* target = GetTargetWindow();
243 SetTapDownTarget(target);
244 }
245
246 void LongPressAutoclickRingHandler::StartAnimation(int delay_ms) {
247 switch (current_animation_type_) {
248 case GROW_ANIMATION: {
249 aura::Window* root_window = tap_down_target_->GetRootWindow();
250 if (!root_window) {
251 StopAutoclickRing();
252 return;
253 }
254 view_.reset(
255 new LongPressAutoclickRingView(tap_down_location_, root_window));
256 SetDuration(delay_ms);
257 Start();
258 break;
259 }
260 case SHRINK_ANIMATION:
261 SetDuration(delay_ms);
262 Start();
263 break;
264 default:
265 NOTREACHED();
266 break;
267 }
268 }
269
270 void LongPressAutoclickRingHandler::StopAutoclickRing() {
271 // Since, Animation::Stop() calls AnimationStopped(), we need to reset the
272 // |current_animation_type_| before Stop(), otherwise AnimationStopped() may
273 // start the timer again.
274 current_animation_type_ = NONE;
275 Stop();
276 view_.reset();
277 SetTapDownTarget(nullptr);
278 }
279
280 void LongPressAutoclickRingHandler::SetTapDownTarget(aura::Window* target) {
281 if (tap_down_target_ == target)
282 return;
283
284 if (tap_down_target_)
285 tap_down_target_->RemoveObserver(this);
286 tap_down_target_ = target;
287 if (tap_down_target_)
288 tap_down_target_->AddObserver(this);
289 }
290
291 void LongPressAutoclickRingHandler::AnimateToState(double state) {
292 DCHECK(view_.get());
293 switch (current_animation_type_) {
294 case GROW_ANIMATION:
295 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
296 view_->UpdateWithGrowAnimation(this);
297 break;
298 case SHRINK_ANIMATION:
299 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
300 view_->UpdateWithShrinkAnimation(this);
301 break;
302 default:
303 NOTREACHED();
304 break;
305 }
306 }
307
308 void LongPressAutoclickRingHandler::AnimationStopped() {
309 switch (current_animation_type_) {
310 case GROW_ANIMATION:
311 current_animation_type_ = SHRINK_ANIMATION;
312 StartAnimation(0);
313 break;
314 case SHRINK_ANIMATION:
315 current_animation_type_ = NONE;
316 // fall through to reset the view.
317 default:
318 view_.reset();
319 SetTapDownTarget(nullptr);
320 break;
321 }
322 }
323
324 void LongPressAutoclickRingHandler::OnWindowDestroying(aura::Window* window) {
325 DCHECK_EQ(tap_down_target_, window);
326 StopAutoclickRing();
327 }
328
329 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698