Lagrange [work/v1.15]

Added tab context menu items for changing tab order

=> a6353f70558553bfada274147a82997d4c79ab08

diff --git a/po/en.po b/po/en.po
index a4433caa..e429e327 100644
--- a/po/en.po
+++ b/po/en.po
@@ -172,6 +172,12 @@ msgstr "Close Tabs To Right"
 msgid "menu.duptab"
 msgstr "Duplicate Tab"
 
+msgid "menu.movetab.left"
+msgstr "Move Tab Left"
+
+msgid "menu.movetab.right"
+msgstr "Move Tab Right"
+
 msgid "menu.split.merge"
 msgstr "Unsplit"
 
diff --git a/res/lang/cs.bin b/res/lang/cs.bin
index 8cdbed59..8dfd137f 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 8a294ca4..c7e8b6fd 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 9a4029f1..1156d3a2 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 4daa72a7..1cb1dff7 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 aab45c44..55c03194 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 10188964..e19a556e 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 bccc98b6..c70c4037 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 c50caa4d..af586967 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 1ab16b46..64c831ee 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 4ec109fc..fdbf3118 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 e3c34beb..91677f87 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 5570e349..fd4d0b45 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 ce6aac3b..ca609204 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 ce5a10c9..97fbb74a 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 21d1cd3a..41878135 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 34d9dcb3..3b3afe12 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 c0f06c15..1dddec90 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 c067b156..e37a947b 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 525b90f3..ea472b4c 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 461b2ad5..3329bb80 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 448350b9..a40dcac0 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 622dc980..3aef2d8c 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 fe0f2b42..cb990f8a 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 4668a81f..5058e09d 100644
Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index c6f99bb2..9c40329d 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -4190,6 +4190,15 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
         removeTicker_App(prerender_DocumentWidget_, d);
         return iFalse;
     }
+    else if (equal_Command(cmd, "tabs.move") && d == document_App()) {
+        int dir = iSign(arg_Command(cmd));
+        if (dir) {
+            iWidget *tabs = findWidget_App("doctabs");
+            size_t tabPos = tabPageIndex_Widget(tabs, d);
+            moveTabPage_Widget(tabs, tabPos, tabPos + dir);
+        }
+        return iTrue;
+    }
     else if (equal_Command(cmd, "tab.created")) {
         /* Space for tab buttons has changed. */
         updateWindowTitle_DocumentWidget_(d);
diff --git a/src/ui/keys.c b/src/ui/keys.c
index 663fc49d..8aa80e1c 100644
--- a/src/ui/keys.c
+++ b/src/ui/keys.c
@@ -232,6 +232,8 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] =
     { 79, { "${LC:menu.reopentab}",         SDLK_t, KMOD_SECONDARY,         "tabs.new reopen:1"                 }, 0 },        
     { 80, { "${keys.tab.prev}",             prevTab_KeyShortcut,            "tabs.prev"                         }, 0 },
     { 81, { "${keys.tab.next}",             nextTab_KeyShortcut,            "tabs.next"                         }, 0 },
+    { 84, { "${LC:menu.movetab.left}",      moveTabLeft_KeyShortcut,        "tabs.move arg:-1"                  }, 0 },
+    { 85, { "${LC:menu.movetab.right}",     moveTabRight_KeyShortcut,       "tabs.move arg:1"                   }, 0 },
     { 90, { "${keys.split.menu}",           SDLK_j, KMOD_PRIMARY,           "splitmenu.open"                    }, 0 },
     { 91, { "${keys.split.next}",           SDLK_TAB, KMOD_CTRL,            "keyroot.next",                     }, 0 },
     { 92, { "${keys.split.item} ${menu.split.merge}",           '1', 0,     "ui.split arg:0",                   }, noDirectTrigger_BindFlag },
diff --git a/src/ui/keys.h b/src/ui/keys.h
index 205bd0d8..170f92f9 100644
--- a/src/ui/keys.h
+++ b/src/ui/keys.h
@@ -39,6 +39,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 #   define closeTab_KeyShortcut         SDLK_w,             KMOD_PRIMARY
 #   define prevTab_KeyShortcut          SDLK_LEFTBRACKET,   0
 #   define nextTab_KeyShortcut          SDLK_RIGHTBRACKET,  0
