2 * Copyright Neil Brown ©2022-2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * lib-menu: support drop-down and pop-up menus.
7 * A menu is created by called attach-menu with x,y being location
8 * in either the pane or (if str contains 'D') the dispay.
9 * Entries are added by calling "menu-add" with str being the value to
10 * be reported and optionally str2 being the name to display.
12 * A popup will be created which takes the focus. up/down moves the selection
13 * and enter selects, as can the mouse.
15 * The selection is sent to the original focus with a callback specified in
16 * str2 when the menu is attached.
29 m = vmark_new(ci->focus, MARK_UNGROUPED, NULL);
30 call("doc:set-ref", ci->focus, 0, m);
31 call("doc:list-add", ci->focus, 0, m);
32 call("doc:set-attr", ci->focus, 0, m, "name", 0, NULL,
34 call("doc:set-attr", ci->focus, 0, m, "value", 0, NULL,
37 call("doc:set-attr", ci->focus, 0, m, "disabled",
46 if (ci->str && strcmp(ci->str, "BG") == 0) {
47 char *s = call_ret(str, "doc:get-attr", ci->home,
48 0, ci->mark, "disabled");
49 char *v = (s && *s) ? "fg:white-40" : "fg:black";
50 comm_call(ci->comm2, "cb", ci->focus, 0, ci->mark,
55 if (ci->str && strcmp(ci->str, "shortcut") == 0) {
56 char *s = call_ret(str, "doc:get-attr", ci->home,
57 0, ci->mark, "value");
58 /* a leading space on 'value' suppresses listing as a shortcut */
59 char *v = (s && *s != ' ') ? s : "";
60 comm_call(ci->comm2, "cb", ci->focus, 0, ci->mark,
68 DEF_CMD(menu_reposition)
72 struct pane *p = call_ret(pane, "ThisPopup", ci->focus);
74 if (!p || lines <= 0 || cols <= 0)
76 if (lines > p->parent->h - p->y)
77 lines = p->parent->h - p->y;
78 if (cols > p->parent->w - p->x)
79 cols = p->parent->w - p->x;
80 /* Add 1 to cols so that if menu gets wider we will see that and resize */
81 pane_resize(p, p->x, p->y, cols+1, lines);
87 call("Abort", ci->focus);
93 struct mark *m = ci->mark;
97 m = call_ret(mark, "doc:point", ci->focus);
100 val = pane_mark_attr(ci->focus, m, "value");
101 call("popup:close", ci->focus, 0, m, val);
105 static struct map *menu_map;
106 DEF_LOOKUP_CMD(menu_handle, menu_map);
110 struct pane *docp, *p, *p2;
111 /* Multi-line temporary popup with x,y location provided. */
112 const char *mode = "Mtx";
113 const char *mmode = ci->str ?: "";
115 if (strchr(mmode, 'D'))
116 /* per-display, not per-pane */
119 docp = call_ret(pane, "attach-doc-list", ci->focus);
122 call("doc:set:autoclose", docp, 1);
123 attr_set_str(&docp->attrs, "render-simple", "format");
124 attr_set_int(&docp->attrs, "render-wrap", 0);
125 attr_set_str(&docp->attrs, "heading", "");
127 /* show the 'value' - presumably a key name */
128 attr_set_str(&docp->attrs, "line-format", "<%BG><action-activate:menu-select>%name<rtab>%shortcut</></>");
130 attr_set_str(&docp->attrs, "line-format", "<%BG><action-activate:menu-select>%name</></>");
131 attr_set_str(&docp->attrs, "done-key", ci->str2 ?: "menu-done");
132 /* No borders, just a shaded background to make menu stand out */
133 attr_set_str(&docp->attrs, "borders", "");
134 attr_set_str(&docp->attrs, "background", "color:white-80");
135 p = call_ret(pane, "PopupTile", ci->focus, 0, NULL, mode,
136 0, NULL, NULL, ci->x, ci->y);
139 p2 = home_call_ret(pane, docp, "doc:attach-view", p,
145 p2 = pane_register(p2, 0, &menu_handle.c);
148 call("Mouse-grab", p2);
149 return comm_call(ci->comm2, "cb:attach", p2);
152 static void menu_init_map(void)
154 menu_map = key_alloc();
156 key_add(menu_map, "render:reposition", &menu_reposition);
158 key_add(menu_map, "menu-add", &menu_add);
159 key_add(menu_map, "Cancel", &menu_abort);
160 key_add(menu_map, "K:Enter", &menu_done);
161 key_add(menu_map, "menu-select", &menu_done);
162 key_add(menu_map, "doc:get-attr", &menu_attr);
165 void edlib_init(struct pane *ed safe)
168 call_comm("global-set-command", ed, &menu_attach,
169 0, NULL, "attach-menu");