1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ash/touch/touch_hud_projection.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ash/root_window_controller.h" 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ash/shell.h" 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "third_party/skia/include/effects/SkGradientShader.h" 10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h" 12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/linear_animation.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/canvas.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/size.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/views/widget/widget.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace ash { 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kPointRadius = 20; 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC); 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst SkColor kProjectionStrokeColor = SK_ColorGRAY; 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kProjectionAlpha = 0xB0; 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFadeoutDurationInMs = 250; 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFadeoutFrameRate = 60; 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// TouchPointView draws a single touch point. This object manages its own 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// lifetime and deletes itself upon fade-out completion or whenever |Remove()| 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// is explicitly called. 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass TouchPointView : public views::View, 30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public gfx::AnimationDelegate, 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public views::WidgetObserver { 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit TouchPointView(views::Widget* parent_widget) 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : circle_center_(kPointRadius + 1, kPointRadius + 1), 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_center_(SkPoint::Make(kPointRadius + 1, 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kPointRadius + 1)) { 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetPaintToLayer(true); 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetFillsBoundsOpaquely(false); 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2)); 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch stroke_paint_.setStyle(SkPaint::kStroke_Style); 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch stroke_paint_.setColor(kProjectionStrokeColor); 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_colors_[0] = kProjectionFillColor; 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_colors_[1] = kProjectionStrokeColor; 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_pos_[0] = SkFloatToScalar(0.9f); 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_pos_[1] = SkFloatToScalar(1.0f); 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch parent_widget->GetContentsView()->AddChildView(this); 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch parent_widget->AddObserver(this); 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void UpdateTouch(const ui::TouchEvent& touch) { 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (touch.type() == ui::ET_TOUCH_RELEASED || 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch touch.type() == ui::ET_TOUCH_CANCELLED) { 59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) fadeout_.reset(new gfx::LinearAnimation(kFadeoutDurationInMs, 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kFadeoutFrameRate, 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this)); 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fadeout_->Start(); 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch SetX(parent()->GetMirroredXInView(touch.root_location().x()) - 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch kPointRadius - 1); 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetY(touch.root_location().y() - kPointRadius - 1); 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void Remove() { 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delete this; 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~TouchPointView() { 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch GetWidget()->RemoveObserver(this); 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch parent()->RemoveChildView(this); 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Overridden from views::View. 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int alpha = kProjectionAlpha; 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (fadeout_) 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0)); 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fill_paint_.setAlpha(alpha); 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch stroke_paint_.setAlpha(alpha); 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkShader* shader = SkGradientShader::CreateRadial( 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_center_, 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkIntToScalar(kPointRadius), 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_colors_, 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gradient_pos_, 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch arraysize(gradient_colors_), 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkShader::kMirror_TileMode); 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fill_paint_.setShader(shader); 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch shader->unref(); 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fill_paint_); 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch stroke_paint_); 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Overridden from gfx::AnimationDelegate. 103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE { 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_EQ(fadeout_.get(), animation); 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delete this; 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE { 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_EQ(fadeout_.get(), animation); 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SchedulePaint(); 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE { 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AnimationEnded(animation); 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Overridden from views::WidgetObserver. 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (fadeout_) 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) fadeout_->Stop(); 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) else 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Remove(); 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const gfx::Point circle_center_; 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const SkPoint gradient_center_; 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkPaint fill_paint_; 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkPaint stroke_paint_; 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkColor gradient_colors_[2]; 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkScalar gradient_pos_[2]; 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) scoped_ptr<gfx::Animation> fadeout_; 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(TouchPointView); 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TouchHudProjection::TouchHudProjection(aura::Window* initial_root) 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : TouchObserverHUD(initial_root) { 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTouchHudProjection::~TouchHudProjection() { 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid TouchHudProjection::Clear() { 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (std::map<int, TouchPointView*>::iterator iter = points_.begin(); 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch iter != points_.end(); iter++) 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch iter->second->Remove(); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch points_.clear(); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid TouchHudProjection::OnTouchEvent(ui::TouchEvent* event) { 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (event->type() == ui::ET_TOUCH_PRESSED) { 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchPointView* point = new TouchPointView(widget()); 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch point->UpdateTouch(*event); 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::pair<std::map<int, TouchPointView*>::iterator, bool> result = 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch points_.insert(std::make_pair(event->touch_id(), point)); 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If a |TouchPointView| is already mapped to the touch id, remove it and 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // replace it with the new one. 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!result.second) { 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch result.first->second->Remove(); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch result.first->second = point; 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::map<int, TouchPointView*>::iterator iter = 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch points_.find(event->touch_id()); 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (iter != points_.end()) { 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch iter->second->UpdateTouch(*event); 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (event->type() == ui::ET_TOUCH_RELEASED || 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch event->type() == ui::ET_TOUCH_CANCELLED) 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch points_.erase(iter); 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid TouchHudProjection::SetHudForRootWindowController( 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RootWindowController* controller) { 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch controller->set_touch_hud_projection(this); 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid TouchHudProjection::UnsetHudForRootWindowController( 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RootWindowController* controller) { 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch controller->set_touch_hud_projection(NULL); 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace ash 187