summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-04-28 17:48:38 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-04-28 17:48:38 +0300
commit87b5dbd9c0393e787d2499d796486d3293f17214 (patch)
tree556f0b6b6a0188fdf9bd02275f796656ef428e86 /src/ui
parent408597bd4f71a13a511b6af33601dff0be2ed317 (diff)
Working on multiple UI roots
Root focus switching and opening links in the other root.
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c15
-rw-r--r--src/ui/keys.c9
-rw-r--r--src/ui/lookupwidget.c3
-rw-r--r--src/ui/root.c6
-rw-r--r--src/ui/util.c4
-rw-r--r--src/ui/util.h8
-rw-r--r--src/ui/widget.c13
-rw-r--r--src/ui/window.c64
-rw-r--r--src/ui/window.h3
9 files changed, 96 insertions, 29 deletions
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
847static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { 847static 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
425iBool processEvent_Keys(const SDL_Event *ev) { 427iBool 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
172int openTabMode_Sym(int kmods) { 172int 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
177iRangei intersect_Rangei(iRangei a, iRangei b) { 179iRangei 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
67enum iOpenTabFlag {
68 new_OpenTabFlag = iBit(1),
69 newBackground_OpenTabFlag = iBit(2),
70 otherRoot_OpenTabFlag = iBit(3),
71};
72
67iBool isMod_Sym (int key); 73iBool isMod_Sym (int key);
68int normalizedMod_Sym (int key); 74int normalizedMod_Sym (int key);
69int keyMods_Sym (int kmods); /* shift, alt, control, or gui */ 75int keyMods_Sym (int kmods); /* shift, alt, control, or gui */
70void toString_Sym (int key, int kmods, iString *str); 76void toString_Sym (int key, int kmods, iString *str);
71int openTabMode_Sym (int kmods); 77int openTabMode_Sym (int kmods); /* returns OpenTabFlags */
72 78
73iRangei intersect_Rangei (iRangei a, iRangei b); 79iRangei intersect_Rangei (iRangei a, iRangei b);
74iRangei union_Rangei (iRangei a, iRangei b); 80iRangei 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
1406iAny *findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir) { 1407iAny *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
184static void windowSizeChanged_Window_(iWindow *d) { 186static 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
534iRoot *otherRoot_Window(const iWindow *d, iRoot *root) {
535 return root == d->roots[0] && d->roots[1] ? d->roots[1] : d->roots[0];
536}
537
533static void invalidate_Window_(iWindow *d) { 538static 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
889iBool 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
884iBool dispatchEvent_Window(iWindow *d, const SDL_Event *ev) { 898iBool 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);
93void setTitle_Window (iWindow *, const iString *title); 94void setTitle_Window (iWindow *, const iString *title);
94void setUiScale_Window (iWindow *, float uiScale); 95void setUiScale_Window (iWindow *, float uiScale);
95void setFreezeDraw_Window (iWindow *, iBool freezeDraw); 96void setFreezeDraw_Window (iWindow *, iBool freezeDraw);
97iBool setKeyRoot_Window (iWindow *, iRoot *root);
96void setCursor_Window (iWindow *, int cursor); 98void setCursor_Window (iWindow *, int cursor);
97void setSnap_Window (iWindow *, int snapMode); 99void setSnap_Window (iWindow *, int snapMode);
98void setKeyboardHeight_Window(iWindow *, int height); 100void setKeyboardHeight_Window(iWindow *, int height);
@@ -111,6 +113,7 @@ SDL_Renderer *renderer_Window (const iWindow *);
111int snap_Window (const iWindow *); 113int snap_Window (const iWindow *);
112iBool isFullscreen_Window (const iWindow *); 114iBool isFullscreen_Window (const iWindow *);
113iRoot * findRoot_Window (const iWindow *, const iWidget *widget); 115iRoot * findRoot_Window (const iWindow *, const iWidget *widget);
116iRoot * otherRoot_Window (const iWindow *, iRoot *root);
114 117
115iWindow * get_Window (void); 118iWindow * get_Window (void);
116 119