Lagrange [work/v1.10]

Mobile: User-configurable phone toolbar buttons

=> 5d247c7fafddcb46d83572af788a04f835d48d42

diff --git a/po/en.po b/po/en.po
index a4b83dcc..cf9643a0 100644
--- a/po/en.po
+++ b/po/en.po
@@ -344,6 +344,9 @@ msgstr "Go to Parent"
 msgid "menu.root"
 msgstr "Go to Root"
 
+msgid "menu.home"
+msgstr "Go Home"
+
 msgid "menu.reload"
 msgstr "Reload Page"
 
@@ -1419,6 +1422,15 @@ msgstr "Load image on scroll:"
 msgid "prefs.hidetoolbarscroll"
 msgstr "Hide toolbar on scroll:"
 
+msgid "heading.prefs.toolbaractions"
+msgstr "Toolbar Actions"
+
+msgid "prefs.toolbaraction1"
+msgstr "Button 1"
+
+msgid "prefs.toolbaraction2"
+msgstr "Button 2"
+
 msgid "prefs.ostheme"
 msgstr "Use system theme:"
 
diff --git a/res/lang/cs.bin b/res/lang/cs.bin
index bc34d7e8..9069f4b0 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 5fb9eb03..62893c64 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 114fa684..12cde1d0 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 3d16450c..be6c9cef 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 fe6bdbb5..feb0b8ea 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 c96da0b0..26188c5b 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 d06dfc9c..86efb862 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 4cda45d8..e6977fd9 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 7ffb40ec..f282366d 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 e698c7ac..3ca7ee30 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 f951f0c5..29faea06 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 c4671e06..9c8bc9bd 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 2788dc3f..4414fdb3 100644
Binary files a/res/lang/isv.bin and b/res/lang/isv.bin differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index 29260245..aae2b705 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 712d8a01..1166b064 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 79b1208f..b43f885c 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 79e76d20..eec114aa 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 31f9536e..0202545c 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 758dba68..95bdffdc 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 6aedfe5f..e222a609 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 036ecca3..648016a8 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 d2aa482d..daa31717 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 58eecf51..1e66c6cf 100644
--- a/src/app.c
+++ b/src/app.c
@@ -248,6 +248,10 @@ static iString *serializePrefs_App_(const iApp *d) {
     appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
     appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing);
     appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey);
+#if defined (iPlatformMobile)
+    appendFormat_String(str, "toolbar.action.set arg:%d button:0\n", d->prefs.toolbarActions[0]);
+    appendFormat_String(str, "toolbar.action.set arg:%d button:1\n", d->prefs.toolbarActions[1]);
+#endif
     iConstForEach(StringSet, fp, d->prefs.disabledFontPacks) {
         appendFormat_String(str, "fontpack.disable id:%s\n", cstr_String(fp.value));
     }
@@ -1870,6 +1874,12 @@ static void updatePrefsPinSplitButtons_(iWidget *d, int value) {
     }
 }
 
+static void updatePrefsToolBarActionButton_(iWidget *prefs, int buttonIndex, int action) {
+    updateDropdownSelection_LabelWidget(
+        findChild_Widget(prefs, format_CStr("prefs.toolbaraction%d", buttonIndex + 1)),
+        format_CStr(" arg:%d button:%d", action, buttonIndex));    
+}
+
 static void updateScrollSpeedButtons_(iWidget *d, enum iScrollType type, const int value) {
     const char *typeStr = (type == mouse_ScrollType ? "mouse" : "keyboard");
     for (int i = 0; i <= 40; i++) {
@@ -1960,6 +1970,10 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
                                             format_CStr("returnkey.set arg:%d", arg_Command(cmd)));
         return iFalse;
     }
