]> git.neil.brown.name Git - edlib.git/blobdiff - lib-menu.c
TODO: clean out done items.
[edlib.git] / lib-menu.c
index db98bf097a4b724d1197a1e6adbafcb5e9950a29..33bc6e1839ca5d9b0a01ff15cbce42bd0416cf31 100644 (file)
@@ -7,7 +7,8 @@
  * A menu is created by called attach-menu with x,y being location
  * in either the pane or (if str contains 'D') the dispay.
  * Entries are added by calling "menu-add" with str being the value to
- * be reported and optionally str2 being the name to display.
+ * be displayed (the name) and optionally str2 being a different value
+ * to be reported (the action).
  *
  * A popup will be created which takes the focus. up/down moves the selection
  * and enter selects, as can the mouse.
@@ -17,6 +18,7 @@
  *
  */
 
+#define PANE_DATA_VOID
 #include "core.h"
 #include "misc.h"
 
@@ -30,23 +32,74 @@ DEF_CMD(menu_add)
        call("doc:set-ref", ci->focus, 0, m);
        call("doc:list-add", ci->focus, 0, m);
        call("doc:set-attr", ci->focus, 0, m, "name", 0, NULL,
-            ci->str2 ?: ci->str);
-       call("doc:set-attr", ci->focus, 0, m, "value", 0, NULL,
             ci->str);
+       call("doc:set-attr", ci->focus, 0, m, "action", 0, NULL,
+            ci->str2 ?: ci->str);
+       if (ci->num & 1)
+               call("doc:set-attr", ci->focus, 0, m, "disabled",
+                    0, NULL, "1");
 
        mark_free(m);
        return 1;
 }
 
+DEF_CMD(menu_clear)
+{
+       struct mark *m = vmark_new(ci->focus, MARK_UNGROUPED, NULL);
+
+       call("doc:set-ref", ci->focus, 1, m);
+       while (call("doc:list-del", ci->focus, 0, m) > 0)
+               ;
+       return 1;
+}
+
+DEF_CMD(menu_attr)
+{
+       if (ci->str && strcmp(ci->str, "FG") == 0) {
+               char *s = call_ret(str, "doc:get-attr", ci->home,
+                                  0, ci->mark, "disabled");
+               char *v = (s && *s) ? "fg:white-40" : "fg:black";
+               comm_call(ci->comm2, "cb", ci->focus, 0, ci->mark,
+                         v, 0, NULL, ci->str);
+               free(s);
+               return 1;
+       }
+       if (ci->str && strcmp(ci->str, "fg") == 0) {
+               char *s = call_ret(str, "doc:get-attr", ci->home,
+                                  0, ci->mark, "disabled");
+               char *v = (s && *s) ? "fg:blue+60" : "fg:blue";
+               comm_call(ci->comm2, "cb", ci->focus, 0, ci->mark,
+                         v, 0, NULL, ci->str);
+               free(s);
+               return 1;
+       }
+       if (ci->str && strcmp(ci->str, "shortcut") == 0) {
+               char *s = call_ret(str, "doc:get-attr", ci->home,
+                                  0, ci->mark, "action");
+               /* a leading space on 'action' suppresses listing as a shortcut */
+               char *v = (s && *s != ' ') ? s : "";
+               comm_call(ci->comm2, "cb", ci->focus, 0, ci->mark,
+                         v, 0, NULL, ci->str);
+               free(s);
+               return 1;
+       }
+       return Efallthrough;
+}
+
 DEF_CMD(menu_reposition)
 {
        int lines = ci->num;
        int cols = ci->num2;
        struct pane *p = call_ret(pane, "ThisPopup", ci->focus);
 
-       if (p && lines != 0 && cols != 0 &&
-           (lines <= p->h && cols <= p->w))
-               pane_resize(p, p->x, p->y, cols, lines);
+       if (!p || lines <= 0 || cols <= 0)
+               return Efallthrough;
+       if (lines > p->parent->h - p->y)
+               lines = p->parent->h - p->y;
+       if (cols > p->parent->w - p->x)
+               cols = p->parent->w - p->x;
+       /* Add 1 to cols so that if menu gets wider we will see that and resize */
+       pane_resize(p, p->x, p->y, cols+1, lines);
        return Efallthrough;
 }
 
@@ -65,7 +118,7 @@ DEF_CMD(menu_done)
                m = call_ret(mark, "doc:point", ci->focus);
        if (!m)
                return Enoarg;
-       val = pane_mark_attr(ci->focus, m, "value");
+       val = pane_mark_attr(ci->focus, m, "action");
        call("popup:close", ci->focus, 0, m, val);
        return 1;
 }
