1 // Copyright 2013 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.
5 #include "ash/touch/touch_hud_projection.h"
7 #include "ash/root_window_controller.h"
9 #include "skia/ext/refptr.h"
10 #include "third_party/skia/include/effects/SkGradientShader.h"
11 #include "ui/events/event.h"
12 #include "ui/gfx/animation/animation_delegate.h"
13 #include "ui/gfx/animation/linear_animation.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/geometry/size.h"
16 #include "ui/views/widget/widget.h"
20 const int kPointRadius
= 20;
21 const SkColor kProjectionFillColor
= SkColorSetRGB(0xF5, 0xF5, 0xDC);
22 const SkColor kProjectionStrokeColor
= SK_ColorGRAY
;
23 const int kProjectionAlpha
= 0xB0;
24 const int kFadeoutDurationInMs
= 250;
25 const int kFadeoutFrameRate
= 60;
27 // TouchPointView draws a single touch point. This object manages its own
28 // lifetime and deletes itself upon fade-out completion or whenever |Remove()|
29 // is explicitly called.
30 class TouchPointView
: public views::View
,
31 public gfx::AnimationDelegate
,
32 public views::WidgetObserver
{
34 explicit TouchPointView(views::Widget
* parent_widget
)
35 : circle_center_(kPointRadius
+ 1, kPointRadius
+ 1),
36 gradient_center_(SkPoint::Make(kPointRadius
+ 1,
38 SetPaintToLayer(true);
39 SetFillsBoundsOpaquely(false);
41 SetSize(gfx::Size(2 * kPointRadius
+ 2, 2 * kPointRadius
+ 2));
43 stroke_paint_
.setStyle(SkPaint::kStroke_Style
);
44 stroke_paint_
.setColor(kProjectionStrokeColor
);
46 gradient_colors_
[0] = kProjectionFillColor
;
47 gradient_colors_
[1] = kProjectionStrokeColor
;
49 gradient_pos_
[0] = SkFloatToScalar(0.9f
);
50 gradient_pos_
[1] = SkFloatToScalar(1.0f
);
52 parent_widget
->GetContentsView()->AddChildView(this);
54 parent_widget
->AddObserver(this);
57 void UpdateTouch(const ui::TouchEvent
& touch
) {
58 if (touch
.type() == ui::ET_TOUCH_RELEASED
||
59 touch
.type() == ui::ET_TOUCH_CANCELLED
) {
60 fadeout_
.reset(new gfx::LinearAnimation(kFadeoutDurationInMs
,
65 SetX(parent()->GetMirroredXInView(touch
.root_location().x()) -
67 SetY(touch
.root_location().y() - kPointRadius
- 1);
76 ~TouchPointView() override
{
77 GetWidget()->RemoveObserver(this);
78 parent()->RemoveChildView(this);
81 // Overridden from views::View.
82 void OnPaint(gfx::Canvas
* canvas
) override
{
83 int alpha
= kProjectionAlpha
;
85 alpha
= static_cast<int>(fadeout_
->CurrentValueBetween(alpha
, 0));
86 fill_paint_
.setAlpha(alpha
);
87 stroke_paint_
.setAlpha(alpha
);
88 skia::RefPtr
<SkShader
> shader
= skia::AdoptRef(
89 SkGradientShader::CreateRadial(gradient_center_
,
90 SkIntToScalar(kPointRadius
),
93 arraysize(gradient_colors_
),
94 SkShader::kMirror_TileMode
));
95 fill_paint_
.setShader(shader
.get());
96 canvas
->DrawCircle(circle_center_
, SkIntToScalar(kPointRadius
),
98 canvas
->DrawCircle(circle_center_
, SkIntToScalar(kPointRadius
),
102 // Overridden from gfx::AnimationDelegate.
103 void AnimationEnded(const gfx::Animation
* animation
) override
{
104 DCHECK_EQ(fadeout_
.get(), animation
);
108 void AnimationProgressed(const gfx::Animation
* animation
) override
{
109 DCHECK_EQ(fadeout_
.get(), animation
);
113 void AnimationCanceled(const gfx::Animation
* animation
) override
{
114 AnimationEnded(animation
);
117 // Overridden from views::WidgetObserver.
118 void OnWidgetDestroying(views::Widget
* widget
) override
{
125 const gfx::Point circle_center_
;
126 const SkPoint gradient_center_
;
129 SkPaint stroke_paint_
;
130 SkColor gradient_colors_
[2];
131 SkScalar gradient_pos_
[2];
133 scoped_ptr
<gfx::Animation
> fadeout_
;
135 DISALLOW_COPY_AND_ASSIGN(TouchPointView
);
138 TouchHudProjection::TouchHudProjection(aura::Window
* initial_root
)
139 : TouchObserverHUD(initial_root
) {
142 TouchHudProjection::~TouchHudProjection() {
145 void TouchHudProjection::Clear() {
146 for (std::map
<int, TouchPointView
*>::iterator iter
= points_
.begin();
147 iter
!= points_
.end(); iter
++)
148 iter
->second
->Remove();
152 void TouchHudProjection::OnTouchEvent(ui::TouchEvent
* event
) {
153 if (event
->type() == ui::ET_TOUCH_PRESSED
) {
154 TouchPointView
* point
= new TouchPointView(widget());
155 point
->UpdateTouch(*event
);
156 std::pair
<std::map
<int, TouchPointView
*>::iterator
, bool> result
=
157 points_
.insert(std::make_pair(event
->touch_id(), point
));
158 // If a |TouchPointView| is already mapped to the touch id, remove it and
159 // replace it with the new one.
160 if (!result
.second
) {
161 result
.first
->second
->Remove();
162 result
.first
->second
= point
;
165 std::map
<int, TouchPointView
*>::iterator iter
=
166 points_
.find(event
->touch_id());
167 if (iter
!= points_
.end()) {
168 iter
->second
->UpdateTouch(*event
);
169 if (event
->type() == ui::ET_TOUCH_RELEASED
||
170 event
->type() == ui::ET_TOUCH_CANCELLED
)
176 void TouchHudProjection::SetHudForRootWindowController(
177 RootWindowController
* controller
) {
178 controller
->set_touch_hud_projection(this);
181 void TouchHudProjection::UnsetHudForRootWindowController(
182 RootWindowController
* controller
) {
183 controller
->set_touch_hud_projection(NULL
);