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);
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();
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();
if (fDisplayStats) {
drawStats(canvas);
}
+ fCommands.drawHelp(canvas);
}
void Viewer::drawStats(SkCanvas* canvas) {
#define Viewer_DEFINED
#include "sk_app/Application.h"
+#include "sk_app/CommandSet.h"
#include "sk_app/Window.h"
#include "gm.h"
#include "SkAnimTimer.h"
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;
SkScalar fZoomLevel;
SkScalar fZoomScale;
+ sk_app::CommandSet fCommands;
};
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
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,
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) {