15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/gestures/long_press_affordance_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/display/display_controller.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/root_window_controller.h" 968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ash/shell.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPath.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkRect.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/effects/SkGradientShader.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/client/screen_position_client.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h" 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h" 2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/events/gestures/gesture_configuration.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/transform.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace ash { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceOuterRadius = 60; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceInnerRadius = 50; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Angles from x-axis at which the outer and inner circles start. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceOuterStartAngle = -109; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceInnerStartAngle = -65; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceGlowWidth = 20; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following is half width to avoid division by 2. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceArcWidth = 3; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start and end values for various animations. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kAffordanceScaleStartValue = 0.8; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kAffordanceScaleEndValue = 1.0; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kAffordanceShrinkScaleEndValue = 0.5; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kAffordanceOpacityStartValue = 0.1; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kAffordanceOpacityEndValue = 0.5; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceAngleStartValue = 0; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The end angle is a bit greater than 360 to make sure the circle completes at 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the end of the animation. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceAngleEndValue = 380; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceDelayBeforeShrinkMs = 200; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceShrinkAnimationDurationMs = 100; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Visual constants. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kAffordanceGlowStartColor = SkColorSetARGB(24, 255, 255, 255); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kAffordanceGlowEndColor = SkColorSetARGB(0, 255, 255, 255); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kAffordanceArcColor = SkColorSetARGB(80, 0, 0, 0); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAffordanceFrameRateHz = 60; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)views::Widget* CreateAffordanceWidget(aura::Window* root_window) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* widget = new views::Widget; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget::InitParams params; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.keep_on_top = true; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.accept_events = false; 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.context = root_window; 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget->Init(params); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget->SetOpacity(0xFF); 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetRootWindowController(root_window)->GetContainer( 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) kShellWindowId_OverlayContainer)->AddChild(widget->GetNativeWindow()); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return widget; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintAffordanceArc(gfx::Canvas* canvas, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point& center, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int radius, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_angle, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int end_angle) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kStroke_Style); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStrokeWidth(2 * kAffordanceArcWidth); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(kAffordanceArcColor); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setAntiAlias(true); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath arc_path; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arc_path.addArc(SkRect::MakeXYWH(center.x() - radius, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center.y() - radius, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2 * radius, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2 * radius), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_angle, end_angle); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawPath(arc_path, paint); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintAffordanceGlow(gfx::Canvas* canvas, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point& center, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_radius, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int end_radius, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColor* colors, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar* pos, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_colors) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPoint sk_center; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int radius = (end_radius + start_radius) / 2; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int glow_width = end_radius - start_radius; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sk_center.iset(center.x(), center.y()); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) skia::RefPtr<SkShader> shader = skia::AdoptRef( 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkGradientShader::CreateTwoPointRadial( 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sk_center, 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkIntToScalar(start_radius), 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sk_center, 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkIntToScalar(end_radius), 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) colors, 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pos, 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_colors, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkShader::kClamp_TileMode)); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(shader); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kStroke_Style); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStrokeWidth(glow_width); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) paint.setShader(shader.get()); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setAntiAlias(true); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPath arc_path; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arc_path.addArc(SkRect::MakeXYWH(center.x() - radius, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center.y() - radius, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2 * radius, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2 * radius), 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 360); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawPath(arc_path, paint); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// View of the LongPressAffordanceHandler. Draws the actual contents and 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// updates as the animation proceeds. It also maintains the views::Widget that 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the animation is shown in. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LongPressAffordanceHandler::LongPressAffordanceView 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public views::View { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LongPressAffordanceView(const gfx::Point& event_location, 1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* root_window) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : views::View(), 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_(CreateAffordanceWidget(root_window)), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_angle_(kAffordanceAngleStartValue), 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_scale_(kAffordanceScaleStartValue) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->SetContentsView(this); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->SetAlwaysOnTop(true); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are owned by the LongPressAffordance. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_owned_by_client(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point point = event_location; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aura::client::GetScreenPositionClient(root_window)->ConvertPointToScreen( 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root_window, &point); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->SetBounds(gfx::Rect( 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.x() - (kAffordanceOuterRadius + kAffordanceGlowWidth), 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point.y() - (kAffordanceOuterRadius + kAffordanceGlowWidth), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPreferredSize().width(), 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPreferredSize().height())); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->Show(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->GetNativeView()->layer()->SetOpacity(kAffordanceOpacityStartValue); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~LongPressAffordanceView() { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) void UpdateWithGrowAnimation(gfx::Animation* animation) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the portion of the circle filled so far and re-draw. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_angle_ = animation->CurrentValueBetween(kAffordanceAngleStartValue, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceAngleEndValue); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_scale_ = animation->CurrentValueBetween(kAffordanceScaleStartValue, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceScaleEndValue); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->GetNativeView()->layer()->SetOpacity( 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animation->CurrentValueBetween(kAffordanceOpacityStartValue, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceOpacityEndValue)); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) void UpdateWithShrinkAnimation(gfx::Animation* animation) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_scale_ = animation->CurrentValueBetween(kAffordanceScaleEndValue, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceShrinkScaleEndValue); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_->GetNativeView()->layer()->SetOpacity( 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animation->CurrentValueBetween(kAffordanceOpacityEndValue, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceOpacityStartValue)); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from views::View. 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual gfx::Size GetPreferredSize() const OVERRIDE { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(2 * (kAffordanceOuterRadius + kAffordanceGlowWidth), 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2 * (kAffordanceOuterRadius + kAffordanceGlowWidth)); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point center(GetPreferredSize().width() / 2, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPreferredSize().height() / 2); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Save(); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Transform scale; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scale.Scale(current_scale_, current_scale_); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to scale from the center. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Translate(center.OffsetFromOrigin()); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Transform(scale); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Translate(-center.OffsetFromOrigin()); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint affordance glow 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_radius = kAffordanceInnerRadius - kAffordanceGlowWidth; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int end_radius = kAffordanceOuterRadius + kAffordanceGlowWidth; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int num_colors = 3; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar pos[num_colors] = {0, 0.5, 1}; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkColor colors[num_colors] = {kAffordanceGlowEndColor, 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceGlowStartColor, kAffordanceGlowEndColor}; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintAffordanceGlow(canvas, center, start_radius, end_radius, colors, pos, 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_colors); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint inner circle. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintAffordanceArc(canvas, center, kAffordanceInnerRadius, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceInnerStartAngle, -current_angle_); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint outer circle. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintAffordanceArc(canvas, center, kAffordanceOuterRadius, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceOuterStartAngle, current_angle_); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Restore(); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<views::Widget> widget_; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int current_angle_; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double current_scale_; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(LongPressAffordanceView); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LongPressAffordanceHandler, public 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LongPressAffordanceHandler::LongPressAffordanceHandler() 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : gfx::LinearAnimation(kAffordanceFrameRateHz, NULL), 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tap_down_target_(NULL), 2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) current_animation_type_(NONE) {} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)LongPressAffordanceHandler::~LongPressAffordanceHandler() { 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StopAffordance(); 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LongPressAffordanceHandler::ProcessEvent(aura::Window* target, 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ui::GestureEvent* event) { 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Once we have a target, we are only interested in events with that target. 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (tap_down_target_ && tap_down_target_ != target) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event->type()) { 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case ui::ET_GESTURE_TAP_DOWN: { 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Start timer that will start animation on "semi-long-press". 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tap_down_location_ = event->root_location(); 255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetTapDownTarget(target); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_animation_type_ = GROW_ANIMATION; 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int64 timer_start_time_ms = 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_.Start(FROM_HERE, 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(timer_start_time_ms), 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &LongPressAffordanceHandler::StartAnimation); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case ui::ET_GESTURE_TAP: 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case ui::ET_GESTURE_TAP_CANCEL: 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StopAffordance(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_GESTURE_LONG_PRESS: 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) End(); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LongPressAffordanceHandler, private 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LongPressAffordanceHandler::StartAnimation() { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (current_animation_type_) { 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case GROW_ANIMATION: { 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) aura::Window* root_window = tap_down_target_->GetRootWindow(); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!root_window) { 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StopAffordance(); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_.reset(new LongPressAffordanceView(tap_down_location_, root_window)); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDuration( 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::GestureConfiguration::long_press_time_in_seconds() * 1000 - 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000 - 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kAffordanceDelayBeforeShrinkMs); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Start(); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHRINK_ANIMATION: 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDuration(kAffordanceShrinkAnimationDurationMs); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Start(); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void LongPressAffordanceHandler::StopAffordance() { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_.IsRunning()) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_.Stop(); 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Since, Animation::Stop() calls AnimationStopped(), we need to reset the 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // |current_animation_type_| before Stop(), otherwise AnimationStopped() may 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start the timer again. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_animation_type_ = NONE; 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Stop(); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_.reset(); 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetTapDownTarget(NULL); 316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void LongPressAffordanceHandler::SetTapDownTarget(aura::Window* target) { 319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (tap_down_target_ == target) 320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (tap_down_target_) 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tap_down_target_->RemoveObserver(this); 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tap_down_target_ = target; 325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (tap_down_target_) 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tap_down_target_->AddObserver(this); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LongPressAffordanceHandler::AnimateToState(double state) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(view_.get()); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (current_animation_type_) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GROW_ANIMATION: 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->UpdateWithGrowAnimation(this); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHRINK_ANIMATION: 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->UpdateWithShrinkAnimation(this); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void LongPressAffordanceHandler::AnimationStopped() { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (current_animation_type_) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GROW_ANIMATION: 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_animation_type_ = SHRINK_ANIMATION; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_.Start(FROM_HERE, 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kAffordanceDelayBeforeShrinkMs), 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, &LongPressAffordanceHandler::StartAnimation); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHRINK_ANIMATION: 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_animation_type_ = NONE; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fall through to reset the view. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_.reset(); 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetTapDownTarget(NULL); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void LongPressAffordanceHandler::OnWindowDestroying(aura::Window* window) { 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(tap_down_target_, window); 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StopAffordance(); 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ash 368