aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/viewer/SlideDir.cpp
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-02-19 13:25:18 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-19 18:43:44 +0000
commit65fce9edc44a18e7dc56035cd1bbbd3acc7a7b30 (patch)
tree20b5a7f558af4d287b1aa49cdaf1754ec51eaa6b /tools/viewer/SlideDir.cpp
parentcad0acf4db5b03f9b9bf6afedde162fd1c8c4c92 (diff)
SlideDir focus w/ animation
Add an animated "focus" mode for SlideDir. Clicking a cell focuses. SPACE unfocuses. When a slide is focused, mouse and key events are passed through. TBR= Change-Id: Iec47e2327e3b21bd626846bb0d3f9107bf680b1b Reviewed-on: https://skia-review.googlesource.com/108101 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com>
Diffstat (limited to 'tools/viewer/SlideDir.cpp')
-rw-r--r--tools/viewer/SlideDir.cpp255
1 files changed, 223 insertions, 32 deletions
diff --git a/tools/viewer/SlideDir.cpp b/tools/viewer/SlideDir.cpp
index 23f1a219f1..b48c987d3a 100644
--- a/tools/viewer/SlideDir.cpp
+++ b/tools/viewer/SlideDir.cpp
@@ -13,17 +13,25 @@
#include "SkSGColor.h"
#include "SkSGDraw.h"
#include "SkSGGroup.h"
+#include "SkSGRect.h"
#include "SkSGRenderNode.h"
#include "SkSGScene.h"
#include "SkSGText.h"
#include "SkSGTransform.h"
#include "SkTypeface.h"
+#include <cmath>
+
namespace {
-static constexpr float kAspectRatio = 1.5f;
-static constexpr float kLabelSize = 12.0f;
-static constexpr SkSize kPadding = { 12.0f, 24.0f };
+static constexpr float kAspectRatio = 1.5f;
+static constexpr float kLabelSize = 12.0f;
+static constexpr SkSize kPadding = { 12.0f , 24.0f };
+static constexpr SkSize kFocusInset = { 100.0f, 100.0f };
+static constexpr float kFocusDuration = 250;
+
+// TODO: better unfocus binding?
+static constexpr SkUnichar kUnfocusKey = ' ';
class SlideAdapter final : public sksg::RenderNode {
public:
@@ -72,11 +80,124 @@ private:
using INHERITED = sksg::RenderNode;
};
+SkMatrix SlideMatrix(const sk_sp<Slide>& slide, const SkRect& dst) {
+ const auto slideSize = slide->getDimensions();
+ return SkMatrix::MakeRectToRect(SkRect::MakeIWH(slideSize.width(), slideSize.height()),
+ dst,
+ SkMatrix::kCenter_ScaleToFit);
+}
+
} // namespace
struct SlideDir::Rec {
- sk_sp<sksg::Matrix> fMatrix;
- SkRect fRect;
+ sk_sp<Slide> fSlide;
+ sk_sp<sksg::Transform> fTransform;
+ SkRect fRect;
+};
+
+class SlideDir::FocusController final : public sksg::Animator {
+public:
+ FocusController(const SlideDir* dir, const SkRect& focusRect)
+ : fDir(dir)
+ , fRect(focusRect)
+ , fTarget(nullptr)
+ , fState(State::kIdle) {}
+
+ bool hasFocus() const { return fState == State::kFocused; }
+
+ void startFocus(const Rec* target) {
+ fTarget = target;
+ fM0 = SlideMatrix(fTarget->fSlide, fTarget->fRect);
+ fM1 = SlideMatrix(fTarget->fSlide, fRect);
+
+ fTimeBase = 0;
+ fState = State::kFocusing;
+ }
+
+ void startUnfocus() {
+ SkASSERT(fTarget);
+
+ SkTSwap(fM1, fM0);
+
+ fTimeBase = 0;
+ fState = State::kUnfocusing;
+ }
+
+ bool onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState state, uint32_t modifiers) {
+ SkASSERT(fTarget);
+
+ // Map coords to slide space.
+ const auto xform = SkMatrix::MakeRectToRect(fRect,
+ SkRect::MakeSize(fDir->fWinSize),
+ SkMatrix::kCenter_ScaleToFit);
+ const auto pt = xform.mapXY(x, y);
+
+ return fTarget->fSlide->onMouse(pt.x(), pt.y(), state, modifiers);
+ }
+
+ bool onChar(SkUnichar c) {
+ SkASSERT(fTarget);
+
+ return fTarget->fSlide->onChar(c);
+ }
+
+protected:
+ void onTick(float t) {
+ if (!this->isAnimating())
+ return;
+
+ if (!fTimeBase) {
+ fTimeBase = t;
+ }
+
+ const auto rel_t = SkTPin((t - fTimeBase) / kFocusDuration, 0.0f, 1.0f);
+
+ SkMatrix m;
+ for (int i = 0; i < 9; ++i) {
+ m[i] = fM0[i] + rel_t * (fM1[i] - fM0[i]);
+ }
+
+ SkASSERT(fTarget);
+ fTarget->fTransform->getMatrix()->setMatrix(m);
+
+ if (rel_t < 1)
+ return;
+
+ switch (fState) {
+ case State::kFocusing:
+ fState = State::kFocused;
+ break;
+ case State::kUnfocusing:
+ fState = State::kIdle;
+ break;
+
+ case State::kIdle:
+ case State::kFocused:
+ SkASSERT(false);
+ break;
+ }
+ }
+
+private:
+ enum class State {
+ kIdle,
+ kFocusing,
+ kUnfocusing,
+ kFocused,
+ };
+
+ bool isAnimating() const { return fState == State::kFocusing || fState == State::kUnfocusing; }
+
+ const SlideDir* fDir;
+ const SkRect fRect;
+ const Rec* fTarget;
+
+ SkMatrix fM0 = SkMatrix::I(),
+ fM1 = SkMatrix::I();
+ float fTimeBase = 0;
+ State fState = State::kIdle;
+
+ using INHERITED = sksg::Animator;
};
SlideDir::SlideDir(const SkString& name, SkTArray<sk_sp<Slide>, true>&& slides, int columns)
@@ -85,12 +206,15 @@ SlideDir::SlideDir(const SkString& name, SkTArray<sk_sp<Slide>, true>&& slides,
fName = name;
}
-static sk_sp<sksg::RenderNode> MakeLabel(const SkString& txt, const SkRect& dst) {
+static sk_sp<sksg::RenderNode> MakeLabel(const SkString& txt,
+ const SkPoint& pos,
+ const SkMatrix& dstXform) {
+ const auto size = kLabelSize / std::sqrt(dstXform.getScaleX() * dstXform.getScaleY());
auto text = sksg::Text::Make(nullptr, txt);
text->setFlags(SkPaint::kAntiAlias_Flag);
- text->setSize(kLabelSize);
+ text->setSize(size);
text->setAlign(SkPaint::kCenter_Align);
- text->setPosition(SkPoint::Make(dst.centerX(), dst.bottom()));
+ text->setPosition(pos + SkPoint::Make(0, size));
return sksg::Draw::Make(std::move(text), sksg::Color::Make(SK_ColorBLACK));
}
@@ -114,42 +238,47 @@ void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
// ...
//
- fSize = SkSize::Make(winWidth, winHeight).toCeil();
-
- const auto cellWidth = winWidth / fColumns,
- cellHeight = cellWidth / kAspectRatio;
+ fWinSize = SkSize::Make(winWidth, winHeight);
+ const auto cellWidth = winWidth / fColumns;
+ fCellSize = SkSize::Make(cellWidth, cellWidth / kAspectRatio);
sksg::AnimatorList sceneAnimators;
- auto root = sksg::Group::Make();
+ fRoot = sksg::Group::Make();
for (int i = 0; i < fSlides.count(); ++i) {
const auto& slide = fSlides[i];
slide->load(winWidth, winHeight);
const auto slideSize = slide->getDimensions();
- const auto cell = SkRect::MakeXYWH(cellWidth * (i % fColumns),
- cellHeight * (i / fColumns),
- cellWidth,
- cellHeight),
+ const auto cell = SkRect::MakeXYWH(fCellSize.width() * (i % fColumns),
+ fCellSize.height() * (i / fColumns),
+ fCellSize.width(),
+ fCellSize.height()),
slideRect = cell.makeInset(kPadding.width(), kPadding.height());
- auto matrix = sksg::Matrix::Make(
- SkMatrix::MakeRectToRect(SkRect::MakeIWH(slideSize.width(), slideSize.height()),
- slideRect,
- SkMatrix::kCenter_ScaleToFit));
-
- auto adapter = sk_make_sp<SlideAdapter>(slide);
- auto slideGrp = sksg::Group::Make();
- slideGrp->addChild(sksg::Transform::Make(adapter, matrix));
- slideGrp->addChild(MakeLabel(slide->getName(), cell));
+ auto slideMatrix = SlideMatrix(slide, slideRect);
+ auto adapter = sk_make_sp<SlideAdapter>(slide);
+ auto slideGrp = sksg::Group::Make();
+ slideGrp->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeIWH(slideSize.width(),
+ slideSize.height())),
+ sksg::Color::Make(0xfff0f0f0)));
+ slideGrp->addChild(adapter);
+ slideGrp->addChild(MakeLabel(slide->getName(),
+ SkPoint::Make(slideSize.width() / 2, slideSize.height()),
+ slideMatrix));
+ auto slideTransform = sksg::Transform::Make(std::move(slideGrp), slideMatrix);
sceneAnimators.push_back(adapter->makeForwardingAnimator());
- root->addChild(std::move(slideGrp));
- fRecs.push_back({ matrix, slideRect });
+ fRoot->addChild(slideTransform);
+ fRecs.push_back({ slide, slideTransform, slideRect });
}
- fScene = sksg::Scene::Make(std::move(root), std::move(sceneAnimators));
+ fScene = sksg::Scene::Make(fRoot, std::move(sceneAnimators));
+
+ const auto focusRect = SkRect::MakeSize(fWinSize).makeInset(kFocusInset.width(),
+ kFocusInset.height());
+ fFocusController = skstd::make_unique<FocusController>(this, focusRect);
}
void SlideDir::unload() {
@@ -159,11 +288,14 @@ void SlideDir::unload() {
fRecs.reset();
fScene.reset();
+ fFocusController.reset();
+ fRoot.reset();
fTimeBase = 0;
}
SkISize SlideDir::getDimensions() const {
- return fSize;
+ return SkSize::Make(fWinSize.width(),
+ fCellSize.height() * (fSlides.count() / fColumns)).toCeil();
}
void SlideDir::draw(SkCanvas* canvas) {
@@ -175,15 +307,74 @@ bool SlideDir::animate(const SkAnimTimer& timer) {
// Reset the animation time.
fTimeBase = timer.msec();
}
- fScene->animate(timer.msec() - fTimeBase);
+
+ const auto t = timer.msec() - fTimeBase;
+ fScene->animate(t);
+ fFocusController->tick(t);
return true;
}
bool SlideDir::onChar(SkUnichar c) {
+ if (fFocusController->hasFocus()) {
+ if (c == kUnfocusKey) {
+ fFocusController->startUnfocus();
+ return true;
+ }
+ return fFocusController->onChar(c);
+ }
+
return false;
}
-bool SlideDir::onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState, uint32_t modifiers) {
+bool SlideDir::onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState state,
+ uint32_t modifiers) {
+ if (state == sk_app::Window::kMove_InputState || modifiers)
+ return false;
+
+ if (fFocusController->hasFocus()) {
+ return fFocusController->onMouse(x, y, state, modifiers);
+ }
+
+ const auto* cell = this->findCell(x, y);
+ if (!cell)
+ return false;
+
+ static constexpr SkScalar kClickMoveTolerance = 4;
+
+ switch (state) {
+ case sk_app::Window::kDown_InputState:
+ fTrackingCell = cell;
+ fTrackingPos = SkPoint::Make(x, y);
+ break;
+ case sk_app::Window::kUp_InputState:
+ if (cell == fTrackingCell &&
+ SkPoint::Distance(fTrackingPos, SkPoint::Make(x, y)) < kClickMoveTolerance) {
+
+ // Move the slide cell to front.
+ fRoot->removeChild(cell->fTransform);
+ fRoot->addChild(cell->fTransform);
+
+ fFocusController->startFocus(cell);
+ }
+ break;
+ default:
+ break;
+ }
+
return false;
}
+
+const SlideDir::Rec* SlideDir::findCell(float x, float y) const {
+ // TODO: use SG hit testing instead of layout info?
+ const auto size = this->getDimensions();
+ if (x < 0 || y < 0 || x >= size.width() || y >= size.height()) {
+ return nullptr;
+ }
+
+ const int col = static_cast<int>(x / fCellSize.width()),
+ row = static_cast<int>(y / fCellSize.height()),
+ idx = row * fColumns + col;
+
+ return idx <= fRecs.count() ? &fRecs[idx] : nullptr;
+}