diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/bindingswidget.c | 1 | ||||
-rw-r--r-- | src/ui/certimportwidget.c | 4 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 2 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 2 | ||||
-rw-r--r-- | src/ui/lookupwidget.c | 4 | ||||
-rw-r--r-- | src/ui/translation.c | 5 | ||||
-rw-r--r-- | src/ui/util.c | 74 | ||||
-rw-r--r-- | src/ui/util.h | 4 | ||||
-rw-r--r-- | src/ui/widget.c | 222 | ||||
-rw-r--r-- | src/ui/widget.h | 5 | ||||
-rw-r--r-- | src/ui/window.c | 15 |
11 files changed, 255 insertions, 83 deletions
diff --git a/src/ui/bindingswidget.c b/src/ui/bindingswidget.c index c73982b3..dc23dd6e 100644 --- a/src/ui/bindingswidget.c +++ b/src/ui/bindingswidget.c | |||
@@ -110,6 +110,7 @@ static void updateItems_BindingsWidget_(iBindingsWidget *d) { | |||
110 | void init_BindingsWidget(iBindingsWidget *d) { | 110 | void init_BindingsWidget(iBindingsWidget *d) { |
111 | iWidget *w = as_Widget(d); | 111 | iWidget *w = as_Widget(d); |
112 | init_Widget(w); | 112 | init_Widget(w); |
113 | setId_Widget(w, "bindings"); | ||
113 | setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); | 114 | setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); |
114 | d->activePos = iInvalidPos; | 115 | d->activePos = iInvalidPos; |
115 | d->contextPos = iInvalidPos; | 116 | d->contextPos = iInvalidPos; |
diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c index 43e8ff97..a4245603 100644 --- a/src/ui/certimportwidget.c +++ b/src/ui/certimportwidget.c | |||
@@ -148,8 +148,8 @@ void init_CertImportWidget(iCertImportWidget *d) { | |||
148 | } | 148 | } |
149 | addChild_Widget(w, iClob(page)); | 149 | addChild_Widget(w, iClob(page)); |
150 | arrange_Widget(w); | 150 | arrange_Widget(w); |
151 | setSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); | 151 | setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); |
152 | setSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); | 152 | setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); |
153 | /* Buttons. */ | 153 | /* Buttons. */ |
154 | addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); | 154 | addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); |
155 | iWidget *buttons = makeDialogButtons_Widget( | 155 | iWidget *buttons = makeDialogButtons_Widget( |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 07b359da..9a50b611 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1752,7 +1752,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1752 | delete_Array(items); | 1752 | delete_Array(items); |
1753 | /* Enforce a minimum size. */ | 1753 | /* Enforce a minimum size. */ |
1754 | iWidget *sizer = new_Widget(); | 1754 | iWidget *sizer = new_Widget(); |
1755 | setSize_Widget(sizer, init_I2(gap_UI * 65, 1)); | 1755 | setFixedSize_Widget(sizer, init_I2(gap_UI * 65, 1)); |
1756 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); | 1756 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); |
1757 | setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); | 1757 | setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); |
1758 | if (deviceType_App() != phone_AppDeviceType) { | 1758 | if (deviceType_App() != phone_AppDeviceType) { |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 5593b5b9..0856db93 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -248,7 +248,7 @@ void setMaxLen_InputWidget(iInputWidget *d, size_t maxLen) { | |||
248 | /* Set a fixed size. */ | 248 | /* Set a fixed size. */ |
249 | iBlock *content = new_Block(maxLen); | 249 | iBlock *content = new_Block(maxLen); |
250 | fill_Block(content, 'M'); | 250 | fill_Block(content, 'M'); |
251 | setSize_Widget( | 251 | setFixedSize_Widget( |
252 | as_Widget(d), | 252 | as_Widget(d), |
253 | add_I2(measure_Text(d->font, cstr_Block(content)), init_I2(6 * gap_UI, 2 * gap_UI))); | 253 | add_I2(measure_Text(d->font, cstr_Block(content)), init_I2(6 * gap_UI, 2 * gap_UI))); |
254 | delete_Block(content); | 254 | delete_Block(content); |
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index c711d61f..f3fd54d2 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c | |||
@@ -657,8 +657,8 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | |||
657 | const iWindow *window = get_Window(); | 657 | const iWindow *window = get_Window(); |
658 | const iInt2 rootSize = rootSize_Window(window); | 658 | const iInt2 rootSize = rootSize_Window(window); |
659 | const iRect navBarBounds = bounds_Widget(findWidget_App("navbar")); | 659 | const iRect navBarBounds = bounds_Widget(findWidget_App("navbar")); |
660 | setSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), | 660 | setFixedSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), |
661 | (rootSize.y - bottom_Rect(navBarBounds)) / 2)); | 661 | (rootSize.y - bottom_Rect(navBarBounds)) / 2)); |
662 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); | 662 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); |
663 | #if defined (iPlatformAppleMobile) | 663 | #if defined (iPlatformAppleMobile) |
664 | /* Adjust height based on keyboard size. */ { | 664 | /* Adjust height based on keyboard size. */ { |
diff --git a/src/ui/translation.c b/src/ui/translation.c index 86607fc6..4102fcb9 100644 --- a/src/ui/translation.c +++ b/src/ui/translation.c | |||
@@ -442,8 +442,9 @@ iBool handleCommand_Translation(iTranslation *d, const char *cmd) { | |||
442 | setFlags_Widget(as_Widget(acceptButton), disabled_WidgetFlag, iTrue); | 442 | setFlags_Widget(as_Widget(acceptButton), disabled_WidgetFlag, iTrue); |
443 | iTranslationProgressWidget *prog = new_TranslationProgressWidget(); | 443 | iTranslationProgressWidget *prog = new_TranslationProgressWidget(); |
444 | setPos_Widget(as_Widget(prog), langs->rect.pos); | 444 | setPos_Widget(as_Widget(prog), langs->rect.pos); |
445 | setSize_Widget(as_Widget(prog), langs->rect.size); | 445 | setFixedSize_Widget(as_Widget(prog), init_I2(width_Rect(innerBounds_Widget(d->dlg)), |
446 | addChild_Widget(d->dlg, iClob(prog)); | 446 | langs->rect.size.y)); |
447 | addChildFlags_Widget(d->dlg, iClob(prog), 0); | ||
447 | submit_Translation(d); | 448 | submit_Translation(d); |
448 | } | 449 | } |
449 | return iTrue; | 450 | return iTrue; |
diff --git a/src/ui/util.c b/src/ui/util.c index 41b8f65c..564cf785 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -438,7 +438,7 @@ iInt2 delta_Click(const iClick *d) { | |||
438 | iWidget *makePadding_Widget(int size) { | 438 | iWidget *makePadding_Widget(int size) { |
439 | iWidget *pad = new_Widget(); | 439 | iWidget *pad = new_Widget(); |
440 | setId_Widget(pad, "padding"); | 440 | setId_Widget(pad, "padding"); |
441 | setSize_Widget(pad, init1_I2(size)); | 441 | setFixedSize_Widget(pad, init1_I2(size)); |
442 | return pad; | 442 | return pad; |
443 | } | 443 | } |
444 | 444 | ||
@@ -463,7 +463,7 @@ iWidget *makeHDiv_Widget(void) { | |||
463 | 463 | ||
464 | iWidget *addAction_Widget(iWidget *parent, int key, int kmods, const char *command) { | 464 | iWidget *addAction_Widget(iWidget *parent, int key, int kmods, const char *command) { |
465 | iLabelWidget *action = newKeyMods_LabelWidget("", key, kmods, command); | 465 | iLabelWidget *action = newKeyMods_LabelWidget("", key, kmods, command); |
466 | setSize_Widget(as_Widget(action), zero_I2()); | 466 | setFixedSize_Widget(as_Widget(action), zero_I2()); |
467 | addChildFlags_Widget(parent, iClob(action), hidden_WidgetFlag); | 467 | addChildFlags_Widget(parent, iClob(action), hidden_WidgetFlag); |
468 | return as_Widget(action); | 468 | return as_Widget(action); |
469 | } | 469 | } |
@@ -856,16 +856,23 @@ iWidget *removeTabPage_Widget(iWidget *tabs, size_t index) { | |||
856 | } | 856 | } |
857 | 857 | ||
858 | void resizeToLargestPage_Widget(iWidget *tabs) { | 858 | void resizeToLargestPage_Widget(iWidget *tabs) { |
859 | // puts("RESIZE TO LARGEST PAGE ..."); | ||
860 | iWidget *pages = findChild_Widget(tabs, "tabs.pages"); | ||
861 | iForEach(ObjectList, i, children_Widget(pages)) { | ||
862 | setMinSize_Widget(i.object, zero_I2()); | ||
863 | // resetSize_Widget(i.object); | ||
864 | } | ||
859 | arrange_Widget(tabs); | 865 | arrange_Widget(tabs); |
860 | iInt2 largest = zero_I2(); | 866 | iInt2 largest = zero_I2(); |
861 | iWidget *pages = findChild_Widget(tabs, "tabs.pages"); | 867 | iConstForEach(ObjectList, j, children_Widget(pages)) { |
862 | iConstForEach(ObjectList, i, children_Widget(pages)) { | 868 | const iWidget *page = constAs_Widget(j.object); |
863 | largest = max_I2(largest, ((const iWidget *) i.object)->rect.size); | 869 | largest = max_I2(largest, page->rect.size); |
864 | } | 870 | } |
865 | iForEach(ObjectList, j, children_Widget(pages)) { | 871 | iForEach(ObjectList, k, children_Widget(pages)) { |
866 | setSize_Widget(j.object, largest); | 872 | setMinSize_Widget(k.object, largest); |
867 | } | 873 | } |
868 | setSize_Widget(tabs, addY_I2(largest, height_Widget(findChild_Widget(tabs, "tabs.buttons")))); | 874 | setFixedSize_Widget(tabs, addY_I2(largest, height_Widget(findChild_Widget(tabs, "tabs.buttons")))); |
875 | // puts("... DONE WITH RESIZE TO LARGEST PAGE"); | ||
869 | } | 876 | } |
870 | 877 | ||
871 | iLabelWidget *tabButtonForPage_Widget_(iWidget *tabs, const iWidget *page) { | 878 | iLabelWidget *tabButtonForPage_Widget_(iWidget *tabs, const iWidget *page) { |
@@ -1012,7 +1019,7 @@ static void updateSheetPanelMetrics_(iWidget *sheet) { | |||
1012 | setSize_Widget(pad, init1_I2(naviHeight)); | 1019 | setSize_Widget(pad, init1_I2(naviHeight)); |
1013 | } | 1020 | } |
1014 | #endif | 1021 | #endif |
1015 | setSize_Widget(navi, init_I2(-1, naviHeight)); | 1022 | setFixedSize_Widget(navi, init_I2(-1, naviHeight)); |
1016 | } | 1023 | } |
1017 | 1024 | ||
1018 | static iBool slidePanelHandler_(iWidget *d, const char *cmd) { | 1025 | static iBool slidePanelHandler_(iWidget *d, const char *cmd) { |
@@ -1786,12 +1793,16 @@ static iBool toggleHandler_(iWidget *d, const char *cmd) { | |||
1786 | isSelected_Widget(d) ? 1 : 0)); | 1793 | isSelected_Widget(d) ? 1 : 0)); |
1787 | return iTrue; | 1794 | return iTrue; |
1788 | } | 1795 | } |
1796 | else if (equal_Command(cmd, "lang.changed")) { | ||
1797 | /* TODO: Measure labels again. */ | ||
1798 | } | ||
1789 | return iFalse; | 1799 | return iFalse; |
1790 | } | 1800 | } |
1791 | 1801 | ||
1792 | iWidget *makeToggle_Widget(const char *id) { | 1802 | iWidget *makeToggle_Widget(const char *id) { |
1793 | iWidget *toggle = as_Widget(new_LabelWidget("${toggle.yes}", "toggle")); /* "YES" for sizing */ | 1803 | iWidget *toggle = as_Widget(new_LabelWidget("${toggle.yes}", "toggle")); /* "YES" for sizing */ |
1794 | setId_Widget(toggle, id); | 1804 | setId_Widget(toggle, id); |
1805 | /* TODO: Measure both labels and use the larger of the two. */ | ||
1795 | updateTextCStr_LabelWidget((iLabelWidget *) toggle, "${toggle.no}"); /* actual initial value */ | 1806 | updateTextCStr_LabelWidget((iLabelWidget *) toggle, "${toggle.no}"); /* actual initial value */ |
1796 | setFlags_Widget(toggle, fixedWidth_WidgetFlag, iTrue); | 1807 | setFlags_Widget(toggle, fixedWidth_WidgetFlag, iTrue); |
1797 | setCommandHandler_Widget(toggle, toggleHandler_); | 1808 | setCommandHandler_Widget(toggle, toggleHandler_); |
@@ -1879,6 +1890,36 @@ static int cmp_MenuItem_(const void *e1, const void *e2) { | |||
1879 | } | 1890 | } |
1880 | #endif | 1891 | #endif |
1881 | 1892 | ||
1893 | void updatePreferencesLayout_Widget(iWidget *prefs) { | ||
1894 | if (!prefs) return; | ||
1895 | /* Doing manual layout here because the widget arranging logic isn't sophisticated enough. */ | ||
1896 | /* TODO: Make the arranging more sophisticated to automate this. */ | ||
1897 | static const char *inputIds[] = { | ||
1898 | "prefs.searchurl", | ||
1899 | "prefs.downloads", | ||
1900 | "prefs.ca.file", | ||
1901 | "prefs.ca.path", | ||
1902 | "prefs.proxy.gemini", | ||
1903 | "prefs.proxy.gopher", | ||
1904 | "prefs.proxy.http" | ||
1905 | }; | ||
1906 | iWidget *tabs = findChild_Widget(prefs, "prefs.tabs"); | ||
1907 | /* Input fields expand to the right edge. */ | ||
1908 | /* TODO: Add an arrangement flag for this. */ | ||
1909 | iForIndices(i, inputIds) { | ||
1910 | iInputWidget *input = findChild_Widget(tabs, inputIds[i]); | ||
1911 | if (input) { | ||
1912 | as_Widget(input)->rect.size.x = 0; | ||
1913 | } | ||
1914 | } | ||
1915 | as_Widget(findChild_Widget(prefs, "bindings"))->rect.size.x = 0; | ||
1916 | resizeToLargestPage_Widget(tabs); | ||
1917 | arrange_Widget(prefs); | ||
1918 | iForIndices(i, inputIds) { | ||
1919 | expandInputFieldWidth_(findChild_Widget(tabs, inputIds[i])); | ||
1920 | } | ||
1921 | } | ||
1922 | |||
1882 | iWidget *makePreferences_Widget(void) { | 1923 | iWidget *makePreferences_Widget(void) { |
1883 | iWidget *dlg = makeSheet_Widget("prefs"); | 1924 | iWidget *dlg = makeSheet_Widget("prefs"); |
1884 | addChildFlags_Widget(dlg, | 1925 | addChildFlags_Widget(dlg, |
@@ -2021,7 +2062,7 @@ iWidget *makePreferences_Widget(void) { | |||
2021 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 2062 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
2022 | } | 2063 | } |
2023 | /* Layout. */ { | 2064 | /* Layout. */ { |
2024 | appendTwoColumnPage_(tabs, "${heading.prefs.style}", '4', &headings, &values); | 2065 | setId_Widget(appendTwoColumnPage_(tabs, "${heading.prefs.style}", '4', &headings, &values), "prefs.page.style"); |
2025 | makeTwoColumnHeading_("${heading.prefs.fonts}", headings, values); | 2066 | makeTwoColumnHeading_("${heading.prefs.fonts}", headings, values); |
2026 | /* Fonts. */ { | 2067 | /* Fonts. */ { |
2027 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.headingfont}"))); | 2068 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.headingfont}"))); |
@@ -2096,22 +2137,13 @@ iWidget *makePreferences_Widget(void) { | |||
2096 | appendFramelessTabPage_(tabs, iClob(bind), "${heading.prefs.keys}", '6', KMOD_PRIMARY); | 2137 | appendFramelessTabPage_(tabs, iClob(bind), "${heading.prefs.keys}", '6', KMOD_PRIMARY); |
2097 | } | 2138 | } |
2098 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); | 2139 | addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); |
2099 | resizeToLargestPage_Widget(tabs); | 2140 | updatePreferencesLayout_Widget(dlg); |
2100 | arrange_Widget(dlg); | ||
2101 | /* Set input field sizes. */ { | ||
2102 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.searchurl")); | ||
2103 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.downloads")); | ||
2104 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.ca.file")); | ||
2105 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.ca.path")); | ||
2106 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gemini")); | ||
2107 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gopher")); | ||
2108 | expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.http")); | ||
2109 | } | ||
2110 | addChild_Widget(dlg, | 2141 | addChild_Widget(dlg, |
2111 | iClob(makeDialogButtons_Widget( | 2142 | iClob(makeDialogButtons_Widget( |
2112 | (iMenuItem[]){ { "${dismiss}", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1))); | 2143 | (iMenuItem[]){ { "${dismiss}", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1))); |
2113 | addChild_Widget(get_Window()->root, iClob(dlg)); | 2144 | addChild_Widget(get_Window()->root, iClob(dlg)); |
2114 | finalizeSheet_Widget(dlg); | 2145 | finalizeSheet_Widget(dlg); |
2146 | //printTree_Widget(dlg); | ||
2115 | return dlg; | 2147 | return dlg; |
2116 | } | 2148 | } |
2117 | 2149 | ||
diff --git a/src/ui/util.h b/src/ui/util.h index c6320e29..02b0df38 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -228,7 +228,9 @@ iWidget * makeMessage_Widget (const char *title, const char *msg); | |||
228 | iWidget * makeQuestion_Widget (const char *title, const char *msg, | 228 | iWidget * makeQuestion_Widget (const char *title, const char *msg, |
229 | const iMenuItem *items, size_t numItems); | 229 | const iMenuItem *items, size_t numItems); |
230 | 230 | ||
231 | iWidget * makePreferences_Widget (void); | 231 | iWidget * makePreferences_Widget (void); |
232 | void updatePreferencesLayout_Widget (iWidget *prefs); | ||
233 | |||
232 | iWidget * makeBookmarkEditor_Widget (void); | 234 | iWidget * makeBookmarkEditor_Widget (void); |
233 | iWidget * makeBookmarkCreation_Widget (const iString *url, const iString *title, iChar icon); | 235 | iWidget * makeBookmarkCreation_Widget (const iString *url, const iString *title, iChar icon); |
234 | iWidget * makeIdentityCreation_Widget (void); | 236 | iWidget * makeIdentityCreation_Widget (void); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 91f6c12d..baabf673 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -86,6 +86,7 @@ void init_Widget(iWidget *d) { | |||
86 | init_String(&d->id); | 86 | init_String(&d->id); |
87 | d->flags = 0; | 87 | d->flags = 0; |
88 | d->rect = zero_Rect(); | 88 | d->rect = zero_Rect(); |
89 | d->minSize = zero_I2(); | ||
89 | d->bgColor = none_ColorId; | 90 | d->bgColor = none_ColorId; |
90 | d->frameColor = none_ColorId; | 91 | d->frameColor = none_ColorId; |
91 | init_Anim(&d->visualOffset, 0.0f); | 92 | init_Anim(&d->visualOffset, 0.0f); |
@@ -188,20 +189,25 @@ void setPos_Widget(iWidget *d, iInt2 pos) { | |||
188 | setFlags_Widget(d, fixedPosition_WidgetFlag, iTrue); | 189 | setFlags_Widget(d, fixedPosition_WidgetFlag, iTrue); |
189 | } | 190 | } |
190 | 191 | ||
191 | void setSize_Widget(iWidget *d, iInt2 size) { | 192 | void setFixedSize_Widget(iWidget *d, iInt2 fixedSize) { |
192 | int flags = fixedSize_WidgetFlag; | 193 | int flags = fixedSize_WidgetFlag; |
193 | if (size.x < 0) { | 194 | if (fixedSize.x < 0) { |
194 | size.x = d->rect.size.x; | 195 | fixedSize.x = d->rect.size.x; |
195 | flags &= ~fixedWidth_WidgetFlag; | 196 | flags &= ~fixedWidth_WidgetFlag; |
196 | } | 197 | } |
197 | if (size.y < 0) { | 198 | if (fixedSize.y < 0) { |
198 | size.y = d->rect.size.y; | 199 | fixedSize.y = d->rect.size.y; |
199 | flags &= ~fixedHeight_WidgetFlag; | 200 | flags &= ~fixedHeight_WidgetFlag; |
200 | } | 201 | } |
201 | d->rect.size = size; | 202 | d->rect.size = fixedSize; |
202 | setFlags_Widget(d, flags, iTrue); | 203 | setFlags_Widget(d, flags, iTrue); |
203 | } | 204 | } |
204 | 205 | ||
206 | void setMinSize_Widget(iWidget *d, iInt2 minSize) { | ||
207 | d->minSize = minSize; | ||
208 | /* rearranging needed to apply this */ | ||
209 | } | ||
210 | |||
205 | void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) { | 211 | void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) { |
206 | d->padding[0] = left; | 212 | d->padding[0] = left; |
207 | d->padding[1] = top; | 213 | d->padding[1] = top; |
@@ -268,33 +274,79 @@ static int widestChild_Widget_(const iWidget *d) { | |||
268 | return width; | 274 | return width; |
269 | } | 275 | } |
270 | 276 | ||
277 | static void arrange_Widget_(iWidget *); | ||
278 | static const iBool tracing_ = iFalse; | ||
279 | |||
280 | #define TRACE(d, ...) if (tracing_) { printf_Widget_(d, __VA_ARGS__); } | ||
281 | |||
282 | static int depth_Widget_(const iWidget *d) { | ||
283 | int depth = 0; | ||
284 | for (const iWidget *w = d->parent; w; w = w->parent) { | ||
285 | depth++; | ||
286 | } | ||
287 | return depth; | ||
288 | } | ||
289 | |||
290 | static void printf_Widget_(const iWidget *d, const char *format, ...) { | ||
291 | va_list args; | ||
292 | va_start(args, format); | ||
293 | iString *msg = new_String(); | ||
294 | for (size_t i = 0; i < depth_Widget_(d); ++i) { | ||
295 | appendCStr_String(msg, "| "); | ||
296 | } | ||
297 | appendFormat_String(msg, "[%p] %s(%s) ", d, class_Widget(d)->name, cstr_String(id_Widget(d))); | ||
298 | while (size_String(msg) < 44 + depth_Widget_(d) * 4) { | ||
299 | appendCStr_String(msg, " "); | ||
300 | } | ||
301 | iBlock *msg2 = new_Block(0); | ||
302 | vprintf_Block(msg2, format, args); | ||
303 | va_end(args); | ||
304 | printf("%s%s\n", cstr_String(msg), cstr_Block(msg2)); | ||
305 | delete_Block(msg2); | ||
306 | delete_String(msg); | ||
307 | } | ||
308 | |||
271 | static void setWidth_Widget_(iWidget *d, int width) { | 309 | static void setWidth_Widget_(iWidget *d, int width) { |
272 | iAssert(width >= 0); | 310 | iAssert(width >= 0); |
311 | TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x); | ||
312 | width = iMax(width, d->minSize.x); | ||
273 | if (~d->flags & fixedWidth_WidgetFlag || d->flags & collapse_WidgetFlag) { | 313 | if (~d->flags & fixedWidth_WidgetFlag || d->flags & collapse_WidgetFlag) { |
274 | if (d->rect.size.x != width) { | 314 | if (d->rect.size.x != width) { |
275 | d->rect.size.x = width; | 315 | d->rect.size.x = width; |
316 | TRACE(d, "width has changed to %d", width); | ||
276 | if (class_Widget(d)->sizeChanged) { | 317 | if (class_Widget(d)->sizeChanged) { |
277 | const int oldHeight = d->rect.size.y; | 318 | const int oldHeight = d->rect.size.y; |
278 | class_Widget(d)->sizeChanged(d); | 319 | class_Widget(d)->sizeChanged(d); |
279 | if (d->rect.size.y != oldHeight) { | 320 | if (d->rect.size.y != oldHeight) { |
321 | TRACE(d, "sizeChanged() cuased height change to %d; redoing parent", d->rect.size.y); | ||
280 | /* Widget updated its height. */ | 322 | /* Widget updated its height. */ |
281 | arrange_Widget(d->parent); | 323 | arrange_Widget_(d->parent); |
324 | TRACE(d, "parent layout redone"); | ||
282 | } | 325 | } |
283 | } | 326 | } |
284 | } | 327 | } |
285 | } | 328 | } |
329 | else { | ||
330 | TRACE(d, "changing width not allowed; flags: %x", d->flags); | ||
331 | } | ||
286 | } | 332 | } |
287 | 333 | ||
288 | static void setHeight_Widget_(iWidget *d, int height) { | 334 | static void setHeight_Widget_(iWidget *d, int height) { |
289 | iAssert(height >= 0); | 335 | iAssert(height >= 0); |
336 | TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y); | ||
337 | height = iMax(height, d->minSize.y); | ||
290 | if (~d->flags & fixedHeight_WidgetFlag || d->flags & collapse_WidgetFlag) { | 338 | if (~d->flags & fixedHeight_WidgetFlag || d->flags & collapse_WidgetFlag) { |
291 | if (d->rect.size.y != height) { | 339 | if (d->rect.size.y != height) { |
292 | d->rect.size.y = height; | 340 | d->rect.size.y = height; |
341 | TRACE(d, "height has changed to %d", height); | ||
293 | if (class_Widget(d)->sizeChanged) { | 342 | if (class_Widget(d)->sizeChanged) { |
294 | class_Widget(d)->sizeChanged(d); | 343 | class_Widget(d)->sizeChanged(d); |
295 | } | 344 | } |
296 | } | 345 | } |
297 | } | 346 | } |
347 | else { | ||
348 | TRACE(d, "changing height not allowed; flags: %x", d->flags); | ||
349 | } | ||
298 | } | 350 | } |
299 | 351 | ||
300 | iLocalDef iBool isCollapsed_Widget_(const iWidget *d) { | 352 | iLocalDef iBool isCollapsed_Widget_(const iWidget *d) { |
@@ -336,29 +388,63 @@ static void centerHorizontal_Widget_(iWidget *d) { | |||
336 | : rootSize_Window(get_Window()).x) - | 388 | : rootSize_Window(get_Window()).x) - |
337 | width_Rect(d->rect)) / | 389 | width_Rect(d->rect)) / |
338 | 2; | 390 | 2; |
391 | TRACE(d, "center horizontally: %d", d->rect.pos.x); | ||
339 | } | 392 | } |
340 | 393 | ||
341 | void arrange_Widget(iWidget *d) { | 394 | static void boundsOfChildren_Widget_(const iWidget *d, iRect *bounds_out) { |
395 | *bounds_out = zero_Rect(); | ||
396 | iConstForEach(ObjectList, i, d->children) { | ||
397 | const iWidget *child = constAs_Widget(i.object); | ||
398 | if (isCollapsed_Widget_(child)) { | ||
399 | continue; | ||
400 | } | ||
401 | iRect childRect = child->rect; | ||
402 | if (child->flags & ignoreForParentWidth_WidgetFlag) { | ||
403 | childRect.size.x = 0; | ||
404 | } | ||
405 | if (isEmpty_Rect(*bounds_out)) { | ||
406 | *bounds_out = childRect; | ||
407 | } | ||
408 | else { | ||
409 | *bounds_out = union_Rect(*bounds_out, childRect); | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | static void arrange_Widget_(iWidget *d) { | ||
415 | TRACE(d, "arranging..."); | ||
342 | if (isCollapsed_Widget_(d)) { | 416 | if (isCollapsed_Widget_(d)) { |
417 | TRACE(d, "collapsed => END"); | ||
343 | setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue); | 418 | setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue); |
344 | return; | 419 | return; |
345 | } | 420 | } |
346 | if (d->flags & moveToParentLeftEdge_WidgetFlag) { | 421 | if (d->flags & moveToParentLeftEdge_WidgetFlag) { |
347 | d->rect.pos.x = d->padding[0]; /* FIXME: Shouldn't this be d->parent->padding[0]? */ | 422 | d->rect.pos.x = d->padding[0]; /* FIXME: Shouldn't this be d->parent->padding[0]? */ |
423 | TRACE(d, "move to parent left edge: %d", d->rect.pos.x); | ||
348 | } | 424 | } |
349 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { | 425 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { |
350 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); | 426 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); |
427 | TRACE(d, "move to parent right edge: %d", d->rect.pos.x); | ||
351 | } | 428 | } |
352 | else if (d->flags & moveToParentBottomEdge_WidgetFlag) { | 429 | else if (d->flags & moveToParentBottomEdge_WidgetFlag) { |
353 | d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect); | 430 | d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect); |
431 | TRACE(d, "move to parent bottom edge: %d", d->rect.pos.y); | ||
354 | } | 432 | } |
355 | else if (d->flags & centerHorizontal_WidgetFlag) { | 433 | else if (d->flags & centerHorizontal_WidgetFlag) { |
356 | centerHorizontal_Widget_(d); | 434 | centerHorizontal_Widget_(d); |
357 | } | 435 | } |
358 | if (d->flags & resizeToParentWidth_WidgetFlag) { | 436 | if (d->flags & resizeToParentWidth_WidgetFlag) { |
359 | setWidth_Widget_(d, width_Rect(innerRect_Widget_(d->parent))); | 437 | iRect childBounds = zero_Rect(); |
438 | if (flags_Widget(d->parent) & arrangeWidth_WidgetFlag) { | ||
439 | /* Can't go narrower than what the children require, though. */ | ||
440 | boundsOfChildren_Widget_(d, &childBounds); | ||
441 | } | ||
442 | TRACE(d, "resize to parent width; child bounds width %d", childBounds.size.x, childBounds.size.y); | ||
443 | setWidth_Widget_(d, iMaxi(width_Rect(innerRect_Widget_(d->parent)), | ||
444 | width_Rect(childBounds))); | ||
360 | } | 445 | } |
361 | if (d->flags & resizeToParentHeight_WidgetFlag) { | 446 | if (d->flags & resizeToParentHeight_WidgetFlag) { |
447 | TRACE(d, "resize to parent height"); | ||
362 | setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); | 448 | setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); |
363 | } | 449 | } |
364 | if (d->flags & safePadding_WidgetFlag) { | 450 | if (d->flags & safePadding_WidgetFlag) { |
@@ -370,46 +456,44 @@ void arrange_Widget(iWidget *d) { | |||
370 | } | 456 | } |
371 | /* The rest of the arrangement depends on child widgets. */ | 457 | /* The rest of the arrangement depends on child widgets. */ |
372 | if (!d->children) { | 458 | if (!d->children) { |
459 | TRACE(d, "no children => END"); | ||
373 | return; | 460 | return; |
374 | } | 461 | } |
375 | const size_t childCount = numArrangedChildren_Widget_(d); | 462 | const size_t childCount = numArrangedChildren_Widget_(d); |
376 | /* There may still be unarranged children that need arranging internally. */ | 463 | TRACE(d, "%d arranged children", childCount); |
377 | if (childCount == 0) { | ||
378 | iForEach(ObjectList, i, d->children) { | ||
379 | iWidget *child = as_Widget(i.object); | ||
380 | if (isArranged_Widget_(child)) { | ||
381 | arrange_Widget(child); | ||
382 | } | ||
383 | } | ||
384 | return; | ||
385 | } | ||
386 | /* Resize children to fill the parent widget. */ | 464 | /* Resize children to fill the parent widget. */ |
387 | if (d->flags & resizeChildren_WidgetFlag) { | 465 | if (d->flags & resizeChildren_WidgetFlag) { |
388 | const iInt2 dirs = init_I2((d->flags & resizeWidthOfChildren_WidgetFlag) != 0, | 466 | const iInt2 dirs = init_I2((d->flags & resizeWidthOfChildren_WidgetFlag) != 0, |
389 | (d->flags & resizeHeightOfChildren_WidgetFlag) != 0); | 467 | (d->flags & resizeHeightOfChildren_WidgetFlag) != 0); |
468 | TRACE(d, "resize children, x:%d y:%d", dirs.x, dirs.y); | ||
390 | /* Collapse hidden children. */ | 469 | /* Collapse hidden children. */ |
391 | iBool collapseChanged = iFalse; | 470 | iBool collapseChanged = iFalse; |
392 | iForEach(ObjectList, c, d->children) { | 471 | iForEach(ObjectList, c, d->children) { |
393 | iWidget *child = as_Widget(c.object); | 472 | iWidget *child = as_Widget(c.object); |
394 | if (!isCollapsed_Widget_(child) && child->flags & wasCollapsed_WidgetFlag) { | 473 | if (!isCollapsed_Widget_(child) && child->flags & wasCollapsed_WidgetFlag) { |
395 | setFlags_Widget(child, wasCollapsed_WidgetFlag, iFalse); | 474 | setFlags_Widget(child, wasCollapsed_WidgetFlag, iFalse); |
475 | TRACE(d, "child %p is uncollapsed", child); | ||
396 | /* Undo collapse and determine the normal size again. */ | 476 | /* Undo collapse and determine the normal size again. */ |
397 | arrange_Widget(d); | 477 | arrange_Widget_(d); |
398 | collapseChanged = iTrue; | 478 | collapseChanged = iTrue; |
399 | } | 479 | } |
400 | else if (isCollapsed_Widget_(child) && ~child->flags & wasCollapsed_WidgetFlag) { | 480 | else if (isCollapsed_Widget_(child) && ~child->flags & wasCollapsed_WidgetFlag) { |
401 | setFlags_Widget(child, wasCollapsed_WidgetFlag, iTrue); | 481 | setFlags_Widget(child, wasCollapsed_WidgetFlag, iTrue); |
402 | collapseChanged = iTrue; | 482 | collapseChanged = iTrue; |
483 | TRACE(d, "child %p flagged as collapsed", child); | ||
403 | } | 484 | } |
404 | } | 485 | } |
405 | if (collapseChanged) { | 486 | if (collapseChanged) { |
406 | arrange_Widget(d); /* Redo with the new child sizes. */ | 487 | TRACE(d, "redoing arrangement due to changes in child collapse state"); |
488 | arrange_Widget_(d); /* Redo with the new child sizes. */ | ||
407 | return; | 489 | return; |
408 | } | 490 | } |
409 | const int expCount = numExpandingChildren_Widget_(d); | 491 | const int expCount = numExpandingChildren_Widget_(d); |
492 | TRACE(d, "%d expanding children", expCount); | ||
410 | /* Only resize the expanding children, not touching the others. */ | 493 | /* Only resize the expanding children, not touching the others. */ |
411 | if (expCount > 0) { | 494 | if (expCount > 0) { |
412 | iInt2 avail = innerRect_Widget_(d).size; | 495 | iInt2 avail = innerRect_Widget_(d).size; |
496 | TRACE(d, "inner size: %dx%d", avail.x, avail.y); | ||
413 | iConstForEach(ObjectList, i, d->children) { | 497 | iConstForEach(ObjectList, i, d->children) { |
414 | const iWidget *child = constAs_Widget(i.object); | 498 | const iWidget *child = constAs_Widget(i.object); |
415 | if (!isArranged_Widget_(child)) { | 499 | if (!isArranged_Widget_(child)) { |
@@ -420,9 +504,11 @@ void arrange_Widget(iWidget *d) { | |||
420 | } | 504 | } |
421 | } | 505 | } |
422 | avail = divi_I2(max_I2(zero_I2(), avail), expCount); | 506 | avail = divi_I2(max_I2(zero_I2(), avail), expCount); |
507 | TRACE(d, "changing child sizes (expand mode)..."); | ||
423 | iForEach(ObjectList, j, d->children) { | 508 | iForEach(ObjectList, j, d->children) { |
424 | iWidget *child = as_Widget(j.object); | 509 | iWidget *child = as_Widget(j.object); |
425 | if (!isArranged_Widget_(child)) { | 510 | if (!isArranged_Widget_(child)) { |
511 | TRACE(d, "child %p is not arranged", child); | ||
426 | continue; | 512 | continue; |
427 | } | 513 | } |
428 | if (child->flags & expand_WidgetFlag) { | 514 | if (child->flags & expand_WidgetFlag) { |
@@ -445,6 +531,7 @@ void arrange_Widget(iWidget *d) { | |||
445 | } | 531 | } |
446 | } | 532 | } |
447 | } | 533 | } |
534 | TRACE(d, "...done changing child sizes (expand mode)"); | ||
448 | } | 535 | } |
449 | else { | 536 | else { |
450 | /* Evenly size all children. */ | 537 | /* Evenly size all children. */ |
@@ -458,6 +545,7 @@ void arrange_Widget(iWidget *d) { | |||
458 | childSize.y /= childCount; | 545 | childSize.y /= childCount; |
459 | unpaddedChildSize.y /= childCount; | 546 | unpaddedChildSize.y /= childCount; |
460 | } | 547 | } |
548 | TRACE(d, "begin changing child sizes (EVEN mode)..."); | ||
461 | iForEach(ObjectList, i, d->children) { | 549 | iForEach(ObjectList, i, d->children) { |
462 | iWidget *child = as_Widget(i.object); | 550 | iWidget *child = as_Widget(i.object); |
463 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { | 551 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { |
@@ -468,34 +556,52 @@ void arrange_Widget(iWidget *d) { | |||
468 | setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y); | 556 | setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y); |
469 | } | 557 | } |
470 | } | 558 | } |
559 | else { | ||
560 | TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child, | ||
561 | (child->flags & parentCannotResize_WidgetFlag) != 0); | ||
562 | } | ||
471 | } | 563 | } |
564 | TRACE(d, "...done changing child sizes (EVEN mode)"); | ||
472 | } | 565 | } |
473 | } | 566 | } |
474 | if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { | 567 | if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { |
475 | const int widest = widestChild_Widget_(d); | 568 | const int widest = widestChild_Widget_(d); |
569 | TRACE(d, "resizing children to widest child (%d)...", widest); | ||
476 | iForEach(ObjectList, i, d->children) { | 570 | iForEach(ObjectList, i, d->children) { |
477 | iWidget *child = as_Widget(i.object); | 571 | iWidget *child = as_Widget(i.object); |
478 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { | 572 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { |
479 | setWidth_Widget_(child, widest); | 573 | setWidth_Widget_(child, widest); |
480 | } | 574 | } |
575 | else { | ||
576 | TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child, | ||
577 | (child->flags & parentCannotResize_WidgetFlag) != 0); | ||
578 | } | ||
481 | } | 579 | } |
580 | TRACE(d, "...done resizing children to widest child"); | ||
482 | } | 581 | } |
483 | iInt2 pos = initv_I2(d->padding); | 582 | iInt2 pos = initv_I2(d->padding); |
583 | TRACE(d, "begin positioning children from %d,%d (flags:%s%s)...", pos.x, pos.y, | ||
584 | d->flags & arrangeHorizontal_WidgetFlag ? " horiz" : "", | ||
585 | d->flags & arrangeVertical_WidgetFlag ? " vert" : ""); | ||
484 | iForEach(ObjectList, i, d->children) { | 586 | iForEach(ObjectList, i, d->children) { |
485 | iWidget *child = as_Widget(i.object); | 587 | iWidget *child = as_Widget(i.object); |
486 | arrange_Widget(child); | 588 | arrange_Widget_(child); |
487 | if (!isArranged_Widget_(child)) { | 589 | if (!isArranged_Widget_(child)) { |
590 | TRACE(d, "child %p arranging prohibited", child); | ||
488 | continue; | 591 | continue; |
489 | } | 592 | } |
490 | if (child->flags & centerHorizontal_WidgetFlag) { | 593 | if (child->flags & centerHorizontal_WidgetFlag) { |
594 | TRACE(d, "child %p is centered, skipping", child); | ||
491 | continue; | 595 | continue; |
492 | } | 596 | } |
493 | if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) { | 597 | if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) { |
494 | if (child->flags & | 598 | if (child->flags & |
495 | (moveToParentLeftEdge_WidgetFlag | moveToParentRightEdge_WidgetFlag)) { | 599 | (moveToParentLeftEdge_WidgetFlag | moveToParentRightEdge_WidgetFlag)) { |
600 | TRACE(d, "child %p is attached an edge, skipping", child); | ||
496 | continue; /* Not part of the sequential arrangement .*/ | 601 | continue; /* Not part of the sequential arrangement .*/ |
497 | } | 602 | } |
498 | child->rect.pos = pos; | 603 | child->rect.pos = pos; |
604 | TRACE(d, "child %p set position to %d,%d", child, pos.x, pos.y); | ||
499 | if (d->flags & arrangeHorizontal_WidgetFlag) { | 605 | if (d->flags & arrangeHorizontal_WidgetFlag) { |
500 | pos.x += child->rect.size.x; | 606 | pos.x += child->rect.size.x; |
501 | } | 607 | } |
@@ -506,30 +612,20 @@ void arrange_Widget(iWidget *d) { | |||
506 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag && | 612 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag && |
507 | ~child->flags & moveToParentBottomEdge_WidgetFlag) { | 613 | ~child->flags & moveToParentBottomEdge_WidgetFlag) { |
508 | child->rect.pos = pos; | 614 | child->rect.pos = pos; |
615 | TRACE(d, "child %p set position to %d,%d (not sequential, children being resized)", child, pos.x, pos.y); | ||
509 | } | 616 | } |
510 | else if (d->flags & resizeWidthOfChildren_WidgetFlag) { | 617 | else if (d->flags & resizeWidthOfChildren_WidgetFlag) { |
511 | child->rect.pos.x = pos.x; | 618 | child->rect.pos.x = pos.x; |
619 | TRACE(d, "child %p set X to %d (not sequential, children being resized)", child, pos.x); | ||
512 | } | 620 | } |
513 | } | 621 | } |
622 | TRACE(d, "...done positioning children"); | ||
514 | /* Update the size of the widget according to the arrangement. */ | 623 | /* Update the size of the widget according to the arrangement. */ |
515 | if (d->flags & arrangeSize_WidgetFlag) { | 624 | if (d->flags & arrangeSize_WidgetFlag) { |
516 | iRect bounds = zero_Rect(); | 625 | iRect bounds; |
517 | iConstForEach(ObjectList, i, d->children) { | 626 | boundsOfChildren_Widget_(d, &bounds); |
518 | const iWidget *child = constAs_Widget(i.object); | 627 | TRACE(d, "begin arranging own size; bounds of children: %d,%d %dx%d", |
519 | if (isCollapsed_Widget_(child)) { | 628 | bounds.pos.x, bounds.pos.y, bounds.size.x, bounds.size.y); |
520 | continue; | ||
521 | } | ||
522 | iRect childRect = child->rect; | ||
523 | if (child->flags & ignoreForParentWidth_WidgetFlag) { | ||
524 | childRect.size.x = 0; | ||
525 | } | ||
526 | if (isEmpty_Rect(bounds)) { | ||
527 | bounds = childRect; | ||
528 | } | ||
529 | else { | ||
530 | bounds = union_Rect(bounds, childRect); | ||
531 | } | ||
532 | } | ||
533 | adjustEdges_Rect(&bounds, -d->padding[1], d->padding[2], d->padding[3], -d->padding[0]); | 629 | adjustEdges_Rect(&bounds, -d->padding[1], d->padding[2], d->padding[3], -d->padding[0]); |
534 | if (d->flags & arrangeWidth_WidgetFlag) { | 630 | if (d->flags & arrangeWidth_WidgetFlag) { |
535 | setWidth_Widget_(d, bounds.size.x); | 631 | setWidth_Widget_(d, bounds.size.x); |
@@ -539,14 +635,15 @@ void arrange_Widget(iWidget *d) { | |||
539 | if (child->flags & | 635 | if (child->flags & |
540 | (resizeToParentWidth_WidgetFlag | | 636 | (resizeToParentWidth_WidgetFlag | |
541 | moveToParentLeftEdge_WidgetFlag | | 637 | moveToParentLeftEdge_WidgetFlag | |
542 | moveToParentBottomEdge_WidgetFlag | | ||
543 | moveToParentRightEdge_WidgetFlag)) { | 638 | moveToParentRightEdge_WidgetFlag)) { |
544 | arrange_Widget(child); | 639 | TRACE(d, "rearranging child %p because its size or position depends on parent width", child); |
640 | arrange_Widget_(child); | ||
545 | } | 641 | } |
546 | } | 642 | } |
547 | if (d->flags & moveToParentRightEdge_WidgetFlag) { | 643 | if (d->flags & moveToParentRightEdge_WidgetFlag) { |
548 | /* TODO: Fix this: not DRY. See beginning of method. */ | 644 | /* TODO: Fix this: not DRY. See beginning of method. */ |
549 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); | 645 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); |
646 | TRACE(d, "after width change moving to right edge of parent, set X to %d", d, d->rect.pos.x); | ||
550 | } | 647 | } |
551 | } | 648 | } |
552 | if (d->flags & arrangeHeight_WidgetFlag) { | 649 | if (d->flags & arrangeHeight_WidgetFlag) { |
@@ -554,8 +651,10 @@ void arrange_Widget(iWidget *d) { | |||
554 | /* Parent size changed, must update the children.*/ | 651 | /* Parent size changed, must update the children.*/ |
555 | iForEach(ObjectList, j, d->children) { | 652 | iForEach(ObjectList, j, d->children) { |
556 | iWidget *child = as_Widget(j.object); | 653 | iWidget *child = as_Widget(j.object); |
557 | if (child->flags & resizeToParentHeight_WidgetFlag) { | 654 | if (child->flags & (resizeToParentHeight_WidgetFlag | |
558 | arrange_Widget(child); | 655 | moveToParentBottomEdge_WidgetFlag)) { |
656 | TRACE(d, "rearranging child %p because its size or position depends on parent height", child); | ||
657 | arrange_Widget_(child); | ||
559 | } | 658 | } |
560 | } | 659 | } |
561 | } | 660 | } |
@@ -566,9 +665,31 @@ void arrange_Widget(iWidget *d) { | |||
566 | if (d->flags & centerHorizontal_WidgetFlag) { | 665 | if (d->flags & centerHorizontal_WidgetFlag) { |
567 | centerHorizontal_Widget_(d); | 666 | centerHorizontal_Widget_(d); |
568 | } | 667 | } |
668 | TRACE(d, "...done arranging own size"); | ||
669 | } | ||
670 | TRACE(d, "END"); | ||
671 | } | ||
672 | |||
673 | void resetSize_Widget(iWidget *d) { | ||
674 | if (~d->flags & fixedWidth_WidgetFlag) { | ||
675 | d->rect.size.x = d->minSize.x; | ||
676 | } | ||
677 | if (~d->flags & fixedHeight_WidgetFlag) { | ||
678 | d->rect.size.y = d->minSize.y; | ||
679 | } | ||
680 | iForEach(ObjectList, i, children_Widget(d)) { | ||
681 | iWidget *child = as_Widget(i.object); | ||
682 | if (isArranged_Widget_(child)) { | ||
683 | resetSize_Widget(child); | ||
684 | } | ||
569 | } | 685 | } |
570 | } | 686 | } |
571 | 687 | ||
688 | void arrange_Widget(iWidget *d) { | ||
689 | //resetSize_Widget_(d); /* back to initial default sizes */ | ||
690 | arrange_Widget_(d); | ||
691 | } | ||
692 | |||
572 | static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { | 693 | static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { |
573 | if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { | 694 | if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { |
574 | const int off = iRound(value_Anim(&d->visualOffset)); | 695 | const int off = iRound(value_Anim(&d->visualOffset)); |
@@ -1354,6 +1475,7 @@ void refresh_Widget(const iAnyObject *d) { | |||
1354 | postRefresh_App(); | 1475 | postRefresh_App(); |
1355 | } | 1476 | } |
1356 | 1477 | ||
1478 | /* Debug utility for inspecting widget trees. */ | ||
1357 | #include "labelwidget.h" | 1479 | #include "labelwidget.h" |
1358 | static void printTree_Widget_(const iWidget *d, int indent) { | 1480 | static void printTree_Widget_(const iWidget *d, int indent) { |
1359 | for (int i = 0; i < indent; ++i) { | 1481 | for (int i = 0; i < indent; ++i) { |
@@ -1365,9 +1487,17 @@ static void printTree_Widget_(const iWidget *d, int indent) { | |||
1365 | cstr_String(text_LabelWidget((const iLabelWidget *) d)), | 1487 | cstr_String(text_LabelWidget((const iLabelWidget *) d)), |
1366 | cstr_String(command_LabelWidget((const iLabelWidget *) d))); | 1488 | cstr_String(command_LabelWidget((const iLabelWidget *) d))); |
1367 | } | 1489 | } |
1368 | printf("size:%dx%d [%d..%d %d:%d] flags:%08llx%s\n", d->rect.size.x, d->rect.size.y, | 1490 | printf("size:%dx%d {min:%dx%d} [%d..%d %d:%d] flags:%08llx%s%s%s%s%s\n", |
1369 | d->padding[0], d->padding[2], d->padding[1], d->padding[3], | 1491 | d->rect.size.x, d->rect.size.y, |
1370 | (long long unsigned int) d->flags, d->flags & tight_WidgetFlag ? " tight" : ""); | 1492 | d->minSize.x, d->minSize.y, |
1493 | d->padding[0], d->padding[2], | ||
1494 | d->padding[1], d->padding[3], | ||
1495 | (long long unsigned int) d->flags, | ||
1496 | d->flags & expand_WidgetFlag ? " exp" : "", | ||
1497 | d->flags & tight_WidgetFlag ? " tight" : "", | ||
1498 | d->flags & fixedWidth_WidgetFlag ? " fixW" : "", | ||
1499 | d->flags & fixedHeight_WidgetFlag ? " fixH" : "", | ||
1500 | d->flags & resizeToParentWidth_WidgetFlag ? " rsPrnW" : ""); | ||
1371 | iConstForEach(ObjectList, i, d->children) { | 1501 | iConstForEach(ObjectList, i, d->children) { |
1372 | printTree_Widget_(i.object, indent + 1); | 1502 | printTree_Widget_(i.object, indent + 1); |
1373 | } | 1503 | } |
diff --git a/src/ui/widget.h b/src/ui/widget.h index bde13272..4c5b7d85 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -129,6 +129,7 @@ struct Impl_Widget { | |||
129 | iString id; | 129 | iString id; |
130 | int64_t flags; | 130 | int64_t flags; |
131 | iRect rect; | 131 | iRect rect; |
132 | iInt2 minSize; | ||
132 | int padding[4]; /* left, top, right, bottom */ | 133 | int padding[4]; /* left, top, right, bottom */ |
133 | iAnim visualOffset; | 134 | iAnim visualOffset; |
134 | int bgColor; | 135 | int bgColor; |
@@ -221,7 +222,8 @@ iBool hasParent_Widget (const iWidget *d, const iWidget *someParent | |||
221 | void setId_Widget (iWidget *, const char *id); | 222 | void setId_Widget (iWidget *, const char *id); |
222 | void setFlags_Widget (iWidget *, int64_t flags, iBool set); | 223 | void setFlags_Widget (iWidget *, int64_t flags, iBool set); |
223 | void setPos_Widget (iWidget *, iInt2 pos); | 224 | void setPos_Widget (iWidget *, iInt2 pos); |
224 | void setSize_Widget (iWidget *, iInt2 size); | 225 | void setFixedSize_Widget (iWidget *, iInt2 fixedSize); |
226 | void setMinSize_Widget (iWidget *, iInt2 minSize); | ||
225 | void setPadding_Widget (iWidget *, int left, int top, int right, int bottom); | 227 | void setPadding_Widget (iWidget *, int left, int top, int right, int bottom); |
226 | iLocalDef void setPadding1_Widget (iWidget *d, int padding) { setPadding_Widget(d, padding, padding, padding, padding); } | 228 | iLocalDef void setPadding1_Widget (iWidget *d, int padding) { setPadding_Widget(d, padding, padding, padding, padding); } |
227 | void setVisualOffset_Widget (iWidget *, int value, uint32_t span, int animFlags); | 229 | void setVisualOffset_Widget (iWidget *, int value, uint32_t span, int animFlags); |
@@ -238,6 +240,7 @@ iAny * removeChild_Widget (iWidget *, iAnyObject *child); /* returns a | |||
238 | iAny * child_Widget (iWidget *, size_t index); /* O(n) */ | 240 | iAny * child_Widget (iWidget *, size_t index); /* O(n) */ |
239 | size_t childIndex_Widget (const iWidget *, const iAnyObject *child); /* O(n) */ | 241 | size_t childIndex_Widget (const iWidget *, const iAnyObject *child); /* O(n) */ |
240 | void arrange_Widget (iWidget *); | 242 | void arrange_Widget (iWidget *); |
243 | void resetSize_Widget (iWidget *); | ||
241 | iBool dispatchEvent_Widget (iWidget *, const SDL_Event *); | 244 | iBool dispatchEvent_Widget (iWidget *, const SDL_Event *); |
242 | iBool processEvent_Widget (iWidget *, const SDL_Event *); | 245 | iBool processEvent_Widget (iWidget *, const SDL_Event *); |
243 | void postCommand_Widget (const iAnyObject *, const char *cmd, ...); | 246 | void postCommand_Widget (const iAnyObject *, const char *cmd, ...); |
diff --git a/src/ui/window.c b/src/ui/window.c index a3675ae5..1b6c5e89 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -875,10 +875,10 @@ static void updateMetrics_Window_(iWindow *d) { | |||
875 | iWidget *appMax = findChild_Widget(winBar, "winbar.max"); | 875 | iWidget *appMax = findChild_Widget(winBar, "winbar.max"); |
876 | iWidget *appClose = findChild_Widget(winBar, "winbar.close"); | 876 | iWidget *appClose = findChild_Widget(winBar, "winbar.close"); |
877 | setPadding_Widget(winBar, 0, gap_UI / 3, 0, 0); | 877 | setPadding_Widget(winBar, 0, gap_UI / 3, 0, 0); |
878 | setSize_Widget(appMin, init_I2(gap_UI * 11.5f, height_Widget(appTitle))); | 878 | setFixedSize_Widget(appMin, init_I2(gap_UI * 11.5f, height_Widget(appTitle))); |
879 | setSize_Widget(appMax, appMin->rect.size); | 879 | setFixedSize_Widget(appMax, appMin->rect.size); |
880 | setSize_Widget(appClose, appMin->rect.size); | 880 | setFixedSize_Widget(appClose, appMin->rect.size); |
881 | setSize_Widget(appIcon, init_I2(appIconSize_(), appMin->rect.size.y)); | 881 | setFixedSize_Widget(appIcon, init_I2(appIconSize_(), appMin->rect.size.y)); |
882 | } | 882 | } |
883 | iWidget *navBar = findChild_Widget(d->root, "navbar"); | 883 | iWidget *navBar = findChild_Widget(d->root, "navbar"); |
884 | iWidget *lock = findChild_Widget(navBar, "navbar.lock"); | 884 | iWidget *lock = findChild_Widget(navBar, "navbar.lock"); |
@@ -888,7 +888,7 @@ static void updateMetrics_Window_(iWindow *d) { | |||
888 | setPadding_Widget(as_Widget(url), 0, gap_UI, 0, gap_UI); | 888 | setPadding_Widget(as_Widget(url), 0, gap_UI, 0, gap_UI); |
889 | navBar->rect.size.y = 0; /* recalculate height based on children (FIXME: shouldn't be needed) */ | 889 | navBar->rect.size.y = 0; /* recalculate height based on children (FIXME: shouldn't be needed) */ |
890 | updateSize_LabelWidget((iLabelWidget *) lock); | 890 | updateSize_LabelWidget((iLabelWidget *) lock); |
891 | setSize_Widget(embedPad, init_I2(width_Widget(lock) + gap_UI / 2, 1)); | 891 | setFixedSize_Widget(embedPad, init_I2(width_Widget(lock) + gap_UI / 2, 1)); |
892 | setContentPadding_InputWidget((iInputWidget *) url, width_Widget(lock) * 0.75, | 892 | setContentPadding_InputWidget((iInputWidget *) url, width_Widget(lock) * 0.75, |
893 | width_Widget(lock) * 0.75); | 893 | width_Widget(lock) * 0.75); |
894 | rightEmbed->rect.pos.y = gap_UI; | 894 | rightEmbed->rect.pos.y = gap_UI; |
@@ -1251,6 +1251,7 @@ static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { | |||
1251 | const iInt2 oldSize = *size; | 1251 | const iInt2 oldSize = *size; |
1252 | SDL_GetRendererOutputSize(d->render, &size->x, &size->y); | 1252 | SDL_GetRendererOutputSize(d->render, &size->x, &size->y); |
1253 | size->y -= d->keyboardHeight; | 1253 | size->y -= d->keyboardHeight; |
1254 | d->root->minSize = *size; | ||
1254 | if (notifyAlways || !isEqual_I2(oldSize, *size)) { | 1255 | if (notifyAlways || !isEqual_I2(oldSize, *size)) { |
1255 | const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); | 1256 | const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); |
1256 | const iBool isVert = (d->place.lastNotifiedSize.y != size->y); | 1257 | const iBool isVert = (d->place.lastNotifiedSize.y != size->y); |
@@ -1465,7 +1466,7 @@ void init_Window(iWindow *d, iRect rect) { | |||
1465 | setupWindow_iOS(d); | 1466 | setupWindow_iOS(d); |
1466 | #endif | 1467 | #endif |
1467 | d->root = new_Widget(); | 1468 | d->root = new_Widget(); |
1468 | setFlags_Widget(d->root, focusRoot_WidgetFlag, iTrue); | 1469 | setFlags_Widget(d->root, fixedSize_WidgetFlag | focusRoot_WidgetFlag, iTrue); |
1469 | d->presentTime = 0.0; | 1470 | d->presentTime = 0.0; |
1470 | d->frameTime = SDL_GetTicks(); | 1471 | d->frameTime = SDL_GetTicks(); |
1471 | d->loadAnimTimer = 0; | 1472 | d->loadAnimTimer = 0; |
@@ -1840,7 +1841,9 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
1840 | insertMacMenus_(); | 1841 | insertMacMenus_(); |
1841 | #endif | 1842 | #endif |
1842 | invalidate_Window_(d); | 1843 | invalidate_Window_(d); |
1844 | updatePreferencesLayout_Widget(findChild_Widget(d->root, "prefs")); | ||
1843 | arrange_Widget(d->root); | 1845 | arrange_Widget(d->root); |
1846 | printTree_Widget(findChild_Widget(d->root, "prefs")); | ||
1844 | } | 1847 | } |
1845 | if (oldHover != hover_Widget()) { | 1848 | if (oldHover != hover_Widget()) { |
1846 | postRefresh_App(); | 1849 | postRefresh_App(); |