Lagrange [work/v1.15]

Vertical tabs for Preferences; reorganized pages

=> 430525d298e75ae2c24de54af58f6f12c5374437

diff --git a/po/en.po b/po/en.po
index 37dfffed..a4433caa 100644
--- a/po/en.po
+++ b/po/en.po
@@ -1531,6 +1531,9 @@ msgstr "Fonts"
 msgid "heading.prefs.general"
 msgstr "General"
 
+msgid "heading.prefs.appearance"
+msgstr "Appearance"
+
 # tab button
 msgid "heading.prefs.interface"
 msgstr "UI"
@@ -1539,6 +1542,12 @@ msgstr "UI"
 msgid "heading.prefs.keys"
 msgstr "Keys"
 
+msgid "heading.prefs.layout"
+msgstr "Page Layout"
+
+msgid "heading.prefs.content"
+msgstr "Content"
+
 # tab button
 msgid "heading.prefs.network"
 msgstr "Network"
@@ -1566,7 +1575,7 @@ msgstr "Wide Layout"
 
 # tab button
 msgid "heading.prefs.style"
-msgstr "Style"
+msgstr "Page Style"
 
 # tab button
 msgid "heading.prefs.userinterface"
@@ -1596,7 +1605,7 @@ msgstr "Open images in Data URLs:"
 
 # User preference that controls whether index.gmi pages get automatically opened when browsing the contents of a directory inside a compressed archive.
 msgid "prefs.archive.openindex"
-msgstr "Open archive indices:"
+msgstr "Open index.gmi in ZIP archives:"
 
 msgid "prefs.markdown.viewsource"
 msgstr "View Markdown as source:"
@@ -1623,7 +1632,7 @@ msgid "prefs.scrollspeed.mouse"
 msgstr "Mouse speed:"
 
 msgid "prefs.imageloadscroll"
-msgstr "Load image on scroll:"
+msgstr "Load next image on scroll key:"
 
 msgid "prefs.uilayout"
 msgstr "Layout:"
@@ -1662,7 +1671,7 @@ msgid "prefs.ostheme"
 msgstr "Use system theme:"
 
 msgid "prefs.theme"
-msgstr "Theme:"
+msgstr "UI theme:"
 
 msgid "prefs.theme.black"
 msgstr "Black"
@@ -1701,7 +1710,7 @@ msgid "prefs.uilang"
 msgstr "Language:"
 
 msgid "prefs.time.24h"
-msgstr "24-Hour Time"
+msgstr "24-hour time:"
 
 msgid "prefs.retaintabs"
 msgstr "Restore tabs at launch:"
@@ -1728,10 +1737,10 @@ msgid "prefs.animate"
 msgstr "Animations:"
 
 msgid "prefs.retainwindow"
-msgstr "Retain placement:"
+msgstr "Save window placement:"
 
 msgid "prefs.sideicon"
-msgstr "Capsule icon:"
+msgstr "Capsule icon on left side:"
 
 msgid "prefs.doctheme.dark"
 msgstr "Dark theme:"
@@ -1789,7 +1798,7 @@ msgid "prefs.tui.simple"
 msgstr "Simple characters:"
 
 msgid "prefs.font.ui"
-msgstr "UI:"
+msgstr "UI font:"
 
 msgid "prefs.font.heading"
 msgstr "Headings:"
@@ -1817,7 +1826,7 @@ msgid "prefs.mono.gopher"
 msgstr "Gopher"
 
 msgid "prefs.gopher.gemstyle"
-msgstr "Styling on Gopher:"
+msgstr "Autodetect Gopher menu styling:"
 
 msgid "prefs.boldlink"
 msgstr "Bold links:"
@@ -1834,7 +1843,7 @@ msgid "prefs.boldlink.light"
 msgstr "On Light"
 
 msgid "prefs.gemtext.ansi"
-msgstr "ANSI escapes:"
+msgstr "Gemtext ANSI escapes:"
 
 # Color of the text foreground, i.e., the characters.
 msgid "prefs.gemtext.ansi.fg"
@@ -1848,10 +1857,10 @@ msgid "prefs.gemtext.ansi.fontstyle"
 msgstr "Font Style"
 
 msgid "prefs.font.warnmissing"
-msgstr "Glyph warnings:"
+msgstr "Font glyph warnings:"
 
 msgid "prefs.font.smooth"
-msgstr "Smoothing:"
+msgstr "Font smoothing:"
 
 msgid "prefs.linewidth"
 msgstr "Line width:"
@@ -1884,7 +1893,7 @@ msgid "prefs.justify"
 msgstr "Justify:"
 
 msgid "prefs.plaintext.wrap"
-msgstr "Wrap plain text:"
+msgstr "Wrap long plaintext lines:"
 
 msgid "prefs.decodeurls"
 msgstr "Decode URLs:"
diff --git a/res/lang/cs.bin b/res/lang/cs.bin
index 4e802ba7..8cdbed59 100644
Binary files a/res/lang/cs.bin and b/res/lang/cs.bin differ
diff --git a/res/lang/de.bin b/res/lang/de.bin
index 31715f3e..8a294ca4 100644
Binary files a/res/lang/de.bin and b/res/lang/de.bin differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index 2e2f9522..9a4029f1 100644
Binary files a/res/lang/en.bin and b/res/lang/en.bin differ
diff --git a/res/lang/eo.bin b/res/lang/eo.bin
index 59151ad9..4daa72a7 100644
Binary files a/res/lang/eo.bin and b/res/lang/eo.bin differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 000b46f7..aab45c44 100644
Binary files a/res/lang/es.bin and b/res/lang/es.bin differ
diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin
index ed686023..10188964 100644
Binary files a/res/lang/es_MX.bin and b/res/lang/es_MX.bin differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 5966054d..bccc98b6 100644
Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 4759de0d..c50caa4d 100644
Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ
diff --git a/res/lang/gl.bin b/res/lang/gl.bin
index 2eda23ee..1ab16b46 100644
Binary files a/res/lang/gl.bin and b/res/lang/gl.bin differ
diff --git a/res/lang/hu.bin b/res/lang/hu.bin
index 81d49de8..4ec109fc 100644
Binary files a/res/lang/hu.bin and b/res/lang/hu.bin differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index dd963eca..e3c34beb 100644
Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 6a79a05b..5570e349 100644
Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ
diff --git a/res/lang/isv.bin b/res/lang/isv.bin
index d484ea8f..ce6aac3b 100644
Binary files a/res/lang/isv.bin and b/res/lang/isv.bin differ
diff --git a/res/lang/it.bin b/res/lang/it.bin
index 1d907cfa..ce5a10c9 100644
Binary files a/res/lang/it.bin and b/res/lang/it.bin differ
diff --git a/res/lang/nl.bin b/res/lang/nl.bin
index 8c3c7d74..21d1cd3a 100644
Binary files a/res/lang/nl.bin and b/res/lang/nl.bin differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index e309f76e..34d9dcb3 100644
Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 1ac217bd..c0f06c15 100644
Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ
diff --git a/res/lang/sk.bin b/res/lang/sk.bin
index 5ecef86c..c067b156 100644
Binary files a/res/lang/sk.bin and b/res/lang/sk.bin differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index 4e70b7b4..525b90f3 100644
Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index 65cac0c0..461b2ad5 100644
Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ
diff --git a/res/lang/tr.bin b/res/lang/tr.bin
index 42704ae2..448350b9 100644
Binary files a/res/lang/tr.bin and b/res/lang/tr.bin differ
diff --git a/res/lang/uk.bin b/res/lang/uk.bin
index dd0c6a55..622dc980 100644
Binary files a/res/lang/uk.bin and b/res/lang/uk.bin differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 84cfdb8b..fe0f2b42 100644
Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index 11baf6a0..4668a81f 100644
Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ
diff --git a/src/app.c b/src/app.c
index 564cd9b6..fd000dbd 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2546,6 +2546,8 @@ static void updatePrefsThemeButtons_(iWidget *d) {
                         selected_WidgetFlag,
                         prefs_App()->accent == i);
     }