+#   define moveTabLeft_KeyShortcut      SDLK_LEFTBRACKET,   KMOD_ALT
+#   define moveTabRight_KeyShortcut     SDLK_RIGHTBRACKET,  KMOD_ALT
 #   define navigateBack_KeyShortcut     SDLK_LEFT,          0
 #   define navigateForward_KeyShortcut  SDLK_RIGHT,         0
 #   define navigateParent_KeyShortcut   SDLK_r,             KMOD_SHIFT
@@ -61,6 +63,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 #   define closeTab_KeyShortcut         SDLK_w,             KMOD_PRIMARY
 #   define prevTab_KeyShortcut          SDLK_LEFTBRACKET,   KMOD_SECONDARY
 #   define nextTab_KeyShortcut          SDLK_RIGHTBRACKET,  KMOD_SECONDARY
+#   define moveTabLeft_KeyShortcut      SDLK_LEFTBRACKET,   KMOD_TERTIARY
+#   define moveTabRight_KeyShortcut     SDLK_RIGHTBRACKET,  KMOD_TERTIARY
 #   define navigateBack_KeyShortcut     SDLK_LEFT,          KMOD_PRIMARY
 #   define navigateForward_KeyShortcut  SDLK_RIGHT,         KMOD_PRIMARY
 #   define navigateParent_KeyShortcut   SDLK_UP,            KMOD_PRIMARY
@@ -83,6 +87,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 #   define closeTab_KeyShortcut         SDLK_w,             KMOD_PRIMARY
 #   define prevTab_KeyShortcut          SDLK_PAGEUP,        KMOD_PRIMARY
 #   define nextTab_KeyShortcut          SDLK_PAGEDOWN,      KMOD_PRIMARY
+#   define moveTabLeft_KeyShortcut      SDLK_PAGEUP,        KMOD_SECONDARY
+#   define moveTabRight_KeyShortcut     SDLK_PAGEDOWN,      KMOD_SECONDARY
 #   define navigateBack_KeyShortcut     SDLK_LEFT,          KMOD_ALT
 #   define navigateForward_KeyShortcut  SDLK_RIGHT,         KMOD_ALT
 #   define navigateParent_KeyShortcut   SDLK_UP,            KMOD_ALT
diff --git a/src/ui/root.c b/src/ui/root.c
index e93adc57..5422e676 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -1840,8 +1840,11 @@ void createUserInterface_Root(iRoot *d) {
                 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" },
                 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" },
                 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" },
+                { "---" },
+                { leftAngle_Icon " ${menu.movetab.left}", 0, 0, "tabs.move arg:-1" },
+                { rightAngle_Icon " ${menu.movetab.right}", 0, 0, "tabs.move arg:1" },
             },
