diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-28 17:48:38 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-28 17:48:38 +0300 |
commit | 87b5dbd9c0393e787d2499d796486d3293f17214 (patch) | |
tree | 556f0b6b6a0188fdf9bd02275f796656ef428e86 /src | |
parent | 408597bd4f71a13a511b6af33601dff0be2ed317 (diff) |
Working on multiple UI roots
Root focus switching and opening links in the other root.
Diffstat (limited to 'src')
-rw-r--r-- | src/app.c | 27 | ||||
-rw-r--r-- | src/app.h | 1 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 15 | ||||
-rw-r--r-- | src/ui/keys.c | 9 | ||||
-rw-r--r-- | src/ui/lookupwidget.c | 3 | ||||
-rw-r--r-- | src/ui/root.c | 6 | ||||
-rw-r--r-- | src/ui/util.c | 4 | ||||
-rw-r--r-- | src/ui/util.h | 8 | ||||
-rw-r--r-- | src/ui/widget.c | 13 | ||||
-rw-r--r-- | src/ui/window.c | 64 | ||||
-rw-r--r-- | src/ui/window.h | 3 |
11 files changed, 117 insertions, 36 deletions
@@ -1306,7 +1306,7 @@ void postCommandf_App(const char *command, ...) { | |||
1306 | 1306 | ||
1307 | void rootOrder_App(iRoot *roots[2]) { | 1307 | void rootOrder_App(iRoot *roots[2]) { |
1308 | const iWindow *win = app_.window; | 1308 | const iWindow *win = app_.window; |
1309 | roots[0] = get_Root(); | 1309 | roots[0] = win->keyRoot; |
1310 | roots[1] = (roots[0] == win->roots[0] ? win->roots[1] : win->roots[0]); | 1310 | roots[1] = (roots[0] == win->roots[0] ? win->roots[1] : win->roots[0]); |
1311 | } | 1311 | } |
1312 | 1312 | ||
@@ -1535,7 +1535,7 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe | |||
1535 | } | 1535 | } |
1536 | arrange_Widget(tabs); | 1536 | arrange_Widget(tabs); |
1537 | refresh_Widget(tabs); | 1537 | refresh_Widget(tabs); |
1538 | postCommandf_App("tab.created id:%s", cstr_String(id_Widget(as_Widget(doc)))); | 1538 | postCommandf_Root(get_Root(), "tab.created id:%s", cstr_String(id_Widget(as_Widget(doc)))); |
1539 | return doc; | 1539 | return doc; |
1540 | } | 1540 | } |
1541 | 1541 | ||
@@ -1906,10 +1906,16 @@ iBool handleCommand_App(const char *cmd) { | |||
1906 | openInDefaultBrowser_App(url); | 1906 | openInDefaultBrowser_App(url); |
1907 | return iTrue; | 1907 | return iTrue; |
1908 | } | 1908 | } |
1909 | iDocumentWidget *doc = document_Command(cmd); | ||
1910 | const int newTab = argLabel_Command(cmd, "newtab"); | 1909 | const int newTab = argLabel_Command(cmd, "newtab"); |
1911 | if (newTab) { | 1910 | iRoot *root = get_Root(); |
1912 | doc = newTab_App(NULL, (newTab & 1) != 0); /* `newtab:2` to open in background */ | 1911 | iRoot *oldRoot = root; |
1912 | if (newTab & otherRoot_OpenTabFlag) { | ||
1913 | root = otherRoot_Window(d->window, root); | ||
1914 | setCurrent_Root(root); /* need to change for widget creation */ | ||
1915 | } | ||
1916 | iDocumentWidget *doc = document_Command(cmd); | ||
1917 | if (newTab & (new_OpenTabFlag | newBackground_OpenTabFlag)) { | ||
1918 | doc = newTab_App(NULL, (newTab & new_OpenTabFlag) != 0); /* `newtab:2` to open in background */ | ||
1913 | } | 1919 | } |
1914 | iHistory *history = history_DocumentWidget(doc); | 1920 | iHistory *history = history_DocumentWidget(doc); |
1915 | const iBool isHistory = argLabel_Command(cmd, "history") != 0; | 1921 | const iBool isHistory = argLabel_Command(cmd, "history") != 0; |
@@ -1936,14 +1942,15 @@ iBool handleCommand_App(const char *cmd) { | |||
1936 | is already available, e.g., it's from "about:" or restored from cache. */ | 1942 | is already available, e.g., it's from "about:" or restored from cache. */ |
1937 | const iRangecc gotoHeading = range_Command(cmd, "gotoheading"); | 1943 | const iRangecc gotoHeading = range_Command(cmd, "gotoheading"); |
1938 | if (gotoHeading.start) { | 1944 | if (gotoHeading.start) { |
1939 | postCommandf_App("document.goto heading:%s", cstr_Rangecc(gotoHeading)); | 1945 | postCommandf_Root(root, "document.goto heading:%s", cstr_Rangecc(gotoHeading)); |
1940 | } | 1946 | } |
1941 | const iRangecc gotoUrlHeading = range_Command(cmd, "gotourlheading"); | 1947 | const iRangecc gotoUrlHeading = range_Command(cmd, "gotourlheading"); |
1942 | if (gotoUrlHeading.start) { | 1948 | if (gotoUrlHeading.start) { |
1943 | postCommandf_App("document.goto heading:%s", | 1949 | postCommandf_Root(root, "document.goto heading:%s", |
1944 | cstrCollect_String(urlDecode_String( | 1950 | cstrCollect_String(urlDecode_String( |
1945 | collect_String(newRange_String(gotoUrlHeading))))); | 1951 | collect_String(newRange_String(gotoUrlHeading))))); |
1946 | } | 1952 | } |
1953 | setCurrent_Root(oldRoot); | ||
1947 | } | 1954 | } |
1948 | else if (equal_Command(cmd, "document.request.cancelled")) { | 1955 | else if (equal_Command(cmd, "document.request.cancelled")) { |
1949 | /* TODO: How should cancelled requests be treated in the history? */ | 1956 | /* TODO: How should cancelled requests be treated in the history? */ |
@@ -2016,6 +2023,12 @@ iBool handleCommand_App(const char *cmd) { | |||
2016 | } | 2023 | } |
2017 | return iTrue; | 2024 | return iTrue; |
2018 | } | 2025 | } |
2026 | else if (equal_Command(cmd, "keyroot.next")) { | ||
2027 | if (setKeyRoot_Window(d->window, otherRoot_Window(d->window, d->window->keyRoot))) { | ||
2028 | setFocus_Widget(NULL); | ||
2029 | } | ||
2030 | return iTrue; | ||
2031 | } | ||
2019 | else if (equal_Command(cmd, "quit")) { | 2032 | else if (equal_Command(cmd, "quit")) { |
2020 | SDL_Event ev; | 2033 | SDL_Event ev; |
2021 | ev.type = SDL_QUIT; | 2034 | ev.type = SDL_QUIT; |
@@ -71,6 +71,7 @@ const iString *downloadDir_App (void); | |||
71 | const iString *debugInfo_App (void); | 71 | const iString *debugInfo_App (void); |
72 | 72 | ||
73 | int run_App (int argc, char **argv); | 73 | int run_App (int argc, char **argv); |
74 | void rootOrder_App (iRoot *roots[2]); /* TODO: max roots? */ | ||
74 | void processEvents_App (enum iAppEventMode mode); | 75 | void processEvents_App (enum iAppEventMode mode); |
75 | iBool handleCommand_App (const char *cmd); | 76 | iBool handleCommand_App (const char *cmd); |
76 | void refresh_App (void); | 77 | void refresh_App (void); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 2f20958f..1d6c340c 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -845,7 +845,8 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
845 | } | 845 | } |
846 | 846 | ||
847 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | 847 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { |
848 | iLabelWidget *tabButton = tabPageButton_Widget(findWidget_App("doctabs"), d); | 848 | iLabelWidget *tabButton = tabPageButton_Widget(findChild_Widget(root_Widget(constAs_Widget(d)), |
849 | "doctabs"), d); | ||
849 | if (!tabButton) { | 850 | if (!tabButton) { |
850 | /* Not part of the UI at the moment. */ | 851 | /* Not part of the UI at the moment. */ |
851 | return; | 852 | return; |
@@ -2868,8 +2869,16 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2868 | { openTabBg_Icon " ${link.newtab.background}", | 2869 | { openTabBg_Icon " ${link.newtab.background}", |
2869 | 0, | 2870 | 0, |
2870 | 0, | 2871 | 0, |
2871 | format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) } }, | 2872 | format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) }, |
2872 | 2); | 2873 | { "${link.side}", |
2874 | 0, | ||
2875 | 0, | ||
2876 | format_CStr("!open newtab:4 url:%s", cstr_String(linkUrl)) }, | ||
2877 | { "${link.side.newtab}", | ||
2878 | 0, | ||
2879 | 0, | ||
2880 | format_CStr("!open newtab:5 url:%s", cstr_String(linkUrl)) } }, | ||
2881 | 4); | ||
2873 | } | 2882 | } |
2874 | else if (!willUseProxy_App(scheme)) { | 2883 | else if (!willUseProxy_App(scheme)) { |
2875 | pushBack_Array( | 2884 | pushBack_Array( |
diff --git a/src/ui/keys.c b/src/ui/keys.c index 6ad9d360..68319598 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c | |||
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
22 | 22 | ||
23 | #include "keys.h" | 23 | #include "keys.h" |
24 | #include "util.h" | 24 | #include "util.h" |
25 | #include "window.h" | ||
25 | #include "app.h" | 26 | #include "app.h" |
26 | 27 | ||
27 | #include <the_Foundation/file.h> | 28 | #include <the_Foundation/file.h> |
@@ -223,6 +224,7 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] = | |||
223 | { 77, { "${keys.tab.close}", closeTab_KeyShortcut, "tabs.close" }, 0 }, | 224 | { 77, { "${keys.tab.close}", closeTab_KeyShortcut, "tabs.close" }, 0 }, |
224 | { 80, { "${keys.tab.prev}", prevTab_KeyShortcut, "tabs.prev" }, 0 }, | 225 | { 80, { "${keys.tab.prev}", prevTab_KeyShortcut, "tabs.prev" }, 0 }, |
225 | { 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 }, | 226 | { 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 }, |
227 | { 91, { "${keys.frame.next}", SDLK_TAB, KMOD_CTRL, "keyroot.next", }, 0 }, | ||
226 | { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, | 228 | { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, |
227 | /* The following cannot currently be changed (built-in duplicates). */ | 229 | /* The following cannot currently be changed (built-in duplicates). */ |
228 | #if defined (iPlatformApple) | 230 | #if defined (iPlatformApple) |
@@ -424,21 +426,22 @@ void setLabel_Keys(int id, const char *label) { | |||
424 | 426 | ||
425 | iBool processEvent_Keys(const SDL_Event *ev) { | 427 | iBool processEvent_Keys(const SDL_Event *ev) { |
426 | iKeys *d = &keys_; | 428 | iKeys *d = &keys_; |
429 | iRoot *root = get_Window()->keyRoot; | ||
427 | if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { | 430 | if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { |
428 | const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod)); | 431 | const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod)); |
429 | if (bind) { | 432 | if (bind) { |
430 | if (ev->type == SDL_KEYUP) { | 433 | if (ev->type == SDL_KEYUP) { |
431 | if (bind->flags & argRelease_BindFlag) { | 434 | if (bind->flags & argRelease_BindFlag) { |
432 | postCommandf_App("%s release:1", cstr_String(&bind->command)); | 435 | postCommandf_Root(root, "%s release:1", cstr_String(&bind->command)); |
433 | return iTrue; | 436 | return iTrue; |
434 | } | 437 | } |
435 | return iFalse; | 438 | return iFalse; |
436 | } | 439 | } |
437 | if (ev->key.repeat && (bind->flags & argRepeat_BindFlag)) { | 440 | if (ev->key.repeat && (bind->flags & argRepeat_BindFlag)) { |
438 | postCommandf_App("%s repeat:1", cstr_String(&bind->command)); | 441 | postCommandf_Root(root, "%s repeat:1", cstr_String(&bind->command)); |
439 | } | 442 | } |
440 | else { | 443 | else { |
441 | postCommandString_Root(NULL, &bind->command); | 444 | postCommandString_Root(root, &bind->command); |
442 | } | 445 | } |
443 | return iTrue; | 446 | return iTrue; |
444 | } | 447 | } |
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index e0de97bf..b3e88ce8 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c | |||
@@ -742,7 +742,8 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | |||
742 | return iTrue; | 742 | return iTrue; |
743 | } | 743 | } |
744 | } | 744 | } |
745 | if (key == SDLK_DOWN && !mods && focus_Widget() == findWidget_App("url") && | 745 | if (isVisible_Widget(w) && |
746 | key == SDLK_DOWN && !mods && focus_Widget() == findWidget_App("url") && | ||
746 | numItems_ListWidget(d->list)) { | 747 | numItems_ListWidget(d->list)) { |
747 | setCursor_LookupWidget_(d, 1); /* item 0 is always the first heading */ | 748 | setCursor_LookupWidget_(d, 1); /* item 0 is always the first heading */ |
748 | setFocus_Widget(w); | 749 | setFocus_Widget(w); |
diff --git a/src/ui/root.c b/src/ui/root.c index 8faeb215..aec5f26f 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -716,14 +716,14 @@ static iBool handleSearchBarCommands_(iWidget *searchBar, const char *cmd) { | |||
716 | equal_Rangecc(range_Command(cmd, "id"), "find.input")) { | 716 | equal_Rangecc(range_Command(cmd, "id"), "find.input")) { |
717 | iInputWidget *input = findChild_Widget(searchBar, "find.input"); | 717 | iInputWidget *input = findChild_Widget(searchBar, "find.input"); |
718 | if (arg_Command(cmd) && argLabel_Command(cmd, "enter") && isVisible_Widget(input)) { | 718 | if (arg_Command(cmd) && argLabel_Command(cmd, "enter") && isVisible_Widget(input)) { |
719 | postCommand_App("find.next"); | 719 | postCommand_Root(searchBar->root, "find.next"); |
720 | /* Keep focus when pressing Enter. */ | 720 | /* Keep focus when pressing Enter. */ |
721 | if (!isEmpty_String(text_InputWidget(input))) { | 721 | if (!isEmpty_String(text_InputWidget(input))) { |
722 | postCommand_App("focus.set id:find.input"); | 722 | postCommand_Root(searchBar->root, "focus.set id:find.input"); |
723 | } | 723 | } |
724 | } | 724 | } |
725 | else { | 725 | else { |
726 | postCommand_App("find.clearmark"); | 726 | postCommand_Root(searchBar->root, "find.clearmark"); |
727 | } | 727 | } |
728 | return iTrue; | 728 | return iTrue; |
729 | } | 729 | } |
diff --git a/src/ui/util.c b/src/ui/util.c index b487e13d..9a023ab9 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -171,7 +171,9 @@ int keyMods_Sym(int kmods) { | |||
171 | 171 | ||
172 | int openTabMode_Sym(int kmods) { | 172 | int openTabMode_Sym(int kmods) { |
173 | const int km = keyMods_Sym(kmods); | 173 | const int km = keyMods_Sym(kmods); |
174 | return ((km & KMOD_PRIMARY) && (km & KMOD_SHIFT)) ? 1 : (km & KMOD_PRIMARY) ? 2 : 0; | 174 | return (km & KMOD_ALT ? otherRoot_OpenTabFlag : 0) | /* open to the side */ |
175 | (((km & KMOD_PRIMARY) && (km & KMOD_SHIFT)) ? new_OpenTabFlag : | ||
176 | (km & KMOD_PRIMARY) ? newBackground_OpenTabFlag : 0); | ||
175 | } | 177 | } |
176 | 178 | ||
177 | iRangei intersect_Rangei(iRangei a, iRangei b) { | 179 | iRangei intersect_Rangei(iRangei a, iRangei b) { |
diff --git a/src/ui/util.h b/src/ui/util.h index b8d10cf0..8dd16a7f 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -64,11 +64,17 @@ iLocalDef iBool isPerPixel_MouseWheelEvent(const SDL_MouseWheelEvent *ev) { | |||
64 | # define KMOD_SECONDARY KMOD_GUI | 64 | # define KMOD_SECONDARY KMOD_GUI |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | enum iOpenTabFlag { | ||
68 | new_OpenTabFlag = iBit(1), | ||
69 | newBackground_OpenTabFlag = iBit(2), | ||
70 | otherRoot_OpenTabFlag = iBit(3), | ||
71 | }; | ||
72 | |||
67 | iBool isMod_Sym (int key); | 73 | iBool isMod_Sym (int key); |
68 | int normalizedMod_Sym (int key); | 74 | int normalizedMod_Sym (int key); |
69 | int keyMods_Sym (int kmods); /* shift, alt, control, or gui */ | 75 | int keyMods_Sym (int kmods); /* shift, alt, control, or gui */ |
70 | void toString_Sym (int key, int kmods, iString *str); | 76 | void toString_Sym (int key, int kmods, iString *str); |
71 | int openTabMode_Sym (int kmods); | 77 | int openTabMode_Sym (int kmods); /* returns OpenTabFlags */ |
72 | 78 | ||
73 | iRangei intersect_Rangei (iRangei a, iRangei b); | 79 | iRangei intersect_Rangei (iRangei a, iRangei b); |
74 | iRangei union_Rangei (iRangei a, iRangei b); | 80 | iRangei union_Rangei (iRangei a, iRangei b); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 6d6bc202..bb71df7c 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -1346,6 +1346,7 @@ void setFocus_Widget(iWidget *d) { | |||
1346 | win->focus = d; | 1346 | win->focus = d; |
1347 | if (d) { | 1347 | if (d) { |
1348 | iAssert(flags_Widget(d) & focusable_WidgetFlag); | 1348 | iAssert(flags_Widget(d) & focusable_WidgetFlag); |
1349 | setKeyRoot_Window(get_Window(), d->root); | ||
1349 | postCommand_Widget(d, "focus.gained"); | 1350 | postCommand_Widget(d, "focus.gained"); |
1350 | } | 1351 | } |
1351 | } | 1352 | } |
@@ -1404,13 +1405,17 @@ static const iWidget *findFocusRoot_Widget_(const iWidget *d) { | |||
1404 | } | 1405 | } |
1405 | 1406 | ||
1406 | iAny *findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir) { | 1407 | iAny *findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir) { |
1407 | const iWidget *root = findFocusRoot_Widget_(get_Root()->widget); | 1408 | iRoot *uiRoot = (startFrom ? startFrom->root : get_Window()->keyRoot); |
1408 | iAssert(root != NULL); | 1409 | const iWidget *focusRoot = findFocusRoot_Widget_(uiRoot->widget); |
1410 | iAssert(focusRoot != NULL); | ||
1409 | iBool getNext = (startFrom ? iFalse : iTrue); | 1411 | iBool getNext = (startFrom ? iFalse : iTrue); |
1410 | const iWidget *found = findFocusable_Widget_(root, startFrom, &getNext, focusDir); | 1412 | const iWidget *found = findFocusable_Widget_(focusRoot, startFrom, &getNext, focusDir); |
1411 | if (!found && startFrom) { | 1413 | if (!found && startFrom) { |
1412 | getNext = iTrue; | 1414 | getNext = iTrue; |
1413 | found = findFocusable_Widget_(root, NULL, &getNext, focusDir); | 1415 | /* Switch to the next root, if available. */ |
1416 | found = findFocusable_Widget_(findFocusRoot_Widget_(otherRoot_Window(get_Window(), | ||
1417 | uiRoot)->widget), | ||
1418 | NULL, &getNext, focusDir); | ||
1414 | } | 1419 | } |
1415 | return iConstCast(iWidget *, found); | 1420 | return iConstCast(iWidget *, found); |
1416 | } | 1421 | } |
diff --git a/src/ui/window.c b/src/ui/window.c index 78ea182c..54f05a20 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -179,21 +179,22 @@ static void setupUserInterface_Window(iWindow *d) { | |||
179 | createUserInterface_Root(d->roots[i]); | 179 | createUserInterface_Root(d->roots[i]); |
180 | setCurrent_Root(NULL); | 180 | setCurrent_Root(NULL); |
181 | } | 181 | } |
182 | /* One of the roots always has keyboard input focus. */ | ||
183 | d->keyRoot = d->roots[0]; | ||
182 | } | 184 | } |
183 | 185 | ||
184 | static void windowSizeChanged_Window_(iWindow *d) { | 186 | static void windowSizeChanged_Window_(iWindow *d) { |
185 | const int numRoots = numRoots_Window(d); | 187 | const int numRoots = numRoots_Window(d); |
186 | /* Horizontal split frame. */ | 188 | /* Horizontal split frame. */ |
187 | const iInt2 rootSize = div_I2(d->size, init_I2(numRoots, 1)); | 189 | const iInt2 rootSize = d->size; |
188 | iForIndices(i, d->roots) { | 190 | iForIndices(i, d->roots) { |
189 | iRoot *root = d->roots[i]; | 191 | iRoot *root = d->roots[i]; |
190 | if (root) { | 192 | if (root) { |
191 | root->widget->rect.pos = init_I2(rootSize.x * i, 0); | 193 | iRect *rect = &root->widget->rect; |
192 | root->widget->rect.size = addX_I2(rootSize, -gap_UI / 4); | 194 | /* Horizontal split frame. */ |
193 | if (i == 1) { | 195 | rect->pos = init_I2(rootSize.x * i / numRoots, 0); |
194 | root->widget->rect.pos.x += gap_UI / 8; | 196 | rect->size = init_I2(rootSize.x * (i + 1) / numRoots - rect->pos.x, rootSize.y); |
195 | } | 197 | root->widget->minSize = rect->size; |
196 | root->widget->minSize = root->widget->rect.size; | ||
197 | updatePadding_Root(root); | 198 | updatePadding_Root(root); |
198 | arrange_Widget(root->widget); | 199 | arrange_Widget(root->widget); |
199 | } | 200 | } |
@@ -530,6 +531,10 @@ iRoot *findRoot_Window(const iWindow *d, const iWidget *widget) { | |||
530 | return NULL; | 531 | return NULL; |
531 | } | 532 | } |
532 | 533 | ||
534 | iRoot *otherRoot_Window(const iWindow *d, iRoot *root) { | ||
535 | return root == d->roots[0] && d->roots[1] ? d->roots[1] : d->roots[0]; | ||
536 | } | ||
537 | |||
533 | static void invalidate_Window_(iWindow *d) { | 538 | static void invalidate_Window_(iWindow *d) { |
534 | iUnused(d); | 539 | iUnused(d); |
535 | resetFonts_Text(); | 540 | resetFonts_Text(); |
@@ -881,19 +886,35 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
881 | return iFalse; | 886 | return iFalse; |
882 | } | 887 | } |
883 | 888 | ||
889 | iBool setKeyRoot_Window(iWindow *d, iRoot *root) { | ||
890 | if (d->keyRoot != root) { | ||
891 | d->keyRoot = root; | ||
892 | postRefresh_App(); | ||
893 | return iTrue; | ||
894 | } | ||
895 | return iFalse; | ||
896 | } | ||
897 | |||
884 | iBool dispatchEvent_Window(iWindow *d, const SDL_Event *ev) { | 898 | iBool dispatchEvent_Window(iWindow *d, const SDL_Event *ev) { |
885 | if (ev->type == SDL_MOUSEMOTION) { | 899 | if (ev->type == SDL_MOUSEMOTION) { |
886 | /* Hover widget may change. */ | 900 | /* Hover widget may change. */ |
887 | setHover_Widget(NULL); | 901 | setHover_Widget(NULL); |
888 | } | 902 | } |
889 | iForIndices(i, d->roots) { | 903 | iRoot *order[2]; |
890 | if (d->roots[i]) { | 904 | rootOrder_App(order); |
891 | if (isCommand_SDLEvent(ev) && ev->user.data2 && ev->user.data2 != d->roots[i]) { | 905 | iForIndices(i, order) { |
906 | iRoot *root = order[i]; | ||
907 | if (root) { | ||
908 | if (isCommand_SDLEvent(ev) && ev->user.data2 && ev->user.data2 != root) { | ||
892 | continue; /* Not meant for this root. */ | 909 | continue; /* Not meant for this root. */ |
893 | } | 910 | } |
894 | setCurrent_Root(d->roots[i]); | 911 | setCurrent_Root(root); |
895 | const iBool wasUsed = dispatchEvent_Widget(d->roots[i]->widget, ev); | 912 | const iBool wasUsed = dispatchEvent_Widget(root->widget, ev); |
896 | if (wasUsed) { | 913 | if (wasUsed) { |
914 | if (ev->type == SDL_MOUSEBUTTONDOWN || | ||
915 | ev->type == SDL_MOUSEWHEEL) { | ||
916 | setKeyRoot_Window(d, root); | ||
917 | } | ||
897 | return iTrue; | 918 | return iTrue; |
898 | } | 919 | } |
899 | } | 920 | } |
@@ -982,7 +1003,24 @@ void draw_Window(iWindow *d) { | |||
982 | NULL, | 1003 | NULL, |
983 | &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size }); | 1004 | &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size }); |
984 | } | 1005 | } |
985 | #endif | 1006 | #endif |
1007 | /* Root separator and keyboard focus indicator. */ { | ||
1008 | iPaint p; | ||
1009 | init_Paint(&p); | ||
1010 | const iRect bounds = bounds_Widget(root->widget); | ||
1011 | if (i == 1) { | ||
1012 | fillRect_Paint(&p, (iRect){ | ||
1013 | addX_I2(topLeft_Rect(bounds), -gap_UI / 8), | ||
1014 | init_I2(gap_UI / 4, height_Rect(bounds)) | ||
1015 | }, uiSeparator_ColorId); | ||
1016 | } | ||
1017 | if (root == d->keyRoot) { | ||
1018 | fillRect_Paint(&p, (iRect){ | ||
1019 | topLeft_Rect(bounds), | ||
1020 | init_I2(width_Rect(bounds), gap_UI / 2) | ||
1021 | }, uiBackgroundSelected_ColorId); | ||
1022 | } | ||
1023 | } | ||
986 | } | 1024 | } |
987 | } | 1025 | } |
988 | setCurrent_Root(NULL); | 1026 | setCurrent_Root(NULL); |
diff --git a/src/ui/window.h b/src/ui/window.h index de0133b1..b2b22e90 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -68,6 +68,7 @@ struct Impl_Window { | |||
68 | SDL_Renderer *render; | 68 | SDL_Renderer *render; |
69 | iInt2 size; | 69 | iInt2 size; |
70 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ | 70 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ |
71 | iRoot * keyRoot; /* root that has the current keyboard input focus */ | ||
71 | iWidget * hover; | 72 | iWidget * hover; |
72 | iWidget * mouseGrab; | 73 | iWidget * mouseGrab; |
73 | iWidget * focus; | 74 | iWidget * focus; |
@@ -93,6 +94,7 @@ void resize_Window (iWindow *, int w, int h); | |||
93 | void setTitle_Window (iWindow *, const iString *title); | 94 | void setTitle_Window (iWindow *, const iString *title); |
94 | void setUiScale_Window (iWindow *, float uiScale); | 95 | void setUiScale_Window (iWindow *, float uiScale); |
95 | void setFreezeDraw_Window (iWindow *, iBool freezeDraw); | 96 | void setFreezeDraw_Window (iWindow *, iBool freezeDraw); |
97 | iBool setKeyRoot_Window (iWindow *, iRoot *root); | ||
96 | void setCursor_Window (iWindow *, int cursor); | 98 | void setCursor_Window (iWindow *, int cursor); |
97 | void setSnap_Window (iWindow *, int snapMode); | 99 | void setSnap_Window (iWindow *, int snapMode); |
98 | void setKeyboardHeight_Window(iWindow *, int height); | 100 | void setKeyboardHeight_Window(iWindow *, int height); |
@@ -111,6 +113,7 @@ SDL_Renderer *renderer_Window (const iWindow *); | |||
111 | int snap_Window (const iWindow *); | 113 | int snap_Window (const iWindow *); |
112 | iBool isFullscreen_Window (const iWindow *); | 114 | iBool isFullscreen_Window (const iWindow *); |
113 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); | 115 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); |
116 | iRoot * otherRoot_Window (const iWindow *, iRoot *root); | ||
114 | 117 | ||
115 | iWindow * get_Window (void); | 118 | iWindow * get_Window (void); |
116 | 119 | ||