summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ui/bindingswidget.c46
-rw-r--r--src/ui/keys.c57
-rw-r--r--src/ui/keys.h1
-rw-r--r--src/ui/listwidget.c4
-rw-r--r--src/ui/listwidget.h1
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
80iDefineObjectConstruction(BindingsWidget) 82iDefineObjectConstruction(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
118void deinit_BindingsWidget(iBindingsWidget *d) { 126void 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
59static 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. */ 61static 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
78static 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
78static iBinding *find_Keys_(iKeys *d, int key, int mods) { 89static 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
135void 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
126static const char *filename_Keys_ = "bindings.txt"; 151static 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
61void setKey_Binding (int id, int key, int mods); 61void setKey_Binding (int id, int key, int mods);
62void 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
231size_t hoverItemIndex_ListWidget(const iListWidget *d) {
232 return d->hoverItem;
233}
234
231static void setHoverItem_ListWidget_(iListWidget *d, size_t index) { 235static 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 *);
74size_t itemIndex_ListWidget (const iListWidget *, iInt2 pos); 74size_t itemIndex_ListWidget (const iListWidget *, iInt2 pos);
75const iAnyObject * constItem_ListWidget (const iListWidget *, size_t index); 75const iAnyObject * constItem_ListWidget (const iListWidget *, size_t index);
76const iAnyObject * constHoverItem_ListWidget (const iListWidget *); 76const iAnyObject * constHoverItem_ListWidget (const iListWidget *);
77size_t hoverItemIndex_ListWidget (const iListWidget *);
77 78
78iLocalDef iBool isEmpty_ListWidget(const iListWidget *d) { return numItems_ListWidget(d) == 0; } 79iLocalDef iBool isEmpty_ListWidget(const iListWidget *d) { return numItems_ListWidget(d) == 0; }
79 80