diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-11-21 08:42:15 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-11-21 08:42:15 +0200 |
commit | c651680715f7549a0cdbdbb10d535cba2272d9d0 (patch) | |
tree | 8e29397258b62a1be4349bc5f44e4880697a16c1 /src/ui | |
parent | dc5dd8faaf718dea6f89187eebe2692a65c99439 (diff) |
Clearing and resetting keybindings
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/bindingswidget.c | 46 | ||||
-rw-r--r-- | src/ui/keys.c | 57 | ||||
-rw-r--r-- | src/ui/keys.h | 1 | ||||
-rw-r--r-- | src/ui/listwidget.c | 4 | ||||
-rw-r--r-- | src/ui/listwidget.h | 1 |
5 files changed, 90 insertions, 19 deletions
diff --git a/src/ui/bindingswidget.c b/src/ui/bindingswidget.c index a6e9f6a0..ff68ea7b 100644 --- a/src/ui/bindingswidget.c +++ b/src/ui/bindingswidget.c | |||
@@ -75,6 +75,8 @@ struct Impl_BindingsWidget { | |||
75 | iWidget widget; | 75 | iWidget widget; |
76 | iListWidget *list; | 76 | iListWidget *list; |
77 | size_t activePos; | 77 | size_t activePos; |
78 | size_t contextPos; | ||
79 | iWidget *menu; | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | iDefineObjectConstruction(BindingsWidget) | 82 | iDefineObjectConstruction(BindingsWidget) |
@@ -108,11 +110,17 @@ void init_BindingsWidget(iBindingsWidget *d) { | |||
108 | init_Widget(w); | 110 | init_Widget(w); |
109 | setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); | 111 | setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); |
110 | d->activePos = iInvalidPos; | 112 | d->activePos = iInvalidPos; |
113 | d->contextPos = iInvalidPos; | ||
111 | d->list = new_ListWidget(); | 114 | d->list = new_ListWidget(); |
112 | setItemHeight_ListWidget(d->list, lineHeight_Text(uiLabel_FontId) * 1.5f); | 115 | setItemHeight_ListWidget(d->list, lineHeight_Text(uiLabel_FontId) * 1.5f); |
113 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); | 116 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); |
114 | addChild_Widget(w, iClob(d->list)); | 117 | addChild_Widget(w, iClob(d->list)); |
115 | updateItems_BindingsWidget_(d); | 118 | updateItems_BindingsWidget_(d); |
119 | d->menu = makeMenu_Widget( | ||
120 | w, | ||
121 | (iMenuItem[]){ { "Reset to Default", 0, 0, "binding.reset" }, | ||
122 | { uiTextCaution_ColorEscape "Clear", 0, 0, "binding.clear" } }, | ||
123 | 2); | ||
116 | } | 124 | } |
117 | 125 | ||
118 | void deinit_BindingsWidget(iBindingsWidget *d) { | 126 | void deinit_BindingsWidget(iBindingsWidget *d) { |
@@ -145,9 +153,38 @@ static iBool processEvent_BindingsWidget_(iBindingsWidget *d, const SDL_Event *e | |||
145 | iWidget * w = as_Widget(d); | 153 | iWidget * w = as_Widget(d); |
146 | const char *cmd = command_UserEvent(ev); | 154 | const char *cmd = command_UserEvent(ev); |
147 | if (isCommand_Widget(w, ev, "list.clicked")) { | 155 | if (isCommand_Widget(w, ev, "list.clicked")) { |
148 | setActiveItem_BindingsWidget_(d, arg_Command(cmd)); | 156 | const size_t index = (size_t) arg_Command(cmd); |
157 | setActiveItem_BindingsWidget_(d, d->activePos != index ? index : iInvalidPos); | ||
149 | return iTrue; | 158 | return iTrue; |
150 | } | 159 | } |
160 | else if (isCommand_Widget(w, ev, "menu.closed")) { | ||
161 | invalidateItem_ListWidget(d->list, d->contextPos); | ||
162 | } | ||
163 | else if (isCommand_Widget(w, ev, "binding.reset")) { | ||
164 | iBindingItem *item = item_ListWidget(d->list, d->contextPos); | ||
165 | if (item) { | ||
166 | reset_Binding(item->id); | ||
167 | updateItems_BindingsWidget_(d); | ||
168 | } | ||
169 | return iTrue; | ||
170 | } | ||
171 | else if (isCommand_Widget(w, ev, "binding.clear")) { | ||
172 | setKey_BindingItem_(item_ListWidget(d->list, d->contextPos), 0, 0); | ||
173 | invalidateItem_ListWidget(d->list, d->contextPos); | ||
174 | d->contextPos = iInvalidPos; | ||
175 | postCommand_App("bindings.changed"); | ||
176 | return iTrue; | ||
177 | } | ||
178 | if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT) { | ||
179 | if (!isVisible_Widget(d->menu)) { | ||
180 | d->contextPos = hoverItemIndex_ListWidget(d->list); | ||
181 | } | ||
182 | } | ||
183 | if (d->contextPos != iInvalidPos) { | ||
184 | processContextMenuEvent_Widget(d->menu, ev, { | ||
185 | setActiveItem_BindingsWidget_(d, iInvalidPos); | ||
186 | }); | ||
187 | } | ||
151 | /* Waiting for a keypress? */ | 188 | /* Waiting for a keypress? */ |
152 | if (d->activePos != iInvalidPos) { | 189 | if (d->activePos != iInvalidPos) { |
153 | if (ev->type == SDL_KEYDOWN && !isMod_Sym(ev->key.keysym.sym)) { | 190 | if (ev->type == SDL_KEYDOWN && !isMod_Sym(ev->key.keysym.sym)) { |
@@ -175,8 +212,11 @@ static void draw_BindingItem_(const iBindingItem *d, iPaint *p, iRect itemRect, | |||
175 | const int line = lineHeight_Text(font); | 212 | const int line = lineHeight_Text(font); |
176 | int fg = uiText_ColorId; | 213 | int fg = uiText_ColorId; |
177 | const iBool isPressing = isMouseDown_ListWidget(list) || d->isWaitingForEvent; | 214 | const iBool isPressing = isMouseDown_ListWidget(list) || d->isWaitingForEvent; |
178 | const iBool isHover = (isHover_Widget(constAs_Widget(list)) && | 215 | const iBindingsWidget *parent = (const iBindingsWidget *) parent_Widget(list); |
179 | constHoverItem_ListWidget(list) == d); | 216 | const iBool isMenuOpen = isVisible_Widget(parent->menu); |
217 | const iBool isHover = ((!isMenuOpen && isHover_Widget(constAs_Widget(list)) && | ||
218 | constHoverItem_ListWidget(list) == d) || | ||
219 | (isMenuOpen && constItem_ListWidget(list, parent->contextPos) == d)); | ||
180 | if (isHover || isPressing) { | 220 | if (isHover || isPressing) { |
181 | fg = isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId; | 221 | fg = isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId; |
182 | fillRect_Paint(p, | 222 | fillRect_Paint(p, |
diff --git a/src/ui/keys.c b/src/ui/keys.c index 6d68cc57..5b88bfcf 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c | |||
@@ -56,23 +56,34 @@ static void clear_Keys_(iKeys *d) { | |||
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | static void bindDefaults_(void) { | 59 | /* TODO: This indirection could be used for localization, although all UI strings |
60 | /* TODO: This indirection could be used for localization, although all UI strings | 60 | would need to be similarly handled. */ |
61 | would need to be similarly handled. */ | 61 | static const struct { int id; iMenuItem bind; } defaultBindings_[] = { |
62 | bindLabel_Keys(1, "scroll.top", SDLK_HOME, 0, "Jump to top"); | 62 | { 1, { "Jump to top", SDLK_HOME, 0, "scroll.top" } }, |
63 | bindLabel_Keys(2, "scroll.bottom", SDLK_END, 0, "Jump to bottom"); | 63 | { 2, { "Jump to bottom", SDLK_END, 0, "scroll.bottom" } }, |
64 | bindLabel_Keys(10, "scroll.step arg:-1", SDLK_UP, 0, "Scroll up"); | 64 | { 10, { "Scroll up", SDLK_UP, 0, "scroll.step arg:-1" } }, |
65 | bindLabel_Keys(11, "scroll.step arg:1", SDLK_DOWN, 0, "Scroll down"); | 65 | { 11, { "Scroll down", SDLK_DOWN, 0, "scroll.step arg:1" } }, |
66 | bindLabel_Keys(20, "scroll.page arg:-1", SDLK_PAGEUP, 0, "Scroll up half a page"); | 66 | { 20, { "Scroll up half a page", SDLK_PAGEUP, 0, "scroll.page arg:-1" } }, |
67 | bindLabel_Keys(21, "scroll.page arg:1", SDLK_PAGEDOWN, 0, "Scroll down half a page"); | 67 | { 21, { "Scroll down half a page", SDLK_PAGEDOWN, 0, "scroll.page arg:1" } }, |
68 | bindLabel_Keys(30, "navigate.back", navigateBack_KeyShortcut, "Go back"); | 68 | { 30, { "Go back", navigateBack_KeyShortcut, "navigate.back" } }, |
69 | bindLabel_Keys(31, "navigate.forward", navigateForward_KeyShortcut, "Go forward"); | 69 | { 31, { "Go forward", navigateForward_KeyShortcut, "navigate.forward" } }, |
70 | bindLabel_Keys(32, "navigate.parent", navigateParent_KeyShortcut, "Go to parent directory"); | 70 | { 32, { "Go to parent directory", navigateParent_KeyShortcut, "navigate.parent" } }, |
71 | bindLabel_Keys(33, "navigate.root", navigateRoot_KeyShortcut, "Go to site root"); | 71 | { 33, { "Go to site root", navigateRoot_KeyShortcut, "navigate.root" } }, |
72 | bindLabel_Keys(40, "document.linkkeys", 'f', 0, "Open link via keyboard"); | 72 | { 40, { "Open link via keyboard", 'f', 0, "document.linkkeys"} }, |
73 | /* The following cannot currently be changed (built-in duplicates). */ | 73 | /* The following cannot currently be changed (built-in duplicates). */ |
74 | bind_Keys(1000, "scroll.page arg:-1", SDLK_SPACE, KMOD_SHIFT); | 74 | { 1000, { NULL, SDLK_SPACE, KMOD_SHIFT, "scroll.page arg:-1" } }, |
75 | bind_Keys(1001, "scroll.page arg:1", SDLK_SPACE, 0); | 75 | { 1001, { NULL, SDLK_SPACE, 0, "scroll.page arg:1" } }, |
76 | }; | ||
77 | |||
78 | static void bindDefaults_(void) { | ||
79 | iForIndices(i, defaultBindings_) { | ||
80 | const int id = defaultBindings_[i].id; | ||
81 | const iMenuItem bind = defaultBindings_[i].bind; | ||
82 | bind_Keys(id, bind.command, bind.key, bind.kmods); | ||
83 | if (bind.label) { | ||
84 | setLabel_Keys(id, bind.label); | ||
85 | } | ||
86 | } | ||
76 | } | 87 | } |
77 | 88 | ||
78 | static iBinding *find_Keys_(iKeys *d, int key, int mods) { | 89 | static iBinding *find_Keys_(iKeys *d, int key, int mods) { |
@@ -121,6 +132,20 @@ void setKey_Binding(int id, int key, int mods) { | |||
121 | } | 132 | } |
122 | } | 133 | } |
123 | 134 | ||
135 | void reset_Binding(int id) { | ||
136 | iBinding *bind = findId_Keys_(&keys_, id); | ||
137 | if (bind) { | ||
138 | iForIndices(i, defaultBindings_) { | ||
139 | if (defaultBindings_[i].id == id) { | ||
140 | bind->key = defaultBindings_[i].bind.key; | ||
141 | bind->mods = defaultBindings_[i].bind.kmods; | ||
142 | updateLookup_Keys_(&keys_); | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
124 | /*----------------------------------------------------------------------------------------------*/ | 149 | /*----------------------------------------------------------------------------------------------*/ |
125 | 150 | ||
126 | static const char *filename_Keys_ = "bindings.txt"; | 151 | static const char *filename_Keys_ = "bindings.txt"; |
diff --git a/src/ui/keys.h b/src/ui/keys.h index 5bc9141c..0cd97e2a 100644 --- a/src/ui/keys.h +++ b/src/ui/keys.h | |||
@@ -59,6 +59,7 @@ struct Impl_Binding { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | void setKey_Binding (int id, int key, int mods); | 61 | void setKey_Binding (int id, int key, int mods); |
62 | void reset_Binding (int id); | ||
62 | 63 | ||
63 | /*----------------------------------------------------------------------------------------------*/ | 64 | /*----------------------------------------------------------------------------------------------*/ |
64 | 65 | ||
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 6f0405d7..39b9bfe5 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -228,6 +228,10 @@ iAnyObject *hoverItem_ListWidget(iListWidget *d) { | |||
228 | return item_ListWidget(d, d->hoverItem); | 228 | return item_ListWidget(d, d->hoverItem); |
229 | } | 229 | } |
230 | 230 | ||
231 | size_t hoverItemIndex_ListWidget(const iListWidget *d) { | ||
232 | return d->hoverItem; | ||
233 | } | ||
234 | |||
231 | static void setHoverItem_ListWidget_(iListWidget *d, size_t index) { | 235 | static void setHoverItem_ListWidget_(iListWidget *d, size_t index) { |
232 | if (index < size_PtrArray(&d->items)) { | 236 | if (index < size_PtrArray(&d->items)) { |
233 | const iListItem *item = at_PtrArray(&d->items, index); | 237 | const iListItem *item = at_PtrArray(&d->items, index); |
diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h index 11f1672e..26c1ac9e 100644 --- a/src/ui/listwidget.h +++ b/src/ui/listwidget.h | |||
@@ -74,6 +74,7 @@ int visCount_ListWidget (const iListWidget *); | |||
74 | size_t itemIndex_ListWidget (const iListWidget *, iInt2 pos); | 74 | size_t itemIndex_ListWidget (const iListWidget *, iInt2 pos); |
75 | const iAnyObject * constItem_ListWidget (const iListWidget *, size_t index); | 75 | const iAnyObject * constItem_ListWidget (const iListWidget *, size_t index); |
76 | const iAnyObject * constHoverItem_ListWidget (const iListWidget *); | 76 | const iAnyObject * constHoverItem_ListWidget (const iListWidget *); |
77 | size_t hoverItemIndex_ListWidget (const iListWidget *); | ||
77 | 78 | ||
78 | iLocalDef iBool isEmpty_ListWidget(const iListWidget *d) { return numItems_ListWidget(d) == 0; } | 79 | iLocalDef iBool isEmpty_ListWidget(const iListWidget *d) { return numItems_ListWidget(d) == 0; } |
79 | 80 | ||