+    updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.accent"),
+                                        format_CStr(" arg:%u", prefs_App()->accent));
 }
 
 static void updatePrefsPinSplitButtons_(iWidget *d, int value) {
@@ -2640,11 +2642,14 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
         postCommand_App("prefs.changed");
         return iTrue;
     }
+    /*
     else if (equal_Command(cmd, "tabs.changed")) {
         setFlags_Widget(findChild_Widget(d, "prefs.aboutfonts"), hidden_WidgetFlag,
-                        !equal_Rangecc(range_Command(cmd, "id"), "prefs.page.fonts"));
+                        !equal_Rangecc(range_Command(cmd, "id"), "prefs.page.style") &&
+                        !equal_Rangecc(range_Command(cmd, "id"), "prefs.page.appearance"));
         return iFalse;
     }
+    */
     else if (equal_Command(cmd, "uilang")) {
         updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.uilang"),
                                             cstr_String(string_Command(cmd, "id")));
diff --git a/src/defs.h b/src/defs.h
index cf90b27f..2048b744 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -254,6 +254,12 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {
 #define toggleYes_Icon      check_Icon
 #define toggleNo_Icon       bullet_Icon
 #define spartan_Icon        "\U0001f4aa"
+#define keyboard_Icon       "\u2328"
+#define network_Icon        "\U0001f5a7"
+#define computer_Icon       "\U0001f5b3"
+#define palette_Icon        "\U0001f3a8"
+#define pageLayout_Icon     page_Icon //"\u21b9" //"\U0001F5B9"
+#define fonts_Icon          "\U0001f5da"
 
 #if defined (iPlatformTerminal)
 #   undef page_Icon
diff --git a/src/ui/color.c b/src/ui/color.c
index 899e3a28..3f392987 100644
--- a/src/ui/color.c
+++ b/src/ui/color.c
@@ -80,7 +80,7 @@ iLocalDef void copy_(enum iColorId dst, enum iColorId src) {
     set_Color(dst, get_Color(src));
 }
 
-static int accentColor_(enum iColorAccent accent, int brightness) {
+int color_ColorAccent(enum iColorAccent accent, iBool isBright) {
     const iBool isMedium = prefs_App()->theme == dark_ColorTheme ||
                            prefs_App()->theme == light_ColorTheme;
     const int brightColors[max_ColorAccent] = {
@@ -99,18 +99,18 @@ static int accentColor_(enum iColorAccent accent, int brightness) {
         indigo_ColorId,
         isMedium ? black_ColorId : gray25_ColorId,
     };
-    return brightness ? brightColors[accent] : darkColors[accent];
+    return isBright ? brightColors[accent] : darkColors[accent];
 }
 
 int accent_Color(iBool isBright) {
-    return accentColor_(prefs_App()->accent, isBright ? 1 : 0);
+    return color_ColorAccent(prefs_App()->accent, isBright);
 }
 
 void setThemePalette_Color(enum iColorTheme theme) {
     const iPrefs *prefs = prefs_App();
     memcpy(uiPalette_, isDark_ColorTheme(theme) ? darkPalette_ : lightPalette_, sizeof(darkPalette_));
-    const int accentHi = accentColor_(prefs->accent, 1);
-    const int accentLo = accentColor_(prefs->accent, 0);
+    const int accentHi = color_ColorAccent(prefs->accent, 1);
+    const int accentLo = color_ColorAccent(prefs->accent, 0);
     switch (theme) {
         case pureBlack_ColorTheme: {
             copy_(uiBackground_ColorId, black_ColorId);
diff --git a/src/ui/color.h b/src/ui/color.h
index 356831d2..ea285ca6 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -272,3 +272,5 @@ enum iColorId   parseEscape_Color       (const char *cstr, const char **endp);
 
 int             accent_Color            (iBool isBright);
 iColor          systemAccent_Color      (void); /* platform-specific impl */
+
+int             color_ColorAccent       (enum iColorAccent, iBool isBright);
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c
index 69b9092a..47f2ccc8 100644
--- a/src/ui/labelwidget.c
+++ b/src/ui/labelwidget.c
@@ -42,6 +42,7 @@ struct Impl_LabelWidget {
     int     kmods;
     iChar   icon;
     int     forceFg;
+    int     iconColor;
     iString command;
     iClick  click;
     struct {
@@ -301,6 +302,13 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int
     if (colorEscape == uiTextCaution_ColorId) {
         *icon = *meta = colorEscape;
     }
+    if (d->iconColor != none_ColorId) {
+        *icon = d->iconColor;
+        if ((*icon >= brown_ColorId && *icon <= blue_ColorId) && !isDarkTheme) {
+            /* Auto-adjust absolute color IDs to suit the UI theme. */
+            (*icon)--; /* make it darker */
+        }
+    }
     if (isHover) {
         if (isFrameless) {
             if (prefs_App()->accent == gray_ColorAccent && prefs_App()->theme >= light_ColorTheme) {
@@ -601,6 +609,7 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) {
     iZap(d->flags);
     d->font = uiLabel_FontId;
     d->forceFg = none_ColorId;
+    d->iconColor = none_ColorId;
     d->icon = 0;
     d->labelOffset = zero_I2();
     initCStr_String(&d->srcLabel, label);
@@ -751,6 +760,10 @@ void setIcon_LabelWidget(iLabelWidget *d, iChar icon) {
     }
 }
 
+void setIconColor_LabelWidget(iLabelWidget *d, int color) {
+    d->iconColor = color;
+}
+
 iBool checkIcon_LabelWidget(iLabelWidget *d) {
     if (isEmpty_String(&d->label)) {
         d->icon = 0;
diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h
index fbc83d2d..3dbc70d9 100644
--- a/src/ui/labelwidget.h
+++ b/src/ui/labelwidget.h
@@ -47,6 +47,7 @@ void    setText_LabelWidget         (iLabelWidget *, const iString *text); /* re
 void    setTextCStr_LabelWidget     (iLabelWidget *, const char *text);
 void    setCommand_LabelWidget      (iLabelWidget *, const iString *command);
 void    setIcon_LabelWidget         (iLabelWidget *, iChar icon);
+void    setIconColor_LabelWidget    (iLabelWidget *, int color);
 
 iBool   checkIcon_LabelWidget       (iLabelWidget *);
 void    updateSize_LabelWidget      (iLabelWidget *);
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index bf840d7b..ea605c85 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -329,10 +329,10 @@ void init_UploadWidget(iUploadWidget *d, enum iUploadProtocol protocol) {
             setId_Widget(as_Widget(d->input), "upload.text");
             setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI * aspectRatio, -1));
             addChild_Widget(page, iClob(d->input));
-            appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0);
+            appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", none_ColorId, '1', 0);
         }
         /* File content. */ {
-            iWidget *page = appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", '2', &headings, &values);
+            iWidget *page = appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", none_ColorId, '2', &headings, &values);
             setBackgroundColor_Widget(page, uiBackgroundSidebar_ColorId);
             addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.name}", NULL)), frameless_WidgetFlag);
             d->filePathLabel = addChildFlags_Widget(values, iClob(new_LabelWidget(uiTextAction_ColorEscape "${upload.file.drophere}", NULL)), frameless_WidgetFlag);
diff --git a/src/ui/util.c b/src/ui/util.c
index 56300a66..87a8ec0b 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1695,8 +1695,27 @@ void setTabBarPosition_Widget(iWidget *tabs, iBool atBottom) {
     iRelease(buttons);
 }
 
+void setVerticalTabBar_Widget(iWidget *tabs) {
+    iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");
+    iWidget *content = findChild_Widget(tabs, "tabs.content");
+    setFlags_Widget(tabs, arrangeVertical_WidgetFlag, iFalse);
+    setFlags_Widget(tabs, arrangeHorizontal_WidgetFlag, iTrue);
+    setFlags_Widget(buttons, arrangeHorizontal_WidgetFlag | arrangeHeight_WidgetFlag |
+                             resizeWidthOfChildren_WidgetFlag, iFalse);
+    setFlags_Widget(buttons, arrangeVertical_WidgetFlag | arrangeWidth_WidgetFlag |
+                    resizeChildrenToWidestChild_WidgetFlag, iTrue);
+    buttons->flags2 |= centerChildrenVertical_WidgetFlag2;
+    setFlags_Widget(content, arrangeHorizontal_WidgetFlag, iFalse);
+    setFlags_Widget(content, arrangeVertical_WidgetFlag, iTrue);
+}
+
+iBool isVerticalTabBar_Widget(const iWidget *tabs) {
+    return (tabs->flags & arrangeVertical_WidgetFlag) == 0;
+}
+
 static void addTabPage_Widget_(iWidget *tabs, enum iWidgetAddPos addPos, iWidget *page,
                                const char *label, int key, int kmods) {
+    const iBool isVerticalTabs = isVerticalTabBar_Widget(tabs);
     iWidget *   pages   = findChild_Widget(tabs, "tabs.pages");
     const iBool isSel   = childCount_Widget(pages) == 0;
     iWidget *   buttons = findChild_Widget(tabs, "tabs.buttons");
@@ -1704,8 +1723,10 @@ static void addTabPage_Widget_(iWidget *tabs, enum iWidgetAddPos addPos, iWidget
         buttons,
         iClob(newKeyMods_LabelWidget(label, key, kmods, format_CStr("tabs.switch page:%p", page))),
         addPos);
+    checkIcon_LabelWidget((iLabelWidget *) button);
     setFlags_Widget(button, selected_WidgetFlag, isSel);
-    setFlags_Widget(button, commandOnClick_WidgetFlag | expand_WidgetFlag, iTrue);
+    setFlags_Widget(button, commandOnClick_WidgetFlag |
+                                (isVerticalTabs ? alignLeft_WidgetFlag : expand_WidgetFlag), iTrue);
     if (prefs_App()->bottomTabBar) {
         setNoBottomFrame_LabelWidget((iLabelWidget *) button, iTrue);
     }
@@ -1772,7 +1793,10 @@ void resizeToLargestPage_Widget(iWidget *tabs) {
     iForEach(ObjectList, k, children_Widget(pages)) {
         setMinSize_Widget(k.object, largest);
     }
-    setFixedSize_Widget(tabs, addY_I2(largest, height_Widget(findChild_Widget(tabs, "tabs.buttons"))));
+    const iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");
+    setFixedSize_Widget(tabs,
+                        isVerticalTabBar_Widget(tabs) ? addX_I2(largest, width_Widget(buttons))
+                                                      : addY_I2(largest, height_Widget(buttons)));
 //    puts("... DONE WITH RESIZE TO LARGEST PAGE");
 }
 
@@ -2394,13 +2418,16 @@ iWidget *makeToggle_Widget(const char *id) {
     return toggle;
 }
 
-void appendFramelessTabPage_Widget(iWidget *tabs, iWidget *page, const char *title, int shortcut,
-                                   int kmods) {
+void appendFramelessTabPage_Widget(iWidget *tabs, iWidget *page, const char *title, int iconColor,
+                                   int shortcut, int kmods) {
     appendTabPage_Widget(tabs, page, title, shortcut, kmods);
     setFlags_Widget(
         (iWidget *) back_ObjectList(children_Widget(findChild_Widget(tabs, "tabs.buttons"))),
         frameless_WidgetFlag | noBackground_WidgetFlag,
         iTrue);
+    if (iconColor != none_ColorId) {
+        setIconColor_LabelWidget(tabPageButton_Widget(tabs, page), iconColor);
+    }
 }
 
 iWidget *makeTwoColumns_Widget(iWidget **headings, iWidget **values) {
@@ -2422,8 +2449,8 @@ iLabelWidget *dialogAcceptButton_Widget(const iWidget *d) {
     return (iLabelWidget *) lastChild_Widget(buttonParent);
 }
 
-iWidget *appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int shortcut, iWidget **headings,
-                                       iWidget **values) {
+iWidget *appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int iconColor,
+                                       int shortcut, iWidget **headings, iWidget **values) {
     /* TODO: Use `makeTwoColumnWidget_()`, see above. */
     iWidget *page = new_Widget();
     setFlags_Widget(page, arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
@@ -2436,20 +2463,26 @@ iWidget *appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int sho
     *values = addChildFlags_Widget(
         columns, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
     addChildFlags_Widget(page, iClob(new_Widget()), expand_WidgetFlag);
-    appendFramelessTabPage_Widget(tabs, iClob(page), title, shortcut, shortcut ? KMOD_PRIMARY : 0);
+    appendFramelessTabPage_Widget(tabs, iClob(page), title, iconColor, shortcut, shortcut ? KMOD_PRIMARY : 0);
     return page;
 }
 
+static void addDialogPaddingSize_(iWidget *headings, iWidget *values, int size) {
+    addChild_Widget(headings, iClob(makePadding_Widget(size)));
+    addChild_Widget(values,   iClob(makePadding_Widget(size)));    
+}
+
 static void addDialogPadding_(iWidget *headings, iWidget *values) {
-    const int bigGap = iMaxi(1, lineHeight_Text(uiLabel_FontId) * 3 / 4);
-    addChild_Widget(headings, iClob(makePadding_Widget(bigGap)));
-    addChild_Widget(values,   iClob(makePadding_Widget(bigGap)));    
+    addDialogPaddingSize_(headings, values, iMaxi(1, lineHeight_Text(uiLabel_FontId) * 3 / 4));
 }
 
 static void makeTwoColumnHeading_(const char *title, iWidget *headings, iWidget *values) {
     if (isTerminal_Platform()) {
         addDialogPadding_(headings, values);
     }
+    else {
+        addDialogPaddingSize_(headings, values, 2 * gap_UI);
+    }
     setFont_LabelWidget(addChildFlags_Widget(headings,
                                              iClob(makeHeading_Widget(
                                                  format_CStr(uiHeading_ColorEscape "%s", title))),
@@ -2534,6 +2567,7 @@ void updatePreferencesLayout_Widget(iWidget *prefs) {
         "prefs.proxy.http"
     };
     iWidget *tabs = findChild_Widget(prefs, "prefs.tabs");
+    tabs->rect.size = zero_I2();
     /* Input fields expand to the right edge. */
     /* TODO: Add an arrangement flag for this. */
     iForIndices(i, inputIds) {
@@ -2609,6 +2643,17 @@ static void addDialogToggleGroup_(iWidget *headings, iWidget *values, const char
         values, iClob(group), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
 }
 
+static iLabelWidget *addDialogDropMenu_(iWidget *headings, iWidget *values, const char *title,
+                                        const iMenuItem *items, size_t numItems, const char *id) {
+    addChild_Widget(headings, iClob(makeHeading_Widget(title)));
+    iLabelWidget *button = makeMenuButton_LabelWidget(
+        items[findWidestLabel_MenuItem(items, numItems)].label, items, numItems);
+    setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"),
+                              uiBackgroundMenu_ColorId);
+    setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag), id);
+    return button;
+}
+
 size_t findWidestLabel_MenuItem(const iMenuItem *items, size_t num) {
     int widest = 0;
     size_t widestPos = iInvalidPos;
@@ -2757,6 +2802,14 @@ iWidget *makePreferences_Widget(void) {
         };
         memcpy(docThemes[i], items, sizeof(items));
     }
+    const iMenuItem accentItems[max_ColorAccent] = {
+        { circle_Icon " ${prefs.accent.teal}", 0, 0, "accent.set arg:0" },
+        { circle_Icon " ${prefs.accent.orange}", 0, 0, "accent.set arg:1" },
+        { circle_Icon " ${prefs.accent.red}", 0, 0, "accent.set arg:2" },
+        { circle_Icon " ${prefs.accent.green}", 0, 0, "accent.set arg:3" },
+        { circle_Icon " ${prefs.accent.blue}", 0, 0, "accent.set arg:4" },
+        { circle_Icon " ${prefs.accent.gray}", 0, 0, "accent.set arg:5" }
+    };
     const iMenuItem imgStyles[] = {
         { "${prefs.imagestyle.original}",  0, 0, format_CStr("imagestyle.set arg:%d", original_ImageStyle) },
         { "${prefs.imagestyle.grayscale}", 0, 0, format_CStr("imagestyle.set arg:%d", grayscale_ImageStyle) },
@@ -3001,11 +3054,17 @@ iWidget *makePreferences_Widget(void) {
     iWidget *dlg = makeSheet_Widget("prefs");
     addDialogTitle_(dlg, "${heading.prefs}", NULL);
     iWidget *tabs = makeTabs_Widget(dlg);
+    setVerticalTabBar_Widget(tabs);
     setBackgroundColor_Widget(findChild_Widget(tabs, "tabs.buttons"), uiBackgroundSidebar_ColorId);
     setId_Widget(tabs, "prefs.tabs");
     iWidget *headings, *values;
-    /* General preferences. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.general}", '1', &headings, &values),
+    /* General settings. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs,
+                                                   gear_Icon " ${heading.prefs.general}",
+                                                   uiIcon_ColorId,
+                                                   '1',
+                                                   &headings,
+                                                   &values),
                      "prefs.page.general");
 #if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
         addPrefsInputWithHeading_(headings, values, "prefs.downloads", iClob(new_InputWidget(0)));
@@ -3014,7 +3073,6 @@ iWidget *makePreferences_Widget(void) {
         addPrefsInputWithHeading_(headings, values, "prefs.searchurl", iClob(searchUrl = new_InputWidget(0)));
         setUrlContent_InputWidget(searchUrl, iTrue);
         addDialogPadding_(headings, values);
-        addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink");
         addDialogToggle_(headings, values, "${prefs.retaintabs}", "prefs.retaintabs");
         if (deviceType_App() != phone_AppDeviceType) {
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.pinsplit}")));
@@ -3026,15 +3084,12 @@ iWidget *makePreferences_Widget(void) {
             }
             addChildFlags_Widget(values, iClob(pinSplit), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
         }
-        addDialogToggle_(headings, values, "${prefs.markdown.viewsource}", "prefs.markdown.viewsource");
-        addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom");
-        addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex");
-        addDialogToggle_(headings, values, "${prefs.dataurl.openimages}", "prefs.dataurl.openimages");
         addDialogPadding_(headings, values);
         /* UI languages. */ {
             iArray *uiLangs = collectNew_Array(sizeof(iMenuItem));
             pushBackN_Array(uiLangs, langItems, iElemCount(langItems) - 1);
             /* TODO: Add an arrange flag for resizing parent to widest child. */
+            /*
             size_t widestPos = findWidestLabel_MenuItem(data_Array(uiLangs), size_Array(uiLangs));
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.uilang}")));
             setId_Widget(addChildFlags_Widget(values,
@@ -3042,87 +3097,17 @@ iWidget *makePreferences_Widget(void) {
                                                   value_Array(uiLangs, widestPos, iMenuItem).label,
                                                   data_Array(uiLangs),
                                                   size_Array(uiLangs))),
-                                              alignLeft_WidgetFlag),
-                         "prefs.uilang");
-        }
-        addDialogToggle_(headings, values, "${prefs.time.24h}", "prefs.time.24h");
-    }
-    /* User Interface. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.interface}", '2', &headings, &values),
-                     "prefs.page.ui");
-        addDialogToggle_(headings, values, "${prefs.animate}", "prefs.animate");
-        if (!isTerminal_Platform()) {
-            addDialogToggle_(headings, values, "${prefs.blink}", "prefs.blink");
-        }
-        addDialogToggleGroup_(
-            headings,
-            values,
-            "${prefs.uilayout}",
-            (const char *[]) {
-#if defined (LAGRANGE_MAC_MENUBAR)
-                "prefs.bottomnavbar", "prefs.bottomtabbar", NULL
-#else
-                "prefs.bottomnavbar", "prefs.bottomtabbar", "prefs.menubar", NULL
-#endif
-            },
-            iInvalidSize);
-        addDialogToggle_(headings, values, "${prefs.evensplit}", "prefs.evensplit");
-        addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.returnkey}")));
-        /* Return key behaviors. */ {
-            iLabelWidget *returnKey = makeMenuButton_LabelWidget(
-                returnKeyBehaviors[findWidestLabel_MenuItem(returnKeyBehaviors,
-                                                        iElemCount(returnKeyBehaviors) - 1)]
-                    .label,
-                returnKeyBehaviors,
-                iElemCount(returnKeyBehaviors) - 1);
-            setBackgroundColor_Widget(findChild_Widget(as_Widget(returnKey), "menu"),
-                                      uiBackgroundMenu_ColorId);
-            setId_Widget(addChildFlags_Widget(values, iClob(returnKey), alignLeft_WidgetFlag),
-                         "prefs.returnkey");
-        }
-#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME)
-        addDialogToggle_(headings, values, "${prefs.customframe}", "prefs.customframe");
-#endif
-        makeTwoColumnHeading_("${heading.prefs.scrolling}", headings, values);
-        addDialogToggle_(headings, values, "${prefs.smoothscroll}", "prefs.smoothscroll");
-        /* Scroll speeds. */ {
-            for (int type = 0; type < max_ScrollType; type++) {
-                const char *typeStr = (type == mouse_ScrollType ? "mouse" : "keyboard");
-                addChild_Widget(headings,
-                                iClob(makeHeading_Widget(type == mouse_ScrollType
-                                                             ? "${prefs.scrollspeed.mouse}"
-                                                             : "${prefs.scrollspeed.keyboard}")));
-                /* TODO: Make a SliderWidget. */
-                iWidget *scrollSpeed = new_Widget();                
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.7",  typeStr), "0", format_CStr("scrollspeed arg:7  type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.10", typeStr), "1", format_CStr("scrollspeed arg:10 type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.13", typeStr), "2", format_CStr("scrollspeed arg:13 type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.17", typeStr), "3", format_CStr("scrollspeed arg:17 type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.23", typeStr), "4", format_CStr("scrollspeed arg:23 type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.30", typeStr), "5", format_CStr("scrollspeed arg:30 type:%d", type));
-                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.40", typeStr), "6", format_CStr("scrollspeed arg:40 type:%d", type));
-                addChildFlags_Widget(
-                    values, iClob(scrollSpeed), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
-            }
-        }
-        if (!isTerminal_Platform()) {
-            addDialogToggle_(headings, values, "${prefs.imageloadscroll}", "prefs.imageloadscroll");
-        }
-        if (deviceType_App() == phone_AppDeviceType) {
-            addDialogToggle_(headings, values, "${prefs.hidetoolbarscroll}", "prefs.hidetoolbarscroll");
-        }
-        if (!isTerminal_Platform()) {
-            makeTwoColumnHeading_("${heading.prefs.sizing}", headings, values);
-            addPrefsInputWithHeading_(headings, values, "prefs.uiscale", iClob(new_InputWidget(5)));
-            if (deviceType_App() == desktop_AppDeviceType) {
-                addDialogToggle_(headings, values, "${prefs.retainwindow}", "prefs.retainwindow");
-            }
+                                              algnLeft_WidgetFlag),
+                         "prefs.uilang");*/
+            addDialogDropMenu_(headings, values, "${prefs.uilang}",
+                               constData_Array(uiLangs), size_Array(uiLangs),
+                               "prefs.uilang");
         }
     }
-    /* Colors. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.colors}", '3', &headings, &values),
-                     "prefs.page.color");
-        makeTwoColumnHeading_("${heading.prefs.uitheme}", headings, values);
+    /* Appearance. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs, palette_Icon " ${heading.prefs.appearance}", red_ColorId, '2', &headings, &values),
+                     "prefs.page.appearance");
+//        makeTwoColumnHeading_("${heading.prefs.uitheme}", headings, values);
 #if (defined (iPlatformApple) || defined (iPlatformMSys)) && !defined (iPlatformTerminal)
         addDialogToggle_(headings, values, "${prefs.ostheme}", "prefs.ostheme");
 #endif
@@ -3135,7 +3120,23 @@ iWidget *makePreferences_Widget(void) {
             setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("${prefs.theme.white}", "theme.set arg:3"))), "prefs.theme.3");
         }
         addChildFlags_Widget(values, iClob(themes), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
-        /* Accents. */
+        /* Accents. */ {
+            iLabelWidget *accentMenu = addDialogDropMenu_(headings,
+                                                          values,
+                                                          "${prefs.accent}",
+                                                          accentItems,
+                                                          iElemCount(accentItems),
+                                                          "prefs.accent");
+            int accentId = 0;
+            iForEach(ObjectList,
+                     i,
+                     children_Widget(findChild_Widget(constAs_Widget(accentMenu), "menu"))) {
+                if (isInstance_Object(i.object, &Class_LabelWidget)) {
+                    setIconColor_LabelWidget(i.object, color_ColorAccent(accentId++, iTrue));
+                }
+            }
+        }
+#if 0
         iWidget *accent = new_Widget(); {
             setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.teal}", "accent.set arg:0"))), "prefs.accent.0");
             setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.orange}", "accent.set arg:1"))), "prefs.accent.1");
@@ -3143,15 +3144,53 @@ iWidget *makePreferences_Widget(void) {
             setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.green}", "accent.set arg:3"))), "prefs.accent.3");
             setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.blue}", "accent.set arg:4"))), "prefs.accent.4");
             setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.gray}", "accent.set arg:5"))), "prefs.accent.5");
-#if defined (iPlatformApple)
+#  if defined (iPlatformApple)
             /* TODO: Re-enable this! Accent colors should now be applied in a way that suits 
                the system accents, as long as there are light and dark variants. */
 //            setId_Widget(addChild_Widget(accent, iClob(new_LabelWidget("${prefs.accent.system}", "accent.set arg:2"))), "prefs.accent.2");
-#endif
+#  endif
         }
         addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.accent}")));
         addChildFlags_Widget(values, iClob(accent), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
-        makeTwoColumnHeading_("${heading.prefs.pagecontent}", headings, values);
+#endif
+        addDialogPadding_(headings, values);
+#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME)
+        addDialogToggle_(headings, values, "${prefs.customframe}", "prefs.customframe");
+#endif
+        addDialogToggleGroup_(
+            headings,
+            values,
+            "${prefs.uilayout}",
+            (const char *[]) {
+#if defined (LAGRANGE_MAC_MENUBAR)
+                "prefs.bottomnavbar", "prefs.bottomtabbar", NULL
+#else
+                "prefs.bottomnavbar", "prefs.bottomtabbar", "prefs.menubar", NULL
+#endif
+            },
+            iInvalidSize);
+        addDialogToggle_(headings, values, "${prefs.evensplit}", "prefs.evensplit");        
+        if (!isTerminal_Platform()) {
+            addDialogPadding_(headings, values);
+//            makeTwoColumnHeading_("${heading.prefs.sizing}", headings, values);
+            addPrefsInputWithHeading_(headings, values, "prefs.uiscale", iClob(new_InputWidget(5)));
+            addDialogToggle_(headings, values, "${prefs.retainwindow}", "prefs.retainwindow");
+            addDialogPadding_(headings, values);
+            addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.ui}")));
+            addFontButtons_(values, "ui");
+            addDialogToggle_(headings, values, "${prefs.font.smooth}", "prefs.font.smooth");                
+        }
+    }
+    /* Page style. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs,
+                                                   fonts_Icon " ${heading.prefs.style}",
+                                                   orange_ColorId,
+                                                   '3',
+                                                   &headings,
+                                                   &values),
+                     "prefs.page.style");
+        //        makeTwoColumnHeading_("${heading.prefs.paragraph}", headings, values);
+        //        makeTwoColumnHeading_("${heading.prefs.pagecontent}", headings, values);
         for (int i = 0; i < 2; ++i) {
             const iBool isDark = (i == 0);
             const char *mode = isDark ? "dark" : "light";
@@ -3173,6 +3212,14 @@ iWidget *makePreferences_Widget(void) {
             addRadioButton_(sats, "prefs.saturation.0", "0 %", "saturation.set arg:0");
         }
         addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
+        addDialogPadding_(headings, values);
+        addDialogToggleGroup_(headings,
+                              values,
+                              "${prefs.boldlink}",
+                              (const char *[]){ "prefs.boldlink.visited",
+                                                "prefs.boldlink.dark",
+                                                "prefs.boldlink.light" },
+                              3);
         /* Colorize images. */ {
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.imagestyle}")));
             iLabelWidget *button = makeMenuButton_LabelWidget(
@@ -3184,11 +3231,10 @@ iWidget *makePreferences_Widget(void) {
             setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag),
                          "prefs.imagestyle");
         }
-    }
-    /* Fonts. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts");
-        /* Fonts. */
+//        addDialogPadding_(headings, values);
+        /* Text settings. */
         if (!isTerminal_Platform()) {
+            makeTwoColumnHeading_("${heading.prefs.fonts}", headings, values);
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.heading}")));
             addFontButtons_(values, "heading");
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.body}")));
@@ -3203,28 +3249,20 @@ iWidget *makePreferences_Widget(void) {
                                   2);
             addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.monodoc}")));
             addFontButtons_(values, "monodoc");
-            addDialogPadding_(headings, values);
-            addDialogToggleGroup_(headings,
-                                  values,
-                                  "${prefs.gemtext.ansi}",
-                                  (const char *[]){ "prefs.gemtext.ansi.fg",
-                                                    "prefs.gemtext.ansi.bg",
-                                                    "prefs.gemtext.ansi.fontstyle" },
-                                  3);
-            addDialogToggle_(headings, values, "${prefs.font.warnmissing}", "prefs.font.warnmissing");
-            addDialogToggle_(headings, values, "${prefs.font.smooth}", "prefs.font.smooth");                
-            addDialogPadding_(headings, values);
-            addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.ui}")));
-            addFontButtons_(values, "ui");
         }
         else {
             /* Terminal font settings. */
             addDialogToggle_(headings, values, "${prefs.tui.simple}", "prefs.tui.simple");
         }
     }
-    /* Style. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.style}", '5', &headings, &values), "prefs.page.style");
-//        makeTwoColumnHeading_("${heading.prefs.paragraph}", headings, values);
+    /* Page layout. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs,
+                                                   pageLayout_Icon " ${heading.prefs.layout}",
+                                                   orange_ColorId,
+                                                   '4',
+                                                   &headings,
+                                                   &values),
+                     "prefs.page.layout");
         addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}")));
         iWidget *widths = new_Widget();
         /* Line widths. */ {
@@ -3241,37 +3279,110 @@ iWidget *makePreferences_Widget(void) {
         }
         addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
         addPrefsInputWithHeading_(headings, values, "prefs.linespacing", iClob(new_InputWidget(5)));
+        addPrefsInputWithHeading_(headings, values, "prefs.tabwidth", iClob(new_InputWidget(5)));
 #if defined (LAGRANGE_ENABLE_HARFBUZZ)
         addDialogToggle_(headings, values, "${prefs.justify}", "prefs.justify");
 #endif
         addDialogToggle_(headings, values, "${prefs.biglede}", "prefs.biglede");
-        addDialogToggle_(headings, values, "${prefs.plaintext.wrap}", "prefs.plaintext.wrap");
-        addDialogToggle_(headings, values, "${prefs.gopher.gemstyle}", "prefs.gopher.gemstyle");
         addDialogPadding_(headings, values);
-        addPrefsInputWithHeading_(headings, values, "prefs.tabwidth", iClob(new_InputWidget(5)));
         addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.quoteicon}")));
         iWidget *quote = new_Widget(); {
             addRadioButton_(quote, "prefs.quoteicon.1", "${prefs.quoteicon.icon}", "quoteicon.set arg:1");
             addRadioButton_(quote, "prefs.quoteicon.0", "${prefs.quoteicon.line}", "quoteicon.set arg:0");
         }
         addChildFlags_Widget(values, iClob(quote), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
+        addDialogToggle_(headings, values, "${prefs.plaintext.wrap}", "prefs.plaintext.wrap");
+        addDialogPadding_(headings, values);
+        addDialogToggle_(headings, values, "${prefs.centershort}", "prefs.centershort");
+        addDialogToggle_(headings, values, "${prefs.sideicon}", "prefs.sideicon");
+        addDialogToggle_(headings, values, "${prefs.collapsepreonload}", "prefs.collapsepreonload");
+    }
+    /* Content. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs, photo_Icon " ${heading.prefs.content}", green_ColorId, '5', &headings, &values), "prefs.page.content");
         addDialogToggleGroup_(headings,
                               values,
-                              "${prefs.boldlink}",
-                              (const char *[]){ "prefs.boldlink.visited",
-                                                "prefs.boldlink.dark",
-                                                "prefs.boldlink.light" },
+                              "${prefs.gemtext.ansi}",
+                              (const char *[]){ "prefs.gemtext.ansi.fg",
+                                                "prefs.gemtext.ansi.bg",
+                                                "prefs.gemtext.ansi.fontstyle" },
                               3);
+        addDialogToggle_(headings, values, "${prefs.gopher.gemstyle}", "prefs.gopher.gemstyle");
+        addDialogToggle_(headings, values, "${prefs.markdown.viewsource}", "prefs.markdown.viewsource");
         addDialogPadding_(headings, values);
-        addDialogToggle_(headings, values, "${prefs.sideicon}", "prefs.sideicon");
-        addDialogToggle_(headings, values, "${prefs.centershort}", "prefs.centershort");
-        addDialogToggle_(headings, values, "${prefs.collapsepreonload}", "prefs.collapsepreonload");
+        addDialogToggle_(headings, values, "${prefs.dataurl.openimages}", "prefs.dataurl.openimages");
+        addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex");        
+        addDialogPadding_(headings, values);
+        addDialogToggle_(headings, values, "${prefs.font.warnmissing}", "prefs.font.warnmissing");
+    }
+    /* User Interface. */ {
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs, computer_Icon " ${heading.prefs.interface}", cyan_ColorId, '6', &headings, &values),
+                     "prefs.page.ui");
+        addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink");
+        addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom");
+        /* Return key behaviors. */ {
+            addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.returnkey}")));
+            iLabelWidget *returnKey = makeMenuButton_LabelWidget(
+                returnKeyBehaviors[findWidestLabel_MenuItem(returnKeyBehaviors,
+                                                            iElemCount(returnKeyBehaviors) - 1)]
+                    .label,
+                returnKeyBehaviors,
+                iElemCount(returnKeyBehaviors) - 1);
+            setBackgroundColor_Widget(findChild_Widget(as_Widget(returnKey), "menu"),
+                                      uiBackgroundMenu_ColorId);
+            setId_Widget(addChildFlags_Widget(values, iClob(returnKey), alignLeft_WidgetFlag),
+                         "prefs.returnkey");
+        }
+        if (!isTerminal_Platform()) {
+            addDialogToggle_(headings, values, "${prefs.imageloadscroll}", "prefs.imageloadscroll");
+        }
+        addDialogToggle_(headings, values, "${prefs.time.24h}", "prefs.time.24h");
+        addDialogPadding_(headings, values);
+        addDialogToggle_(headings, values, "${prefs.animate}", "prefs.animate");
+        if (!isTerminal_Platform()) {
+            addDialogToggle_(headings, values, "${prefs.blink}", "prefs.blink");
+        }
+//        makeTwoColumnHeading_("${heading.prefs.scrolling}", headings, values);
+        addDialogToggle_(headings, values, "${prefs.smoothscroll}", "prefs.smoothscroll");
+        /* Scroll speeds. */ {
+            for (int type = 0; type < max_ScrollType; type++) {
+                const char *typeStr = (type == mouse_ScrollType ? "mouse" : "keyboard");
+                addChild_Widget(headings,
+                                iClob(makeHeading_Widget(type == mouse_ScrollType
+                                                             ? "${prefs.scrollspeed.mouse}"
+                                                             : "${prefs.scrollspeed.keyboard}")));
+                /* TODO: Make a SliderWidget. */
+                iWidget *scrollSpeed = new_Widget();                
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.7",  typeStr), "0", format_CStr("scrollspeed arg:7  type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.10", typeStr), "1", format_CStr("scrollspeed arg:10 type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.13", typeStr), "2", format_CStr("scrollspeed arg:13 type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.17", typeStr), "3", format_CStr("scrollspeed arg:17 type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.23", typeStr), "4", format_CStr("scrollspeed arg:23 type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.30", typeStr), "5", format_CStr("scrollspeed arg:30 type:%d", type));
+                addRadioButton_(scrollSpeed, format_CStr("prefs.scrollspeed.%s.40", typeStr), "6", format_CStr("scrollspeed arg:40 type:%d", type));
+                addChildFlags_Widget(
+                    values, iClob(scrollSpeed), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
+            }
+        }
+//        if (deviceType_App() == phone_AppDeviceType) {
+//            addDialogToggle_(headings, values, "${prefs.hidetoolbarscroll}", "prefs.hidetoolbarscroll");
+//        }
+    }
+    /* Keybindings. */ {
+        iBindingsWidget *bind = new_BindingsWidget();
+        appendFramelessTabPage_Widget(tabs, iClob(bind), keyboard_Icon " ${heading.prefs.keys}", cyan_ColorId, '7', KMOD_PRIMARY);
     }
     /* Network. */ {
-        setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.network}", '6', &headings, &values), "prefs.page.network");
+        setId_Widget(appendTwoColumnTabPage_Widget(tabs,
+                                                   network_Icon " ${heading.prefs.network}",
+                                                   blue_ColorId,
+                                                   '8',
+                                                   &headings,
+                                                   &values),
+                     "prefs.page.network");
         addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}")));
         addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
         addPrefsInputWithHeading_(headings, values, "prefs.urlsize", iClob(new_InputWidget(10)));
+        addDialogPadding_(headings, values);
         /* Cache size. */ {
             iInputWidget *cache = new_InputWidget(4);
             setSelectAllOnFocus_InputWidget(cache, iTrue);
@@ -3294,17 +3405,14 @@ iWidget *makePreferences_Widget(void) {
                                          resizeToParentHeight_WidgetFlag);
             setContentPadding_InputWidget(mem, 0, width_Widget(unit) - 4 * gap_UI);
         }
-        makeTwoColumnHeading_("${heading.prefs.certs}", headings, values);
-        addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0)));
-        addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0)));
         makeTwoColumnHeading_("${heading.prefs.proxies}", headings, values);
         addPrefsInputWithHeading_(headings, values, "prefs.proxy.gemini", iClob(new_InputWidget(0)));
         addPrefsInputWithHeading_(headings, values, "prefs.proxy.gopher", iClob(new_InputWidget(0)));
         addPrefsInputWithHeading_(headings, values, "prefs.proxy.http", iClob(new_InputWidget(0)));
