123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/touch/touch_hud_renderer.h"
- #include <memory>
- #include "base/scoped_observation.h"
- #include "base/time/time.h"
- #include "third_party/skia/include/effects/SkGradientShader.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_owner.h"
- #include "ui/events/event.h"
- #include "ui/gfx/animation/linear_animation.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/skia_conversions.h"
- #include "ui/views/animation/animation_delegate_views.h"
- #include "ui/views/view.h"
- #include "ui/views/widget/widget.h"
- #include "ui/views/widget/widget_observer.h"
- namespace ash {
- constexpr int kPointRadius = 20;
- constexpr SkColor4f kProjectionFillColor{0.96f, 0.96f, 0.86f, 1.0f};
- constexpr SkColor4f kProjectionStrokeColor = SkColors::kGray;
- constexpr int kProjectionAlpha = 0xB0;
- constexpr base::TimeDelta kFadeoutDuration = base::Milliseconds(250);
- constexpr int kFadeoutFrameRate = 60;
- // TouchPointView draws a single touch point.
- class TouchPointView : public views::View,
- public views::AnimationDelegateViews,
- public views::WidgetObserver {
- public:
- explicit TouchPointView(views::Widget* parent_widget)
- : views::AnimationDelegateViews(this) {
- SetPaintToLayer();
- layer()->SetFillsBoundsOpaquely(false);
- SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2));
- widget_observation_.Observe(parent_widget);
- }
- TouchPointView(const TouchPointView&) = delete;
- TouchPointView& operator=(const TouchPointView&) = delete;
- ~TouchPointView() override = default;
- // Begins fadeout animation. After this is called, |this| owns itself and is
- // responsible for deleting itself when the animation ends or the host widget
- // is destroyed.
- void FadeOut(std::unique_ptr<TouchPointView> self) {
- DCHECK_EQ(this, self.get());
- owned_self_reference_ = std::move(self);
- fadeout_ = std::make_unique<gfx::LinearAnimation>(kFadeoutDuration,
- kFadeoutFrameRate, this);
- fadeout_->Start();
- }
- void UpdateLocation(const ui::LocatedEvent& touch) {
- SetPosition(
- gfx::Point(parent()->GetMirroredXInView(touch.root_location().x()) -
- kPointRadius - 1,
- touch.root_location().y() - kPointRadius - 1));
- }
- private:
- // views::View:
- void OnPaint(gfx::Canvas* canvas) override {
- int alpha = kProjectionAlpha;
- if (fadeout_)
- alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0));
- cc::PaintFlags fill_flags;
- fill_flags.setAlpha(alpha);
- constexpr SkColor4f gradient_colors[2] = {kProjectionFillColor,
- kProjectionStrokeColor};
- constexpr SkScalar gradient_pos[2] = {SkFloatToScalar(0.9f),
- SkFloatToScalar(1.0f)};
- constexpr gfx::Point center(kPointRadius + 1, kPointRadius + 1);
- fill_flags.setShader(cc::PaintShader::MakeRadialGradient(
- gfx::PointToSkPoint(center), SkIntToScalar(kPointRadius),
- gradient_colors, gradient_pos, std::size(gradient_colors),
- SkTileMode::kMirror));
- canvas->DrawCircle(center, SkIntToScalar(kPointRadius), fill_flags);
- cc::PaintFlags stroke_flags;
- stroke_flags.setStyle(cc::PaintFlags::kStroke_Style);
- stroke_flags.setColor(kProjectionStrokeColor);
- stroke_flags.setAlpha(alpha);
- canvas->DrawCircle(center, SkIntToScalar(kPointRadius), stroke_flags);
- }
- // views::AnimationDelegateViews:
- void AnimationEnded(const gfx::Animation* animation) override {
- DCHECK_EQ(fadeout_.get(), animation);
- owned_self_reference_.reset();
- }
- void AnimationProgressed(const gfx::Animation* animation) override {
- DCHECK_EQ(fadeout_.get(), animation);
- SchedulePaint();
- }
- void AnimationCanceled(const gfx::Animation* animation) override {
- AnimationEnded(animation);
- }
- // views::WidgetObserver:
- void OnWidgetDestroying(views::Widget* widget) override {
- owned_self_reference_.reset();
- }
- std::unique_ptr<gfx::Animation> fadeout_;
- // When non-null, |owned_self_reference_| refers to |this|, and |this| owns
- // itself. This should be non-null when fading out, and null otherwise.
- std::unique_ptr<TouchPointView> owned_self_reference_;
- base::ScopedObservation<views::Widget, views::WidgetObserver>
- widget_observation_{this};
- };
- TouchHudRenderer::TouchHudRenderer(views::Widget* parent_widget)
- : parent_widget_(parent_widget) {
- parent_widget_->AddObserver(this);
- }
- TouchHudRenderer::~TouchHudRenderer() {
- if (parent_widget_)
- parent_widget_->RemoveObserver(this);
- CHECK(!IsInObserverList());
- }
- void TouchHudRenderer::Clear() {
- points_.clear();
- }
- void TouchHudRenderer::HandleTouchEvent(const ui::TouchEvent& event) {
- int id = event.pointer_details().id;
- auto iter = points_.find(id);
- if (event.type() == ui::ET_TOUCH_PRESSED) {
- if (iter != points_.end()) {
- TouchPointView* view = iter->second;
- view->parent()->RemoveChildViewT(view);
- points_.erase(iter);
- }
- TouchPointView* point = parent_widget_->GetContentsView()->AddChildView(
- std::make_unique<TouchPointView>(parent_widget_));
- point->UpdateLocation(event);
- auto result = points_.insert(std::make_pair(id, point));
- DCHECK(result.second);
- return;
- }
- if (iter == points_.end())
- return;
- if (event.type() == ui::ET_TOUCH_RELEASED ||
- event.type() == ui::ET_TOUCH_CANCELLED) {
- TouchPointView* view = iter->second;
- view->FadeOut(view->parent()->RemoveChildViewT(view));
- points_.erase(iter);
- } else {
- iter->second->UpdateLocation(event);
- }
- }
- void TouchHudRenderer::OnWidgetDestroying(views::Widget* widget) {
- DCHECK_EQ(widget, parent_widget_);
- parent_widget_->RemoveObserver(this);
- parent_widget_ = nullptr;
- Clear();
- }
- } // namespace ash
|