diff options
author | mohsen@chromium.org <mohsen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-27 03:25:05 +0000 |
---|---|---|
committer | mohsen@chromium.org <mohsen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-27 03:25:05 +0000 |
commit | 093c01cb08c0c148befce50164aedd58abb54395 (patch) | |
tree | 43b4c9412071bbfdcd40fbb22b2e828f3f660a20 | |
parent | 1786d84c72c33d3fcece9622b98c5d584f6b1b31 (diff) | |
download | chromium_src-093c01cb08c0c148befce50164aedd58abb54395.zip chromium_src-093c01cb08c0c148befce50164aedd58abb54395.tar.gz chromium_src-093c01cb08c0c148befce50164aedd58abb54395.tar.bz2 |
Added projection mode to touch HUD
Projection mode is useful in presentations when the screen is projected
using a projector. In this mode, only active touch points are shown
without any trails.
BUG=233565
Review URL: https://chromiumcodereview.appspot.com/14399005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196931 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/touch/touch_observer_hud.cc | 381 | ||||
-rw-r--r-- | ash/touch/touch_observer_hud.h | 20 |
2 files changed, 300 insertions, 101 deletions
diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc index ab87c66..47fccff 100644 --- a/ash/touch/touch_observer_hud.cc +++ b/ash/touch/touch_observer_hud.cc @@ -15,8 +15,11 @@ #include "base/utf_string_conversions.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkXfermode.h" +#include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" +#include "ui/base/animation/animation_delegate.h" +#include "ui/base/animation/linear_animation.h" #include "ui/base/events/event.h" #include "ui/gfx/canvas.h" #include "ui/gfx/display.h" @@ -40,20 +43,28 @@ namespace ash { namespace internal { const int kPointRadius = 20; -const int kColors[] = { - static_cast<int>(SK_ColorYELLOW), - static_cast<int>(SK_ColorGREEN), - static_cast<int>(SK_ColorRED), - static_cast<int>(SK_ColorBLUE), - static_cast<int>(SK_ColorGRAY), - static_cast<int>(SK_ColorMAGENTA), - static_cast<int>(SK_ColorCYAN), - static_cast<int>(SK_ColorWHITE), - static_cast<int>(SK_ColorBLACK) +const SkColor kColors[] = { + SK_ColorYELLOW, + SK_ColorGREEN, + SK_ColorRED, + SK_ColorBLUE, + SK_ColorGRAY, + SK_ColorMAGENTA, + SK_ColorCYAN, + SK_ColorWHITE, + SK_ColorBLACK, + SkColorSetRGB(0xFF, 0x8C, 0x00), + SkColorSetRGB(0x8B, 0x45, 0x13), + SkColorSetRGB(0xFF, 0xDE, 0xAD), }; const int kAlpha = 0x60; +const SkColor kProjectionFillColor = SkColorSetRGB(0xF5, 0xF5, 0xDC); +const SkColor kProjectionStrokeColor = SK_ColorGRAY; +const int kProjectionAlpha = 0xB0; const int kMaxPaths = arraysize(kColors); const int kReducedScale = 10; +const int kFadeoutDurationInMs = 250; +const int kFadeoutFrameRate = 60; const char* GetTouchEventLabel(ui::EventType type) { switch (type) { @@ -146,6 +157,12 @@ struct TouchPointLog { // (starting from a touch-press and ending at touch-release). class TouchTrace { public: + typedef std::vector<TouchPointLog>::iterator iterator; + typedef std::vector<TouchPointLog>::const_iterator const_iterator; + typedef std::vector<TouchPointLog>::reverse_iterator reverse_iterator; + typedef std::vector<TouchPointLog>::const_reverse_iterator + const_reverse_iterator; + TouchTrace() { } @@ -153,16 +170,18 @@ class TouchTrace { log_.push_back(TouchPointLog(touch)); } - bool empty() const { return log_.empty(); } + const std::vector<TouchPointLog>& log() const { return log_; } + + bool active() const { + return !log_.empty() && log_.back().type != ui::ET_TOUCH_RELEASED && + log_.back().type != ui::ET_TOUCH_CANCELLED; + } // Returns a list containing data from all events for the touch point. scoped_ptr<ListValue> GetAsList() const { scoped_ptr<ListValue> list(new ListValue()); - for (std::vector<TouchPointLog>::const_iterator i = log_.begin(); - i != log_.end(); ++i) { + for (const_iterator i = log_.begin(); i != log_.end(); ++i) list->Append((*i).GetAsDictionary().release()); - } - return list.Pass(); } @@ -176,15 +195,90 @@ class TouchTrace { DISALLOW_COPY_AND_ASSIGN(TouchTrace); }; -class TouchHudCanvas : public views::View { +// A TouchLog keeps track of all touch events of all touch points. +class TouchLog { + public: + TouchLog() : next_trace_index_(0) { + } + + void AddTouchPoint(const ui::TouchEvent& touch) { + if (touch.type() == ui::ET_TOUCH_PRESSED) + StartTrace(touch); + AddToTrace(touch); + } + + void Reset() { + next_trace_index_ = 0; + for (int i = 0; i < kMaxPaths; ++i) + traces_[i].Reset(); + } + + scoped_ptr<ListValue> GetAsList() const { + scoped_ptr<ListValue> list(new ListValue()); + for (int i = 0; i < kMaxPaths; ++i) { + if (!traces_[i].log().empty()) + list->Append(traces_[i].GetAsList().release()); + } + return list.Pass(); + } + + int GetTraceIndex(int touch_id) const { + return touch_id_to_trace_index_.at(touch_id); + } + + const TouchTrace* traces() const { + return traces_; + } + + private: + void StartTrace(const ui::TouchEvent& touch) { + // Find the first inactive spot; otherwise, overwrite the one + // |next_trace_index_| is pointing to. + int old_trace_index = next_trace_index_; + do { + if (!traces_[next_trace_index_].active()) + break; + next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; + } while (next_trace_index_ != old_trace_index); + int touch_id = touch.touch_id(); + traces_[next_trace_index_].Reset(); + touch_id_to_trace_index_[touch_id] = next_trace_index_; + next_trace_index_ = (next_trace_index_ + 1) % kMaxPaths; + } + + void AddToTrace(const ui::TouchEvent& touch) { + int touch_id = touch.touch_id(); + int trace_index = touch_id_to_trace_index_[touch_id]; + traces_[trace_index].AddTouchPoint(touch); + } + + TouchTrace traces_[kMaxPaths]; + int next_trace_index_; + + std::map<int, int> touch_id_to_trace_index_; + + DISALLOW_COPY_AND_ASSIGN(TouchLog); +}; + +class TouchHudCanvas : public views::View, public ui::AnimationDelegate { public: - explicit TouchHudCanvas(TouchObserverHUD* owner) + TouchHudCanvas(TouchObserverHUD* owner, const TouchLog& touch_log) : owner_(owner), - path_index_(0), - color_index_(0), + touch_log_(touch_log), scale_(1) { SetPaintToLayer(true); SetFillsBoundsOpaquely(false); + + paint_.setStyle(SkPaint::kFill_Style); + + projection_stroke_paint_.setStyle(SkPaint::kStroke_Style); + projection_stroke_paint_.setColor(kProjectionStrokeColor); + + projection_gradient_colors_[0] = kProjectionFillColor; + projection_gradient_colors_[1] = kProjectionStrokeColor; + + projection_gradient_pos_[0] = SkFloatToScalar(0.9f); + projection_gradient_pos_[1] = SkFloatToScalar(1.0f); } virtual ~TouchHudCanvas() {} @@ -200,91 +294,151 @@ class TouchHudCanvas : public views::View { int scale() const { return scale_; } - void Start(const ui::TouchEvent& touch) { - int id = touch.touch_id(); - paths_[path_index_].reset(); - traces_[path_index_].Reset(); - colors_[path_index_] = SkColorSetA(kColors[color_index_], kAlpha); - color_index_ = (color_index_ + 1) % arraysize(kColors); - touch_id_to_path_[id] = path_index_; - path_index_ = (path_index_ + 1) % kMaxPaths; - AddPoint(touch); - SchedulePaint(); + void TouchPointAdded(int touch_id) { + int trace_index = touch_log_.GetTraceIndex(touch_id); + const TouchTrace& trace = touch_log_.traces()[trace_index]; + const TouchPointLog& point = trace.log().back(); + if (point.type == ui::ET_TOUCH_PRESSED) + StartedTrace(trace_index); + if (point.type != ui::ET_TOUCH_CANCELLED) + AddedPointToTrace(trace_index); + if (owner_->mode() == TouchObserverHUD::PROJECTION && !trace.active()) + StartAnimation(trace_index); } - void AddPoint(const ui::TouchEvent& touch) { - int id = touch.touch_id(); - const gfx::Point& point = touch.root_location(); - int path_id = touch_id_to_path_[id]; - SkScalar x = SkIntToScalar(point.x()); - SkScalar y = SkIntToScalar(point.y()); - SkPoint last; - if (!paths_[path_id].getLastPt(&last) || x != last.x() || y != last.y()) { - paths_[path_id].addCircle(x, y, SkIntToScalar(kPointRadius)); - traces_[path_id].AddTouchPoint(touch); - } - SchedulePaint(); + void StopAnimations() { + for (int i = 0; i < kMaxPaths; ++i) + fadeouts_[i].reset(NULL); } void Clear() { - path_index_ = 0; - color_index_ = 0; - for (size_t i = 0; i < arraysize(paths_); ++i) { + for (int i = 0; i < kMaxPaths; ++i) paths_[i].reset(); - traces_[i].Reset(); - } + if (owner_->mode() == TouchObserverHUD::PROJECTION) + StopAnimations(); SchedulePaint(); } - scoped_ptr<ListValue> GetAsList() const { - scoped_ptr<ListValue> list(new ListValue()); - for (size_t i = 0; i < arraysize(traces_); ++i) { - if (!traces_[i].empty()) - list->Append(traces_[i].GetAsList().release()); + private: + void StartedTrace(int trace_index) { + paths_[trace_index].reset(); + colors_[trace_index] = SkColorSetA(kColors[trace_index], kAlpha); + } + + void AddedPointToTrace(int trace_index) { + const TouchTrace& trace = touch_log_.traces()[trace_index]; + const TouchPointLog& point = trace.log().back(); + const gfx::Point& location = point.location; + SkScalar x = SkIntToScalar(location.x()); + SkScalar y = SkIntToScalar(location.y()); + SkPoint last; + if (!paths_[trace_index].getLastPt(&last) || x != last.x() || + y != last.y()) { + paths_[trace_index].addCircle(x, y, SkIntToScalar(kPointRadius)); + SchedulePaint(); } - return list.Pass(); } - private: + void StartAnimation(int path_index) { + DCHECK(!fadeouts_[path_index].get()); + fadeouts_[path_index].reset(new ui::LinearAnimation(kFadeoutDurationInMs, + kFadeoutFrameRate, + this)); + fadeouts_[path_index]->Start(); + } + // Overridden from views::View. virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { - canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); - canvas->DrawColor(SkColorSetARGB(0, 0, 0, 0)); - - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - for (size_t i = 0; i < arraysize(paths_); ++i) { - if (paths_[i].countPoints() == 0) - continue; - paint.setColor(colors_[i]); - canvas->DrawPath(paths_[i], paint); + if (owner_->mode() == TouchObserverHUD::PROJECTION) { + for (int i = 0; i < kMaxPaths; ++i) { + const TouchTrace& trace = touch_log_.traces()[i]; + if (!trace.active() && !fadeouts_[i].get()) + continue; + TouchTrace::const_reverse_iterator point = trace.log().rbegin(); + while (point != trace.log().rend() && + point->type == ui::ET_TOUCH_CANCELLED) + point++; + DCHECK(point != trace.log().rend()); + int alpha = kProjectionAlpha; + if (fadeouts_[i].get()) + alpha = static_cast<int>(fadeouts_[i]->CurrentValueBetween(alpha, 0)); + projection_fill_paint_.setAlpha(alpha); + projection_stroke_paint_.setAlpha(alpha); + SkShader* shader = SkGradientShader::CreateRadial( + SkPoint::Make(SkIntToScalar(point->location.x()), + SkIntToScalar(point->location.y())), + SkIntToScalar(kPointRadius), + projection_gradient_colors_, + projection_gradient_pos_, + arraysize(projection_gradient_colors_), + SkShader::kMirror_TileMode, + NULL); + projection_fill_paint_.setShader(shader); + shader->unref(); + canvas->DrawCircle(point->location, SkIntToScalar(kPointRadius), + projection_fill_paint_); + canvas->DrawCircle(point->location, SkIntToScalar(kPointRadius), + projection_stroke_paint_); + } + } else { + for (int i = 0; i < kMaxPaths; ++i) { + if (paths_[i].countPoints() == 0) + continue; + paint_.setColor(colors_[i]); + canvas->DrawPath(paths_[i], paint_); + } } } - TouchObserverHUD* owner_; + // Overridden from ui::AnimationDelegate. + virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { + for (int i = 0; i < kMaxPaths; ++i) + if (fadeouts_[i].get() == animation) { + fadeouts_[i].reset(NULL); + break; + } + } + + // Overridden from ui::AnimationDelegate. + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { + SchedulePaint(); + } + + // Overridden from ui::AnimationDelegate. + virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { + AnimationEnded(animation); + } + + const TouchObserverHUD* const owner_; + const TouchLog& touch_log_; + + SkPaint paint_; + SkPaint projection_fill_paint_; + SkPaint projection_stroke_paint_; + SkColor projection_gradient_colors_[2]; + SkScalar projection_gradient_pos_[2]; + SkPath paths_[kMaxPaths]; + scoped_ptr<ui::Animation> fadeouts_[kMaxPaths]; SkColor colors_[kMaxPaths]; - TouchTrace traces_[kMaxPaths]; - int path_index_; - int color_index_; int scale_; - std::map<int, int> touch_id_to_path_; - DISALLOW_COPY_AND_ASSIGN(TouchHudCanvas); }; TouchObserverHUD::TouchObserverHUD(aura::RootWindow* initial_root) : display_id_(initial_root->GetProperty(kDisplayIdKey)), - root_window_(initial_root) { + root_window_(initial_root), + mode_(FULLSCREEN), + touch_log_(new TouchLog()) { const gfx::Display& display = Shell::GetInstance()->display_manager()->GetDisplayForId(display_id_); views::View* content = new views::View; - canvas_ = new TouchHudCanvas(this); + canvas_ = new TouchHudCanvas(this, *touch_log_); content->AddChildView(canvas_); const gfx::Size& display_size = display.size(); @@ -296,7 +450,6 @@ TouchObserverHUD::TouchObserverHUD(aura::RootWindow* initial_root) views::BoxLayout::kVertical, 0, 0, 0)); for (int i = 0; i < kMaxTouchPoints; ++i) { - touch_status_[i] = ui::ET_UNKNOWN; touch_labels_[i] = new views::Label; touch_labels_[i]->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); touch_labels_[i]->SetShadowColors(SK_ColorWHITE, @@ -367,34 +520,75 @@ scoped_ptr<DictionaryValue> TouchObserverHUD::GetAllAsDictionary() { } void TouchObserverHUD::ChangeToNextMode() { - if (widget_->IsVisible()) { - if (canvas_->scale() == kReducedScale) { - widget_->Hide(); - } else { - label_container_->SetVisible(true); - canvas_->SetScale(kReducedScale); - } - } else { - canvas_->SetScale(1); - label_container_->SetVisible(false); - widget_->Show(); + switch (mode_) { + case FULLSCREEN: + SetMode(REDUCED_SCALE); + break; + case REDUCED_SCALE: + SetMode(PROJECTION); + break; + case PROJECTION: + SetMode(INVISIBLE); + break; + case INVISIBLE: + SetMode(FULLSCREEN); + break; } } void TouchObserverHUD::Clear() { if (widget_->IsVisible()) canvas_->Clear(); + for (int i = 0; i < kMaxTouchPoints; ++i) + touch_labels_[i]->SetText(string16()); + label_container_->SetSize(label_container_->GetPreferredSize()); } scoped_ptr<ListValue> TouchObserverHUD::GetLogAsList() const { - return canvas_->GetAsList(); + return touch_log_->GetAsList(); +} + +void TouchObserverHUD::SetMode(Mode mode) { + if (mode_ == mode) + return; + mode_ = mode; + canvas_->StopAnimations(); + switch (mode) { + case FULLSCREEN: + case PROJECTION: + label_container_->SetVisible(false); + canvas_->SetScale(1); + canvas_->SchedulePaint(); + widget_->Show(); + break; + case REDUCED_SCALE: + label_container_->SetVisible(true); + canvas_->SetScale(kReducedScale); + canvas_->SchedulePaint(); + widget_->Show(); + break; + case INVISIBLE: + widget_->Hide(); + break; + } } void TouchObserverHUD::UpdateTouchPointLabel(int index) { + int trace_index = touch_log_->GetTraceIndex(index); + const TouchTrace& trace = touch_log_->traces()[trace_index]; + TouchTrace::const_reverse_iterator point = trace.log().rbegin(); + ui::EventType touch_status = point->type; + float touch_radius = std::max(point->radius_x, point->radius_y); + while (point != trace.log().rend() && point->type == ui::ET_TOUCH_CANCELLED) + point++; + DCHECK(point != trace.log().rend()); + gfx::Point touch_position = point->location; + std::string string = base::StringPrintf("%2d: %s %s (%.4f)", - index, GetTouchEventLabel(touch_status_[index]), - touch_positions_[index].ToString().c_str(), - touch_radius_[index]); + index, + GetTouchEventLabel(touch_status), + touch_position.ToString().c_str(), + touch_radius); touch_labels_[index]->SetText(UTF8ToUTF16(string)); } @@ -402,17 +596,8 @@ void TouchObserverHUD::OnTouchEvent(ui::TouchEvent* event) { if (event->touch_id() >= kMaxTouchPoints) return; - if (event->type() != ui::ET_TOUCH_CANCELLED) - touch_positions_[event->touch_id()] = event->root_location(); - - touch_radius_[event->touch_id()] = std::max(event->radius_x(), - event->radius_y()); - - if (event->type() == ui::ET_TOUCH_PRESSED) - canvas_->Start(*event); - else if (event->type() != ui::ET_TOUCH_CANCELLED) - canvas_->AddPoint(*event); - touch_status_[event->touch_id()] = event->type(); + touch_log_->AddTouchPoint(*event); + canvas_->TouchPointAdded(event->touch_id()); UpdateTouchPointLabel(event->touch_id()); label_container_->SetSize(label_container_->GetPreferredSize()); diff --git a/ash/touch/touch_observer_hud.h b/ash/touch/touch_observer_hud.h index 1a79015..1831b85 100644 --- a/ash/touch/touch_observer_hud.h +++ b/ash/touch/touch_observer_hud.h @@ -8,6 +8,7 @@ #include "ash/ash_export.h" #include "ash/display/display_controller.h" #include "ash/shell.h" +#include "base/memory/scoped_ptr.h" #include "base/values.h" #include "ui/base/events/event_handler.h" #include "ui/gfx/display_observer.h" @@ -36,6 +37,7 @@ namespace ash { namespace internal { class TouchHudCanvas; +class TouchLog; // An event filter which handles system level gesture events. Objects of this // class manage their own lifetime. @@ -48,6 +50,13 @@ class ASH_EXPORT TouchObserverHUD #endif // defined(OS_CHROMEOS) public DisplayController::Observer { public: + enum Mode { + FULLSCREEN, + REDUCED_SCALE, + PROJECTION, + INVISIBLE, + }; + explicit TouchObserverHUD(aura::RootWindow* initial_root); // Returns the log of touch events as a dictionary mapping id of each display @@ -66,11 +75,15 @@ class ASH_EXPORT TouchObserverHUD // trace of one touch point. scoped_ptr<ListValue> GetLogAsList() const; + Mode mode() const { return mode_; } + private: friend class TouchHudTest; virtual ~TouchObserverHUD(); + void SetMode(Mode mode); + void UpdateTouchPointLabel(int index); // Overriden from ui::EventHandler: @@ -98,13 +111,14 @@ class ASH_EXPORT TouchObserverHUD const int64 display_id_; aura::RootWindow* root_window_; + Mode mode_; + + scoped_ptr<TouchLog> touch_log_; + views::Widget* widget_; TouchHudCanvas* canvas_; views::View* label_container_; views::Label* touch_labels_[kMaxTouchPoints]; - gfx::Point touch_positions_[kMaxTouchPoints]; - float touch_radius_[kMaxTouchPoints]; - ui::EventType touch_status_[kMaxTouchPoints]; DISALLOW_COPY_AND_ASSIGN(TouchObserverHUD); }; |