+    else if (equal_Command(cmd, "toolbar.action.set")) {
+        updatePrefsToolBarActionButton_(d, argLabel_Command(cmd, "button"), arg_Command(cmd));
+        return iFalse;
+    }
     else if (equal_Command(cmd, "pinsplit.set")) {
         updatePrefsPinSplitButtons_(d, arg_Command(cmd));
         return iFalse;
@@ -2268,6 +2282,12 @@ iBool handleCommand_App(const char *cmd) {
         }
         return iTrue;
     }
+    else if (equal_Command(cmd, "toolbar.action.set")) {
+        d->prefs.toolbarActions[iClamp(argLabel_Command(cmd, "button"), 0, 1)] =
+            iClamp(arg_Command(cmd), 0, max_ToolbarAction - 1);
+        postCommand_App("~toolbar.actions.changed");
+        return iTrue;        
+    }
     else if (equal_Command(cmd, "translation.languages")) {
         d->prefs.langFrom = argLabel_Command(cmd, "from");
         d->prefs.langTo   = argLabel_Command(cmd, "to");
@@ -3006,6 +3026,8 @@ iBool handleCommand_App(const char *cmd) {
         updateDropdownSelection_LabelWidget(
             findChild_Widget(dlg, "prefs.returnkey"),
             format_CStr("returnkey.set arg:%d", d->prefs.returnKey));
+        updatePrefsToolBarActionButton_(dlg, 0, d->prefs.toolbarActions[0]);
+        updatePrefsToolBarActionButton_(dlg, 1, d->prefs.toolbarActions[1]);
         setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize);
         setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"),
                             collectNewFormat_String("%g", uiScale_Window(as_Window(d->window))));
diff --git a/src/defs.h b/src/defs.h
index 9a466674..25c0ceeb 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -66,6 +66,23 @@ enum iReturnKeyFlag {
     accept_ReturnKeyFlag        = 4, /* shift */
 };
 
