aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorGravatar brianosman <brianosman@google.com>2016-05-10 06:50:49 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-05-10 06:50:49 -0700
commit622c8d5de12f264e496e8d4664a2eea9333922d0 (patch)
tree6c548356f43ad6675d944c85d729200687e73261 /tools
parent3622a17291ccddcb073275e50a8711bf61b7bf27 (diff)
Add flexible keybinding/command system to sk_app.
Viewer demonstrates use: Just create an instance of CommandSet, register with the window, and add commands. Hopefully, we can keep all commands in one place, and get some nice side-benefits. With this framework, if you want to add a new command, you are only required to add code in ONE place. And you get added to the help screen, for free. CommandSet automatically binds 'h' to cycle through the help modes. (Functional grouping is most useful for general use, but the other mode is nice to know what a key does, or to find an unused key for a new feature). Grouped by function: https://screenshot.googleplex.com/G5h3f52wFKu.png Alphabetical by key: https://screenshot.googleplex.com/nZiopabLKJ6.png BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1955293002 Review-Url: https://codereview.chromium.org/1955293002
Diffstat (limited to 'tools')
-rw-r--r--tools/viewer/Viewer.cpp116
-rw-r--r--tools/viewer/Viewer.h4
-rw-r--r--tools/viewer/sk_app/CommandSet.cpp157
-rw-r--r--tools/viewer/sk_app/CommandSet.h107
-rw-r--r--tools/viewer/sk_app/Window.h76
-rw-r--r--tools/viewer/sk_app/win/Window_win.cpp16
6 files changed, 352 insertions, 124 deletions
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 62c3048d91..7dd265e6e2 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -22,19 +22,6 @@ Application* Application::Create(int argc, char** argv, void* platformData) {
return new Viewer(argc, argv, platformData);
}
-static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t modifiers,
- void* userData) {
- Viewer* vv = reinterpret_cast<Viewer*>(userData);
-
- return vv->onKey(key, state, modifiers);
-}
-
-static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) {
- Viewer* vv = reinterpret_cast<Viewer*>(userData);
-
- return vv->onChar(c, modifiers);
-}
-
static void on_paint_handler(SkCanvas* canvas, void* userData) {
Viewer* vv = reinterpret_cast<Viewer*>(userData);
@@ -76,10 +63,47 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
fWindow->attach(Window::kVulkan_BackendType, DisplayParams());
// register callbacks
- fWindow->registerKeyFunc(on_key_handler, this);
- fWindow->registerCharFunc(on_char_handler, this);
+ fCommands.attach(fWindow);
fWindow->registerPaintFunc(on_paint_handler, this);
+ // add key-bindings
+ fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() {
+ this->fDisplayStats = !this->fDisplayStats;
+ fWindow->inval();
+ });
+ fCommands.addCommand('c', "Modes", "Toggle sRGB color mode", [this]() {
+ DisplayParams params = fWindow->getDisplayParams();
+ params.fProfileType = (kLinear_SkColorProfileType == params.fProfileType)
+ ? kSRGB_SkColorProfileType : kLinear_SkColorProfileType;
+ fWindow->setDisplayParams(params);
+ this->updateTitle();
+ fWindow->inval();
+ });
+ fCommands.addCommand(Window::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
+ int previousSlide = fCurrentSlide;
+ fCurrentSlide++;
+ if (fCurrentSlide >= fSlides.count()) {
+ fCurrentSlide = 0;
+ }
+ this->setupCurrentSlide(previousSlide);
+ });
+ fCommands.addCommand(Window::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
+ int previousSlide = fCurrentSlide;
+ fCurrentSlide--;
+ if (fCurrentSlide < 0) {
+ fCurrentSlide = fSlides.count() - 1;
+ }
+ this->setupCurrentSlide(previousSlide);
+ });
+ fCommands.addCommand(Window::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
+ this->changeZoomLevel(1.f / 32.f);
+ fWindow->inval();
+ });
+ fCommands.addCommand(Window::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
+ this->changeZoomLevel(-1.f / 32.f);
+ fWindow->inval();
+ });
+
// set up slides
this->initSlides();
@@ -208,67 +232,6 @@ void Viewer::updateMatrix(){
fLocalMatrix = m;
}
-bool Viewer::onKey(Window::Key key, Window::InputState state, uint32_t modifiers) {
- if (Window::kDown_InputState == state) {
- switch (key) {
- case Window::kRight_Key: {
- int previousSlide = fCurrentSlide;
- fCurrentSlide++;
- if (fCurrentSlide >= fSlides.count()) {
- fCurrentSlide = 0;
- }
- setupCurrentSlide(previousSlide);
- return true;
- }
-
- case Window::kLeft_Key: {
- int previousSlide = fCurrentSlide;
- fCurrentSlide--;
- if (fCurrentSlide < 0) {
- fCurrentSlide = fSlides.count() - 1;
- }
- setupCurrentSlide(previousSlide);
- return true;
- }
-
- case Window::kUp_Key: {
- this->changeZoomLevel(1.f / 32.f);
- fWindow->inval();
- return true;
- }
-
- case Window::kDown_Key: {
- this->changeZoomLevel(-1.f / 32.f);
- fWindow->inval();
- return true;
- }
-
- default:
- break;
- }
- }
-
- return false;
-}
-
-bool Viewer::onChar(SkUnichar c, uint32_t modifiers) {
- switch (c) {
- case 's':
- fDisplayStats = !fDisplayStats;
- return true;
- case 'c':
- DisplayParams params = fWindow->getDisplayParams();
- params.fProfileType = (kLinear_SkColorProfileType == params.fProfileType)
- ? kSRGB_SkColorProfileType : kLinear_SkColorProfileType;
- fWindow->setDisplayParams(params);
- this->updateTitle();
- fWindow->inval();
- return true;
- }
-
- return false;
-}
-
void Viewer::onPaint(SkCanvas* canvas) {
int count = canvas->save();
@@ -296,6 +259,7 @@ void Viewer::onPaint(SkCanvas* canvas) {
if (fDisplayStats) {
drawStats(canvas);
}
+ fCommands.drawHelp(canvas);
}
void Viewer::drawStats(SkCanvas* canvas) {
diff --git a/tools/viewer/Viewer.h b/tools/viewer/Viewer.h
index 2e9650a846..033bd6969b 100644
--- a/tools/viewer/Viewer.h
+++ b/tools/viewer/Viewer.h
@@ -9,6 +9,7 @@
#define Viewer_DEFINED
#include "sk_app/Application.h"
+#include "sk_app/CommandSet.h"
#include "sk_app/Window.h"
#include "gm.h"
#include "SkAnimTimer.h"
@@ -21,8 +22,6 @@ public:
Viewer(int argc, char** argv, void* platformData);
~Viewer() override;
- bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers);
- bool onChar(SkUnichar, uint32_t modifiers);
void onPaint(SkCanvas* canvas);
void onIdle(double ms) override;
@@ -55,6 +54,7 @@ private:
SkScalar fZoomLevel;
SkScalar fZoomScale;
+ sk_app::CommandSet fCommands;
};
diff --git a/tools/viewer/sk_app/CommandSet.cpp b/tools/viewer/sk_app/CommandSet.cpp
new file mode 100644
index 0000000000..e426eaab21
--- /dev/null
+++ b/tools/viewer/sk_app/CommandSet.cpp
@@ -0,0 +1,157 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "CommandSet.h"
+
+#include "SkCanvas.h"
+#include "SkTSort.h"
+
+namespace sk_app {
+
+static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t modifiers,
+ void* userData) {
+ CommandSet* cs = reinterpret_cast<CommandSet*>(userData);
+ return cs->onKey(key, state, modifiers);
+}
+
+static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) {
+ CommandSet* cs = reinterpret_cast<CommandSet*>(userData);
+ return cs->onChar(c, modifiers);
+}
+
+CommandSet::CommandSet()
+ : fHelpMode(kNone_HelpMode) {
+ this->addCommand('h', "Overlays", "Show help screen", [this]() {
+ switch (this->fHelpMode) {
+ case kNone_HelpMode:
+ this->fHelpMode = kGrouped_HelpMode;
+ break;
+ case kGrouped_HelpMode:
+ this->fHelpMode = kAlphabetical_HelpMode;
+ break;
+ case kAlphabetical_HelpMode:
+ this->fHelpMode = kNone_HelpMode;
+ break;
+ }
+ fWindow->inval();
+ });
+}
+
+void CommandSet::attach(Window* window) {
+ fWindow = window;
+ window->registerKeyFunc(on_key_handler, this);
+ window->registerCharFunc(on_char_handler, this);
+}
+
+bool CommandSet::onKey(Window::Key key, Window::InputState state, uint32_t modifiers) {
+ if (Window::kDown_InputState == state) {
+ for (Command& cmd : fCommands) {
+ if (Command::kKey_CommandType == cmd.fType && key == cmd.fKey) {
+ cmd.fFunction();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CommandSet::onChar(SkUnichar c, uint32_t modifiers) {
+ for (Command& cmd : fCommands) {
+ if (Command::kChar_CommandType == cmd.fType && c == cmd.fChar) {
+ cmd.fFunction();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CommandSet::addCommand(SkUnichar c, const char* group, const char* description,
+ std::function<void(void)> function) {
+ fCommands.push_back(Command(c, group, description, function));
+}
+
+void CommandSet::addCommand(Window::Key k, const char* keyName, const char* group,
+ const char* description, std::function<void(void)> function) {
+ fCommands.push_back(Command(k, keyName, group, description, function));
+}
+
+#if defined(SK_BUILD_FOR_WIN32)
+ #define SK_strcasecmp _stricmp
+#else
+ #define SK_strcasecmp strcasecmp
+#endif
+
+bool CommandSet::compareCommandKey(const Command& first, const Command& second) {
+ return SK_strcasecmp(first.fKeyName.c_str(), second.fKeyName.c_str()) < 0;
+}
+
+bool CommandSet::compareCommandGroup(const Command& first, const Command& second) {
+ return SK_strcasecmp(first.fGroup.c_str(), second.fGroup.c_str()) < 0;
+}
+
+void CommandSet::drawHelp(SkCanvas* canvas) {
+ if (kNone_HelpMode == fHelpMode) {
+ return;
+ }
+
+ // Sort commands for current mode:
+ SkTQSort(fCommands.begin(), fCommands.end() - 1,
+ kAlphabetical_HelpMode == fHelpMode ? compareCommandKey : compareCommandGroup);
+
+ SkPaint bgPaint;
+ bgPaint.setColor(0xC0000000);
+ canvas->drawPaint(bgPaint);
+
+ SkPaint paint;
+ paint.setTextSize(16);
+ paint.setAntiAlias(true);
+ paint.setColor(0xFFFFFFFF);
+
+ SkPaint groupPaint;
+ groupPaint.setTextSize(18);
+ groupPaint.setUnderlineText(true);
+ groupPaint.setAntiAlias(true);
+ groupPaint.setColor(0xFFFFFFFF);
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+
+ // Measure all key strings:
+ SkScalar keyWidth = 0;
+ for (Command& cmd : fCommands) {
+ keyWidth = SkMaxScalar(keyWidth,
+ paint.measureText(cmd.fKeyName.c_str(), cmd.fKeyName.size()));
+ }
+ keyWidth += paint.measureText(" ", 1);
+
+ // If we're grouping by category, we'll be adding text height on every new group (including the
+ // first), so no need to do that here. Otherwise, skip down so the first line is where we want.
+ if (kGrouped_HelpMode != fHelpMode) {
+ y += paint.getTextSize();
+ }
+
+ // Print everything:
+ SkString lastGroup;
+ for (Command& cmd : fCommands) {
+ if (kGrouped_HelpMode == fHelpMode && lastGroup != cmd.fGroup) {
+ // Group change. Advance and print header:
+ y += paint.getTextSize();
+ canvas->drawText(cmd.fGroup.c_str(), cmd.fGroup.size(), x, y, groupPaint);
+ y += groupPaint.getTextSize() + 2;
+ lastGroup = cmd.fGroup;
+ }
+
+ canvas->drawText(cmd.fKeyName.c_str(), cmd.fKeyName.size(), x, y, paint);
+ SkString text = SkStringPrintf(": %s", cmd.fDescription.c_str());
+ canvas->drawText(text.c_str(), text.size(), x + keyWidth, y, paint);
+ y += paint.getTextSize() + 2;
+ }
+}
+
+} // namespace sk_app
diff --git a/tools/viewer/sk_app/CommandSet.h b/tools/viewer/sk_app/CommandSet.h
new file mode 100644
index 0000000000..5e6373c935
--- /dev/null
+++ b/tools/viewer/sk_app/CommandSet.h
@@ -0,0 +1,107 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef CommandSet_DEFINED
+#define CommandSet_DEFINED
+
+#include "SkString.h"
+#include "Window.h"
+
+#include <functional>
+
+class SkCanvas;
+
+namespace sk_app {
+
+/**
+ * Helper class used by applications that want to hook keypresses to trigger events.
+ *
+ * An app can simply store an instance of CommandSet and then use it as follows:
+ * 1) Attach to the Window at initialization time. This registers key handlers on the window.
+ * 2) Register commands to be executed for characters or keys. Each command needs a Group and a
+ * description (both just strings). Commands attached to Keys (rather than characters) also need
+ * a displayable name for the Key. Finally, a function to execute when the key or character is
+ * pressed must be supplied. The easiest option to is pass in a lambda that captures [this]
+ * (your application object), and performs whatever action is desired.
+ * 3) At the end of your onPaint, call drawHelp, and pass in the application's canvas.
+
+ * The CommandSet always binds 'h' to cycle through two different help screens. The first shows
+ * all commands, organized by Group (with headings for each Group). The second shows all commands
+ * alphabetically by key/character.
+ */
+class CommandSet {
+public:
+ CommandSet();
+
+ void attach(Window* window);
+ bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers);
+ bool onChar(SkUnichar, uint32_t modifiers);
+
+ void addCommand(SkUnichar c, const char* group, const char* description,
+ std::function<void(void)> function);
+ void addCommand(Window::Key k, const char* keyName, const char* group, const char* description,
+ std::function<void(void)> function);
+
+ void drawHelp(SkCanvas* canvas);
+
+private:
+ struct Command {
+ enum CommandType {
+ kChar_CommandType,
+ kKey_CommandType,
+ };
+
+ Command(SkUnichar c, const char* group, const char* description,
+ std::function<void(void)> function)
+ : fType(kChar_CommandType)
+ , fChar(c)
+ , fKeyName(SkStringPrintf("%c", c))
+ , fGroup(group)
+ , fDescription(description)
+ , fFunction(function) {}
+
+ Command(Window::Key k, const char* keyName, const char* group, const char* description,
+ std::function<void(void)> function)
+ : fType(kKey_CommandType)
+ , fKey(k)
+ , fKeyName(keyName)
+ , fGroup(group)
+ , fDescription(description)
+ , fFunction(function) {}
+
+ CommandType fType;
+
+ // For kChar_CommandType
+ SkUnichar fChar;
+
+ // For kKey_CommandType
+ Window::Key fKey;
+
+ // Common to all command types
+ SkString fKeyName;
+ SkString fGroup;
+ SkString fDescription;
+ std::function<void(void)> fFunction;
+ };
+
+ static bool compareCommandKey(const Command& first, const Command& second);
+ static bool compareCommandGroup(const Command& first, const Command& second);
+
+ enum HelpMode {
+ kNone_HelpMode,
+ kGrouped_HelpMode,
+ kAlphabetical_HelpMode,
+ };
+
+ Window* fWindow;
+ SkTArray<Command> fCommands;
+ HelpMode fHelpMode;
+};
+
+} // namespace sk_app
+
+#endif
diff --git a/tools/viewer/sk_app/Window.h b/tools/viewer/sk_app/Window.h
index 56444a67b7..5a7c9b8360 100644
--- a/tools/viewer/sk_app/Window.h
+++ b/tools/viewer/sk_app/Window.h
@@ -41,45 +41,45 @@ public:
void detach();
// input handling
- enum Key {
- kNONE_Key, //corresponds to android's UNKNOWN
-
- kLeftSoftKey_Key,
- kRightSoftKey_Key,
-
- kHome_Key, //!< the home key - added to match android
- kBack_Key, //!< (CLR)
- kSend_Key, //!< the green (talk) key
- kEnd_Key, //!< the red key
-
- k0_Key,
- k1_Key,
- k2_Key,
- k3_Key,
- k4_Key,
- k5_Key,
- k6_Key,
- k7_Key,
- k8_Key,
- k9_Key,
- kStar_Key, //!< the * key
- kHash_Key, //!< the # key
-
- kUp_Key,
- kDown_Key,
- kLeft_Key,
- kRight_Key,
-
- kOK_Key, //!< the center key
-
- kVolUp_Key, //!< volume up - match android
- kVolDown_Key, //!< volume down - same
- kPower_Key, //!< power button - same
- kCamera_Key, //!< camera - same
-
- kLast_Key = kCamera_Key
+ enum class Key {
+ kNONE, //corresponds to android's UNKNOWN
+
+ kLeftSoftKey,
+ kRightSoftKey,
+
+ kHome, //!< the home key - added to match android
+ kBack, //!< (CLR)
+ kSend, //!< the green (talk) key
+ kEnd, //!< the red key
+
+ k0,
+ k1,
+ k2,
+ k3,
+ k4,
+ k5,
+ k6,
+ k7,
+ k8,
+ k9,
+ kStar, //!< the * key
+ kHash, //!< the # key
+
+ kUp,
+ kDown,
+ kLeft,
+ kRight,
+
+ kOK, //!< the center key
+
+ kVolUp, //!< volume up - match android
+ kVolDown, //!< volume down - same
+ kPower, //!< power button - same
+ kCamera, //!< camera - same
+
+ kLast = kCamera
};
- static const int kKeyCount = kLast_Key + 1;
+ static const int kKeyCount = static_cast<int>(Key::kLast) + 1;
enum ModifierKeys {
kShift_ModifierKey = 1 << 0,
diff --git a/tools/viewer/sk_app/win/Window_win.cpp b/tools/viewer/sk_app/win/Window_win.cpp
index 16afcc7275..241a41caba 100644
--- a/tools/viewer/sk_app/win/Window_win.cpp
+++ b/tools/viewer/sk_app/win/Window_win.cpp
@@ -93,20 +93,20 @@ static Window::Key get_key(WPARAM vk) {
WPARAM fVK;
Window::Key fKey;
} gPair[] = {
- { VK_BACK, Window::kBack_Key },
- { VK_CLEAR, Window::kBack_Key },
- { VK_RETURN, Window::kOK_Key },
- { VK_UP, Window::kUp_Key },
- { VK_DOWN, Window::kDown_Key },
- { VK_LEFT, Window::kLeft_Key },
- { VK_RIGHT, Window::kRight_Key }
+ { VK_BACK, Window::Key::kBack },
+ { VK_CLEAR, Window::Key::kBack },
+ { VK_RETURN, Window::Key::kOK },
+ { VK_UP, Window::Key::kUp },
+ { VK_DOWN, Window::Key::kDown },
+ { VK_LEFT, Window::Key::kLeft },
+ { VK_RIGHT, Window::Key::kRight }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
if (gPair[i].fVK == vk) {
return gPair[i].fKey;
}
}
- return Window::kNONE_Key;
+ return Window::Key::kNONE;
}
static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {