=> 7d43fe3071b9ba333c5033e94285f67f54606b9c
[1mdiff --git a/src/app.c b/src/app.c[m [1mindex fb29617e..fbd92a06 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -283,6 +283,8 @@[m [mstatic iString *serializePrefs_App_(const iApp *d) {[m { "prefs.archive.openindex", &d->prefs.openArchiveIndexPages },[m { "prefs.biglede", &d->prefs.bigFirstParagraph },[m { "prefs.blink", &d->prefs.blinkingCursor },[m [32m+[m[32m { "prefs.bottomnavbar", &d->prefs.bottomNavBar },[m [32m+[m[32m { "prefs.bottomtabbar", &d->prefs.bottomTabBar },[m { "prefs.boldlink.dark", &d->prefs.boldLinkDark },[m { "prefs.boldlink.light", &d->prefs.boldLinkLight },[m { "prefs.boldlink.visited", &d->prefs.boldLinkVisited },[m [36m@@ -1302,8 +1304,9 @@[m [mstatic void clearCache_App_(void) {[m }[m [m iObjectList *listAllDocuments_App(void) {[m [31m- iWindow *oldWindow = get_Window();[m [31m- iObjectList *allDocs = new_ObjectList();[m [32m+[m[32m iWindow *oldWindow = get_Window();[m [32m+[m[32m iRoot *oldRoot = current_Root();[m [32m+[m[32m iObjectList *allDocs = new_ObjectList();[m iConstForEach(PtrArray, window, mainWindows_App()) {[m setCurrent_Window(window.ptr);[m iObjectList *docs = listDocuments_App(NULL);[m [36m@@ -1313,6 +1316,7 @@[m [miObjectList *listAllDocuments_App(void) {[m iRelease(docs);[m }[m setCurrent_Window(oldWindow);[m [32m+[m[32m setCurrent_Root(oldRoot);[m return allDocs;[m }[m [m [1mdiff --git a/src/prefs.c b/src/prefs.c[m [1mindex 995da0bc..3ec7448a 100644[m [1m--- a/src/prefs.c[m [1m+++ b/src/prefs.c[m [36m@@ -58,6 +58,8 @@[m [mvoid init_Prefs(iPrefs *d) {[m d->sideIcon = iTrue;[m d->hideToolbarOnScroll = iTrue;[m d->blinkingCursor = iTrue;[m [32m+[m[32m d->bottomNavBar = iTrue;[m [32m+[m[32m d->bottomTabBar = iTrue;[m d->pinSplit = 1;[m d->time24h = iTrue;[m d->returnKey = default_ReturnKeyBehavior;[m [1mdiff --git a/src/prefs.h b/src/prefs.h[m [1mindex 7cbbdb4c..7f4509de 100644[m [1m--- a/src/prefs.h[m [1m+++ b/src/prefs.h[m [36m@@ -66,6 +66,8 @@[m [menum iPrefsBool {[m hideToolbarOnScroll_PrefsBool,[m [m blinkingCursor_PrefsBool,[m [32m+[m[32m bottomNavBar_PrefsBool,[m [32m+[m[32m bottomTabBar_PrefsBool,[m [m /* Document presentation */[m sideIcon_PrefsBool,[m [36m@@ -77,9 +79,9 @@[m [menum iPrefsBool {[m smoothScrolling_PrefsBool,[m loadImageInsteadOfScrolling_PrefsBool,[m openDataUrlImagesOnLoad_PrefsBool,[m [32m+[m[41m [m collapsePreOnLoad_PrefsBool,[m openArchiveIndexPages_PrefsBool,[m [31m- [m addBookmarksToBottom_PrefsBool,[m warnAboutMissingGlyphs_PrefsBool,[m [m [36m@@ -98,6 +100,7 @@[m [menum iPrefsBool {[m justifyParagraph_PrefsBool,[m quoteIcon_PrefsBool,[m centerShortDocs_PrefsBool,[m [32m+[m[41m [m plainTextWrap_PrefsBool,[m [m /* Meta */[m [36m@@ -122,6 +125,8 @@[m [mstruct Impl_Prefs {[m iBool hideToolbarOnScroll;[m [m iBool blinkingCursor;[m [32m+[m[32m iBool bottomNavBar;[m [32m+[m[32m iBool bottomTabBar;[m [m /* Document presentation */[m iBool sideIcon;[m [36m@@ -133,9 +138,9 @@[m [mstruct Impl_Prefs {[m iBool smoothScrolling;[m iBool loadImageInsteadOfScrolling;[m iBool openDataUrlImagesOnLoad;[m [31m- iBool collapsePreOnLoad;[m [31m- iBool openArchiveIndexPages;[m [m [32m+[m[32m iBool collapsePreOnLoad;[m [32m+[m[32m iBool openArchiveIndexPages;[m[41m [m iBool addBookmarksToBottom;[m iBool warnAboutMissingGlyphs;[m [m [36m@@ -154,6 +159,7 @@[m [mstruct Impl_Prefs {[m iBool justifyParagraph;[m iBool quoteIcon;[m iBool centerShortDocs;[m [32m+[m[41m [m iBool plainTextWrap;[m };[m };[m [1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex d0e1bd91..d0d565d7 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -881,7 +881,9 @@[m [mstatic void updateVisible_DocumentView_(iDocumentView *d) {[m /* After scrolling/resizing stops, begin pre-rendering the visbuf contents. */ {[m removeTicker_App(prerender_DocumentWidget_, d->owner);[m remove_Periodic(periodic_App(), d);[m [31m- add_Periodic(periodic_App(), d->owner, "document.render");[m [32m+[m[32m if (~d->owner->flags & animationPlaceholder_DocumentWidgetFlag) {[m [32m+[m[32m add_Periodic(periodic_App(), d->owner, "document.render");[m [32m+[m[32m }[m }[m }[m [m [36m@@ -3594,12 +3596,12 @@[m [mstatic iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) {[m static void setupSwipeOverlay_DocumentWidget_(iDocumentWidget *d, iWidget *overlay) {[m iWidget *w = as_Widget(d);[m iWidget *swipeParent = swipeParent_DocumentWidget_(d);[m [32m+[m[32m iAssert(overlay);[m /* The target takes the old document and jumps on top. */[m overlay->rect.pos = windowToInner_Widget(swipeParent, innerToWindow_Widget(w, zero_I2()));[m /* Note: `innerToWindow_Widget` does not apply visual offset. */[m overlay->rect.size = w->rect.size;[m setFlags_Widget(overlay, fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue);[m [31m-// swap_DocumentWidget_(target, d->doc, d);[m setFlags_Widget(as_Widget(d), refChildrenOffset_WidgetFlag, iTrue);[m as_Widget(d)->offsetRef = swipeParent;[m /* `overlay` animates off the screen to the right. */[m [36m@@ -3623,11 +3625,15 @@[m [mstatic void setupSwipeOverlay_DocumentWidget_(iDocumentWidget *d, iWidget *overl[m [m static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {[m /* TODO: Cleanup[m [32m+[m[41m [m If DocumentWidget is refactored to split the document presentation from state[m and request management (a new DocumentView class), plain views could be used for this[m animation without having to mess with the complete state of the DocumentWidget. That[m seems like a less error-prone approach -- the current implementation will likely break[m down (again) if anything is changed in the document internals.[m [32m+[m[41m [m [32m+[m[32m 2022-03-16: Yeah, something did break, again. "swipeout" is not found if the tab bar[m [32m+[m[32m is moved to the bottom, when swiping back.[m */[m iWidget *w = as_Widget(d);[m /* The swipe animation is implemented in a rather complex way. It utilizes both cached[m [1mdiff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c[m [1mindex a4f5498a..afd9c10e 100644[m [1m--- a/src/ui/lookupwidget.c[m [1m+++ b/src/ui/lookupwidget.c[m [36m@@ -657,7 +657,7 @@[m [mstatic iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {[m else if (isResize_UserEvent(ev) || equal_Command(cmd, "keyboard.changed") ||[m (equal_Command(cmd, "layout.changed") &&[m equal_Rangecc(range_Command(cmd, "id"), "navbar"))) {[m [31m- /* Position the lookup popup under the URL bar. */ {[m [32m+[m[32m /* Position the lookup popup in relation to the URL bar. */ {[m iRoot *root = w->root;[m iWidget *url = findChild_Widget(root->widget, "url");[m const int minWidth = iMin(120 * gap_UI, width_Rect(safeRect_Root(root)));[m [36m@@ -667,19 +667,28 @@[m [mstatic iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {[m extraWidth = minWidth - urlWidth;[m }[m const iRect navBarBounds = bounds_Widget(findChild_Widget(root->widget, "navbar"));[m [32m+[m[32m const iBool atBottom = prefs_App()->bottomNavBar;[m setFixedSize_Widget([m w,[m init_I2(width_Widget(url) + extraWidth,[m [31m- (bottom_Rect(rect_Root(root)) - bottom_Rect(navBarBounds)) / 2));[m [31m- setPos_Widget(w,[m [31m- windowToLocal_Widget(w,[m [31m- max_I2(zero_I2(),[m [31m- addX_I2(bottomLeft_Rect(bounds_Widget(url)),[m [31m- -extraWidth / 2))));[m [32m+[m[32m (atBottom ? top_Rect(navBarBounds)[m [32m+[m[32m : (bottom_Rect(rect_Root(root)) - bottom_Rect(navBarBounds))) /[m [32m+[m[32m 2));[m [32m+[m[32m const iInt2 topLeft = atBottom[m [32m+[m[32m ? addY_I2(topLeft_Rect(bounds_Widget(url)), -w->rect.size.y)[m [32m+[m[32m : bottomLeft_Rect(bounds_Widget(url));[m [32m+[m[32m setPos_Widget([m [32m+[m[32m w, windowToLocal_Widget(w, max_I2(zero_I2(), addX_I2(topLeft, -extraWidth / 2))));[m #if defined(iPlatformMobile)[m /* TODO: Check this again. */[m /* Adjust height based on keyboard size. */ {[m [31m- w->rect.size.y = bottom_Rect(visibleRect_Root(root)) - top_Rect(bounds_Widget(w));[m [32m+[m[32m if (!atBottom) {[m [32m+[m[32m w->rect.size.y = bottom_Rect(visibleRect_Root(root)) - top_Rect(bounds_Widget(w));[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m w->rect.pos = windowToLocal_Widget(w, visibleRect_Root(root).pos);[m [32m+[m[32m w->rect.size.y = height_Rect(visibleRect_Root(root)) - height_Rect(navBarBounds);[m [32m+[m[32m }[m # if defined (iPlatformAppleMobile)[m if (deviceType_App() == phone_AppDeviceType) {[m float l = 0.0f, r = 0.0f;[m [36m@@ -738,7 +747,7 @@[m [mstatic iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {[m setFocus_Widget(url);[m return iTrue;[m case SDLK_UP:[m [31m- if (!moveCursor_LookupWidget_(d, -1)) {[m [32m+[m[32m if (!moveCursor_LookupWidget_(d, -1) && !prefs_App()->bottomNavBar) {[m setCursor_LookupWidget_(d, iInvalidPos);[m setFocus_Widget(url);[m }[m [36m@@ -767,9 +776,10 @@[m [mstatic iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {[m }[m /* Focus switching between URL bar and lookup results. */[m if (isVisible_Widget(w)) {[m [31m- if (((key == SDLK_DOWN && !mods) || key == SDLK_TAB) &&[m [31m- focus_Widget() == findWidget_App("url") &&[m [31m- numItems_ListWidget(d->list)) {[m [32m+[m[32m if (((!mods && ((key == SDLK_DOWN && !prefs_App()->bottomNavBar) ||[m [32m+[m[32m (key == SDLK_UP && prefs_App()->bottomNavBar))) ||[m [32m+[m[32m key == SDLK_TAB) &&[m [32m+[m[32m focus_Widget() == findWidget_App("url") && numItems_ListWidget(d->list)) {[m setCursor_LookupWidget_(d, 1); /* item 0 is always the first heading */[m setFocus_Widget(w);[m return iTrue;[m [1mdiff --git a/src/ui/mobile.c b/src/ui/mobile.c[m [1mindex 19d39bf1..3b47d4a1 100644[m [1m--- a/src/ui/mobile.c[m [1m+++ b/src/ui/mobile.c[m [36m@@ -1027,6 +1027,17 @@[m [mvoid setupSheetTransition_Mobile(iWidget *sheet, int flags) {[m }[m }[m [m [32m+[m[32mint leftSafeInset_Mobile(void) {[m [32m+[m[32m#if defined (iPlatformAppleMobile)[m [32m+[m[32m float left;[m [32m+[m[32m safeAreaInsets_iOS(&left, NULL, NULL, NULL);[m [32m+[m[32m return iRound(left);[m [32m+[m[32m#else[m [32m+[m[32m return 0;[m [32m+[m[32m#endif[m [32m+[m[32m}[m [32m+[m [32m+[m int bottomSafeInset_Mobile(void) {[m #if defined (iPlatformAppleMobile)[m float bot;[m [1mdiff --git a/src/ui/mobile.h b/src/ui/mobile.h[m [1mindex a719f20b..79986771 100644[m [1m--- a/src/ui/mobile.h[m [1m+++ b/src/ui/mobile.h[m [36m@@ -68,4 +68,5 @@[m [menum iTransitionDir {[m void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming);[m void setupSheetTransition_Mobile (iWidget *sheet, int flags);[m [m [32m+[m[32mint leftSafeInset_Mobile (void);[m int bottomSafeInset_Mobile (void);[m [1mdiff --git a/src/ui/root.c b/src/ui/root.c[m [1mindex a7c39e22..bff2dbb9 100644[m [1m--- a/src/ui/root.c[m [1m+++ b/src/ui/root.c[m [36m@@ -241,6 +241,8 @@[m [mstatic int loadAnimIndex_ = 0;[m [m static iRoot * activeRoot_ = NULL;[m [m [32m+[m[32mstatic void setupMovableElements_Root_ (iRoot *);[m [32m+[m iDefineTypeConstruction(Root)[m iDefineAudienceGetter(Root, visualOffsetsChanged)[m [m [36m@@ -521,6 +523,7 @@[m [mstatic iBool handleRootCommands_(iWidget *root, const char *cmd) {[m addChildPos_Widget(findChild_Widget(root, "tabs.content"), iClob(sidebar), front_WidgetAddPos); [m setWidth_SidebarWidget(sidebar, 73.0f);[m setFlags_Widget(as_Widget(sidebar), fixedHeight_WidgetFlag | fixedPosition_WidgetFlag, iFalse);[m [32m+[m[32m showToolbar_Root(root->root, iFalse);[m }[m else {[m addChild_Widget(root, iClob(sidebar));[m [36m@@ -532,26 +535,8 @@[m [mstatic iBool handleRootCommands_(iWidget *root, const char *cmd) {[m setMidHeight_SidebarWidget(sidebar, midHeight);[m setFixedSize_Widget(as_Widget(sidebar), init_I2(-1, midHeight));[m setPos_Widget(as_Widget(sidebar), init_I2(0, height_Widget(root) - midHeight));[m [32m+[m[32m showToolbar_Root(root->root, iTrue);[m }[m [31m-#if 0[m [31m- iSidebarWidget *sidebar = findChild_Widget(root, "sidebar");[m [31m- iSidebarWidget *sidebar2 = findChild_Widget(root, "sidebar2");[m [31m- setFlags_Widget(findChild_Widget(as_Widget(sidebar), "buttons"),[m [31m- borderTop_WidgetFlag,[m [31m- isPortrait_App());[m [31m- if (isLandscape_App()) {[m [31m- addChildPos_Widget(findChild_Widget(root, "tabs.content"), iClob(sidebar), front_WidgetAddPos);[m [31m- setWidth_SidebarWidget(sidebar, 73.0f);[m [31m- if (isVisible_Widget(findWidget_App("sidebar2"))) {[m [31m- postCommand_App("sidebar2.toggle");[m [31m- }[m [31m- }[m [31m- else {[m [31m- addChildPos_Widget(findChild_Widget(root, "stack"), iClob(sidebar), back_WidgetAddPos);[m [31m- setWidth_SidebarWidget(sidebar, (float) width_Widget(root) / (float) gap_UI);[m [31m- setWidth_SidebarWidget(sidebar2, (float) width_Widget(root) / (float) gap_UI);[m [31m- }[m [31m-#endif[m return iFalse;[m }[m else if (equal_Command(cmd, "root.arrange")) {[m [36m@@ -651,7 +636,7 @@[m [mstatic uint32_t updateReloadAnimation_Root_(uint32_t interval, void *root) {[m }[m [m static void setReloadLabel_Root_(iRoot *d, iBool animating) {[m [31m- const iBool isMobile = deviceType_App() != desktop_AppDeviceType;[m [32m+[m[32m// const iBool isMobile = deviceType_App() != desktop_AppDeviceType;[m iLabelWidget *label = findChild_Widget(d->widget, "reload");[m updateTextCStr_LabelWidget([m label, animating ? loadAnimationCStr_() : (/*isMobile ? pageMenuCStr_ :*/ reloadCStr_));[m [36m@@ -691,22 +676,21 @@[m [mvoid updatePadding_Root(iRoot *d) {[m [m void updateToolbarColors_Root(iRoot *d) {[m #if defined (iPlatformMobile)[m [31m- iWidget *toolBar = findChild_Widget(d->widget, "toolbar");[m [31m- if (toolBar) {[m [31m- const iBool isSidebarVisible =[m [31m- isVisible_Widget(findChild_Widget(d->widget, "sidebar")) ||[m [31m- isVisible_Widget(findChild_Widget(d->widget, "sidebar2"));[m [31m- const int bg = isSidebarVisible ? uiBackgroundSidebar_ColorId :[m [31m- tmBannerBackground_ColorId;[m [31m- setBackgroundColor_Widget(toolBar, bg);[m [32m+[m[32m iWidget *bottomBar = findChild_Widget(d->widget, "bottombar");[m [32m+[m[32m if (bottomBar) {[m [32m+[m[32m iWidget *toolBar = findChild_Widget(bottomBar, "toolbar");[m [32m+[m[32m const iWidget *tabs = findChild_Widget(d->widget, "doctabs");[m [32m+[m[32m const size_t numPages = childCount_Widget(findChild_Widget(tabs, "tabs.pages"));[m [32m+[m[32m const iBool useThemeColors = !prefs_App()->bottomNavBar &&[m [32m+[m[32m !(prefs_App()->bottomTabBar && numPages > 1);[m [32m+[m[32m const int bg = useThemeColors ? tmBannerBackground_ColorId : uiBackground_ColorId;[m [32m+[m[32m setBackgroundColor_Widget(bottomBar, bg);[m iForEach(ObjectList, i, children_Widget(toolBar)) {[m [31m-// iLabelWidget *btn = i.object;[m [31m- setTextColor_LabelWidget(i.object, isSidebarVisible ? uiTextDim_ColorId :[m [31m- tmBannerIcon_ColorId);[m [32m+[m[32m setTextColor_LabelWidget(i.object, useThemeColors ? tmBannerIcon_ColorId : uiTextDim_ColorId);[m setBackgroundColor_Widget(i.object, bg); /* using noBackground, but ident has outline */[m }[m setTextColor_LabelWidget(findChild_Widget(toolBar, "toolbar.name"),[m [31m- isSidebarVisible ? uiTextDim_ColorId : tmBannerIcon_ColorId);[m [32m+[m[32m useThemeColors ? tmBannerIcon_ColorId : uiTextDim_ColorId);[m }[m #else[m iUnused(d);[m [36m@@ -736,17 +720,19 @@[m [mvoid notifyVisualOffsetChange_Root(iRoot *d) {[m void dismissPortraitPhoneSidebars_Root(iRoot *d) {[m if (deviceType_App() == phone_AppDeviceType && isPortrait_App()) {[m iWidget *sidebar = findChild_Widget(d->widget, "sidebar");[m [31m- iWidget *sidebar2 = findChild_Widget(d->widget, "sidebar2");[m [32m+[m[32m// iWidget *sidebar2 = findChild_Widget(d->widget, "sidebar2");[m if (isVisible_Widget(sidebar)) {[m postCommand_App("sidebar.toggle");[m setVisualOffset_Widget(sidebar, height_Widget(sidebar), 250, easeIn_AnimFlag);[m }[m [32m+[m[32m#if 0[m if (isVisible_Widget(sidebar2)) {[m postCommand_App("sidebar2.toggle");[m setVisualOffset_Widget(sidebar2, height_Widget(sidebar2), 250, easeIn_AnimFlag);[m }[m // setFlags_Widget(findWidget_App("toolbar.ident"), noBackground_WidgetFlag, iTrue);[m // setFlags_Widget(findWidget_App("toolbar.view"), noBackground_WidgetFlag, iTrue);[m [32m+[m[32m#endif[m }[m }[m [m [36m@@ -799,14 +785,23 @@[m [miBool isNarrow_Root(const iRoot *d) {[m return width_Rect(safeRect_Root(d)) / gap_UI < 140;[m }[m [m [32m+[m[32mstatic void updateNavBarParent_(iWidget *navBar) {[m [32m+[m[32m /* The navbar can be */[m [32m+[m[32m}[m [32m+[m static void updateNavBarSize_(iWidget *navBar) {[m const iBool isPhone = deviceType_App() == phone_AppDeviceType;[m const iBool isNarrow = !isPhone && isNarrow_Root(navBar->root);[m /* Adjust navbar padding. */ {[m [31m- int hPad = isPortraitPhone_App() ? 0 : isPhone || isNarrow ? gap_UI / 2 : (gap_UI * 3 / 2);[m [32m+[m[32m int hPad = isPortraitPhone_App() ? 0 : isPhone || isNarrow ? gap_UI / 2 : (gap_UI * 3 / 2);[m int vPad = gap_UI * 3 / 2;[m [32m+[m[32m int botPad = vPad / 2;[m int topPad = !findWidget_Root("winbar") ? gap_UI / 2 : 0;[m [31m- setPadding_Widget(navBar, hPad, vPad / 3 + topPad, hPad, vPad / 2);[m [32m+[m[32m if (isLandscape_App() && prefs_App()->bottomNavBar) {[m [32m+[m[32m botPad += bottomSafeInset_Mobile();[m [32m+[m[32m hPad += leftSafeInset_Mobile();[m [32m+[m[32m }[m [32m+[m[32m setPadding_Widget(navBar, hPad, vPad / 3 + topPad, hPad, botPad);[m }[m /* Button sizing. */[m if (isNarrow ^ ((flags_Widget(navBar) & tight_WidgetFlag) != 0)) {[m [36m@@ -1069,6 +1064,7 @@[m [mstatic iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {[m updateNavBarIdentity_(navBar);[m }[m setFocus_Widget(NULL);[m [32m+[m[32m updateToolbarColors_Root(as_Widget(doc)->root);[m makePaletteGlobal_GmDocument(document_DocumentWidget(doc));[m refresh_Widget(findWidget_Root("doctabs"));[m }[m [36m@@ -1197,6 +1193,30 @@[m [mstatic iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) {[m updateToolBarActions_(toolBar);[m return iFalse; [m }[m [32m+[m[32m else if (equal_Command(cmd, "keyboard.changed") && prefs_App()->bottomNavBar) {[m [32m+[m[32m int height = arg_Command(cmd);[m [32m+[m[32m iWidget *bottomBar = findChild_Widget(root_Widget(toolBar), "bottombar");[m [32m+[m[32m if (!bottomBar) {[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m [32m+[m[32m if (focus_Widget() == findChild_Widget(root_Widget(toolBar), "url") && height > 0) {[m [32m+[m[32m int inputHeight = 5 * gap_UI; /* TODO: Why this amount? Something's funny here. */[m [32m+[m[32m int keyboardPad = height - (isPortrait_App() ? height_Widget(toolBar) : inputHeight);[m [32m+[m[32m bottomBar->padding[3] = keyboardPad;[m [32m+[m[32m arrange_Widget(bottomBar);[m [32m+[m[32m arrange_Widget(bottomBar);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, keyboardPad, 0, 0);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, 0, 400, easeOut_AnimFlag | softer_AnimFlag);[m [32m+[m[32m }[m [32m+[m[32m if (height == 0) {[m [32m+[m[32m setVisualOffset_Widget(bottomBar, -bottomBar->padding[3], 0, 0);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, 0, 350, easeOut_AnimFlag | softer_AnimFlag);[m [32m+[m[32m bottomBar->padding[3] = 0;[m [32m+[m[32m arrange_Widget(bottomBar);[m [32m+[m[32m arrange_Widget(bottomBar);[m [32m+[m[32m }[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m return iFalse;[m }[m [m [36m@@ -1547,6 +1567,7 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m iWidget *docTabs = makeTabs_Widget(mainStack);[m setId_Widget(docTabs, "doctabs");[m setBackgroundColor_Widget(docTabs, uiBackground_ColorId);[m [32m+[m[32m// setTabBarPosition_Widget(docTabs, prefs_App()->bottomTabBar);[m iDocumentWidget *doc;[m appendTabPage_Widget(docTabs, iClob(doc = new_DocumentWidget()), "Document", 0, 0);[m addTabCloseButton_Widget(docTabs, as_Widget(doc), "tabs.close");[m [36m@@ -1616,17 +1637,24 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m #if defined (iPlatformMobile)[m /* Bottom toolbar. */[m if (deviceType_App() == phone_AppDeviceType) {[m [32m+[m[32m iWidget *bottomBar = new_Widget();[m [32m+[m[32m setId_Widget(bottomBar, "bottombar");[m [32m+[m[32m addChildFlags_Widget(root,[m [32m+[m[32m iClob(bottomBar),[m [32m+[m[32m moveToParentBottomEdge_WidgetFlag |[m [32m+[m[32m parentCannotResizeHeight_WidgetFlag | arrangeVertical_WidgetFlag |[m [32m+[m[32m arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |[m [32m+[m[32m drawBackgroundToBottom_WidgetFlag);[m iWidget *toolBar = new_Widget();[m [31m- addChild_Widget(root, iClob(toolBar));[m [32m+[m[32m addChild_Widget(bottomBar, iClob(toolBar));[m setId_Widget(toolBar, "toolbar");[m setDrawBufferEnabled_Widget(toolBar, iTrue);[m setCommandHandler_Widget(toolBar, handleToolBarCommands_);[m [31m- setFlags_Widget(toolBar, moveToParentBottomEdge_WidgetFlag |[m [31m- parentCannotResizeHeight_WidgetFlag |[m [31m- resizeWidthOfChildren_WidgetFlag |[m [31m- arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag |[m [31m- commandOnClick_WidgetFlag |[m [31m- drawBackgroundToBottom_WidgetFlag, iTrue);[m [32m+[m[32m setFlags_Widget(toolBar,[m [32m+[m[32m //moveToParentBottomEdge_WidgetFlag | parentCannotResizeHeight_WidgetFlag |[m [32m+[m[32m resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag |[m [32m+[m[32m arrangeHorizontal_WidgetFlag | commandOnClick_WidgetFlag | collapse_WidgetFlag,[m [32m+[m[32m iTrue);[m setId_Widget(addChildFlags_Widget(toolBar,[m iClob(newLargeIcon_LabelWidget("", "...")),[m frameless_WidgetFlag),[m [36m@@ -1641,21 +1669,18 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m iClob(newLargeIcon_LabelWidget("\U0001f464", "identmenu.open")),[m frameless_WidgetFlag | fixedHeight_WidgetFlag),[m "toolbar.ident");[m [31m- setId_Widget(addChildFlags_Widget(toolBar,[m [31m- iClob(newLargeIcon_LabelWidget(book_Icon, "toolbar.showview arg:-1")),[m [31m- frameless_WidgetFlag | commandOnClick_WidgetFlag),[m [32m+[m[32m setId_Widget(addChildFlags_Widget([m [32m+[m[32m toolBar,[m [32m+[m[32m iClob(newLargeIcon_LabelWidget(book_Icon, "toolbar.showview arg:-1")),[m [32m+[m[32m frameless_WidgetFlag | commandOnClick_WidgetFlag),[m "toolbar.view");[m [31m- iLabelWidget *idName;[m [32m+[m[32m iLabelWidget *idName;[m setId_Widget(addChildFlags_Widget(identButton,[m iClob(idName = new_LabelWidget("", NULL)),[m frameless_WidgetFlag |[m [31m- noBackground_WidgetFlag |[m [31m- moveToParentBottomEdge_WidgetFlag |[m [31m- resizeToParentWidth_WidgetFlag[m [31m- /*fixedPosition_WidgetFlag |[m [31m- fixedSize_WidgetFlag |[m [31m- ignoreForParentWidth_WidgetFlag |[m [31m- ignoreForParentHeight_WidgetFlag*/),[m [32m+[m[32m noBackground_WidgetFlag |[m [32m+[m[32m moveToParentBottomEdge_WidgetFlag |[m [32m+[m[32m resizeToParentWidth_WidgetFlag),[m "toolbar.name");[m setFont_LabelWidget(idName, uiLabelTiny_FontId);[m iLabelWidget *menuButton = makeMenuButton_LabelWidget(menu_Icon, phoneNavMenuItems_,[m [36m@@ -1679,6 +1704,7 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m setId_Widget(menu, "toolbar.menu"); /* view menu */[m }[m #endif[m [32m+[m[32m setupMovableElements_Root_(d);[m updateNavBarActions_(navBar);[m updatePadding_Root(d);[m /* Global context menus. */ {[m [36m@@ -1773,23 +1799,181 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m }[m }[m [m [32m+[m[32mstatic void setupMovableElements_Root_(iRoot *d) {[m [32m+[m[32m /* The navbar and the tab bar may be move depending on preferences. */[m [32m+[m[32m const iPrefs *prefs = prefs_App();[m [32m+[m[32m iWidget *bottomBar = findChild_Widget(d->widget, "bottombar");[m [32m+[m[32m iWidget *toolBar = findChild_Widget(bottomBar, "toolbar");[m [32m+[m[32m iWidget *navBar = findChild_Widget(d->widget, "navbar");[m [32m+[m[32m iWidget *winBar = findChild_Widget(d->widget, "winbar"); /* optional: custom window frame */[m [32m+[m[32m iWidget *div = findChild_Widget(d->widget, "navdiv");[m [32m+[m[32m iWidget *docTabs = findChild_Widget(d->widget, "doctabs");[m [32m+[m[32m iWidget *tabBar = findChild_Widget(docTabs, "tabs.buttons");[m [32m+[m[32m if (prefs->bottomNavBar) {[m [32m+[m[32m if (deviceType_App() == phone_AppDeviceType) {[m [32m+[m[32m /* When at the bottom, the navbar is at the top of the bottombar, and gets fully hidden[m [32m+[m[32m when the toolbar is hidden. */[m [32m+[m[32m if (parent_Widget(navBar) != bottomBar) {[m [32m+[m[32m removeChild_Widget(navBar->parent, navBar);[m [32m+[m[32m addChildPos_Widget(bottomBar, navBar, front_WidgetAddPos);[m [32m+[m[32m iRelease(navBar);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m /* On desktop/tablet, a bottom navbar is at the bottom of the main layout. */[m [32m+[m[32m removeChild_Widget(navBar->parent, navBar);[m [32m+[m[32m addChildPos_Widget(div, navBar, back_WidgetAddPos);[m [32m+[m[32m iRelease(navBar);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m /* In the top navbar layout, the navbar is always the first (or second) child. */[m [32m+[m[32m removeChild_Widget(navBar->parent, navBar);[m [32m+[m[32m if (winBar) {[m [32m+[m[32m iAssert(indexOfChild_Widget(div, winBar) == 0);[m [32m+[m[32m insertChildAfter_Widget(div, navBar, 0);[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m addChildPos_Widget(div, navBar, front_WidgetAddPos);[m [32m+[m[32m }[m [32m+[m[32m iRelease(navBar);[m [32m+[m[32m }[m [32m+[m[32m iChangeFlags(tabBar->flags2, permanentVisualOffset_WidgetFlag2, prefs->bottomTabBar);[m [32m+[m[32m setTabBarPosition_Widget(docTabs, prefs->bottomTabBar);[m [32m+[m[32m arrange_Widget(d->widget);[m [32m+[m[32m postRefresh_App();[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void setBottomBarPosition_(iWidget *bottomBar, iBool show, iBool animate) {[m [32m+[m[32m if (deviceType_App() != phone_AppDeviceType) {[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m const iPrefs *prefs = prefs_App();[m [32m+[m[32m float bottomSafe = 0.0f;[m [32m+[m[32m iWidget *tabBar = NULL;[m [32m+[m[32m iRoot *root = bottomBar->root;[m [32m+[m[32m iWidget *docTabs = findChild_Widget(root->widget, "doctabs");[m [32m+[m[32m iWidget *toolBar = findChild_Widget(bottomBar, "toolbar");[m [32m+[m[32m iWidget *navBar = findChild_Widget(root->widget, "navbar");[m [32m+[m[32m const int height = size_Root(root).y - top_Rect(boundsWithoutVisualOffset_Widget(bottomBar));[m [32m+[m[32m size_t numPages = 0;[m [32m+[m[32m iBool bottomTabBar = prefs->bottomTabBar;[m [32m+[m[32m if (prefs->bottomTabBar || prefs->bottomNavBar) {[m [32m+[m[32m tabBar = findChild_Widget(docTabs, "tabs.buttons");[m [32m+[m[32m numPages = tabCount_Widget(docTabs);[m [32m+[m[32m if (numPages == 1) {[m [32m+[m[32m bottomTabBar = iFalse; /* it's not visible */[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m#if defined (iPlatformAppleMobile)[m [32m+[m[32m if (bottomTabBar) {[m [32m+[m[32m safeAreaInsets_iOS(NULL, NULL, NULL, &bottomSafe);[m [32m+[m[32m if (bottomSafe >= gap_UI) {[m [32m+[m[32m bottomSafe -= gap_UI; /* kludge: something's leaving a gap between the tabs and the bottombar */[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m#endif[m [32m+[m[32m showCollapsed_Widget(toolBar, isPortrait_App());[m [32m+[m[32m if (show) {[m [32m+[m[32m if (flags_Widget(bottomBar) & hidden_WidgetFlag) {[m [32m+[m[32m setFlags_Widget(bottomBar, hidden_WidgetFlag, iFalse);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, 0, 200 * animate, easeOut_AnimFlag);[m [32m+[m[32m if (isPortraitPhone_App()) {[m [32m+[m[32m setVisualOffset_Widget(toolBar, 0, 200 * animate, 0);[m [32m+[m[32m }[m [32m+[m[32m setVisualOffset_Widget(navBar, 0, 200 * animate, 0);[m [32m+[m[32m }[m [32m+[m[32m if (bottomTabBar) {[m [32m+[m[32m /* Tab bar needs to stay visible, too. */[m [32m+[m[32m setVisualOffset_Widget(tabBar, -bottomBar->rect.size.y, 200 * animate, easeOut_AnimFlag);[m [32m+[m[32m //tabBar->flags2 |= permanentVisualOffset_WidgetFlag2;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m if (~flags_Widget(bottomBar) & hidden_WidgetFlag) {[m [32m+[m[32m setFlags_Widget(bottomBar, hidden_WidgetFlag, iTrue);[m [32m+[m[32m /* Close any menus that open via the toolbar. */[m [32m+[m[32m closeMenu_Widget(findChild_Widget(findWidget_App("toolbar.navmenu"), "menu"));[m [32m+[m[32m closeMenu_Widget(findChild_Widget(bottomBar, "toolbar.menu"));[m [32m+[m[32m setVisualOffset_Widget(bottomBar, height - bottomSafe, 200 * animate, easeOut_AnimFlag);[m [32m+[m[32m }[m [32m+[m[32m if (bottomTabBar) {[m [32m+[m[32m if (isPortraitPhone_App()) {[m [32m+[m[32m setVisualOffset_Widget(toolBar, bottomSafe, 200 * animate, 0);[m [32m+[m[32m }[m [32m+[m[32m if (prefs->bottomNavBar) {[m [32m+[m[32m setVisualOffset_Widget(navBar, bottomSafe, 200 * animate, 0);[m [32m+[m[32m }[m [32m+[m[32m setVisualOffset_Widget(tabBar, -bottomSafe, 200 * animate, easeOut_AnimFlag);[m [32m+[m[32m //tabBar->flags2 |= hiddenWithVisualOffset_WidgetFlag2;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m void showToolbar_Root(iRoot *d, iBool show) {[m [31m- /* The toolbar is only used on phone portrait layout. */[m [31m- if (isLandscape_App()) return;[m [31m- iWidget *toolBar = findChild_Widget(d->widget, "toolbar");[m [31m- if (!toolBar) return;[m [31m- const int height = size_Root(d).y - top_Rect(boundsWithoutVisualOffset_Widget(toolBar));[m [31m- if (show && !isVisible_Widget(toolBar)) {[m [31m- setFlags_Widget(toolBar, hidden_WidgetFlag, iFalse);[m [31m- setVisualOffset_Widget(toolBar, 0, 200, easeOut_AnimFlag);[m [32m+[m[32m iWidget *bottomBar = findChild_Widget(d->widget, "bottombar");[m [32m+[m[32m if (!bottomBar) return;[m [32m+[m[32m const iPrefs *prefs = prefs_App();[m [32m+[m[32m /* The toolbar is only used in the portrait phone layout, but the bottom bar may have other[m [32m+[m[32m elements regardless. The toolbar is needed for clearing the bottom safe area when there[m [32m+[m[32m is a bottom tab bar, even if the URL is at the top. Note that the entire bottom bar may[m [32m+[m[32m be hidden, but the tab bar remains always visible if there are tabs open. */[m [32m+[m[32m if (isLandscape_App() && !prefs->bottomTabBar && !prefs->bottomNavBar) {[m [32m+[m[32m //setFlags_Widget(bottomBar, hidden_WidgetFlag, iTrue);[m [32m+[m[32m setBottomBarPosition_(bottomBar, iFalse, iTrue);[m [32m+[m[32m return;[m }[m [31m- else if (!show && isVisible_Widget(toolBar)) {[m [32m+[m[32m// iWidget *toolBar = findChild_Widget(bottomBar, "toolbar");[m [32m+[m[32m// iWidget *navBar = findChild_Widget(d->widget, "navbar");[m [32m+[m[32m// const int height = size_Root(d).y - top_Rect(boundsWithoutVisualOffset_Widget(bottomBar));[m [32m+[m[32m// float bottomSafe = 0;[m [32m+[m[32m// const iBool isBottomTabBar = prefs_App()->bottomTabBar;[m [32m+[m[32m// iWidget *tabBar = NULL;[m [32m+[m[32m// if (isBottomTabBar) {[m [32m+[m[32m// tabBar = findChild_Widget(findChild_Widget(d->widget, "doctabs"), "tabs.buttons");[m [32m+[m[32m// const size_t numPages = childCount_Widget(findChild_Widget(tabs, "tabs.pages"));[m [32m+[m[32m// }[m [32m+[m[32m//#if defined (iPlatformAppleMobile)[m [32m+[m[32m// if (isBottomTabBar) {[m [32m+[m[32m// safeAreaInsets_iOS(NULL, NULL, NULL, &bottomSafe);[m [32m+[m[32m// if (bottomSafe >= gap_UI) {[m [32m+[m[32m// bottomSafe -= gap_UI;[m [32m+[m[32m// }[m [32m+[m[32m// }[m [32m+[m[32m//#endif[m [32m+[m[32m setBottomBarPosition_(bottomBar, show, iTrue);[m [32m+[m[41m [m [32m+[m[32m#if 0[m [32m+[m[32m if (show && (!isVisible_Widget(bottomBar) || (isBottomTabBar && ~flags_Widget(tabBar) & dragged_WidgetFlag))) {[m [32m+[m[32m setFlags_Widget(bottomBar, hidden_WidgetFlag, iFalse);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, 0, 200, easeOut_AnimFlag);[m [32m+[m[32m setVisualOffset_Widget(toolBar, 0, 200, 0);[m [32m+[m[32m if (prefs_App()->bottomNavBar) {[m [32m+[m[32m setVisualOffset_Widget(navBar, 0, 200, 0);[m [32m+[m[32m }[m [32m+[m[32m if (isBottomTabBar) {[m [32m+[m[32m /* Tab bar needs to stay visible, too. */[m [32m+[m[32m setVisualOffset_Widget(tabBar, -bottomBar->rect.size.y, 200, easeOut_AnimFlag);[m [32m+[m[32m setFlags_Widget(tabBar, dragged_WidgetFlag, iTrue);[m [32m+[m[32m /* force it to be visible; `dragged` applies the offset even after the animation */[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m else if (!show && isVisible_Widget(bottomBar)) {[m /* Close any menus that open via the toolbar. */[m closeMenu_Widget(findChild_Widget(findWidget_App("toolbar.navmenu"), "menu"));[m [31m- closeMenu_Widget(findChild_Widget(toolBar, "toolbar.menu"));[m [31m- setFlags_Widget(toolBar, hidden_WidgetFlag, iTrue);[m [31m- setVisualOffset_Widget(toolBar, height, 200, easeOut_AnimFlag);[m [32m+[m[32m closeMenu_Widget(findChild_Widget(bottomBar, "toolbar.menu"));[m [32m+[m[32m setFlags_Widget(bottomBar, hidden_WidgetFlag, iTrue);[m [32m+[m[32m setVisualOffset_Widget(bottomBar, height - bottomSafe, 200, easeOut_AnimFlag);[m [32m+[m[32m setVisualOffset_Widget(toolBar, bottomSafe, 200, 0);[m [32m+[m[32m if (prefs_App()->bottomNavBar) {[m [32m+[m[32m setVisualOffset_Widget(navBar, bottomSafe, 200, 0);[m [32m+[m[32m }[m [32m+[m[32m if (isBottomTabBar) {[m [32m+[m[32m setVisualOffset_Widget(tabBar, -bottomSafe, 200, easeOut_AnimFlag);[m [32m+[m[32m tabBar->flags2 |= hiddenWithVisualOffset_WidgetFlag2;[m [32m+[m[32m }[m }[m [32m+[m[32m#endif[m }[m [m size_t windowIndex_Root(const iRoot *d) {[m [1mdiff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c[m [1mindex 70059b6e..17a4e87b 100644[m [1m--- a/src/ui/sidebarwidget.c[m [1m+++ b/src/ui/sidebarwidget.c[m [36m@@ -454,6 +454,7 @@[m [mstatic void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct[m break;[m }[m case bookmarks_SidebarMode: {[m [32m+[m[32m iAssert(get_Root() == d->widget.root);[m iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTree_Bookmark, NULL, NULL)) {[m const iBookmark *bm = i.ptr;[m if (isBookmarkFolded_SidebarWidget_(d, bm)) {[m [1mdiff --git a/src/ui/text.c b/src/ui/text.c[m [1mindex 1ef211ad..62e6b641 100644[m [1m--- a/src/ui/text.c[m [1m+++ b/src/ui/text.c[m [36m@@ -1818,7 +1818,10 @@[m [mvoid process_RunLayer_(iRunLayer *d, int layerIndex) {[m d->xCursor = nextTabStop_Font_(d->font, d->xCursor) - xAdvance;[m }[m const float xf = d->xCursor + xOffset;[m [31m- const float subpixel = xf - (int) xf;[m [32m+[m[32m float subpixel = xf - (int) xf;[m [32m+[m[32m if (subpixel < 0.0f) {[m [32m+[m[32m subpixel = 1.0f + subpixel;[m [32m+[m[32m }[m const int hoff = enableHalfPixelGlyphs_Text ? (int) (subpixel / offsetStep_Glyph_()) : 0;[m if (ch == 0x3001 || ch == 0x3002) {[m /* Vertical misalignment?? */[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 37901c00..176d24c0 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -1490,6 +1490,7 @@[m [miWidget *makeTabs_Widget(iWidget *parent) {[m arrangeHeight_WidgetFlag,[m iTrue);[m setId_Widget(buttons, "tabs.buttons");[m [32m+[m[32m// setBackgroundColor_Widget(buttons, red_ColorId);[m iWidget *content = addChildFlags_Widget(tabs, iClob(makeHDiv_Widget()), expand_WidgetFlag);[m setId_Widget(content, "tabs.content");[m iWidget *pages = addChildFlags_Widget([m [36m@@ -1500,6 +1501,13 @@[m [miWidget *makeTabs_Widget(iWidget *parent) {[m return tabs;[m }[m [m [32m+[m[32mvoid setTabBarPosition_Widget(iWidget *tabs, iBool atBottom) {[m [32m+[m[32m iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");[m [32m+[m[32m removeChild_Widget(tabs, buttons);[m [32m+[m[32m addChildPos_Widget(tabs, buttons, atBottom ? back_WidgetAddPos : front_WidgetAddPos);[m [32m+[m[32m iRelease(buttons);[m [32m+[m[32m}[m [32m+[m static void addTabPage_Widget_(iWidget *tabs, enum iWidgetAddPos addPos, iWidget *page,[m const char *label, int key, int kmods) {[m iWidget * pages = findChild_Widget(tabs, "tabs.pages");[m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex 31c8cedc..15dc021d 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -290,6 +290,7 @@[m [mconst char * selectedDropdownCommand_LabelWidget (const iLabelWidget *dropBut[m /*-----------------------------------------------------------------------------------------------*/[m [m iWidget * makeTabs_Widget (iWidget *parent);[m [32m+[m[32mvoid setTabBarPosition_Widget(iWidget *tabs, iBool atBottom);[m void appendTabPage_Widget (iWidget *tabs, iWidget *page, const char *label, int key, int kmods);[m void appendFramelessTabPage_Widget(iWidget *tabs, iWidget *page, const char *title, int shortcut, int kmods);[m iWidget * appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int shortcut, iWidget **headings,[m [1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m [1mindex 80a36db4..82ff4c57 100644[m [1m--- a/src/ui/widget.c[m [1m+++ b/src/ui/widget.c[m [36m@@ -168,8 +168,10 @@[m [mvoid deinit_Widget(iWidget *d) {[m // printf("deinit_Widget %p (%s):\ttreesize=%d\td_obj=%d\n", d, class_Widget(d)->name, nt, totalCount_Object() - no);[m delete_WidgetDrawBuffer(d->drawBuf);[m #if 0 && !defined (NDEBUG)[m [31m- printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id),[m [31m- d->flags & keepOnTop_WidgetFlag ? 1 : 0);[m [32m+[m[32m if (cmp_String(&d->id, "")) {[m [32m+[m[32m printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id),[m [32m+[m[32m d->flags & keepOnTop_WidgetFlag ? 1 : 0);[m [32m+[m[32m }[m #endif[m deinit_String(&d->id);[m if (d->flags & keepOnTop_WidgetFlag) {[m [36m@@ -960,7 +962,8 @@[m [mint visualOffsetByReference_Widget(const iWidget *d) {[m }[m [m static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {[m [31m- if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {[m [32m+[m[32m if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag) ||[m [32m+[m[32m (d->flags2 & permanentVisualOffset_WidgetFlag2)) {[m const int off = iRound(value_Anim(&d->visualOffset));[m if (d->flags & horizontalOffset_WidgetFlag) {[m pos->x += off;[m [36m@@ -1009,7 +1012,9 @@[m [miRect boundsWithoutVisualOffset_Widget(const iWidget *d) {[m [m iInt2 innerToWindow_Widget(const iWidget *d, iInt2 innerCoord) {[m for (const iWidget *w = d; w; w = w->parent) {[m [31m- addv_I2(&innerCoord, w->rect.pos);[m [32m+[m[32m iInt2 pos = w->rect.pos;[m [32m+[m[32m applyVisualOffset_Widget_(w, &pos);[m [32m+[m[32m addv_I2(&innerCoord, pos);[m }[m return innerCoord;[m }[m [36m@@ -1026,13 +1031,13 @@[m [miBool contains_Widget(const iWidget *d, iInt2 windowCoord) {[m }[m [m iBool containsExpanded_Widget(const iWidget *d, iInt2 windowCoord, int expand) {[m [31m- const iRect bounds = {[m [31m- zero_I2(),[m [32m+[m[32m iRect bounds = {[m [32m+[m[32m innerToWindow_Widget(d, zero_I2()),[m addY_I2(d->rect.size,[m d->flags & drawBackgroundToBottom_WidgetFlag ? size_Root(d->root).y : 0)[m };[m return contains_Rect(expand ? expanded_Rect(bounds, init1_I2(expand)) : bounds,[m [31m- windowToInner_Widget(d, windowCoord));[m [32m+[m[32m windowCoord);[m }[m [m iLocalDef iBool isKeyboardEvent_(const SDL_Event *ev) {[m [36m@@ -1056,7 +1061,8 @@[m [miLocalDef iBool isHidden_Widget_(const iWidget *d) {[m }[m [m iLocalDef iBool isDrawn_Widget_(const iWidget *d) {[m [31m- return !isHidden_Widget_(d) || d->flags & visualOffset_WidgetFlag;[m [32m+[m[32m return !isHidden_Widget_(d) || (d->flags & visualOffset_WidgetFlag &&[m [32m+[m[32m ~d->flags2 & permanentVisualOffset_WidgetFlag2);[m }[m [m static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) {[m [36m@@ -1103,6 +1109,14 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m fflush(stdout);[m }[m #endif[m [32m+[m[32m#if 0[m [32m+[m[32m if (ev->type == SDL_MOUSEBUTTONDOWN) {[m [32m+[m[32m printf("[%p] %s:'%s' (on top) ate the button\n",[m [32m+[m[32m widget, class_Widget(widget)->name,[m [32m+[m[32m cstr_String(id_Widget(widget)));[m [32m+[m[32m fflush(stdout);[m [32m+[m[32m }[m [32m+[m[32m#endif[m #if 0[m if (ev->type == SDL_MOUSEMOTION) {[m printf("[%p] %s:'%s' (on top) ate the motion\n",[m [36m@@ -1135,12 +1149,12 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m handle the events first. */[m iReverseForEach(ObjectList, i, d->children) {[m iWidget *child = as_Widget(i.object);[m [31m- //iAssert(child->root == d->root);[m [32m+[m[32m iAssert(child->root == d->root);[m if (child == window_Widget(d)->focus && isKeyboardEvent_(ev)) {[m continue; /* Already dispatched. */[m }[m if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) {[m [31m- /* Already dispatched. */[m [32m+[m[32m /* Already dispatched. */[m continue;[m }[m if (dispatchEvent_Widget(child, ev)) {[m [36m@@ -1180,8 +1194,9 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m return iTrue;[m }[m }[m [32m+[m[32m iAssert(get_Root() == d->root);[m if (class_Widget(d)->processEvent(d, ev)) {[m [31m- //iAssert(get_Root() == d->root);[m [32m+[m[32m iAssert(get_Root() == d->root);[m return iTrue;[m }[m }[m [36m@@ -1387,6 +1402,7 @@[m [miBool processEvent_Widget(iWidget *d, const SDL_Event *ev) {[m d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward");[m }[m setFlags_Widget(d, dragged_WidgetFlag, iFalse);[m [32m+[m[32m return iTrue;[m }[m if (d->commandHandler && d->commandHandler(d, ev->user.data1)) {[m return iTrue;[m [1mdiff --git a/src/ui/widget.h b/src/ui/widget.h[m [1mindex c1b3a9a4..7b9de966 100644[m [1m--- a/src/ui/widget.h[m [1m+++ b/src/ui/widget.h[m [36m@@ -127,6 +127,7 @@[m [menum iWidgetFlag2 {[m slidingSheetDraggable_WidgetFlag2 = iBit(1),[m fadeBackground_WidgetFlag2 = iBit(2),[m visibleOnParentSelected_WidgetFlag2 = iBit(3),[m [32m+[m[32m permanentVisualOffset_WidgetFlag2 = iBit(4), /* usually visual offset overrides hiding */[m };[m [m enum iWidgetAddPos {[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).