summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-05-19 12:08:26 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-05-19 12:08:26 +0300
commitf765b50caed9f2858ddf4e20ba3a6427e4750240 (patch)
tree0546c4d97d705cf8ceb6e807edfa0b05ab128678
parent462e5085392eb78610e9b991ed295f0168a079bb (diff)
parentd2a76230effce8586b7d90beff519e221e744bf7 (diff)
Merge branch 'dev' into work/typesetter
-rw-r--r--README.md2
-rw-r--r--sdl2-macos-ios.diff85
-rw-r--r--sdl2-macos-mouse-scrolling.diff36
-rw-r--r--src/app.c1
-rw-r--r--src/ui/documentwidget.c8
-rw-r--r--src/ui/inputwidget.c3
-rw-r--r--src/ui/mobile.c18
-rw-r--r--src/ui/root.c5
-rw-r--r--src/ui/widget.c52
-rw-r--r--src/ui/window.c7
10 files changed, 147 insertions, 70 deletions
diff --git a/README.md b/README.md
index 3d5ec5ac..f1a62578 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ When using OpenSSL 1.1.1 from Homebrew, you must add its pkgconfig path to your
73 73
74 export PKG_CONFIG_PATH=/opt/homebrew/Cellar/openssl@1.1/1.1.1i/lib/pkgconfig 74 export PKG_CONFIG_PATH=/opt/homebrew/Cellar/openssl@1.1/1.1.1i/lib/pkgconfig
75 75
76Also, SDL's trackpad scrolling behavior on macOS is not optimal for regular GUI apps because it emulates a physical mouse wheel. This may change in a future release of SDL, but at least in 2.0.14 (and earlier) a [small patch](https://git.skyjake.fi/gemini/lagrange/raw/branch/dev/sdl2-macos-mouse-scrolling.diff) is required to allow momentum scrolling to come through as single-pixel mouse wheel events. Note that SDL comes with an Xcode project; use the "Shared Library" target and check that you are doing a Release build. 76Also, SDL's trackpad scrolling behavior on macOS is not optimal for regular GUI apps because it emulates a physical mouse wheel. This may change in a future release of SDL, but at least in 2.0.14 (and earlier) a [small patch](https://git.skyjake.fi/gemini/lagrange/raw/branch/dev/sdl2-macos-ios.diff) is required to allow momentum scrolling to come through as single-pixel mouse wheel events. Note that SDL comes with an Xcode project; use the "Shared Library" target and check that you are doing a Release build.
77 77
78### Compiling on Windows 78### Compiling on Windows
79 79
diff --git a/sdl2-macos-ios.diff b/sdl2-macos-ios.diff
new file mode 100644
index 00000000..04d0f2e5
--- /dev/null
+++ b/sdl2-macos-ios.diff
@@ -0,0 +1,85 @@
1Only in SDL2-2.0.14/src: .DS_Store
2diff -ru SDL2-2.0.14-original/src/events/SDL_mouse.c SDL2-2.0.14/src/events/SDL_mouse.c
3--- SDL2-2.0.14-original/src/events/SDL_mouse.c 2020-12-21 19:44:36.000000000 +0200
4+++ SDL2-2.0.14/src/events/SDL_mouse.c 2021-01-06 18:31:18.000000000 +0200
5@@ -647,8 +647,8 @@
6 event.wheel.preciseX = x;
7 event.wheel.preciseY = y;
8 #endif
9- event.wheel.x = integral_x;
10- event.wheel.y = integral_y;
11+ event.wheel.x = x; //integral_x;
12+ event.wheel.y = y; //integral_y;
13 event.wheel.direction = (Uint32)direction;
14 posted = (SDL_PushEvent(&event) > 0);
15 }
16Only in SDL2-2.0.14/src/video: .DS_Store
17diff -ru SDL2-2.0.14-original/src/video/cocoa/SDL_cocoamouse.m SDL2-2.0.14/src/video/cocoa/SDL_cocoamouse.m
18--- SDL2-2.0.14-original/src/video/cocoa/SDL_cocoamouse.m 2020-12-21 19:44:36.000000000 +0200
19+++ SDL2-2.0.14/src/video/cocoa/SDL_cocoamouse.m 2021-01-06 18:31:18.000000000 +0200
20@@ -423,10 +423,16 @@
21 }
22
23 SDL_MouseID mouseID = mouse->mouseID;
24- CGFloat x = -[event deltaX];
25- CGFloat y = [event deltaY];
26+ CGFloat x = -[event scrollingDeltaX];
27+ CGFloat y = [event scrollingDeltaY];
28 SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL;
29
30+ /* HACK: Make a distinction between precise and imprecise scrolling.
31+ Trackpad seems to be mouseID 0. */
32+ if (![event hasPreciseScrollingDeltas]) {
33+ mouseID = 1;
34+ }
35+
36 if ([event respondsToSelector:@selector(isDirectionInvertedFromDevice)]) {
37 if ([event isDirectionInvertedFromDevice] == YES) {
38 direction = SDL_MOUSEWHEEL_FLIPPED;
39Only in SDL2-2.0.14/src/video/cocoa: SDL_cocoamouse.m.orig
40diff -ru SDL2-2.0.14-original/src/video/uikit/SDL_uikitviewcontroller.h SDL2-2.0.14/src/video/uikit/SDL_uikitviewcontroller.h
41--- SDL2-2.0.14-original/src/video/uikit/SDL_uikitviewcontroller.h 2020-12-21 19:44:36.000000000 +0200
42+++ SDL2-2.0.14/src/video/uikit/SDL_uikitviewcontroller.h 2021-05-17 13:11:13.000000000 +0300
43@@ -58,10 +58,13 @@
44 #if !TARGET_OS_TV
45 - (NSUInteger)supportedInterfaceOrientations;
46 - (BOOL)prefersStatusBarHidden;
47+- (void)setStatusStyle:(UIStatusBarStyle)style;
48+- (UIStatusBarStyle)preferredStatusBarStyle;
49 - (BOOL)prefersHomeIndicatorAutoHidden;
50 - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures;
51
52 @property (nonatomic, assign) int homeIndicatorHidden;
53+@property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
54 #endif
55
56 #if SDL_IPHONE_KEYBOARD
57diff -ru SDL2-2.0.14-original/src/video/uikit/SDL_uikitviewcontroller.m SDL2-2.0.14/src/video/uikit/SDL_uikitviewcontroller.m
58--- SDL2-2.0.14-original/src/video/uikit/SDL_uikitviewcontroller.m 2020-12-21 19:44:36.000000000 +0200
59+++ SDL2-2.0.14/src/video/uikit/SDL_uikitviewcontroller.m 2021-05-17 13:11:58.000000000 +0300
60@@ -104,6 +104,7 @@
61 #endif
62
63 #if !TARGET_OS_TV
64+ self.statusBarStyle = UIStatusBarStyleDefault;
65 SDL_AddHintCallback(SDL_HINT_IOS_HIDE_HOME_INDICATOR,
66 SDL_HideHomeIndicatorHintChanged,
67 (__bridge void *) self);
68@@ -229,6 +230,17 @@
69 return hidden;
70 }
71
72+- (void)setStatusStyle:(UIStatusBarStyle)style
73+{
74+ self.statusBarStyle = style;
75+ [self setNeedsStatusBarAppearanceUpdate];
76+}
77+
78+- (UIStatusBarStyle)preferredStatusBarStyle
79+{
80+ return self.statusBarStyle;
81+}
82+
83 - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
84 {
85 if (self.homeIndicatorHidden >= 0) {
diff --git a/sdl2-macos-mouse-scrolling.diff b/sdl2-macos-mouse-scrolling.diff
deleted file mode 100644
index e2f30c24..00000000
--- a/sdl2-macos-mouse-scrolling.diff
+++ /dev/null
@@ -1,36 +0,0 @@
1diff -r 4f06c06b6d19 src/events/SDL_mouse.c
2--- a/src/events/SDL_mouse.c Wed Aug 05 15:28:51 2020 +0200
3+++ b/src/events/SDL_mouse.c Tue Nov 10 12:16:06 2020 +0200
4@@ -642,8 +642,8 @@
5 event.wheel.preciseX = x;
6 event.wheel.preciseY = y;
7 #endif
8- event.wheel.x = integral_x;
9- event.wheel.y = integral_y;
10+ event.wheel.x = x; //integral_x;
11+ event.wheel.y = y; //integral_y;
12 event.wheel.direction = (Uint32)direction;
13 posted = (SDL_PushEvent(&event) > 0);
14 }
15diff -r 4f06c06b6d19 src/video/cocoa/SDL_cocoamouse.m
16--- a/src/video/cocoa/SDL_cocoamouse.m Wed Aug 05 15:28:51 2020 +0200
17+++ b/src/video/cocoa/SDL_cocoamouse.m Tue Nov 10 12:16:06 2020 +0200
18@@ -424,10 +424,16 @@
19 }
20
21 SDL_MouseID mouseID = mouse->mouseID;
22- CGFloat x = -[event deltaX];
23- CGFloat y = [event deltaY];
24+ CGFloat x = -[event scrollingDeltaX];
25+ CGFloat y = [event scrollingDeltaY];
26 SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL;
27
28+ /* HACK: Make a distinction between precise and imprecise scrolling.
29+ Trackpad seems to be mouseID 0. */
30+ if (![event hasPreciseScrollingDeltas]) {
31+ mouseID = 1;
32+ }
33+
34 if ([event respondsToSelector:@selector(isDirectionInvertedFromDevice)]) {
35 if ([event isDirectionInvertedFromDevice] == YES) {
36 direction = SDL_MOUSEWHEEL_FLIPPED;
diff --git a/src/app.c b/src/app.c
index 73d8f803..3bf9aec1 100644
--- a/src/app.c
+++ b/src/app.c
@@ -732,6 +732,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
732 setupApplication_iOS(); 732 setupApplication_iOS();
733#endif 733#endif
734 init_Keys(); 734 init_Keys();
735 setThemePalette_Color(d->prefs.theme); /* default UI colors */
735 loadPrefs_App_(d); 736 loadPrefs_App_(d);
736 load_Keys(dataDir_App_()); 737 load_Keys(dataDir_App_());
737 d->window = new_Window(d->initialWindowRect); 738 d->window = new_Window(d->initialWindowRect);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 541489c1..9169ea06 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -571,10 +571,11 @@ static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) {
571} 571}
572 572
573static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { 573static int scrollMax_DocumentWidget_(const iDocumentWidget *d) {
574 int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(constAs_Widget(d))) + 574 const iWidget *w = constAs_Widget(d);
575 int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(w)) +
575 (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; 576 (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI;
576 if (d->phoneToolbar) { 577 if (d->phoneToolbar) {
577 sm += size_Root(constAs_Widget(d)->root).y - 578 sm += size_Root(w->root).y -
578 top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar)); 579 top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar));
579 } 580 }
580 return sm; 581 return sm;
@@ -3077,6 +3078,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3077 0, 3078 0,
3078 format_CStr("!open newtab:5 url:%s", cstr_String(linkUrl)) } }, 3079 format_CStr("!open newtab:5 url:%s", cstr_String(linkUrl)) } },
3079 4); 3080 4);
3081 if (deviceType_App() == phone_AppDeviceType) {
3082 removeN_Array(&items, size_Array(&items) - 2, iInvalidSize);
3083 }
3080 } 3084 }
3081 else if (!willUseProxy_App(scheme)) { 3085 else if (!willUseProxy_App(scheme)) {
3082 pushBack_Array( 3086 pushBack_Array(
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 05cd1cc3..0257eda0 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -1162,7 +1162,8 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1162 return iTrue; 1162 return iTrue;
1163 case SDLK_RETURN: 1163 case SDLK_RETURN:
1164 case SDLK_KP_ENTER: 1164 case SDLK_KP_ENTER:
1165 if (mods == KMOD_SHIFT || (~d->inFlags & isUrl_InputWidgetFlag && 1165 if (mods == KMOD_SHIFT || (d->maxLen == 0 &&
1166 ~d->inFlags & isUrl_InputWidgetFlag &&
1166 deviceType_App() != desktop_AppDeviceType)) { 1167 deviceType_App() != desktop_AppDeviceType)) {
1167 pushUndo_InputWidget_(d); 1168 pushUndo_InputWidget_(d);
1168 deleteMarked_InputWidget_(d); 1169 deleteMarked_InputWidget_(d);
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 1f5e9758..6c3a0b32 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -253,7 +253,9 @@ static iAnyObject *addPanelChild_(iWidget *panel, iAnyObject *child, int64_t fla
253 } 253 }
254 } 254 }
255 if ((elementType == toggle_PrefsElement && precedingElementType != toggle_PrefsElement) || 255 if ((elementType == toggle_PrefsElement && precedingElementType != toggle_PrefsElement) ||
256 (elementType == textInput_PrefsElement && precedingElementType != textInput_PrefsElement)) { 256 (elementType == textInput_PrefsElement && precedingElementType != textInput_PrefsElement) ||
257 (elementType == dropdown_PrefsElement && precedingElementType != dropdown_PrefsElement) ||
258 (elementType == radioButton_PrefsElement && precedingElementType == heading_PrefsElement)) {
257 flags |= borderTop_WidgetFlag; 259 flags |= borderTop_WidgetFlag;
258 } 260 }
259 return addChildFlags_Widget(panel, child, flags); 261 return addChildFlags_Widget(panel, child, flags);
@@ -305,6 +307,7 @@ static iWidget *makeValuePadding_(iWidget *value) {
305} 307}
306 308
307static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *value) { 309static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *value) {
310 const iBool isInput = isInstance_Object(value, &Class_InputWidget);
308 iWidget *div = new_Widget(); 311 iWidget *div = new_Widget();
309 setFlags_Widget(div, 312 setFlags_Widget(div,
310 borderBottom_WidgetFlag | arrangeHeight_WidgetFlag | 313 borderBottom_WidgetFlag | arrangeHeight_WidgetFlag |
@@ -313,10 +316,11 @@ static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *val
313 setBackgroundColor_Widget(div, uiBackgroundSidebar_ColorId); 316 setBackgroundColor_Widget(div, uiBackgroundSidebar_ColorId);
314 setPadding_Widget(div, gap_UI, gap_UI, 4 * gap_UI, gap_UI); 317 setPadding_Widget(div, gap_UI, gap_UI, 4 * gap_UI, gap_UI);
315 addChildFlags_Widget(div, iClob(heading), 0); 318 addChildFlags_Widget(div, iClob(heading), 0);
319 setPadding1_Widget(as_Widget(heading), 0);
316 //setFixedSize_Widget(as_Widget(heading), init_I2(-1, height_Widget(value))); 320 //setFixedSize_Widget(as_Widget(heading), init_I2(-1, height_Widget(value)));
317 setFont_LabelWidget(heading, labelFont_()); 321 setFont_LabelWidget(heading, labelFont_());
318 setTextColor_LabelWidget(heading, uiTextStrong_ColorId); 322 setTextColor_LabelWidget(heading, uiTextStrong_ColorId);
319 if (isInstance_Object(value, &Class_InputWidget)) { 323 if (isInput) {
320 addChildFlags_Widget(div, iClob(value), expand_WidgetFlag); 324 addChildFlags_Widget(div, iClob(value), expand_WidgetFlag);
321 } 325 }
322 else if (isInstance_Object(value, &Class_LabelWidget) && 326 else if (isInstance_Object(value, &Class_LabelWidget) &&
@@ -332,6 +336,7 @@ static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *val
332 addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag); 336 addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag);
333 addChild_Widget(div, iClob(value)); 337 addChild_Widget(div, iClob(value));
334 } 338 }
339 printTree_Widget(div);
335 return div; 340 return div;
336} 341}
337 342
@@ -374,7 +379,9 @@ void finalizeSheet_Mobile(iWidget *sheet) {
374 postRefresh_App(); 379 postRefresh_App();
375 return; 380 return;
376 } 381 }
377 /* Landscape Layout    Portrait Layout 382 /* TODO: In portrait, top panel and detail stack are all stacked together.
383
384 Landscape Layout    Portrait Layout
378    385   
379 ┌─────────┬──────Detail─Stack─────┐    ┌─────────┬ ─ ─ ─ ─ ┐ 386 ┌─────────┬──────Detail─Stack─────┐    ┌─────────┬ ─ ─ ─ ─ ┐
380 │ │┌───────────────────┐ │    │ │Detail 387 │ │┌───────────────────┐ │    │ │Detail
@@ -616,10 +623,9 @@ void finalizeSheet_Mobile(iWidget *sheet) {
616 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); 623 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
617 iLabelWidget *aboutButton = addChildFlags_Widget(topPanel, 624 iLabelWidget *aboutButton = addChildFlags_Widget(topPanel,
618 iClob(makePanelButton_(planet_Icon " ${menu.about}", "panel.open")), 625 iClob(makePanelButton_(planet_Icon " ${menu.about}", "panel.open")),
619 chevron_WidgetFlag); 626 chevron_WidgetFlag | borderTop_WidgetFlag);
620 addChildFlags_Widget(topPanel, 627 addChildFlags_Widget(topPanel,
621 iClob(makePanelButton_(info_Icon " ${menu.help}", "!open url:about:help")), 628 iClob(makePanelButton_(info_Icon " ${menu.help}", "!open url:about:help")), 0);
622 borderTop_WidgetFlag);
623 /* The About panel. */ { 629 /* The About panel. */ {
624 iWidget *panel = addChildPanel_(detailStack, aboutButton, NULL); 630 iWidget *panel = addChildPanel_(detailStack, aboutButton, NULL);
625 iString *msg = collectNew_String(); 631 iString *msg = collectNew_String();
diff --git a/src/ui/root.c b/src/ui/root.c
index 8c98bdd3..9ed62711 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -776,17 +776,12 @@ static iBool handleSearchBarCommands_(iWidget *searchBar, const char *cmd) {
776 else if (equal_Command(cmd, "focus.gained")) { 776 else if (equal_Command(cmd, "focus.gained")) {
777 if (pointer_Command(cmd) == findChild_Widget(searchBar, "find.input")) { 777 if (pointer_Command(cmd) == findChild_Widget(searchBar, "find.input")) {
778 if (!isVisible_Widget(searchBar)) { 778 if (!isVisible_Widget(searchBar)) {
779// setFlags_Widget(searchBar, hidden_WidgetFlag | disabled_WidgetFlag, iFalse);
780// arrange_Widget(root_Widget(searchBar));
781// postRefresh_App();
782 showCollapsed_Widget(searchBar, iTrue); 779 showCollapsed_Widget(searchBar, iTrue);
783 } 780 }
784 } 781 }
785 } 782 }
786 else if (equal_Command(cmd, "find.close")) { 783 else if (equal_Command(cmd, "find.close")) {
787 if (isVisible_Widget(searchBar)) { 784 if (isVisible_Widget(searchBar)) {
788 //setFlags_Widget(searchBar, hidden_WidgetFlag | disabled_WidgetFlag, iTrue);
789 //arrange_Widget(searchBar->parent);
790 showCollapsed_Widget(searchBar, iFalse); 785 showCollapsed_Widget(searchBar, iFalse);
791 if (isFocused_Widget(findChild_Widget(searchBar, "find.input"))) { 786 if (isFocused_Widget(findChild_Widget(searchBar, "find.input"))) {
792 setFocus_Widget(NULL); 787 setFocus_Widget(NULL);
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 3439fb1b..43bbe56e 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -314,50 +314,48 @@ static void printf_Widget_(const iWidget *d, const char *format, ...) {
314 delete_String(msg); 314 delete_String(msg);
315} 315}
316 316
317static void setWidth_Widget_(iWidget *d, int width) { 317static iBool setWidth_Widget_(iWidget *d, int width) {
318 iAssert(width >= 0); 318 iAssert(width >= 0);
319 TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x); 319 TRACE(d, "attempt to set width to %d (current: %d, min width: %d)", width, d->rect.size.x, d->minSize.x);
320 width = iMax(width, d->minSize.x); 320 width = iMax(width, d->minSize.x);
321 if (~d->flags & fixedWidth_WidgetFlag) { //} || d->flags & collapse_WidgetFlag) { 321 if (~d->flags & fixedWidth_WidgetFlag) {
322 if (d->rect.size.x != width) { 322 if (d->rect.size.x != width) {
323 d->rect.size.x = width; 323 d->rect.size.x = width;
324 TRACE(d, "width has changed to %d", width); 324 TRACE(d, "width has changed to %d", width);
325 if (class_Widget(d)->sizeChanged) { 325 if (class_Widget(d)->sizeChanged) {
326 const int oldHeight = d->rect.size.y; 326 const int oldHeight = d->rect.size.y;
327 class_Widget(d)->sizeChanged(d); 327 class_Widget(d)->sizeChanged(d);
328 if (d->rect.size.y != oldHeight) {
329 TRACE(d, "sizeChanged() cuased height change to %d; redoing parent", d->rect.size.y);
330 /* Widget updated its height. */
331 arrange_Widget_(d->parent);
332 TRACE(d, "parent layout redone");
333 }
334 } 328 }
329 return iTrue;
335 } 330 }
336 } 331 }
337 else { 332 else {
338 TRACE(d, "changing width not allowed; flags: %x", d->flags); 333 TRACE(d, "changing width not allowed; flags: %x", d->flags);
339 } 334 }
335 return iFalse;
340} 336}
341 337
342static void setHeight_Widget_(iWidget *d, int height) { 338static iBool setHeight_Widget_(iWidget *d, int height) {
343 iAssert(height >= 0); 339 iAssert(height >= 0);
344 if (d->sizeRef) { 340 if (d->sizeRef) {
345 return; /* height defined by another widget */ 341 return; /* height defined by another widget */
346 } 342 }
347 TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y); 343 TRACE(d, "attempt to set height to %d (current: %d, min height: %d)", height, d->rect.size.y, d->minSize.y);
348 height = iMax(height, d->minSize.y); 344 height = iMax(height, d->minSize.y);
349 if (~d->flags & fixedHeight_WidgetFlag) { //} || d->flags & collapse_WidgetFlag) { 345 if (~d->flags & fixedHeight_WidgetFlag) {
350 if (d->rect.size.y != height) { 346 if (d->rect.size.y != height) {
351 d->rect.size.y = height; 347 d->rect.size.y = height;
352 TRACE(d, "height has changed to %d", height); 348 TRACE(d, "height has changed to %d", height);
353 if (class_Widget(d)->sizeChanged) { 349 if (class_Widget(d)->sizeChanged) {
354 class_Widget(d)->sizeChanged(d); 350 class_Widget(d)->sizeChanged(d);
355 } 351 }
352 return iTrue;
356 } 353 }
357 } 354 }
358 else { 355 else {
359 TRACE(d, "changing height not allowed; flags: %x", d->flags); 356 TRACE(d, "changing height not allowed; flags: %x", d->flags);
360 } 357 }
358 return iFalse;
361} 359}
362 360
363iLocalDef iRect innerRect_Widget_(const iWidget *d) { 361iLocalDef iRect innerRect_Widget_(const iWidget *d) {
@@ -578,6 +576,12 @@ static void arrange_Widget_(iWidget *d) {
578 TRACE(d, "...done changing child sizes (EVEN mode)"); 576 TRACE(d, "...done changing child sizes (EVEN mode)");
579 } 577 }
580 } 578 }
579 /* Children arrange themselves. */ {
580 iForEach(ObjectList, i, d->children) {
581 iWidget *child = as_Widget(i.object);
582 arrange_Widget_(child);
583 }
584 }
581 /* Resize the expanding children to fill the remaining available space. */ 585 /* Resize the expanding children to fill the remaining available space. */
582 if (expCount > 0 && (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag))) { 586 if (expCount > 0 && (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag))) {
583 TRACE(d, "%d expanding children, resizing them %s...", expCount, 587 TRACE(d, "%d expanding children, resizing them %s...", expCount,
@@ -600,16 +604,20 @@ static void arrange_Widget_(iWidget *d) {
600 TRACE(d, "child %p size is not arranged", child); 604 TRACE(d, "child %p size is not arranged", child);
601 continue; 605 continue;
602 } 606 }
607 iBool sizeChanged = iFalse;
603 if (child->flags & expand_WidgetFlag) { 608 if (child->flags & expand_WidgetFlag) {
604 if (d->flags & arrangeHorizontal_WidgetFlag) { 609 if (d->flags & arrangeHorizontal_WidgetFlag) {
605 setWidth_Widget_(child, avail.x); 610 sizeChanged |= setWidth_Widget_(child, avail.x);
606 setHeight_Widget_(child, height_Rect(innerRect)); 611 sizeChanged |= setHeight_Widget_(child, height_Rect(innerRect));
607 } 612 }
608 else if (d->flags & arrangeVertical_WidgetFlag) { 613 else if (d->flags & arrangeVertical_WidgetFlag) {
609 setWidth_Widget_(child, width_Rect(innerRect)); 614 sizeChanged |= setWidth_Widget_(child, width_Rect(innerRect));
610 setHeight_Widget_(child, avail.y); 615 sizeChanged |= setHeight_Widget_(child, avail.y);
611 } 616 }
612 } 617 }
618 if (sizeChanged) {
619 arrange_Widget_(child); /* its children may need rearranging */
620 }
613 } 621 }
614 } 622 }
615 if (d->flags & resizeChildrenToWidestChild_WidgetFlag) { 623 if (d->flags & resizeChildrenToWidestChild_WidgetFlag) {
@@ -618,7 +626,9 @@ static void arrange_Widget_(iWidget *d) {
618 iForEach(ObjectList, i, d->children) { 626 iForEach(ObjectList, i, d->children) {
619 iWidget *child = as_Widget(i.object); 627 iWidget *child = as_Widget(i.object);
620 if (isArrangedSize_Widget_(child)) { 628 if (isArrangedSize_Widget_(child)) {
621 setWidth_Widget_(child, widest); 629 if (setWidth_Widget_(child, widest)) {
630 arrange_Widget_(child); /* its children may need rearranging */
631 }
622 } 632 }
623 else { 633 else {
624 TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child, 634 TRACE(d, "child %p cannot be resized (parentCannotResize: %d)", child,
@@ -633,7 +643,6 @@ static void arrange_Widget_(iWidget *d) {
633 d->flags & arrangeVertical_WidgetFlag ? " vert" : ""); 643 d->flags & arrangeVertical_WidgetFlag ? " vert" : "");
634 iForEach(ObjectList, i, d->children) { 644 iForEach(ObjectList, i, d->children) {
635 iWidget *child = as_Widget(i.object); 645 iWidget *child = as_Widget(i.object);
636 arrange_Widget_(child);
637 if (isCollapsed_Widget_(child) || !isArrangedPos_Widget_(child)) { 646 if (isCollapsed_Widget_(child) || !isArrangedPos_Widget_(child)) {
638 TRACE(d, "child %p arranging prohibited", child); 647 TRACE(d, "child %p arranging prohibited", child);
639 continue; 648 continue;
@@ -726,13 +735,15 @@ static void resetArrangement_Widget_(iWidget *d) {
726 if (d->flags & arrangeHorizontal_WidgetFlag) { 735 if (d->flags & arrangeHorizontal_WidgetFlag) {
727 child->rect.pos.x = 0; 736 child->rect.pos.x = 0;
728 } 737 }
729 if (d->flags & resizeWidthOfChildren_WidgetFlag && child->flags & expand_WidgetFlag) { 738 if (d->flags & resizeWidthOfChildren_WidgetFlag && child->flags & expand_WidgetFlag &&
739 ~child->flags & fixedWidth_WidgetFlag) {
730 child->rect.size.x = 0; 740 child->rect.size.x = 0;
731 } 741 }
732 if (d->flags & arrangeVertical_WidgetFlag) { 742 if (d->flags & arrangeVertical_WidgetFlag) {
733 child->rect.pos.y = 0; 743 child->rect.pos.y = 0;
734 } 744 }
735 if (d->flags & resizeHeightOfChildren_WidgetFlag && child->flags & expand_WidgetFlag) { 745 if (d->flags & resizeHeightOfChildren_WidgetFlag && child->flags & expand_WidgetFlag &&
746 ~child->flags & fixedHeight_WidgetFlag) {
736 child->rect.size.y = 0; 747 child->rect.size.y = 0;
737 } 748 }
738 } 749 }
@@ -741,6 +752,11 @@ static void resetArrangement_Widget_(iWidget *d) {
741 752
742void arrange_Widget(iWidget *d) { 753void arrange_Widget(iWidget *d) {
743 if (d) { 754 if (d) {
755#if !defined (NDEBUG)
756 if (tracing_) {
757 puts("\n==== NEW WIDGET ARRANGEMENT ====\n");
758 }
759#endif
744 resetArrangement_Widget_(d); /* back to initial default sizes */ 760 resetArrangement_Widget_(d); /* back to initial default sizes */
745 arrange_Widget_(d); 761 arrange_Widget_(d);
746 } 762 }
diff --git a/src/ui/window.c b/src/ui/window.c
index 6b9956ea..87db2f3e 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -59,7 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
59 59
60static iWindow *theWindow_ = NULL; 60static iWindow *theWindow_ = NULL;
61 61
62#if defined (iPlatformApple) || defined (iPlatformLinux) 62#if defined (iPlatformApple) || defined (iPlatformLinux) || defined (iPlatformOther)
63static float initialUiScale_ = 1.0f; 63static float initialUiScale_ = 1.0f;
64#else 64#else
65static float initialUiScale_ = 1.1f; 65static float initialUiScale_ = 1.1f;
@@ -1199,6 +1199,11 @@ void swapRoots_Window(iWindow *d) {
1199 1199
1200void setSplitMode_Window(iWindow *d, int splitFlags) { 1200void setSplitMode_Window(iWindow *d, int splitFlags) {
1201 const int splitMode = splitFlags & mode_WindowSplit; 1201 const int splitMode = splitFlags & mode_WindowSplit;
1202 if (deviceType_App() == phone_AppDeviceType) {
1203 /* There isn't enough room on the phone. */
1204 /* TODO: Maybe in landscape only? */
1205 return;
1206 }
1202 iAssert(current_Root() == NULL); 1207 iAssert(current_Root() == NULL);
1203 if (d->splitMode != splitMode) { 1208 if (d->splitMode != splitMode) {
1204 int oldCount = numRoots_Window(d); 1209 int oldCount = numRoots_Window(d);