diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app.c | 41 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 5 | ||||
-rw-r--r-- | src/ui/root.c | 22 | ||||
-rw-r--r-- | src/ui/util.c | 8 | ||||
-rw-r--r-- | src/ui/util.h | 1 | ||||
-rw-r--r-- | src/ui/widget.c | 10 | ||||
-rw-r--r-- | src/ui/widget.h | 2 | ||||
-rw-r--r-- | src/ui/window.c | 91 | ||||
-rw-r--r-- | src/ui/window.h | 15 |
9 files changed, 170 insertions, 25 deletions
@@ -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 | ||
3971 | static void prerender_DocumentWidget_(iAny *context) { | 3971 | static 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 | ||
881 | void createUserInterface_Root(iRoot *d) { | 887 | void 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 | ||
987 | void 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 | |||
987 | iWidget *tabPage_Widget(iWidget *tabs, size_t index) { | 995 | iWidget *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, | |||
246 | iWidget * tabPage_Widget (iWidget *tabs, size_t index); | 246 | iWidget * tabPage_Widget (iWidget *tabs, size_t index); |
247 | iLabelWidget * tabPageButton_Widget (iWidget *tabs, const iAnyObject *page); | 247 | iLabelWidget * tabPageButton_Widget (iWidget *tabs, const iAnyObject *page); |
248 | iBool isTabButton_Widget (const iWidget *); | 248 | iBool isTabButton_Widget (const iWidget *); |
249 | void moveTabButtonToEnd_Widget(iWidget *tabButton); | ||
249 | size_t tabPageIndex_Widget (const iWidget *tabs, const iAnyObject *page); | 250 | size_t tabPageIndex_Widget (const iWidget *tabs, const iAnyObject *page); |
250 | const iWidget * currentTabPage_Widget (const iWidget *tabs); | 251 | const iWidget * currentTabPage_Widget (const iWidget *tabs); |
251 | size_t tabCount_Widget (const iWidget *tabs); | 252 | size_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 | ||
228 | void 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 | |||
228 | static int numExpandingChildren_Widget_(const iWidget *d) { | 235 | static 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) { | |||
749 | static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) { | 756 | static 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 | ||
120 | enum iWidgetAddPos { | 121 | enum iWidgetAddPos { |
121 | back_WidgetAddPos, | 122 | back_WidgetAddPos, |
@@ -247,6 +248,7 @@ void showCollapsed_Widget (iWidget *, iBool show); /* takes care of re | |||
247 | void setBackgroundColor_Widget (iWidget *, int bgColor); | 248 | void setBackgroundColor_Widget (iWidget *, int bgColor); |
248 | void setFrameColor_Widget (iWidget *, int frameColor); | 249 | void setFrameColor_Widget (iWidget *, int frameColor); |
249 | void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *)); | 250 | void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *)); |
251 | void setRoot_Widget (iWidget *, iRoot *root); /* updates the entire tree */ | ||
250 | iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */ | 252 | iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */ |
251 | iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos); | 253 | iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos); |
252 | iAny * addChildPosFlags_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos, int64_t childFlags); | 254 | iAny * 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 | ||
164 | static int numRoots_Window(const iWindow *d) { | 164 | int 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 | ||
186 | static void windowSizeChanged_Window_(iWindow *d) { | 185 | static 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 | ||
1039 | void resize_Window(iWindow *d, int w, int h) { | 1052 | void 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 | ||
1044 | void setTitle_Window(iWindow *d, const iString *title) { | 1062 | void setTitle_Window(iWindow *d, const iString *title) { |
@@ -1126,6 +1144,51 @@ void setKeyboardHeight_Window(iWindow *d, int height) { | |||
1126 | } | 1144 | } |
1127 | } | 1145 | } |
1128 | 1146 | ||
1147 | void 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 | |||
1129 | void setSnap_Window(iWindow *d, int snapMode) { | 1192 | void 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 | ||
59 | enum 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 | |||
59 | struct Impl_Window { | 70 | struct 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); | |||
98 | void setCursor_Window (iWindow *, int cursor); | 111 | void setCursor_Window (iWindow *, int cursor); |
99 | void setSnap_Window (iWindow *, int snapMode); | 112 | void setSnap_Window (iWindow *, int snapMode); |
100 | void setKeyboardHeight_Window(iWindow *, int height); | 113 | void setKeyboardHeight_Window(iWindow *, int height); |
114 | void setSplitMode_Window (iWindow *, int splitMode); | ||
101 | void showToolbars_Window (iWindow *, iBool show); | 115 | void showToolbars_Window (iWindow *, iBool show); |
102 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); | 116 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); |
103 | 117 | ||
@@ -112,6 +126,7 @@ uint32_t frameTime_Window (const iWindow *); | |||
112 | SDL_Renderer *renderer_Window (const iWindow *); | 126 | SDL_Renderer *renderer_Window (const iWindow *); |
113 | int snap_Window (const iWindow *); | 127 | int snap_Window (const iWindow *); |
114 | iBool isFullscreen_Window (const iWindow *); | 128 | iBool isFullscreen_Window (const iWindow *); |
129 | int numRoots_Window (const iWindow *); | ||
115 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); | 130 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); |
116 | iRoot * otherRoot_Window (const iWindow *, iRoot *root); | 131 | iRoot * otherRoot_Window (const iWindow *, iRoot *root); |
117 | 132 | ||