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

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: Used a timedelta in autoclick controller instead of int. 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/aura/wm_window_aura.h"
10 #include "ash/common/shell_window_ids.h"
11 #include "ash/common/wm/root_window_finder.h"
12 #include "ash/root_window_controller.h"
13 #include "ash/shell.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 AutoclickRingHandler. Draws the actual contents and
jdufault 2016/06/09 16:41:26 Fix wrapping
sammiequon 2016/06/10 19:30:26 Done.
108 // updates as the animation proceeds. It also maintains the views::Widget that
109 // the animation is shown in.
110 class AutoclickRingHandler::AutoclickRingView : public views::View {
111 public:
112 AutoclickRingView(const gfx::Point& event_location, aura::Window* root_window)
113 : views::View(),
114 widget_(CreateAutoclickRingWidget(root_window)),
115 current_angle_(kAutoclickRingAngleStartValue),
116 current_scale_(kAutoclickRingScaleStartValue) {
117 widget_->SetContentsView(this);
118 widget_->SetAlwaysOnTop(true);
119
120 // We are owned by the AutoclickRing.
121 set_owned_by_client();
122 SetNewLocation(event_location, root_window);
123 }
124
125 ~AutoclickRingView() override {}
126
127 void SetNewLocation(const gfx::Point& new_event_location,
128 aura::Window* root_window) {
129 gfx::Point point = new_event_location;
130 aura::client::GetScreenPositionClient(root_window)
131 ->ConvertPointToScreen(root_window, &point);
132 widget_->SetBounds(gfx::Rect(
133 point.x() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
134 point.y() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
135 GetPreferredSize().width(), GetPreferredSize().height()));
136 widget_->Show();
137 widget_->GetNativeView()->layer()->SetOpacity(
138 kAutoclickRingOpacityStartValue);
139 }
140
141 void UpdateWithGrowAnimation(gfx::Animation* animation) {
142 // Update the portion of the circle filled so far and re-draw.
143 current_angle_ = animation->CurrentValueBetween(
144 kAutoclickRingInnerStartAngle, kAutoclickRingAngleEndValue);
145 current_scale_ = animation->CurrentValueBetween(
146 kAutoclickRingScaleStartValue, kAutoclickRingScaleEndValue);
147 widget_->GetNativeView()->layer()->SetOpacity(
148 animation->CurrentValueBetween(kAutoclickRingOpacityStartValue,
149 kAutoclickRingOpacityEndValue));
150 SchedulePaint();
151 }
152
153 void UpdateWithShrinkAnimation(gfx::Animation* animation) {
154 current_scale_ = animation->CurrentValueBetween(
155 kAutoclickRingScaleEndValue, kAutoclickRingShrinkScaleEndValue);
156 widget_->GetNativeView()->layer()->SetOpacity(
157 animation->CurrentValueBetween(kAutoclickRingOpacityEndValue,
158 kAutoclickRingOpacityStartValue));
159 SchedulePaint();
160 }
161
162 private:
163 // Overridden from views::View.
164 gfx::Size GetPreferredSize() const override {
165 return gfx::Size(2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
166 2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth));
167 }
168
169 void OnPaint(gfx::Canvas* canvas) override {
170 gfx::Point center(GetPreferredSize().width() / 2,
171 GetPreferredSize().height() / 2);
172 canvas->Save();
173
174 gfx::Transform scale;
175 scale.Scale(current_scale_, current_scale_);
176 // We want to scale from the center.
177 canvas->Translate(center.OffsetFromOrigin());
178 canvas->Transform(scale);
179 canvas->Translate(-center.OffsetFromOrigin());
180
181 // Paint inner circle.
182 PaintAutoclickRingArc(canvas, center, kAutoclickRingInnerRadius,
183 kAutoclickRingInnerStartAngle, current_angle_);
184 // Paint outer circle.
185 PaintAutoclickRingCircle(canvas, center, kAutoclickRingOuterRadius);
186
187 canvas->Restore();
188 }
189
190 std::unique_ptr<views::Widget> widget_;
191 int current_angle_;
192 double current_scale_;
193
194 DISALLOW_COPY_AND_ASSIGN(AutoclickRingView);
195 };
196
197 ////////////////////////////////////////////////////////////////////////////////
198
199 // AutoclickRingHandler, public
200 AutoclickRingHandler::AutoclickRingHandler()
201 : gfx::LinearAnimation(kAutoclickRingFrameRateHz, nullptr),
202 tap_down_target_(nullptr),
203 current_animation_type_(NONE) {}
204
205 AutoclickRingHandler::~AutoclickRingHandler() {
206 StopAutoclickRing();
207 }
208
209 void AutoclickRingHandler::StartGesture(base::TimeDelta duration,
210 gfx::Point center) {
211 aura::Window* target = GetTargetWindow();
212 if (tap_down_target_ && tap_down_target_ != target)
213 return;
214 StopAutoclickRing();
215 SetTapDownTarget();
216 tap_down_location_ = center;
217 current_animation_type_ = GROW_ANIMATION;
218 StartAnimation(duration);
219 }
220
221 void AutoclickRingHandler::StopGesture() {
222 aura::Window* target = GetTargetWindow();
223 if (tap_down_target_ && tap_down_target_ != target)
224 return;
225 StopAutoclickRing();
226 }
227
228 void AutoclickRingHandler::SetGestureCenter(gfx::Point center) {
229 tap_down_location_ = center;
230 }
231 ////////////////////////////////////////////////////////////////////////////////
jdufault 2016/06/09 16:41:26 Please add a newline before this comment block sta
sammiequon 2016/06/10 19:30:26 Done.
232 // AutoclickRingHandler, private
233 aura::Window* AutoclickRingHandler::GetTargetWindow() {
234 aura::Window* target = ash::WmWindowAura::GetAuraWindow(
235 ash::wm::GetRootWindowAt(tap_down_location_));
236 DCHECK(target) << "Root window not found while rendering autoclick circle;";
237 return target;
238 }
239
240 void AutoclickRingHandler::SetTapDownTarget() {
241 aura::Window* target = GetTargetWindow();
242 SetTapDownTarget(target);
243 }
244
245 void AutoclickRingHandler::StartAnimation(base::TimeDelta delay) {
246 int delay_ms = static_cast<int>(delay.InMilliseconds());
jdufault 2016/06/09 16:41:26 Use brace initialization for casting numeric types
sammiequon 2016/06/10 19:30:26 Done.
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(new AutoclickRingView(tap_down_location_, root_window));
255 SetDuration(delay_ms);
256 Start();
257 break;
258 }
259 case SHRINK_ANIMATION:
260 SetDuration(delay_ms);
261 Start();
262 break;
263 default:
264 NOTREACHED();
265 break;
266 }
267 }
268
269 void AutoclickRingHandler::StopAutoclickRing() {
270 // Since, Animation::Stop() calls AnimationStopped(), we need to reset the
271 // |current_animation_type_| before Stop(), otherwise AnimationStopped() may
272 // start the timer again.
273 current_animation_type_ = NONE;
274 Stop();
275 view_.reset();
276 SetTapDownTarget(nullptr);
277 }
278
279 void AutoclickRingHandler::SetTapDownTarget(aura::Window* target) {
280 if (tap_down_target_ == target)
281 return;
282
283 if (tap_down_target_)
284 tap_down_target_->RemoveObserver(this);
285 tap_down_target_ = target;
286 if (tap_down_target_)
287 tap_down_target_->AddObserver(this);
288 }
289
290 void AutoclickRingHandler::AnimateToState(double state) {
291 DCHECK(view_.get());
292 switch (current_animation_type_) {
293 case GROW_ANIMATION:
294 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
295 view_->UpdateWithGrowAnimation(this);
296 break;
297 case SHRINK_ANIMATION:
298 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
299 view_->UpdateWithShrinkAnimation(this);
300 break;
301 default:
302 NOTREACHED();
303 break;
304 }
305 }
306
307 void AutoclickRingHandler::AnimationStopped() {
308 switch (current_animation_type_) {
309 case GROW_ANIMATION:
310 current_animation_type_ = SHRINK_ANIMATION;
311 StartAnimation(base::TimeDelta());
312 break;
313 case SHRINK_ANIMATION:
314 current_animation_type_ = NONE;
315 // fall through to reset the view.
316 default:
317 view_.reset();
318 SetTapDownTarget(nullptr);
319 break;
320 }
321 }
322
323 void AutoclickRingHandler::OnWindowDestroying(aura::Window* window) {
324 DCHECK_EQ(tap_down_target_, window);
325 StopAutoclickRing();
326 }
327
328 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698