622c8d5de1
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
158 lines
4.8 KiB
C++
158 lines
4.8 KiB
C++
/*
|
|
* 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
|