@@ -75,27 +128,50 @@ DEF_LOOKUP_CMD(menu_handle, menu_map);
 
 DEF_CMD(menu_attach)
 {
+       /* ->str gives the "mode"
+        * D  means per-display menu, not per-pane
+        * V  means show value in menu as well as name
+        * F  means to use the focus as the doc, and its
+        *    parent as the focus.
+        * ->str2 gives command to call on completion, else
+        *    "menu-done" is used.
+        * ->x,y are co-ordinated relative to ->focus where menu
+        *    (Top-Left) appears
+        * ->comm2 returns the created pane.
+        */
        struct pane *docp, *p, *p2;
-       /* Multi-line popup with x,y location provided. */
-       const char *mode = "Mx";
+       /* Multi-line temporary popup with x,y location provided. */
+       const char *mode = "Mtx";
        const char *mmode = ci->str ?: "";
+       struct pane *focus = ci->focus;
 
        if (strchr(mmode, 'D'))
                /* per-display, not per-pane */
-               mode = "DMx";
-
-       docp = call_ret(pane, "attach-doc-list", ci->focus);
-       if (!docp)
-               return Efail;
-       call("doc:set:autoclose", docp, 1);
-       attr_set_str(&docp->attrs, "render-simple", "format");
-       attr_set_str(&docp->attrs, "heading", "");
-       attr_set_str(&docp->attrs, "line-format", "<active-tag:menu-select>%name</>");
-       attr_set_str(&docp->attrs, "done-key", ci->str2 ?: "menu-done");
-       /* No borders, just a shaded background to make menu stand out */
-       attr_set_str(&docp->attrs, "borders", "");
-       attr_set_str(&docp->attrs, "background", "color:white-80");
-       p = call_ret(pane, "PopupTile", ci->focus, 0, NULL, mode,
+               mode = "DMtx";
+
+       if (strchr(mmode, 'F')) {
+               docp = focus;
+               focus = focus->parent;
+       } else {
+               docp = call_ret(pane, "attach-doc-list", ci->focus);
+               if (!docp)
+                       return Efail;
+               call("doc:set:autoclose", docp, 1);
+               attr_set_str(&docp->attrs, "render-simple", "format");
+               attr_set_str(&docp->attrs, "heading", "");
+               if (strchr(mmode, 'V'))
+                       /* show the 'action' - presumably a key name */
+                       attr_set_str(&docp->attrs, "line-format",
+                                    "<%FG><action-activate:menu-select>%name <rtab><%fg>%shortcut</></></>");
+               else
+                       attr_set_str(&docp->attrs, "line-format",
+                                    "<%FG><action-activate:menu-select>%name</></>");
+               attr_set_str(&docp->attrs, "done-key", ci->str2 ?: "menu-done");
+               /* No borders, just a shaded background to make menu stand out */
+               attr_set_str(&docp->attrs, "borders", "");
+               attr_set_str(&docp->attrs, "background", "color:white-80");
+       }
+       p = call_ret(pane, "PopupTile", focus, 0, NULL, mode,
                     0, NULL, NULL, ci->x, ci->y);
        if (!p)
                return Efail;
@@ -105,9 +181,13 @@ DEF_CMD(menu_attach)
                pane_close(p);
                return Efail;
        }
+       call("doc:file", p2, -1);
        p2 = pane_register(p2, 0, &menu_handle.c);
+       /* Don't allow any shift - we size the menu to fit */
        if (!p2)
                return Efail;
+       attr_set_int(&p2->attrs, "render-wrap", 0);
+       call("Mouse-grab", p2);
        return comm_call(ci->comm2, "cb:attach", p2);
 }
 
@@ -118,9 +198,11 @@ static void menu_init_map(void)
        key_add(menu_map, "render:reposition", &menu_reposition);
 
        key_add(menu_map, "menu-add", &menu_add);
-       key_add(menu_map, "K:ESC", &menu_abort);
+       key_add(menu_map, "menu-clear", &menu_clear);
+       key_add(menu_map, "Cancel", &menu_abort);
        key_add(menu_map, "K:Enter", &menu_done);
-       key_add(menu_map, "Activate:menu-select", &menu_done);
+       key_add(menu_map, "menu-select", &menu_done);
+       key_add(menu_map, "doc:get-attr", &menu_attr);
 }
 
 void edlib_init(struct pane *ed safe)
@@ -128,4 +210,8 @@ void edlib_init(struct pane *ed safe)
        menu_init_map();
        call_comm("global-set-command", ed, &menu_attach,
                  0, NULL, "attach-menu");
+       call_comm("global-set-command", ed, &menu_add,
+                 0, NULL, "menu:add");
+       call_comm("global-set-command", ed, &menu_clear,
+                 0, NULL, "menu:clear");
 }