-            6);
+            9);
         iWidget *barMenu =
             makeMenu_Widget(root,
                             (iMenuItem[]){
diff --git a/src/ui/util.c b/src/ui/util.c
index 3bbf0d73..b212f817 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1818,6 +1818,20 @@ iWidget *removeTabPage_Widget(iWidget *tabs, size_t index) {
     return page;
 }
 
+void moveTabPage_Widget(iWidget *tabs, size_t index, size_t newIndex) {
+    const size_t count = tabCount_Widget(tabs);
+    if (index == newIndex || newIndex >= count) {
+        return;
+    }
+    iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");
+    iWidget *pages   = findChild_Widget(tabs, "tabs.pages");
+    iWidget *button  = child_Widget(buttons, index);
+    iWidget *page    = child_Widget(pages, index);
+    changeChildIndex_Widget(buttons, button, newIndex);
+    changeChildIndex_Widget(pages, page, newIndex);
+    arrange_Widget(tabs);
+}
+
 void resizeToLargestPage_Widget(iWidget *tabs) {
     if (!tabs) return;
 //    puts("RESIZE TO LARGEST PAGE ...");
diff --git a/src/ui/util.h b/src/ui/util.h
index 12c91ee0..bccf0455 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -89,18 +89,21 @@ iInt2   coord_MouseWheelEvent   (const SDL_MouseWheelEvent *);
 #if defined (iPlatformTerminal)
 #   define KMOD_PRIMARY     KMOD_CTRL
 #   define KMOD_SECONDARY   KMOD_ALT
+#   define KMOD_TERTIARY    KMOD_CTRL | KMOD_ALT  /* TODO: does this work? */
 #   define KMOD_ACCEPT      KMOD_ALT
 #   define KMOD_UNDO        KMOD_ALT
 #   define KMOD_ZOOM        0
 #elif defined (iPlatformApple)
 #   define KMOD_PRIMARY     KMOD_GUI
 #   define KMOD_SECONDARY   KMOD_GUI | KMOD_SHIFT
+#   define KMOD_TERTIARY    KMOD_GUI | KMOD_SHIFT | KMOD_ALT
 #   define KMOD_ACCEPT      KMOD_PRIMARY
 #   define KMOD_UNDO        KMOD_PRIMARY
 #   define KMOD_ZOOM        KMOD_PRIMARY
 #else
 #   define KMOD_PRIMARY     KMOD_CTRL
 #   define KMOD_SECONDARY   KMOD_CTRL | KMOD_SHIFT
+#   define KMOD_TERTIARY    KMOD_CTRL | KMOD_SHIFT | KMOD_ALT
 #   define KMOD_ACCEPT      KMOD_PRIMARY
 #   define KMOD_UNDO        KMOD_PRIMARY
 #   define KMOD_ZOOM        KMOD_PRIMARY
@@ -338,6 +341,7 @@ iWidget *       appendTwoColumnTabPage_Widget(iWidget *tabs, const char *title,
                                               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            moveTabPage_Widget      (iWidget *tabs, size_t index, size_t newIndex);
 void            resizeToLargestPage_Widget  (iWidget *tabs);
 void            showTabPage_Widget      (iWidget *tabs, const iAnyObject *page);
 void            addTabCloseButton_Widget(iWidget *tabs, const iWidget *page, const char *command);
diff --git a/src/ui/widget.c b/src/ui/widget.c
index a11eaa64..e39208bc 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -2014,6 +2014,29 @@ size_t indexOfChild_Widget(const iWidget *d, const iAnyObject *child) {
     return iInvalidPos;
 }
 
+void changeChildIndex_Widget(iWidget *d, iAnyObject *child, size_t newIndex) {
+    size_t oldIndex = 0;
+    iForEach(ObjectList, i, d->children) {
+        if (i.object == child) {
+            ref_Object(child); /* we keep a reference */
+            remove_ObjectListIterator(&i);
+            break;
+        }
+        oldIndex++;
+    }
+    iAssert(oldIndex <= size_ObjectList(d->children));
+    if (isEmpty_ObjectList(d->children) || newIndex == 0) {
+        pushFront_ObjectList(d->children, child);
+    }
+    else {
+        iObjectListIterator iter;
+        init_ObjectListIterator(&iter, d->children);
+        for (size_t i = 1; i < newIndex; i++, next_ObjectListIterator(&iter)) {}
+        insertAfter_ObjectList(d->children, iter.value, child);
+    }
+    deref_Object(child); /* ObjectList has taken a reference */
+}
+
 iAny *hitChild_Widget(const iWidget *d, iInt2 coord) {
     if (isHidden_Widget_(d)) {
         return NULL;
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 82a51151..fc6f4161 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -317,6 +317,7 @@ iAny *  insertChildAfterFlags_Widget(iWidget *, iAnyObject *child, size_t afterI
 iAny *  removeChild_Widget          (iWidget *, iAnyObject *child); /* returns a ref */
 iAny *  child_Widget                (iWidget *, size_t index); /* O(n) */
 size_t  indexOfChild_Widget         (const iWidget *, const iAnyObject *child); /* O(n) */
+void    changeChildIndex_Widget     (iWidget *, iAnyObject *child, size_t newIndex); /* O(n) */
 void    arrange_Widget              (iWidget *);
 iBool   scrollOverflow_Widget       (iWidget *, int delta); /* moves the widget */
 iBool   dispatchEvent_Widget        (iWidget *, const SDL_Event *);
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.15/cdiff/a6353f70558553bfada274147a82997d4c79ab08
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
32.1091 milliseconds
Gemini-to-HTML Time
0.559676 milliseconds

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