diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 20 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 37 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 10 | ||||
-rw-r--r-- | src/ui/window.c | 39 | ||||
-rw-r--r-- | src/ui/window.h | 1 |
6 files changed, 86 insertions, 23 deletions
@@ -15,7 +15,7 @@ int main(int argc, char **argv) { | |||
15 | init_Foundation(); | 15 | init_Foundation(); |
16 | printf("Lagrange: A Beautiful Gemini Client\n"); | 16 | printf("Lagrange: A Beautiful Gemini Client\n"); |
17 | /* Initialize SDL. */ | 17 | /* Initialize SDL. */ |
18 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { | 18 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { |
19 | fprintf(stderr, "SDL init failed: %s\n", SDL_GetError()); | 19 | fprintf(stderr, "SDL init failed: %s\n", SDL_GetError()); |
20 | return -1; | 20 | return -1; |
21 | } | 21 | } |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 9d95957a..71399d3b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -301,6 +301,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
301 | if (isResize_UserEvent(ev)) { | 301 | if (isResize_UserEvent(ev)) { |
302 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); | 302 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); |
303 | updateVisible_DocumentWidget_(d); | 303 | updateVisible_DocumentWidget_(d); |
304 | refresh_Widget(w); | ||
304 | } | 305 | } |
305 | else if (isCommand_Widget(w, ev, "scroll.moved")) { | 306 | else if (isCommand_Widget(w, ev, "scroll.moved")) { |
306 | d->scrollY = arg_Command(command_UserEvent(ev)); | 307 | d->scrollY = arg_Command(command_UserEvent(ev)); |
@@ -410,30 +411,27 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
410 | } | 411 | } |
411 | 412 | ||
412 | static void draw_DocumentWidget_(const iDocumentWidget *d) { | 413 | static void draw_DocumentWidget_(const iDocumentWidget *d) { |
413 | const iWidget *w = constAs_Widget(d); | 414 | const iWidget *w = constAs_Widget(d); |
415 | const iRect bounds = bounds_Widget(w); | ||
414 | draw_Widget(w); | 416 | draw_Widget(w); |
417 | iDrawContext ctx = { .widget = d, .bounds = documentBounds_DocumentWidget_(d) }; | ||
418 | init_Paint(&ctx.paint); | ||
419 | fillRect_Paint(&ctx.paint, bounds, gray25_ColorId); | ||
415 | /* Update the document? */ | 420 | /* Update the document? */ |
416 | if (!isEmpty_String(d->newSource)) { | 421 | if (!isEmpty_String(d->newSource)) { |
417 | iDocumentWidget *m = iConstCast(iDocumentWidget *, d); | 422 | iDocumentWidget *m = iConstCast(iDocumentWidget *, d); |
418 | /* TODO: Do this in the background. However, that requires a text metrics calculator | 423 | /* TODO: Do this in the background. However, that requires a text metrics calculator |
419 | that does not try to cache the glyph bitmaps. */ | 424 | that does not try to cache the glyph bitmaps. */ |
420 | setSource_GmDocument(m->doc, m->newSource, documentWidth_DocumentWidget_(m)); | 425 | setSource_GmDocument(m->doc, m->newSource, width_Rect(ctx.bounds)); |
426 | postCommandf_App("document.changed url:%s", cstr_String(d->url)); | ||
421 | clear_String(m->newSource); | 427 | clear_String(m->newSource); |
422 | m->scrollY = 0; | 428 | m->scrollY = 0; |
423 | m->state = ready_DocumentState; | 429 | m->state = ready_DocumentState; |
424 | updateVisible_DocumentWidget_(m); | 430 | updateVisible_DocumentWidget_(m); |
425 | } | 431 | } |
426 | if (d->state != ready_DocumentState) return; | 432 | if (d->state != ready_DocumentState) return; |
427 | iDrawContext ctx = { .widget = d, .bounds = documentBounds_DocumentWidget_(d) }; | ||
428 | const iRect bounds = bounds_Widget(w); | ||
429 | init_Paint(&ctx.paint); | ||
430 | fillRect_Paint(&ctx.paint, bounds, gray25_ColorId); | ||
431 | setClip_Paint(&ctx.paint, bounds); | 433 | setClip_Paint(&ctx.paint, bounds); |
432 | render_GmDocument( | 434 | render_GmDocument(d->doc, visibleRange_DocumentWidget_(d), drawRun_DrawContext_, &ctx); |
433 | d->doc, | ||
434 | visibleRange_DocumentWidget_(d), | ||
435 | drawRun_DrawContext_, | ||
436 | &ctx); | ||
437 | clearClip_Paint(&ctx.paint); | 435 | clearClip_Paint(&ctx.paint); |
438 | draw_Widget(w); | 436 | draw_Widget(w); |
439 | } | 437 | } |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 1a692907..b73fac9e 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <the_Foundation/array.h> | 5 | #include <the_Foundation/array.h> |
6 | #include <SDL_timer.h> | 6 | #include <SDL_timer.h> |
7 | 7 | ||
8 | static const int REFRESH_INTERVAL = 256; | ||
9 | |||
8 | struct Impl_InputWidget { | 10 | struct Impl_InputWidget { |
9 | iWidget widget; | 11 | iWidget widget; |
10 | enum iInputMode mode; | 12 | enum iInputMode mode; |
@@ -14,6 +16,7 @@ struct Impl_InputWidget { | |||
14 | size_t cursor; | 16 | size_t cursor; |
15 | int font; | 17 | int font; |
16 | iClick click; | 18 | iClick click; |
19 | uint32_t timer; | ||
17 | }; | 20 | }; |
18 | 21 | ||
19 | iDefineObjectConstructionArgs(InputWidget, (size_t maxLen), maxLen) | 22 | iDefineObjectConstructionArgs(InputWidget, (size_t maxLen), maxLen) |
@@ -33,9 +36,13 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) { | |||
33 | setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); | 36 | setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); |
34 | } | 37 | } |
35 | init_Click(&d->click, d, SDL_BUTTON_LEFT); | 38 | init_Click(&d->click, d, SDL_BUTTON_LEFT); |
39 | d->timer = 0; | ||
36 | } | 40 | } |
37 | 41 | ||
38 | void deinit_InputWidget(iInputWidget *d) { | 42 | void deinit_InputWidget(iInputWidget *d) { |
43 | if (d->timer) { | ||
44 | SDL_RemoveTimer(d->timer); | ||
45 | } | ||
39 | deinit_Array(&d->oldText); | 46 | deinit_Array(&d->oldText); |
40 | deinit_Array(&d->text); | 47 | deinit_Array(&d->text); |
41 | } | 48 | } |
@@ -68,6 +75,7 @@ void setText_InputWidget(iInputWidget *d, const iString *text) { | |||
68 | iConstForEach(String, i, text) { | 75 | iConstForEach(String, i, text) { |
69 | pushBack_Array(&d->text, &i.value); | 76 | pushBack_Array(&d->text, &i.value); |
70 | } | 77 | } |
78 | refresh_Widget(as_Widget(d)); | ||
71 | } | 79 | } |
72 | 80 | ||
73 | void setTextCStr_InputWidget(iInputWidget *d, const char *cstr) { | 81 | void setTextCStr_InputWidget(iInputWidget *d, const char *cstr) { |
@@ -80,6 +88,11 @@ void setCursor_InputWidget(iInputWidget *d, size_t pos) { | |||
80 | d->cursor = iMin(pos, size_Array(&d->text)); | 88 | d->cursor = iMin(pos, size_Array(&d->text)); |
81 | } | 89 | } |
82 | 90 | ||
91 | static uint32_t refreshTimer_(uint32_t interval, void *d) { | ||
92 | refresh_Widget(d); | ||
93 | return interval; | ||
94 | } | ||
95 | |||
83 | void begin_InputWidget(iInputWidget *d) { | 96 | void begin_InputWidget(iInputWidget *d) { |
84 | iWidget *w = as_Widget(d); | 97 | iWidget *w = as_Widget(d); |
85 | if (flags_Widget(w) & selected_WidgetFlag) { | 98 | if (flags_Widget(w) & selected_WidgetFlag) { |
@@ -96,6 +109,8 @@ void begin_InputWidget(iInputWidget *d) { | |||
96 | } | 109 | } |
97 | SDL_StartTextInput(); | 110 | SDL_StartTextInput(); |
98 | setFlags_Widget(w, selected_WidgetFlag, iTrue); | 111 | setFlags_Widget(w, selected_WidgetFlag, iTrue); |
112 | refresh_Widget(w); | ||
113 | d->timer = SDL_AddTimer(REFRESH_INTERVAL, refreshTimer_, d); | ||
99 | } | 114 | } |
100 | 115 | ||
101 | void end_InputWidget(iInputWidget *d, iBool accept) { | 116 | void end_InputWidget(iInputWidget *d, iBool accept) { |
@@ -107,19 +122,23 @@ void end_InputWidget(iInputWidget *d, iBool accept) { | |||
107 | if (!accept) { | 122 | if (!accept) { |
108 | setCopy_Array(&d->text, &d->oldText); | 123 | setCopy_Array(&d->text, &d->oldText); |
109 | } | 124 | } |
125 | SDL_RemoveTimer(d->timer); | ||
126 | d->timer = 0; | ||
110 | SDL_StopTextInput(); | 127 | SDL_StopTextInput(); |
111 | setFlags_Widget(w, selected_WidgetFlag, iFalse); | 128 | setFlags_Widget(w, selected_WidgetFlag, iFalse); |
112 | const char *id = cstr_String(id_Widget(as_Widget(d))); | 129 | const char *id = cstr_String(id_Widget(as_Widget(d))); |
113 | if (!*id) id = "_"; | 130 | if (!*id) id = "_"; |
131 | refresh_Widget(w); | ||
114 | postCommand_Widget(w, "input.ended id:%s arg:%d", id, accept ? 1 : 0); | 132 | postCommand_Widget(w, "input.ended id:%s arg:%d", id, accept ? 1 : 0); |
115 | } | 133 | } |
116 | 134 | ||
117 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | 135 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { |
118 | if (isCommand_Widget(as_Widget(d), ev, "focus.gained")) { | 136 | iWidget *w = as_Widget(d); |
137 | if (isCommand_Widget(w, ev, "focus.gained")) { | ||
119 | begin_InputWidget(d); | 138 | begin_InputWidget(d); |
120 | return iTrue; | 139 | return iTrue; |
121 | } | 140 | } |
122 | else if (isCommand_Widget(as_Widget(d), ev, "focus.lost")) { | 141 | else if (isCommand_Widget(w, ev, "focus.lost")) { |
123 | end_InputWidget(d, iTrue); | 142 | end_InputWidget(d, iTrue); |
124 | return iTrue; | 143 | return iTrue; |
125 | } | 144 | } |
@@ -139,7 +158,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
139 | return iTrue; | 158 | return iTrue; |
140 | } | 159 | } |
141 | const size_t curMax = iMin(size_Array(&d->text), d->maxLen - 1); | 160 | const size_t curMax = iMin(size_Array(&d->text), d->maxLen - 1); |
142 | if (ev->type == SDL_KEYDOWN && isFocused_Widget(as_Widget(d))) { | 161 | if (ev->type == SDL_KEYDOWN && isFocused_Widget(w)) { |
143 | const int key = ev->key.keysym.sym; | 162 | const int key = ev->key.keysym.sym; |
144 | const int mods = keyMods_Sym(ev->key.keysym.mod); | 163 | const int mods = keyMods_Sym(ev->key.keysym.mod); |
145 | switch (key) { | 164 | switch (key) { |
@@ -159,28 +178,33 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
159 | else if (d->cursor > 0) { | 178 | else if (d->cursor > 0) { |
160 | remove_Array(&d->text, --d->cursor); | 179 | remove_Array(&d->text, --d->cursor); |
161 | } | 180 | } |
181 | refresh_Widget(w); | ||
162 | return iTrue; | 182 | return iTrue; |
163 | case SDLK_d: | 183 | case SDLK_d: |
164 | if (mods != KMOD_CTRL) break; | 184 | if (mods != KMOD_CTRL) break; |
165 | case SDLK_DELETE: | 185 | case SDLK_DELETE: |
166 | if (d->cursor < size_Array(&d->text)) { | 186 | if (d->cursor < size_Array(&d->text)) { |
167 | remove_Array(&d->text, d->cursor); | 187 | remove_Array(&d->text, d->cursor); |
188 | refresh_Widget(w); | ||
168 | } | 189 | } |
169 | return iTrue; | 190 | return iTrue; |
170 | case SDLK_k: | 191 | case SDLK_k: |
171 | if (mods == KMOD_CTRL) { | 192 | if (mods == KMOD_CTRL) { |
172 | removeN_Array(&d->text, d->cursor, size_Array(&d->text) - d->cursor); | 193 | removeN_Array(&d->text, d->cursor, size_Array(&d->text) - d->cursor); |
194 | refresh_Widget(w); | ||
173 | return iTrue; | 195 | return iTrue; |
174 | } | 196 | } |
175 | break; | 197 | break; |
176 | case SDLK_HOME: | 198 | case SDLK_HOME: |
177 | case SDLK_END: | 199 | case SDLK_END: |
178 | d->cursor = (key == SDLK_HOME ? 0 : curMax); | 200 | d->cursor = (key == SDLK_HOME ? 0 : curMax); |
201 | refresh_Widget(w); | ||
179 | return iTrue; | 202 | return iTrue; |
180 | case SDLK_a: | 203 | case SDLK_a: |
181 | case SDLK_e: | 204 | case SDLK_e: |
182 | if (mods == KMOD_CTRL) { | 205 | if (mods == KMOD_CTRL) { |
183 | d->cursor = (key == 'a' ? 0 : curMax); | 206 | d->cursor = (key == 'a' ? 0 : curMax); |
207 | refresh_Widget(w); | ||
184 | return iTrue; | 208 | return iTrue; |
185 | } | 209 | } |
186 | break; | 210 | break; |
@@ -191,6 +215,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
191 | else if (d->cursor > 0) { | 215 | else if (d->cursor > 0) { |
192 | d->cursor--; | 216 | d->cursor--; |
193 | } | 217 | } |
218 | refresh_Widget(w); | ||
194 | return iTrue; | 219 | return iTrue; |
195 | case SDLK_RIGHT: | 220 | case SDLK_RIGHT: |
196 | if (mods & KMOD_PRIMARY) { | 221 | if (mods & KMOD_PRIMARY) { |
@@ -199,6 +224,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
199 | else if (d->cursor < curMax) { | 224 | else if (d->cursor < curMax) { |
200 | d->cursor++; | 225 | d->cursor++; |
201 | } | 226 | } |
227 | refresh_Widget(w); | ||
202 | return iTrue; | 228 | return iTrue; |
203 | case SDLK_TAB: | 229 | case SDLK_TAB: |
204 | /* Allow focus switching. */ | 230 | /* Allow focus switching. */ |
@@ -209,7 +235,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
209 | } | 235 | } |
210 | return iTrue; | 236 | return iTrue; |
211 | } | 237 | } |
212 | else if (ev->type == SDL_TEXTINPUT && isFocused_Widget(as_Widget(d))) { | 238 | else if (ev->type == SDL_TEXTINPUT && isFocused_Widget(w)) { |
213 | const iString *uni = collectNewCStr_String(ev->text.text); | 239 | const iString *uni = collectNewCStr_String(ev->text.text); |
214 | const iChar chr = first_String(uni); | 240 | const iChar chr = first_String(uni); |
215 | if (d->mode == insert_InputMode) { | 241 | if (d->mode == insert_InputMode) { |
@@ -225,9 +251,10 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
225 | setFocus_Widget(NULL); | 251 | setFocus_Widget(NULL); |
226 | } | 252 | } |
227 | } | 253 | } |
254 | refresh_Widget(w); | ||
228 | return iTrue; | 255 | return iTrue; |
229 | } | 256 | } |
230 | return processEvent_Widget(as_Widget(d), ev); | 257 | return processEvent_Widget(w, ev); |
231 | } | 258 | } |
232 | 259 | ||
233 | static void draw_InputWidget_(const iInputWidget *d) { | 260 | static void draw_InputWidget_(const iInputWidget *d) { |
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 7b64857b..341c2f0e 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -30,19 +30,23 @@ static void trigger_LabelWidget_(const iLabelWidget *d) { | |||
30 | } | 30 | } |
31 | 31 | ||
32 | static iBool processEvent_LabelWidget_(iLabelWidget *d, const SDL_Event *ev) { | 32 | static iBool processEvent_LabelWidget_(iLabelWidget *d, const SDL_Event *ev) { |
33 | iWidget *w = &d->widget; | ||
33 | if (isCommand_UserEvent(ev, "metrics.changed")) { | 34 | if (isCommand_UserEvent(ev, "metrics.changed")) { |
34 | updateSize_LabelWidget(d); | 35 | updateSize_LabelWidget(d); |
35 | } | 36 | } |
36 | if (!isEmpty_String(&d->command)) { | 37 | if (!isEmpty_String(&d->command)) { |
37 | switch (processEvent_Click(&d->click, ev)) { | 38 | switch (processEvent_Click(&d->click, ev)) { |
38 | case started_ClickResult: | 39 | case started_ClickResult: |
39 | setFlags_Widget(&d->widget, pressed_WidgetFlag, iTrue); | 40 | setFlags_Widget(w, pressed_WidgetFlag, iTrue); |
41 | refresh_Widget(w); | ||
40 | return iTrue; | 42 | return iTrue; |
41 | case aborted_ClickResult: | 43 | case aborted_ClickResult: |
42 | setFlags_Widget(&d->widget, pressed_WidgetFlag, iFalse); | 44 | setFlags_Widget(w, pressed_WidgetFlag, iFalse); |
45 | refresh_Widget(w); | ||
43 | return iTrue; | 46 | return iTrue; |
44 | case finished_ClickResult: | 47 | case finished_ClickResult: |
45 | setFlags_Widget(&d->widget, pressed_WidgetFlag, iFalse); | 48 | setFlags_Widget(w, pressed_WidgetFlag, iFalse); |
49 | refresh_Widget(w); | ||
46 | trigger_LabelWidget_(d); | 50 | trigger_LabelWidget_(d); |
47 | return iTrue; | 51 | return iTrue; |
48 | case double_ClickResult: | 52 | case double_ClickResult: |
diff --git a/src/ui/window.c b/src/ui/window.c index 241cd3b0..43233010 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -49,6 +49,10 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
49 | } | 49 | } |
50 | return iTrue; | 50 | return iTrue; |
51 | } | 51 | } |
52 | else if (equal_Command(cmd, "setfocus")) { | ||
53 | setFocus_Widget(findWidget_App(cstr_String(string_Command(cmd, "id")))); | ||
54 | return iTrue; | ||
55 | } | ||
52 | else if (handleCommand_App(cmd)) { | 56 | else if (handleCommand_App(cmd)) { |
53 | return iTrue; | 57 | return iTrue; |
54 | } | 58 | } |
@@ -70,6 +74,23 @@ static const iMenuItem editMenuItems[] = { | |||
70 | static const iMenuItem viewMenuItems[] = { | 74 | static const iMenuItem viewMenuItems[] = { |
71 | }; | 75 | }; |
72 | 76 | ||
77 | static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | ||
78 | if (equal_Command(cmd, "input.ended")) { | ||
79 | iInputWidget *url = findChild_Widget(navBar, "url"); | ||
80 | if (arg_Command(cmd) && pointer_Command(cmd) == url) { | ||
81 | postCommandf_App("open url:%s", cstr_String(text_InputWidget(url))); | ||
82 | return iTrue; | ||
83 | } | ||
84 | } | ||
85 | else if (equal_Command(cmd, "document.changed")) { | ||
86 | iInputWidget *url = findWidget_App("url"); | ||
87 | setTextCStr_InputWidget(url, valuePtr_Command(cmd, "url")); | ||
88 | setTitle_Window(get_Window(), text_InputWidget(url)); | ||
89 | return iTrue; | ||
90 | } | ||
91 | return iFalse; | ||
92 | } | ||
93 | |||
73 | static void setupUserInterface_Window(iWindow *d) { | 94 | static void setupUserInterface_Window(iWindow *d) { |
74 | /* Children of root cover the entire window. */ | 95 | /* Children of root cover the entire window. */ |
75 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); | 96 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); |
@@ -87,12 +108,14 @@ static void setupUserInterface_Window(iWindow *d) { | |||
87 | arrangeHorizontal_WidgetFlag, | 108 | arrangeHorizontal_WidgetFlag, |
88 | iTrue); | 109 | iTrue); |
89 | addChild_Widget(div, iClob(navBar)); | 110 | addChild_Widget(div, iClob(navBar)); |
90 | setBackgroundColor_Widget(div, gray25_ColorId); | 111 | setCommandHandler_Widget(navBar, handleNavBarCommands_); |
112 | setBackgroundColor_Widget(navBar, gray25_ColorId); | ||
91 | 113 | ||
92 | addChild_Widget(navBar, iClob(new_LabelWidget("Back", 0, 0, "navigate.back"))); | 114 | addChild_Widget(navBar, iClob(new_LabelWidget("Back", 0, 0, "navigate.back"))); |
93 | addChild_Widget(navBar, iClob(new_LabelWidget("Fwd", 0, 0, "navigate.forward"))); | 115 | addChild_Widget(navBar, iClob(new_LabelWidget("Fwd", 0, 0, "navigate.forward"))); |
94 | addChild_Widget(navBar, iClob(new_LabelWidget("Home", 0, 0, "navigate.home"))); | 116 | addChild_Widget(navBar, iClob(new_LabelWidget("Home", 0, 0, "navigate.home"))); |
95 | iInputWidget *url = new_InputWidget(0); | 117 | iInputWidget *url = new_InputWidget(0); |
118 | setId_Widget(as_Widget(url), "url"); | ||
96 | setTextCStr_InputWidget(url, "gemini://"); | 119 | setTextCStr_InputWidget(url, "gemini://"); |
97 | addChildFlags_Widget(navBar, iClob(url), expand_WidgetFlag); | 120 | addChildFlags_Widget(navBar, iClob(url), expand_WidgetFlag); |
98 | } | 121 | } |
@@ -250,6 +273,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
250 | #endif | 273 | #endif |
251 | /* Glboal keyboard shortcuts. */ { | 274 | /* Glboal keyboard shortcuts. */ { |
252 | // addAction_Widget(d->root, SDLK_LEFTBRACKET, KMOD_SHIFT | KMOD_PRIMARY, "tabs.prev"); | 275 | // addAction_Widget(d->root, SDLK_LEFTBRACKET, KMOD_SHIFT | KMOD_PRIMARY, "tabs.prev"); |
276 | addAction_Widget(d->root, 'l', KMOD_PRIMARY, "setfocus id:url"); | ||
253 | } | 277 | } |
254 | } | 278 | } |
255 | 279 | ||
@@ -381,8 +405,13 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
381 | widget = mouseGrab_Widget(); | 405 | widget = mouseGrab_Widget(); |
382 | } | 406 | } |
383 | } | 407 | } |
384 | /* TODO: Auto-refresh when hover widget changes. */ | 408 | iWidget *oldHover = hover_Widget(); |
385 | return dispatchEvent_Widget(widget, &event); | 409 | /* Dispatch the event to the tree of widgets. */ |
410 | iBool wasUsed = dispatchEvent_Widget(widget, &event); | ||
411 | if (oldHover != hover_Widget()) { | ||
412 | postRefresh_App(); | ||
413 | } | ||
414 | return wasUsed; | ||
386 | } | 415 | } |
387 | } | 416 | } |
388 | return iFalse; | 417 | return iFalse; |
@@ -432,6 +461,10 @@ void resize_Window(iWindow *d, int w, int h) { | |||
432 | updateRootSize_Window_(d); | 461 | updateRootSize_Window_(d); |
433 | } | 462 | } |
434 | 463 | ||
464 | void setTitle_Window(iWindow *d, const iString *title) { | ||
465 | SDL_SetWindowTitle(d->win, cstr_String(title)); | ||
466 | } | ||
467 | |||
435 | void setUiScale_Window(iWindow *d, float uiScale) { | 468 | void setUiScale_Window(iWindow *d, float uiScale) { |
436 | uiScale = iClamp(uiScale, 0.5f, 4.0f); | 469 | uiScale = iClamp(uiScale, 0.5f, 4.0f); |
437 | if (d) { | 470 | if (d) { |
diff --git a/src/ui/window.h b/src/ui/window.h index d0413af4..70e52751 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -23,6 +23,7 @@ struct Impl_Window { | |||
23 | iBool processEvent_Window (iWindow *, const SDL_Event *); | 23 | iBool processEvent_Window (iWindow *, const SDL_Event *); |
24 | void draw_Window (iWindow *); | 24 | void draw_Window (iWindow *); |
25 | void resize_Window (iWindow *, int w, int h); | 25 | void resize_Window (iWindow *, int w, int h); |
26 | void setTitle_Window (iWindow *, const iString *title); | ||
26 | void setUiScale_Window (iWindow *, float uiScale); | 27 | void setUiScale_Window (iWindow *, float uiScale); |
27 | 28 | ||
28 | iInt2 rootSize_Window (const iWindow *); | 29 | iInt2 rootSize_Window (const iWindow *); |