brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef CommandSet_DEFINED |
| 9 | #define CommandSet_DEFINED |
| 10 | |
| 11 | #include "SkString.h" |
| 12 | #include "Window.h" |
| 13 | |
| 14 | #include <functional> |
liyuqian | b73c24b | 2016-06-03 08:47:23 -0700 | [diff] [blame] | 15 | #include <vector> |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 16 | |
| 17 | class SkCanvas; |
| 18 | |
| 19 | namespace sk_app { |
| 20 | |
| 21 | /** |
| 22 | * Helper class used by applications that want to hook keypresses to trigger events. |
| 23 | * |
| 24 | * An app can simply store an instance of CommandSet and then use it as follows: |
Brian Osman | 79086b9 | 2017-02-10 13:36:16 -0500 | [diff] [blame^] | 25 | * 1) Attach to the Window at initialization time. |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 26 | * 2) Register commands to be executed for characters or keys. Each command needs a Group and a |
| 27 | * description (both just strings). Commands attached to Keys (rather than characters) also need |
| 28 | * a displayable name for the Key. Finally, a function to execute when the key or character is |
| 29 | * pressed must be supplied. The easiest option to is pass in a lambda that captures [this] |
| 30 | * (your application object), and performs whatever action is desired. |
Brian Osman | 79086b9 | 2017-02-10 13:36:16 -0500 | [diff] [blame^] | 31 | * 3) Register key and char handlers with the Window, and - depending on your state - forward those |
| 32 | * events to the CommandSet's onKey, onChar, and onSoftKey. |
| 33 | * 4) At the end of your onPaint, call drawHelp, and pass in the application's canvas. |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 34 | |
| 35 | * The CommandSet always binds 'h' to cycle through two different help screens. The first shows |
| 36 | * all commands, organized by Group (with headings for each Group). The second shows all commands |
| 37 | * alphabetically by key/character. |
| 38 | */ |
| 39 | class CommandSet { |
| 40 | public: |
| 41 | CommandSet(); |
| 42 | |
| 43 | void attach(Window* window); |
| 44 | bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers); |
| 45 | bool onChar(SkUnichar, uint32_t modifiers); |
liyuqian | b73c24b | 2016-06-03 08:47:23 -0700 | [diff] [blame] | 46 | bool onSoftkey(const SkString& softkey); |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 47 | |
| 48 | void addCommand(SkUnichar c, const char* group, const char* description, |
| 49 | std::function<void(void)> function); |
| 50 | void addCommand(Window::Key k, const char* keyName, const char* group, const char* description, |
| 51 | std::function<void(void)> function); |
| 52 | |
| 53 | void drawHelp(SkCanvas* canvas); |
| 54 | |
liyuqian | b73c24b | 2016-06-03 08:47:23 -0700 | [diff] [blame] | 55 | std::vector<SkString> getCommandsAsSoftkeys() const; |
| 56 | |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 57 | private: |
| 58 | struct Command { |
| 59 | enum CommandType { |
| 60 | kChar_CommandType, |
| 61 | kKey_CommandType, |
| 62 | }; |
| 63 | |
| 64 | Command(SkUnichar c, const char* group, const char* description, |
| 65 | std::function<void(void)> function) |
| 66 | : fType(kChar_CommandType) |
| 67 | , fChar(c) |
Brian Osman | 79086b9 | 2017-02-10 13:36:16 -0500 | [diff] [blame^] | 68 | , fKeyName(' ' == c ? SkString("Space") : SkStringPrintf("%c", c)) |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 69 | , fGroup(group) |
| 70 | , fDescription(description) |
| 71 | , fFunction(function) {} |
| 72 | |
| 73 | Command(Window::Key k, const char* keyName, const char* group, const char* description, |
| 74 | std::function<void(void)> function) |
| 75 | : fType(kKey_CommandType) |
| 76 | , fKey(k) |
| 77 | , fKeyName(keyName) |
| 78 | , fGroup(group) |
| 79 | , fDescription(description) |
| 80 | , fFunction(function) {} |
| 81 | |
| 82 | CommandType fType; |
| 83 | |
| 84 | // For kChar_CommandType |
| 85 | SkUnichar fChar; |
| 86 | |
| 87 | // For kKey_CommandType |
| 88 | Window::Key fKey; |
| 89 | |
| 90 | // Common to all command types |
| 91 | SkString fKeyName; |
| 92 | SkString fGroup; |
| 93 | SkString fDescription; |
| 94 | std::function<void(void)> fFunction; |
liyuqian | b73c24b | 2016-06-03 08:47:23 -0700 | [diff] [blame] | 95 | |
| 96 | SkString getSoftkeyString() const { |
| 97 | return SkStringPrintf("%s (%s)", fKeyName.c_str(), fDescription.c_str()); |
| 98 | } |
brianosman | 622c8d5 | 2016-05-10 06:50:49 -0700 | [diff] [blame] | 99 | }; |
| 100 | |
| 101 | static bool compareCommandKey(const Command& first, const Command& second); |
| 102 | static bool compareCommandGroup(const Command& first, const Command& second); |
| 103 | |
| 104 | enum HelpMode { |
| 105 | kNone_HelpMode, |
| 106 | kGrouped_HelpMode, |
| 107 | kAlphabetical_HelpMode, |
| 108 | }; |
| 109 | |
| 110 | Window* fWindow; |
| 111 | SkTArray<Command> fCommands; |
| 112 | HelpMode fHelpMode; |
| 113 | }; |
| 114 | |
| 115 | } // namespace sk_app |
| 116 | |
| 117 | #endif |