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

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: Rebase. 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 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 kAutoclickRingInnerStartAngle = -90;
37
38 const int kAutoclickRingGlowWidth = 20;
39 // The following is half width to avoid division by 2.
40 const int kAutoclickRingArcWidth = 2;
41
42 // Start and end values for various animations.
43 const double kAutoclickRingScaleStartValue = 1.0;
44 const double kAutoclickRingScaleEndValue = 1.0;
45 const double kAutoclickRingShrinkScaleEndValue = 0.5;
46
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.accept_events = false;
64 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
65 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
66 params.context = root_window;
67 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
68 params.parent = ash::Shell::GetContainer(
69 root_window, ash::kShellWindowId_OverlayContainer);
70
71 widget->Init(params);
72 widget->SetOpacity(1.f);
73 return widget;
74 }
75
76 void PaintAutoclickRingCircle(gfx::Canvas* canvas,
77 gfx::Point& center,
78 int radius) {
79 SkPaint paint;
80 paint.setStyle(SkPaint::kStroke_Style);
81 paint.setStrokeWidth(2 * kAutoclickRingArcWidth);
82 paint.setColor(kAutoclickRingCircleColor);
83 paint.setAntiAlias(true);
84
85 canvas->DrawCircle(center, radius, paint);
86 }
87
88 void PaintAutoclickRingArc(gfx::Canvas* canvas,
89 const 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 updates as
108 // the animation proceeds. It also maintains the views::Widget that the
109 // 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
119 // We are owned by the AutoclickRingHandler.
120 set_owned_by_client();
121 SetNewLocation(event_location, root_window);
122 }
123
124 ~AutoclickRingView() override {}
125
126 void SetNewLocation(const gfx::Point& new_event_location,
127 aura::Window* root_window) {
128 gfx::Point point = new_event_location;
129 widget_->SetBounds(gfx::Rect(
130 point.x() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
131 point.y() - (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
132 GetPreferredSize().width(), GetPreferredSize().height()));
133 widget_->Show();
134 widget_->GetNativeView()->layer()->SetOpacity(
135 kAutoclickRingOpacityStartValue);
136 }
137
138 void UpdateWithGrowAnimation(gfx::Animation* animation) {
139 // Update the portion of the circle filled so far and re-draw.
140 current_angle_ = animation->CurrentValueBetween(
141 kAutoclickRingInnerStartAngle, kAutoclickRingAngleEndValue);
142 current_scale_ = animation->CurrentValueBetween(
143 kAutoclickRingScaleStartValue, kAutoclickRingScaleEndValue);
144 widget_->GetNativeView()->layer()->SetOpacity(
145 animation->CurrentValueBetween(kAutoclickRingOpacityStartValue,
146 kAutoclickRingOpacityEndValue));
147 SchedulePaint();
148 }
149
150 void UpdateWithShrinkAnimation(gfx::Animation* animation) {
151 current_angle_ = animation->CurrentValueBetween(
152 kAutoclickRingInnerStartAngle, kAutoclickRingAngleEndValue);
153 current_scale_ = animation->CurrentValueBetween(
154 kAutoclickRingScaleEndValue, kAutoclickRingShrinkScaleEndValue);
155 widget_->GetNativeView()->layer()->SetOpacity(
156 animation->CurrentValueBetween(kAutoclickRingOpacityStartValue,
157 kAutoclickRingOpacityEndValue));
158 SchedulePaint();
159 }
160
161 private:
162 // Overridden from views::View.
163 gfx::Size GetPreferredSize() const override {
164 return gfx::Size(2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth),
165 2 * (kAutoclickRingOuterRadius + kAutoclickRingGlowWidth));
166 }
167
168 void OnPaint(gfx::Canvas* canvas) override {
169 gfx::Point center(GetPreferredSize().width() / 2,
170 GetPreferredSize().height() / 2);
171 canvas->Save();
172
173 gfx::Transform scale;
174 scale.Scale(current_scale_, current_scale_);
175 // We want to scale from the center.
176 canvas->Translate(center.OffsetFromOrigin());
177 canvas->Transform(scale);
178 canvas->Translate(-center.OffsetFromOrigin());
179
180 // Paint inner circle.
181 PaintAutoclickRingArc(canvas, center, kAutoclickRingInnerRadius,
182 kAutoclickRingInnerStartAngle, current_angle_);
183 // Paint outer circle.
184 PaintAutoclickRingCircle(canvas, center, kAutoclickRingOuterRadius);
185
186 canvas->Restore();
187 }
188
189 std::unique_ptr<views::Widget> widget_;
190 int current_angle_;
191 double current_scale_;
192
193 DISALLOW_COPY_AND_ASSIGN(AutoclickRingView);
194 };
195
196 ////////////////////////////////////////////////////////////////////////////////
197
198 // AutoclickRingHandler, public
199 AutoclickRingHandler::AutoclickRingHandler()
200 : gfx::LinearAnimation(kAutoclickRingFrameRateHz, nullptr),
201 tap_down_target_(nullptr),
202 current_animation_type_(AnimationType::NONE) {}
203
204 AutoclickRingHandler::~AutoclickRingHandler() {
205 StopAutoclickRing();
206 }
207
208 void AutoclickRingHandler::StartGesture(
209 base::TimeDelta duration,
210 const gfx::Point& center_point_in_screen) {
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_point_in_screen;
217 current_animation_type_ = AnimationType::GROW_ANIMATION;
218 animation_duration_ = duration;
219 StartAnimation(base::TimeDelta());
220 }
221
222 void AutoclickRingHandler::StopGesture() {
223 aura::Window* target = GetTargetWindow();
224 if (tap_down_target_ && tap_down_target_ != target)
225 return;
226 StopAutoclickRing();
227 }
228
229 void AutoclickRingHandler::SetGestureCenter(
230 const gfx::Point& center_point_in_screen) {
231 tap_down_location_ = center_point_in_screen;
232 }
233 ////////////////////////////////////////////////////////////////////////////////
234
235 // AutoclickRingHandler, private
236 aura::Window* AutoclickRingHandler::GetTargetWindow() {
237 aura::Window* target = ash::WmWindowAura::GetAuraWindow(
238 ash::wm::GetRootWindowAt(tap_down_location_));
239 DCHECK(target) << "Root window not found while rendering autoclick circle;";
240 return target;
241 }
242
243 void AutoclickRingHandler::SetTapDownTarget() {
244 aura::Window* target = GetTargetWindow();
245 SetTapDownTarget(target);
246 }
247
248 void AutoclickRingHandler::StartAnimation(base::TimeDelta delay) {
249 int delay_ms = int{delay.InMilliseconds()};
250 switch (current_animation_type_) {
251 case AnimationType::GROW_ANIMATION: {
252 aura::Window* root_window = tap_down_target_->GetRootWindow();
253 view_.reset(new AutoclickRingView(tap_down_location_, root_window));
254 SetDuration(delay_ms);
255 Start();
256 break;
257 }
258 case AnimationType::SHRINK_ANIMATION: {
259 aura::Window* root_window = tap_down_target_->GetRootWindow();
260 view_.reset(new AutoclickRingView(tap_down_location_, root_window));
261 SetDuration(delay_ms);
262 Start();
263 break;
264 }
265 case AnimationType::NONE:
266 NOTREACHED();
267 break;
268 }
269 }
270
271 void AutoclickRingHandler::StopAutoclickRing() {
272 // Since, Animation::Stop() calls AnimationStopped(), we need to reset the
273 // |current_animation_type_| before Stop(), otherwise AnimationStopped() may
274 // start the timer again.
275 current_animation_type_ = AnimationType::NONE;
276 Stop();
277 view_.reset();
278 SetTapDownTarget(nullptr);
279 }
280
281 void AutoclickRingHandler::SetTapDownTarget(aura::Window* target) {
282 if (tap_down_target_ == target)
283 return;
284
285 if (tap_down_target_)
286 tap_down_target_->RemoveObserver(this);
287 tap_down_target_ = target;
288 if (tap_down_target_)
289 tap_down_target_->AddObserver(this);
290 }
291
292 void AutoclickRingHandler::AnimateToState(double state) {
293 DCHECK(view_.get());
294 switch (current_animation_type_) {
295 case AnimationType::GROW_ANIMATION:
296 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
297 view_->UpdateWithGrowAnimation(this);
298 break;
299 case AnimationType::SHRINK_ANIMATION:
300 view_->SetNewLocation(tap_down_location_, GetTargetWindow());
301 view_->UpdateWithShrinkAnimation(this);
302 break;
303 case AnimationType::NONE:
304 NOTREACHED();
305 break;
306 }
307 }
308
309 void AutoclickRingHandler::AnimationStopped() {
310 switch (current_animation_type_) {
311 case AnimationType::GROW_ANIMATION:
312 current_animation_type_ = AnimationType::SHRINK_ANIMATION;
313 StartAnimation(animation_duration_);
314 break;
315 case AnimationType::SHRINK_ANIMATION:
316 current_animation_type_ = AnimationType::NONE;
317 break;
318 case AnimationType::NONE:
319 // fall through to reset the view.
320 view_.reset();
321 SetTapDownTarget(nullptr);
322 break;
323 }
324 }
325
326 void AutoclickRingHandler::OnWindowDestroying(aura::Window* window) {
327 DCHECK_EQ(tap_down_target_, window);
328 StopAutoclickRing();
329 }
330
331 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/ui/autoclick_ring_handler.h ('k') | chrome/browser/resources/options/browser_options.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698