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

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: Fixed errors from patch set 2. 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
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(int duration_ms, gfx::Point center) {
210 aura::Window* target = GetTargetWindow();
211 if (tap_down_target_ && tap_down_target_ != target)
212 return;
213 StopAutoclickRing();
214 SetTapDownTarget();
215 tap_down_location_ = center;
216 current_animation_type_ = GROW_ANIMATION;
217 StartAnimation(duration_ms);
218 }
219
220 void AutoclickRingHandler::StopGesture() {
221 aura::Window* target = GetTargetWindow();
222 if (tap_down_target_ && tap_down_target_ != target)
223 return;
224 StopAutoclickRing();
225 }
226
227 void AutoclickRingHandler::SetGestureCenter(gfx::Point center) {
228 tap_down_location_ = center;
229 }
230 ////////////////////////////////////////////////////////////////////////////////
231 // AutoclickRingHandler, private
232 aura::Window* AutoclickRingHandler::GetTargetWindow() {
233 aura::Window* target = ash::WmWindowAura::GetAuraWindow(
234 ash::wm::GetRootWindowAt(tap_down_location_));
235 DCHECK(target) << "Root window not found while rendering autoclick circle;";
236 return target;
237 }
238
239 void AutoclickRingHandler::SetTapDownTarget() {
240 aura::Window* target = GetTargetWindow();
241 SetTapDownTarget(target);
242 }
243
244 void AutoclickRingHandler::StartAnimation(int delay_ms) {
245 switch (current_animation_type_) {
246 case GROW_ANIMATION: {
247 aura::Window* root_window = tap_down_target_->GetRootWindow();
248 if (!root_window) {
249 StopAutoclickRing();
250 return;
251 }
252 view_.reset(new AutoclickRingView(tap_down_location_, root_window));
253 SetDuration(delay_ms);
254 Start();
255 break;
256 }
257 case SHRINK_ANIMATION:
258 SetDuration(delay_ms);
259 Start();
260 break;
261 default:
262 NOTREACHED();
263 break;
264 }
265 }
266
267 void AutoclickRingHandler::StopAutoclickRing() {
268 // Since, Animation::Stop() calls AnimationStopped(), we need to reset the
269 // |current_animation_type_| before Stop(), otherwise AnimationStopped() may
270 // start the timer again.
271 current_animation_type_ = NONE;
272 Stop();
273 view_.reset();
274 SetTapDownTarget(nullptr);
275 }
276
277 void AutoclickRingHandler::SetTapDownTarget(aura::Window* target) {
278 if (tap_down_target_ == target)
279 return;
280
281 if (tap_down_target_)
282 tap_down_target_->RemoveObserver(this);
283 tap_down_target_ = target;
284 if (tap_down_target_)
285 tap_down_target_->AddObserver(this);
286 }
287
288 void AutoclickRingHandler::AnimateToState(double state) {
289 DCHECK(view_.get());
290 switch (current_animation_type_) {
291 case GROW_ANIMATION:
292 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
293 view_->UpdateWithGrowAnimation(this);
294 break;
295 case SHRINK_ANIMATION:
296 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
297 view_->UpdateWithShrinkAnimation(this);
298 break;
299 default:
300 NOTREACHED();
301 break;
302 }
303 }
304
305 void AutoclickRingHandler::AnimationStopped() {
306 switch (current_animation_type_) {
307 case GROW_ANIMATION:
308 current_animation_type_ = SHRINK_ANIMATION;
309 StartAnimation(0);
310 break;
311 case SHRINK_ANIMATION:
312 current_animation_type_ = NONE;
313 // fall through to reset the view.
314 default:
315 view_.reset();
316 SetTapDownTarget(nullptr);
317 break;
318 }
319 }
320
321 void AutoclickRingHandler::OnWindowDestroying(aura::Window* window) {
322 DCHECK_EQ(tap_down_target_, window);
323 StopAutoclickRing();
324 }
325
326 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698