summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.c41
-rw-r--r--src/ui/documentwidget.c5
-rw-r--r--src/ui/root.c22
-rw-r--r--src/ui/util.c8
-rw-r--r--src/ui/util.h1
-rw-r--r--src/ui/widget.c10
-rw-r--r--src/ui/widget.h2
-rw-r--r--src/ui/window.c91
-rw-r--r--src/ui/window.h15
9 files changed, 170 insertions, 25 deletions
diff --git a/src/app.c b/src/app.c
index 2f1e435b..29d8cac4 100644
--- a/src/app.c
+++ b/src/app.c
@@ -406,7 +406,10 @@ static iBool loadState_App_(iApp *d) {
406 readData_File(f, 4, magic); 406 readData_File(f, 4, magic);
407 if (!memcmp(magic, magicTabDocument_App_, 4)) { 407 if (!memcmp(magic, magicTabDocument_App_, 4)) {
408 const int8_t flags = read8_File(f); 408 const int8_t flags = read8_File(f);
409 const int rootIndex = flags & rootIndex1_DocumentStateFlag ? 1 : 0; 409 int rootIndex = flags & rootIndex1_DocumentStateFlag ? 1 : 0;
410 if (rootIndex > numRoots_Window(d->window) - 1) {
411 rootIndex = 0;
412 }
410 setCurrent_Root(d->window->roots[rootIndex]); 413 setCurrent_Root(d->window->roots[rootIndex]);
411 if (isFirstTab[rootIndex]) { 414 if (isFirstTab[rootIndex]) {
412 isFirstTab[rootIndex] = iFalse; 415 isFirstTab[rootIndex] = iFalse;
@@ -1148,9 +1151,12 @@ static int run_App_(iApp *d) {
1148 while (d->isRunning) { 1151 while (d->isRunning) {
1149 dispatchCommands_Periodic(&d->periodic); 1152 dispatchCommands_Periodic(&d->periodic);
1150 processEvents_App(waitForNewEvents_AppEventMode); 1153 processEvents_App(waitForNewEvents_AppEventMode);
1151 setCurrent_Root(NULL);
1152 runTickers_App_(d); 1154 runTickers_App_(d);
1153 refresh_App(); 1155 refresh_App();
1156 /* Change the widget tree while we are not iterating through it. */
1157 if (d->window->splitMode != d->window->pendingSplitMode) {
1158 setSplitMode_Window(d->window, d->window->pendingSplitMode);
1159 }
1154 recycle_Garbage(); 1160 recycle_Garbage();
1155 } 1161 }
1156 SDL_DelEventWatch(resizeWatcher_, d); 1162 SDL_DelEventWatch(resizeWatcher_, d);
@@ -1654,6 +1660,15 @@ iBool handleCommand_App(const char *cmd) {
1654 d->prefs.langTo = argLabel_Command(cmd, "to"); 1660 d->prefs.langTo = argLabel_Command(cmd, "to");
1655 return iTrue; 1661 return iTrue;
1656 } 1662 }
1663 else if (equal_Command(cmd, "ui.frames")) {
1664 d->window->pendingSplitMode =
1665 (argLabel_Command(cmd, "axis") ? vertical_WindowSplit : 0) | (arg_Command(cmd) << 1);
1666 return iTrue;
1667 }
1668// else if (equal_Command(cmd, "window.updatelayout")) {
1669// resize_Window(d->window, -1, -1);
1670// return iTrue;
1671// }
1657 else if (equal_Command(cmd, "window.retain")) { 1672 else if (equal_Command(cmd, "window.retain")) {
1658 d->prefs.retainWindowSize = arg_Command(cmd); 1673 d->prefs.retainWindowSize = arg_Command(cmd);
1659 return iTrue; 1674 return iTrue;
@@ -2009,15 +2024,22 @@ iBool handleCommand_App(const char *cmd) {
2009 arrange_Widget(tabs); 2024 arrange_Widget(tabs);
2010 return iTrue; 2025 return iTrue;
2011 } 2026 }
2012 if (tabCount_Widget(tabs) > 1) { 2027 const iBool isSplit = numRoots_Window(get_Window()) > 1;
2028 if (tabCount_Widget(tabs) > 1 || isSplit) {
2013 iWidget *closed = removeTabPage_Widget(tabs, index); 2029 iWidget *closed = removeTabPage_Widget(tabs, index);
2014 destroy_Widget(closed); /* released later */ 2030 destroy_Widget(closed); /* released later */
2015 if (index == tabCount_Widget(tabs)) { 2031 if (index == tabCount_Widget(tabs)) {
2016 index--; 2032 index--;
2017 } 2033 }
2018 arrange_Widget(tabs); 2034 if (tabCount_Widget(tabs) == 0) {
2019 if (wasCurrent) { 2035 iAssert(isSplit);
2020 postCommandf_App("tabs.switch page:%p", tabPage_Widget(tabs, index)); 2036 postCommand_App("ui.frames arg:0");
2037 }
2038 else {
2039 arrange_Widget(tabs);
2040 if (wasCurrent) {
2041 postCommandf_App("tabs.switch page:%p", tabPage_Widget(tabs, index));
2042 }
2021 } 2043 }
2022 } 2044 }
2023 else { 2045 else {
@@ -2113,7 +2135,7 @@ iBool handleCommand_App(const char *cmd) {
2113 const iPtrArray *homepages = 2135 const iPtrArray *homepages =
2114 list_Bookmarks(d->bookmarks, NULL, filterTagsRegExp_Bookmarks, pattern); 2136 list_Bookmarks(d->bookmarks, NULL, filterTagsRegExp_Bookmarks, pattern);
2115 if (isEmpty_PtrArray(homepages)) { 2137 if (isEmpty_PtrArray(homepages)) {
2116 postCommand_App("open url:about:lagrange"); 2138 postCommand_Root(get_Root(), "open url:about:lagrange");
2117 } 2139 }
2118 else { 2140 else {
2119 iStringSet *urls = iClob(new_StringSet()); 2141 iStringSet *urls = iClob(new_StringSet());
@@ -2125,13 +2147,13 @@ iBool handleCommand_App(const char *cmd) {
2125 } 2147 }
2126 } 2148 }
2127 if (!isEmpty_StringSet(urls)) { 2149 if (!isEmpty_StringSet(urls)) {
2128 postCommandf_App( 2150 postCommandf_Root(get_Root(),
2129 "open url:%s", 2151 "open url:%s",
2130 cstr_String(constAt_StringSet(urls, iRandoms(0, size_StringSet(urls))))); 2152 cstr_String(constAt_StringSet(urls, iRandoms(0, size_StringSet(urls)))));
2131 } 2153 }
2132 } 2154 }
2133 if (argLabel_Command(cmd, "focus")) { 2155 if (argLabel_Command(cmd, "focus")) {
2134 postCommand_App("navigate.focus"); 2156 postCommand_Root(get_Root(), "navigate.focus");
2135 } 2157 }
2136 return iTrue; 2158 return iTrue;
2137 } 2159 }
@@ -2335,6 +2357,7 @@ iObjectList *listDocuments_App(const iRoot *rootOrNull) {
2335 iObjectList *docs = new_ObjectList(); 2357 iObjectList *docs = new_ObjectList();
2336 iForIndices(i, win->roots) { 2358 iForIndices(i, win->roots) {
2337 iRoot *root = win->roots[i]; 2359 iRoot *root = win->roots[i];
2360 if (!root) continue;
2338 if (!rootOrNull || root == rootOrNull) { 2361 if (!rootOrNull || root == rootOrNull) {
2339 const iWidget *tabs = findChild_Widget(root->widget, "doctabs"); 2362 const iWidget *tabs = findChild_Widget(root->widget, "doctabs");
2340 iForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) { 2363 iForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) {
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 21c0aa23..410b793e 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -3969,6 +3969,11 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
3969} 3969}
3970 3970
3971static void prerender_DocumentWidget_(iAny *context) { 3971static void prerender_DocumentWidget_(iAny *context) {
3972 if (current_Root() == NULL) {
3973 /* The widget has probably been removed from the widget tree, pending destruction.
3974 Tickers are not cancelled until the widget is actually destroyed. */
3975 return;
3976 }
3972 const iDocumentWidget *d = context; 3977 const iDocumentWidget *d = context;
3973 iDrawContext ctx = { 3978 iDrawContext ctx = {
3974 .widget = d, 3979 .widget = d,
diff --git a/src/ui/root.c b/src/ui/root.c
index 247faf38..2eca982c 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -304,6 +304,12 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) {
304 } 304 }
305 return iTrue; 305 return iTrue;
306 } 306 }
307 else if (equal_Command(cmd, "splitmenu.open")) {
308 iWidget *menu = findWidget_Root("splitmenu");
309 openMenu_Widget(menu, zero_I2());
310 setPos_Widget(menu, sub_I2(divi_I2(size_Root(get_Root()), 2), divi_I2(menu->rect.size, 2)));
311 return iTrue;
312 }
307 else if (equal_Command(cmd, "contextclick")) { 313 else if (equal_Command(cmd, "contextclick")) {
308 iBool showBarMenu = iFalse; 314 iBool showBarMenu = iFalse;
309 if (equal_Rangecc(range_Command(cmd, "id"), "buttons")) { 315 if (equal_Rangecc(range_Command(cmd, "id"), "buttons")) {
@@ -879,7 +885,7 @@ void updateMetrics_Root(iRoot *d) {
879} 885}
880 886
881void createUserInterface_Root(iRoot *d) { 887void createUserInterface_Root(iRoot *d) {
882 iWidget *root = d->widget = new_Widget(); 888 iWidget *root = d->widget = new_Widget();
883 iAssert(root->root == d); 889 iAssert(root->root == d);
884 setId_Widget(root, "root"); 890 setId_Widget(root, "root");
885 /* Children of root cover the entire window. */ 891 /* Children of root cover the entire window. */
@@ -1231,9 +1237,22 @@ void createUserInterface_Root(iRoot *d) {
1231 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" }, 1237 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },
1232 }, 1238 },
1233 4); 1239 4);
1240 iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){
1241 { "Single Frame", '1', 0, "ui.frames arg:0" },
1242 { "---", 0, 0, NULL },
1243 { "Horizontal", '2', 0, "ui.frames arg:3 axis:0" },
1244 { "Horizontal 1:2", SDLK_d, 0, "ui.frames arg:1 axis:0" },
1245 { "Horizontal 2:1", SDLK_e, 0, "ui.frames arg:2 axis:0" },
1246 { "---", 0, 0, NULL },
1247 { "Vertical", '3', 0, "ui.frames arg:3 axis:1" },
1248 { "Vertical 1:2", SDLK_f, 0, "ui.frames arg:1 axis:1" },
1249 { "Vertical 2:1", SDLK_r, 0, "ui.frames arg:2 axis:1" },
1250 }, 9);
1251 setFlags_Widget(splitMenu, disabledWhenHidden_WidgetFlag, iTrue); /* enabled when open */
1234 setId_Widget(tabsMenu, "doctabs.menu"); 1252 setId_Widget(tabsMenu, "doctabs.menu");
1235 setId_Widget(barMenu, "barmenu"); 1253 setId_Widget(barMenu, "barmenu");
1236 setId_Widget(clipMenu, "clipmenu"); 1254 setId_Widget(clipMenu, "clipmenu");
1255 setId_Widget(splitMenu, "splitmenu");
1237 } 1256 }
1238 /* Global keyboard shortcuts. */ { 1257 /* Global keyboard shortcuts. */ {
1239 addAction_Widget(root, 'l', KMOD_PRIMARY, "navigate.focus"); 1258 addAction_Widget(root, 'l', KMOD_PRIMARY, "navigate.focus");
@@ -1248,6 +1267,7 @@ void createUserInterface_Root(iRoot *d) {
1248 addAction_Widget(root, '3', rightSidebar_KeyModifier, "sidebar2.mode arg:2 toggle:1"); 1267 addAction_Widget(root, '3', rightSidebar_KeyModifier, "sidebar2.mode arg:2 toggle:1");
1249 addAction_Widget(root, '4', rightSidebar_KeyModifier, "sidebar2.mode arg:3 toggle:1"); 1268 addAction_Widget(root, '4', rightSidebar_KeyModifier, "sidebar2.mode arg:3 toggle:1");
1250 addAction_Widget(root, '5', rightSidebar_KeyModifier, "sidebar2.mode arg:4 toggle:1"); 1269 addAction_Widget(root, '5', rightSidebar_KeyModifier, "sidebar2.mode arg:4 toggle:1");
1270 addAction_Widget(root, SDLK_j, KMOD_PRIMARY, "splitmenu.open");
1251 } 1271 }
1252 updateMetrics_Root(d); 1272 updateMetrics_Root(d);
1253} 1273}
diff --git a/src/ui/util.c b/src/ui/util.c
index a1d76709..fd8740b4 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -984,6 +984,14 @@ void prependTabPage_Widget(iWidget *tabs, iWidget *page, const char *label, int
984 addTabPage_Widget_(tabs, front_WidgetAddPos, page, label, key, kmods); 984 addTabPage_Widget_(tabs, front_WidgetAddPos, page, label, key, kmods);
985} 985}
986 986
987void moveTabButtonToEnd_Widget(iWidget *tabButton) {
988 iWidget *buttons = tabButton->parent;
989 iWidget *tabs = buttons->parent;
990 removeChild_Widget(buttons, tabButton);
991 addChild_Widget(buttons, iClob(tabButton));
992 arrange_Widget(tabs);
993}
994
987iWidget *tabPage_Widget(iWidget *tabs, size_t index) { 995iWidget *tabPage_Widget(iWidget *tabs, size_t index) {
988 iWidget *pages = findChild_Widget(tabs, "tabs.pages"); 996 iWidget *pages = findChild_Widget(tabs, "tabs.pages");
989 return child_Widget(pages, index); 997 return child_Widget(pages, index);
diff --git a/src/ui/util.h b/src/ui/util.h
index 8dd16a7f..cbedefaa 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -246,6 +246,7 @@ void setTabPageLabel_Widget (iWidget *tabs, const iAnyObject *page,
246iWidget * tabPage_Widget (iWidget *tabs, size_t index); 246iWidget * tabPage_Widget (iWidget *tabs, size_t index);
247iLabelWidget * tabPageButton_Widget (iWidget *tabs, const iAnyObject *page); 247iLabelWidget * tabPageButton_Widget (iWidget *tabs, const iAnyObject *page);
248iBool isTabButton_Widget (const iWidget *); 248iBool isTabButton_Widget (const iWidget *);
249void moveTabButtonToEnd_Widget(iWidget *tabButton);
249size_t tabPageIndex_Widget (const iWidget *tabs, const iAnyObject *page); 250size_t tabPageIndex_Widget (const iWidget *tabs, const iAnyObject *page);
250const iWidget * currentTabPage_Widget (const iWidget *tabs); 251const iWidget * currentTabPage_Widget (const iWidget *tabs);
251size_t tabCount_Widget (const iWidget *tabs); 252size_t tabCount_Widget (const iWidget *tabs);
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 590dbe70..e4d92b35 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -225,6 +225,13 @@ void setCommandHandler_Widget(iWidget *d, iBool (*handler)(iWidget *, const char
225 d->commandHandler = handler; 225 d->commandHandler = handler;
226} 226}
227 227
228void setRoot_Widget(iWidget *d, iRoot *root) {
229 d->root = root;
230 iForEach(ObjectList, i, d->children) {
231 setRoot_Widget(i.object, root);
232 }
233}
234
228static int numExpandingChildren_Widget_(const iWidget *d) { 235static int numExpandingChildren_Widget_(const iWidget *d) {
229 int count = 0; 236 int count = 0;
230 iConstForEach(ObjectList, i, d->children) { 237 iConstForEach(ObjectList, i, d->children) {
@@ -749,7 +756,8 @@ iLocalDef iBool isMouseEvent_(const SDL_Event *ev) {
749static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) { 756static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) {
750 const iBool isKey = isKeyboardEvent_(ev); 757 const iBool isKey = isKeyboardEvent_(ev);
751 const iBool isMouse = isMouseEvent_(ev); 758 const iBool isMouse = isMouseEvent_(ev);
752 if (d->flags & disabled_WidgetFlag) { 759 if ((d->flags & disabled_WidgetFlag) || (d->flags & hidden_WidgetFlag &&
760 d->flags & disabledWhenHidden_WidgetFlag)) {
753 if (isKey || isMouse) return iFalse; 761 if (isKey || isMouse) return iFalse;
754 } 762 }
755 if (d->flags & hidden_WidgetFlag) { 763 if (d->flags & hidden_WidgetFlag) {
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 2ef035b6..c3c9609e 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -116,6 +116,7 @@ enum iWidgetFlag {
116#define parentCannotResizeHeight_WidgetFlag iBit64(58) 116#define parentCannotResizeHeight_WidgetFlag iBit64(58)
117#define ignoreForParentWidth_WidgetFlag iBit64(59) 117#define ignoreForParentWidth_WidgetFlag iBit64(59)
118#define noFadeBackground_WidgetFlag iBit64(60) 118#define noFadeBackground_WidgetFlag iBit64(60)
119#define disabledWhenHidden_WidgetFlag iBit64(61)
119 120
120enum iWidgetAddPos { 121enum iWidgetAddPos {
121 back_WidgetAddPos, 122 back_WidgetAddPos,
@@ -247,6 +248,7 @@ void showCollapsed_Widget (iWidget *, iBool show); /* takes care of re
247void setBackgroundColor_Widget (iWidget *, int bgColor); 248void setBackgroundColor_Widget (iWidget *, int bgColor);
248void setFrameColor_Widget (iWidget *, int frameColor); 249void setFrameColor_Widget (iWidget *, int frameColor);
249void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *)); 250void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *));
251void setRoot_Widget (iWidget *, iRoot *root); /* updates the entire tree */
250iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */ 252iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */
251iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos); 253iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos);
252iAny * addChildPosFlags_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos, int64_t childFlags); 254iAny * addChildPosFlags_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos, int64_t childFlags);
diff --git a/src/ui/window.c b/src/ui/window.c
index 54f05a20..da1db514 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -161,7 +161,7 @@ static void removeMacMenus_(void) {
161} 161}
162#endif 162#endif
163 163
164static int numRoots_Window(const iWindow *d) { 164int numRoots_Window(const iWindow *d) {
165 int num = 0; 165 int num = 0;
166 iForIndices(i, d->roots) { 166 iForIndices(i, d->roots) {
167 if (d->roots[i]) num++; 167 if (d->roots[i]) num++;
@@ -173,27 +173,38 @@ static void setupUserInterface_Window(iWindow *d) {
173#if defined (iPlatformAppleDesktop) 173#if defined (iPlatformAppleDesktop)
174 insertMacMenus_(); 174 insertMacMenus_();
175#endif 175#endif
176 iForIndices(i, d->roots) { 176 /* One root is created by default. */
177 d->roots[i] = new_Root(); 177 d->roots[0] = new_Root();
178 setCurrent_Root(d->roots[i]); 178 setCurrent_Root(d->roots[0]);
179 createUserInterface_Root(d->roots[i]); 179 createUserInterface_Root(d->roots[0]);
180 setCurrent_Root(NULL); 180 setCurrent_Root(NULL);
181 }
182 /* One of the roots always has keyboard input focus. */ 181 /* One of the roots always has keyboard input focus. */
183 d->keyRoot = d->roots[0]; 182 d->keyRoot = d->roots[0];
184} 183}
185 184
186static void windowSizeChanged_Window_(iWindow *d) { 185static void windowSizeChanged_Window_(iWindow *d) {
187 const int numRoots = numRoots_Window(d); 186 const int numRoots = numRoots_Window(d);
188 /* Horizontal split frame. */
189 const iInt2 rootSize = d->size; 187 const iInt2 rootSize = d->size;
188 const int weights[2] = {
189 d->roots[0] ? (d->splitMode & twoToOne_WindowSplit ? 2 : 1) : 0,
190 d->roots[1] ? (d->splitMode & oneToTwo_WindowSplit ? 2 : 1) : 0,
191 };
192 const int totalWeight = weights[0] + weights[1];
193 int w = 0;
190 iForIndices(i, d->roots) { 194 iForIndices(i, d->roots) {
191 iRoot *root = d->roots[i]; 195 iRoot *root = d->roots[i];
192 if (root) { 196 if (root) {
193 iRect *rect = &root->widget->rect; 197 iRect *rect = &root->widget->rect;
194 /* Horizontal split frame. */ 198 /* Horizontal split frame. */
195 rect->pos = init_I2(rootSize.x * i / numRoots, 0); 199 if (d->splitMode & vertical_WindowSplit) {
196 rect->size = init_I2(rootSize.x * (i + 1) / numRoots - rect->pos.x, rootSize.y); 200 rect->pos = init_I2(0, rootSize.y * w / totalWeight);
201 rect->size = init_I2(rootSize.x, rootSize.y * (w + weights[i]) / totalWeight - rect->pos.y);
202 }
203 else {
204 rect->pos = init_I2(rootSize.x * w / totalWeight, 0);
205 rect->size = init_I2(rootSize.x * (w + weights[i]) / totalWeight - rect->pos.x, rootSize.y);
206 }
207 w += weights[i];
197 root->widget->minSize = rect->size; 208 root->widget->minSize = rect->size;
198 updatePadding_Root(root); 209 updatePadding_Root(root);
199 arrange_Widget(root->widget); 210 arrange_Widget(root->widget);
@@ -378,6 +389,7 @@ void init_Window(iWindow *d, iRect rect) {
378 d->win = NULL; 389 d->win = NULL;
379 d->size = zero_I2(); /* will be updated below */ 390 d->size = zero_I2(); /* will be updated below */
380 iZap(d->roots); 391 iZap(d->roots);
392 d->splitMode = d->pendingSplitMode = 0;
381 d->hover = NULL; 393 d->hover = NULL;
382 d->mouseGrab = NULL; 394 d->mouseGrab = NULL;
383 d->focus = NULL; 395 d->focus = NULL;
@@ -1004,7 +1016,8 @@ void draw_Window(iWindow *d) {
1004 &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size }); 1016 &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size });
1005 } 1017 }
1006#endif 1018#endif
1007 /* Root separator and keyboard focus indicator. */ { 1019 /* Root separator and keyboard focus indicator. */
1020 if (numRoots_Window(d) > 1){
1008 iPaint p; 1021 iPaint p;
1009 init_Paint(&p); 1022 init_Paint(&p);
1010 const iRect bounds = bounds_Widget(root->widget); 1023 const iRect bounds = bounds_Widget(root->widget);
@@ -1017,7 +1030,7 @@ void draw_Window(iWindow *d) {
1017 if (root == d->keyRoot) { 1030 if (root == d->keyRoot) {
1018 fillRect_Paint(&p, (iRect){ 1031 fillRect_Paint(&p, (iRect){
1019 topLeft_Rect(bounds), 1032 topLeft_Rect(bounds),
1020 init_I2(width_Rect(bounds), gap_UI / 2) 1033 init_I2(width_Rect(bounds), gap_UI / 2)
1021 }, uiBackgroundSelected_ColorId); 1034 }, uiBackgroundSelected_ColorId);
1022 } 1035 }
1023 } 1036 }
@@ -1037,8 +1050,13 @@ void draw_Window(iWindow *d) {
1037} 1050}
1038 1051
1039void resize_Window(iWindow *d, int w, int h) { 1052void resize_Window(iWindow *d, int w, int h) {
1040 SDL_SetWindowSize(d->win, w, h); 1053 if (w > 0 && h > 0) {
1041 updateSize_Window_(d, iFalse); 1054 SDL_SetWindowSize(d->win, w, h);
1055 updateSize_Window_(d, iFalse);
1056 }
1057 else {
1058 updateSize_Window_(d, iTrue); /* notify always */
1059 }
1042} 1060}
1043 1061
1044void setTitle_Window(iWindow *d, const iString *title) { 1062void setTitle_Window(iWindow *d, const iString *title) {
@@ -1126,6 +1144,51 @@ void setKeyboardHeight_Window(iWindow *d, int height) {
1126 } 1144 }
1127} 1145}
1128 1146
1147void setSplitMode_Window(iWindow *d, int splitMode) {
1148 iAssert(current_Root() == NULL);
1149 if (d->splitMode != splitMode) {
1150 int oldCount = numRoots_Window(d);
1151 setFreezeDraw_Window(d, iTrue);
1152 if (oldCount == 2 && splitMode == 0) {
1153 /* Keep references to the tabs of the second root. */
1154 iObjectList *tabs = listDocuments_App(d->roots[1]);
1155 iForEach(ObjectList, i, tabs) {
1156 setRoot_Widget(i.object, d->roots[0]);
1157 }
1158 delete_Root(d->roots[1]);
1159 d->roots[1] = NULL;
1160 d->keyRoot = d->roots[0];
1161 /* Move the deleted root's tabs to the first root. */
1162 setCurrent_Root(d->roots[0]);
1163 iWidget *docTabs = findWidget_Root("doctabs");
1164 iForEach(ObjectList, j, tabs) {
1165 appendTabPage_Widget(docTabs, j.object, "", 0, 0);
1166 }
1167 /* The last child is the [+] button for adding a tab. */
1168 moveTabButtonToEnd_Widget(findChild_Widget(docTabs, "newtab"));
1169 iRelease(tabs);
1170 }
1171 else if ((splitMode & mask_WindowSplit) && oldCount == 1) {
1172 /* Add a second root. */
1173 iAssert(d->roots[1] == NULL);
1174 d->roots[1] = new_Root();
1175 setCurrent_Root(d->roots[1]);
1176 createUserInterface_Root(d->roots[1]);
1177 /* If the old root has multiple tabs, move the current one to the new split. */
1178
1179 postCommand_Root(d->roots[1], "navigate.home");
1180 setCurrent_Root(NULL);
1181 }
1182 d->splitMode = splitMode;
1183// windowSizeChanged_Window_(d);
1184 updateSize_Window_(d, iTrue);
1185// postCommand_App("window.resized");
1186 // postCommand_App("metrics.resized");
1187// postCommand_App("window.updatelayout");
1188 postCommand_App("window.unfreeze");
1189 }
1190}
1191
1129void setSnap_Window(iWindow *d, int snapMode) { 1192void setSnap_Window(iWindow *d, int snapMode) {
1130 if (!prefs_App()->customFrame) { 1193 if (!prefs_App()->customFrame) {
1131 if (snapMode == maximized_WindowSnap) { 1194 if (snapMode == maximized_WindowSnap) {
diff --git a/src/ui/window.h b/src/ui/window.h
index b2b22e90..ad577ce4 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -56,6 +56,17 @@ struct Impl_WindowPlacement {
56 int lastHit; 56 int lastHit;
57}; 57};
58 58
59enum iWindowSplit {
60 vertical_WindowSplit = iBit(1),
61 oneToTwo_WindowSplit = iBit(2),
62 twoToOne_WindowSplit = iBit(3),
63 equal_WindowSplit = oneToTwo_WindowSplit | twoToOne_WindowSplit,
64 /* meta */
65 mode_WindowSplit = vertical_WindowSplit | equal_WindowSplit,
66 mask_WindowSplit = equal_WindowSplit,
67 merge_WindowSplit = iBit(10),
68};
69
59struct Impl_Window { 70struct Impl_Window {
60 SDL_Window * win; 71 SDL_Window * win;
61 iWindowPlacement place; 72 iWindowPlacement place;
@@ -67,6 +78,8 @@ struct Impl_Window {
67 uint32_t focusGainedAt; 78 uint32_t focusGainedAt;
68 SDL_Renderer *render; 79 SDL_Renderer *render;
69 iInt2 size; 80 iInt2 size;
81 int splitMode;
82 int pendingSplitMode;
70 iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ 83 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 */ 84 iRoot * keyRoot; /* root that has the current keyboard input focus */
72 iWidget * hover; 85 iWidget * hover;
@@ -98,6 +111,7 @@ iBool setKeyRoot_Window (iWindow *, iRoot *root);
98void setCursor_Window (iWindow *, int cursor); 111void setCursor_Window (iWindow *, int cursor);
99void setSnap_Window (iWindow *, int snapMode); 112void setSnap_Window (iWindow *, int snapMode);
100void setKeyboardHeight_Window(iWindow *, int height); 113void setKeyboardHeight_Window(iWindow *, int height);
114void setSplitMode_Window (iWindow *, int splitMode);
101void showToolbars_Window (iWindow *, iBool show); 115void showToolbars_Window (iWindow *, iBool show);
102iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); 116iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *);
103 117
@@ -112,6 +126,7 @@ uint32_t frameTime_Window (const iWindow *);
112SDL_Renderer *renderer_Window (const iWindow *); 126SDL_Renderer *renderer_Window (const iWindow *);
113int snap_Window (const iWindow *); 127int snap_Window (const iWindow *);
114iBool isFullscreen_Window (const iWindow *); 128iBool isFullscreen_Window (const iWindow *);
129int numRoots_Window (const iWindow *);
115iRoot * findRoot_Window (const iWindow *, const iWidget *widget); 130iRoot * findRoot_Window (const iWindow *, const iWidget *widget);
116iRoot * otherRoot_Window (const iWindow *, iRoot *root); 131iRoot * otherRoot_Window (const iWindow *, iRoot *root);
117 132