+enum iToolbarAction {
+    back_ToolbarAction        = 0,
+    forward_ToolbarAction     = 1,
+    home_ToolbarAction        = 2,
+    parent_ToolbarAction      = 3,
+    reload_ToolbarAction      = 4,
+    newTab_ToolbarAction      = 5,
+    closeTab_ToolbarAction    = 6,
+    addBookmark_ToolbarAction = 7,
+    translate_ToolbarAction   = 8,
+    upload_ToolbarAction      = 9,
+    editPage_ToolbarAction    = 10,
+    findText_ToolbarAction    = 11,
+    settings_ToolbarAction    = 12,
+    max_ToolbarAction
+};
+
 /* Return key behavior is not handled via normal bindings because only certain combinations
    are valid. */
 enum iReturnKeyBehavior {
diff --git a/src/prefs.c b/src/prefs.c
index 6b0164b6..426b7212 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -44,6 +44,8 @@ void init_Prefs(iPrefs *d) {
     d->uiAnimations      = iTrue;
     d->uiScale           = 1.0f; /* default set elsewhere */
     d->zoomPercent       = 100;
+    d->toolbarActions[0] = back_ToolbarAction;
+    d->toolbarActions[1] = forward_ToolbarAction;
     d->sideIcon          = iTrue;
     d->hideToolbarOnScroll = iTrue;
     d->blinkingCursor    = iTrue;
diff --git a/src/prefs.h b/src/prefs.h
index 6c79a3e1..43f7fc0e 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -159,6 +159,7 @@ struct Impl_Prefs {
     enum iColorAccent accent;
     /* Window and User Interface */
     float            uiScale;
+    enum iToolbarAction toolbarActions[2];
     /* Document presentation */
     int              zoomPercent;
     /* Behavior */
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 08d8dba2..e34cad3a 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -37,6 +37,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 #   include "ios.h"
 #endif
 
+const iToolbarActionSpec toolbarActions_Mobile[max_ToolbarAction] = {
+    { backArrow_Icon, "${menu.back}", "navigate.back" },
+    { forwardArrow_Icon, "${menu.forward}", "navigate.forward" },
+    { home_Icon, "${menu.home}", "navigate.home" },
+    { upArrow_Icon, "${menu.parent}", "navigate.parent" },
+    { reload_Icon, "${menu.reload}", "navigate.reload" },
+    { openTab_Icon, "${menu.newtab}", "tabs.new" },
+    { close_Icon, "${menu.closetab}", "tabs.close" },
+    { bookmark_Icon, "${menu.page.bookmark}", "bookmark.add" },
+    { globe_Icon, "${menu.page.translate}", "document.translate" },
+    { upload_Icon, "${menu.page.upload}", "document.upload" },
+    { edit_Icon, "${menu.page.upload.edit}", "document.upload copy:1" },
+    { magnifyingGlass_Icon, "${menu.find}", "focus.set id:find.input" },
+    { gear_Icon, "${menu.settings}", "preferences" },        
+};
+
 iBool isUsingPanelLayout_Mobile(void) {
     return deviceType_App() != desktop_AppDeviceType;
 }
diff --git a/src/ui/mobile.h b/src/ui/mobile.h
index 54f55fd2..c19623f9 100644
--- a/src/ui/mobile.h
+++ b/src/ui/mobile.h
@@ -22,8 +22,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 
 #pragma once
 
+#include "defs.h"
 #include 
 
+iDeclareType(ToolbarActionSpec)
+    
+struct Impl_ToolbarActionSpec {
+    const char *icon;
+    const char *label;
+    const char *command;
+};
+
+const iToolbarActionSpec toolbarActions_Mobile[max_ToolbarAction];
+
 iDeclareType(Widget)
 iDeclareType(MenuItem)
     
diff --git a/src/ui/root.c b/src/ui/root.c
index bc2bc0fb..31176115 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -592,14 +592,21 @@ static void updateNavBarIdentity_(iWidget *navBar) {
 
 static void updateNavDirButtons_(iWidget *navBar) {
     const iHistory *history = history_DocumentWidget(document_App());
-    const iBool atOldest = atOldest_History(history);
-    const iBool atNewest = atNewest_History(history);
+    iBool atOldest = atOldest_History(history);
+    iBool atNewest = atNewest_History(history);
     setFlags_Widget(findChild_Widget(navBar, "navbar.back"), disabled_WidgetFlag, atOldest);
     setFlags_Widget(findChild_Widget(navBar, "navbar.forward"), disabled_WidgetFlag, atNewest);
     iWidget *toolBar = findWidget_App("toolbar");
     if (toolBar) {
-        iLabelWidget *back = findChild_Widget(toolBar, "toolbar.back");
-        iLabelWidget *fwd  = findChild_Widget(toolBar, "toolbar.forward");
+        /* Reset the state. */
+        for (int i = 0; i < 2; i++) {
+            const char *id = (i == 0 ? "toolbar.action1" : "toolbar.action2");            
+            setFlags_Widget(findChild_Widget(toolBar, id), disabled_WidgetFlag, iFalse);
+            setOutline_LabelWidget(findChild_Widget(toolBar, id), iFalse);
+        }
+        /* Disable certain actions. */
+        iLabelWidget *back = findMenuItem_Widget(toolBar, "navigate.back");
+        iLabelWidget *fwd  = findMenuItem_Widget(toolBar, "navigate.forward");
         setFlags_Widget(as_Widget(back), disabled_WidgetFlag, atOldest);
         setOutline_LabelWidget(back, atOldest);
         setFlags_Widget(as_Widget(fwd), disabled_WidgetFlag, atNewest);
@@ -1062,14 +1069,23 @@ static iBool handleSearchBarCommands_(iWidget *searchBar, const char *cmd) {
 }
 
 #if defined (iPlatformMobile)
-static void dismissSidebar_(iWidget *sidebar, const char *toolButtonId) {
-    if (isVisible_Widget(sidebar)) {
-        postCommandf_App("%s.toggle", cstr_String(id_Widget(sidebar)));
-//        if (toolButtonId) {
-            //            setFlags_Widget(findWidget_App(toolButtonId), noBackground_WidgetFlag, iTrue);
-//        }
-        setVisualOffset_Widget(sidebar, height_Widget(sidebar), 250, easeIn_AnimFlag);
+
+static void updateToolBarActions_(iWidget *toolBar) {
+    const iPrefs *prefs = prefs_App();
+    for (int i = 0; i < 2; i++) {
+        int action = prefs->toolbarActions[i]
+                         ? prefs->toolbarActions[i]
+                         : (i == 0 ? back_ToolbarAction : forward_ToolbarAction);
+        iLabelWidget *button =
+            findChild_Widget(toolBar, i == 0 ? "toolbar.action1" : "toolbar.action2");
+        if (button) {
+            setFlags_Widget(as_Widget(button), disabled_WidgetFlag, iFalse);
+            setOutline_LabelWidget(button, iFalse);
+            updateTextCStr_LabelWidget(button, toolbarActions_Mobile[action].icon);
+            setCommand_LabelWidget(button, collectNewCStr_String(toolbarActions_Mobile[action].command));
+        }
     }
+    refresh_Widget(toolBar);
 }
 
 static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) {
@@ -1081,13 +1097,6 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) {
         return iTrue;
     }
     else if (equal_Command(cmd, "toolbar.showview")) {
-        /* TODO: Clean this up. */
-//        iWidget *sidebar  = findWidget_App("sidebar");
-//        iWidget *sidebar2 = findWidget_App("sidebar2");
-//        dismissSidebar_(sidebar2, "toolbar.ident");
-//        const iBool isVisible = isVisible_Widget(sidebar);
-        /* If a sidebar hasn't been shown yet, it's height is zero. */
-//        const int viewHeight = size_Root(get_Root()).y;
         if (arg_Command(cmd) >= 0) {
             postCommandf_App("sidebar.mode arg:%d show:1", arg_Command(cmd));
         }
@@ -1102,29 +1111,6 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) {
             postCommandf_App("sidebar.toggle");
         }
         postCommand_App("preferences idents:1");
-#if 0
-        /* TODO: Clean this up. */
-        iWidget *sidebar2 = findWidget_App("sidebar2");
-        //dismissSidebar_(sidebar, "toolbar.view");
-        if (isVisible_Widget(sidebar)) {
-            postCommandf_App("sidebar.toggle");
-        }
-        const iBool isVisible = isVisible_Widget(sidebar2);
-        //        setFlags_Widget(findChild_Widget(toolBar, "toolbar.ident"), noBackground_WidgetFlag,
-        //                        isVisible);
-        /* If a sidebar hasn't been shown yet, it's height is zero. */
-        const int viewHeight = size_Root(get_Root()).y;
-        if (isVisible) {
-            dismissSidebar_(sidebar2, NULL);
-        }
-        else {
-            postCommand_App("sidebar2.mode arg:3 show:1");
-            int offset = height_Widget(sidebar2);
-            if (offset == 0) offset = size_Root(get_Root()).y;
-            setVisualOffset_Widget(sidebar2, offset, 0, 0);
-            setVisualOffset_Widget(sidebar2, 0, 400, easeOut_AnimFlag | softer_AnimFlag);
-        }
-#endif
         return iTrue;
     }
     else if (equal_Command(cmd, "sidebar.mode.changed")) {
@@ -1132,8 +1118,13 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) {
         updateTextCStr_LabelWidget(viewTool, icon_SidebarMode(arg_Command(cmd)));
         return iFalse;
     }
+    else if (equal_Command(cmd, "toolbar.actions.changed")) {
+        updateToolBarActions_(toolBar);
+        return iFalse;        
+    }
     return iFalse;
 }
+
 #endif /* defined (iPlatformMobile) */
 
 static iLabelWidget *newLargeIcon_LabelWidget(const char *text, const char *cmd) {
@@ -1552,14 +1543,14 @@ void createUserInterface_Root(iRoot *d) {
                      "toolbar.close");
 #else
         setId_Widget(addChildFlags_Widget(toolBar,
-                                          iClob(newLargeIcon_LabelWidget(backArrow_Icon, "navigate.back")),
+                                          iClob(newLargeIcon_LabelWidget("", "...")),
                                           frameless_WidgetFlag),
-                     "toolbar.back");
+                     "toolbar.action1");
 #endif
         setId_Widget(addChildFlags_Widget(toolBar,
-                                          iClob(newLargeIcon_LabelWidget(forwardArrow_Icon, "navigate.forward")),
+                                          iClob(newLargeIcon_LabelWidget("", "...")),
                                           frameless_WidgetFlag),
-                     "toolbar.forward");
+                     "toolbar.action2");
         iWidget *identButton;
         setId_Widget(identButton = addChildFlags_Widget(
                          toolBar,
@@ -1589,10 +1580,10 @@ void createUserInterface_Root(iRoot *d) {
         setId_Widget(as_Widget(menuButton), "toolbar.navmenu");
         addChildFlags_Widget(toolBar, iClob(menuButton), frameless_WidgetFlag);
         iForEach(ObjectList, i, children_Widget(toolBar)) {
-            iLabelWidget *btn = i.object;
             setFlags_Widget(i.object, noBackground_WidgetFlag, iTrue);
         }
         updateToolbarColors_Root(d);
+        updateToolBarActions_(toolBar);
         const iMenuItem items[] = {
             { book_Icon " ${sidebar.bookmarks}", 0, 0, "toolbar.showview arg:0" },
             { star_Icon " ${sidebar.feeds}", 0, 0, "toolbar.showview arg:1" },
diff --git a/src/ui/util.c b/src/ui/util.c
index ab7e9ebf..6add5c89 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -2383,6 +2383,15 @@ iWidget *makePreferences_Widget(void) {
           format_CStr("returnkey.set arg:%d", acceptWithPrimaryMod_ReturnKeyBehavior) },
         { NULL }
     };
+    iMenuItem toolbarActionItems[2][max_ToolbarAction + 1];
+    iZap(toolbarActionItems);
+    for (int j = 0; j < 2; j++) {
+        for (int i = 0; i < max_ToolbarAction; i++) {
+            toolbarActionItems[j][i].label = toolbarActions_Mobile[i].label;
+            toolbarActionItems[j][i].command =
+                format_CStr("toolbar.action.set arg:%d button:%d", i, j);
+        }
+    }
     iMenuItem docThemes[2][max_GmDocumentTheme + 1];
     for (int i = 0; i < 2; ++i) {
         const iBool isDark = (i == 0);
@@ -2476,8 +2485,10 @@ iWidget *makePreferences_Widget(void) {
             { "title id:heading.prefs.interface" },
             { "dropdown device:0 id:prefs.returnkey", 0, 0, (const void *) returnKeyBehaviors },
             { "padding device:1" },
-            //{ "toggle id:prefs.hoverlink" },
             { "toggle device:2 id:prefs.hidetoolbarscroll" },
+            { "heading device:2 id:heading.prefs.toolbaractions" },
+            { "dropdown device:2 id:prefs.toolbaraction1", 0, 0, (const void *) toolbarActionItems[0] },
+            { "dropdown device:2 id:prefs.toolbaraction2", 0, 0, (const void *) toolbarActionItems[1] },
             { "heading id:heading.prefs.sizing" },
             { "input id:prefs.uiscale maxlen:8" },
             { NULL }
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.10/cdiff/5d247c7fafddcb46d83572af788a04f835d48d42
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
67.598992 milliseconds
Gemini-to-HTML Time
0.861814 milliseconds

This content has been proxied by September (ba2dc).