+        makeTwoColumnHeading_("${heading.prefs.certs}", headings, values);
+        addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0)));
+        addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0)));
     }
-    /* Keybindings. */
-    iBindingsWidget *bind = new_BindingsWidget();
-    appendFramelessTabPage_Widget(tabs, iClob(bind), "${heading.prefs.keys}", '7', KMOD_PRIMARY);
     addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));
     updatePreferencesLayout_Widget(dlg);
     const iMenuItem actions[] = { { "${menu.fonts}", 0, 0, "!open url:about:fonts" },
@@ -3314,7 +3422,7 @@ iWidget *makePreferences_Widget(void) {
     iWidget *buttons = addChild_Widget(
         dlg, iClob(makeDialogButtons_Widget(actions + actOffset, iElemCount(actions) - actOffset)));
     setId_Widget(child_Widget(buttons, 0), "prefs.aboutfonts");
-    setFlags_Widget(findChild_Widget(dlg, "prefs.aboutfonts"), hidden_WidgetFlag, iTrue);
+//    setFlags_Widget(findChild_Widget(dlg, "prefs.aboutfonts"), hidden_WidgetFlag, iTrue);
     addChild_Widget(dlg->root->widget, iClob(dlg));    
     setupSheetTransition_Mobile(dlg, iTrue);
     return dlg;
@@ -3450,7 +3558,7 @@ iWidget *makeBookmarkEditor_Widget(uint32_t folderId, iBool withDup) {
             setHint_InputWidget(inputs[3], "${hint.dlg.bookmark.notes}");
             addDialogInputWithHeading_(headings, values, "${dlg.bookmark.icon}",  "bmed.icon",  iClob(inputs[4] = new_InputWidget(1)));            
             /* Buttons for special tags. */
-            addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));
+//            addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));
             iWidget *special = addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));
             setFlags_Widget(special, collapse_WidgetFlag, iTrue);
             setId_Widget(special, "bmed.special");
diff --git a/src/ui/util.h b/src/ui/util.h
index b05550df..bb661944 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -330,10 +330,11 @@ iWidget *       makeMenuBar_Widget      (const iMenuItem *topLevelMenus, size_t
 
 iWidget *       makeTabs_Widget         (iWidget *parent);
 void            setTabBarPosition_Widget(iWidget *tabs, iBool atBottom);
+void            setVerticalTabBar_Widget(iWidget *tabs);
 void            appendTabPage_Widget    (iWidget *tabs, iWidget *page, const char *label, int key, int kmods);
-void            appendFramelessTabPage_Widget(iWidget *tabs, iWidget *page, const char *title, int shortcut, int kmods);
-iWidget *       appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int shortcut, iWidget **headings,
-                                              iWidget **values);
+void            appendFramelessTabPage_Widget(iWidget *tabs, iWidget *page, const char *title, int iconColor, int shortcut, int kmods);
+iWidget *       appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title, int iconColor, int shortcut,
+                                              iWidget **headings, iWidget **values);
 void            prependTabPage_Widget   (iWidget *tabs, iWidget *page, const char *label, int key, int kmods);
 iWidget *       removeTabPage_Widget    (iWidget *tabs, size_t index); /* returns the page */
 void            resizeToLargestPage_Widget  (iWidget *tabs);
@@ -342,6 +343,7 @@ void            addTabCloseButton_Widget(iWidget *tabs, const iWidget *page, con
 void            setTabPageLabel_Widget  (iWidget *tabs, const iAnyObject *page, const iString *label);
 iWidget *       tabPage_Widget          (iWidget *tabs, size_t index);
 iLabelWidget *  tabPageButton_Widget    (iWidget *tabs, const iAnyObject *page);
+iBool           isVerticalTabBar_Widget (const iWidget *tabs);
 iBool           isTabButton_Widget      (const iWidget *);
 void            moveTabButtonToEnd_Widget(iWidget *tabButton);
 size_t          tabPageIndex_Widget     (const iWidget *tabs, const iAnyObject *page);
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.15/cdiff/430525d298e75ae2c24de54af58f6f12c5374437
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
82.128103 milliseconds
Gemini-to-HTML Time
1.814153 milliseconds

This content has been proxied by September (3851b).