menu.c - ltk - GUI toolkit for X11 (WIP)
HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
menu.c (8042B)
---
1 /*
2 * Copyright (c) 2022-2026 lumidify <nobody@lumidify.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stddef.h>
18 #include <string.h>
19
20 #include "err.h"
21 #include "ltkd.h"
22 #include "widget.h"
23 #include "cmd.h"
24 #include "proto_types.h"
25
26 #include <ltk/ltk.h>
27 #include <ltk/util.h>
28 #include <ltk/menu.h>
29 #include <ltk/array.h>
30
31 /* [sub]menu <menu id> create */
32 static int
33 ltkd_menu_cmd_create(
34 ltk_widget_id windowid,
35 ltkd_widget *widget_unneeded,
36 ltkd_cmd_token *tokens,
37 size_t num_tokens,
38 ltkd_error *err) {
39 (void)widget_unneeded;
40 ltkd_cmdarg_parseinfo cmd[] = {
41 {.type = CMDARG_STRING, .optional = 0},
42 {.type = CMDARG_STRING, .optional = 0},
43 {.type = CMDARG_IGNORE, .optional = 0},
44 };
45 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
46 return 1;
47 ltk_widget_id menu;
48 if (!strcmp(cmd[0].val.str, "menu")) {
49 menu = ltk_menu_create(windowid);
50 } else {
51 menu = ltk_submenu_create(windowid);
52 }
53 if (!ltkd_widget_create(menu, cmd[1].val.str, NULL, 0, err)) {
54 ltk_widget_id_destroy(menu, 1);
55 err->arg = 1;
56 return 1;
57 }
58 return 0;
59 }
60
61 /* menu <menu id> insert-entry <entry widget id> <index> */
62 static int
63 ltkd_menu_cmd_insert_entry(
64 ltk_widget_id windowid,
65 ltkd_widget *widget,
66 ltkd_cmd_token *tokens,
67 size_t num_tokens,
68 ltkd_error *err) {
69 (void)windowid;
70 ltk_widget *menuw = ltk_get_widget_from_id(widget->ltkid);
71 ltk_menu *menu = LTK_CAST_MENU(menuw);
72 ltkd_cmdarg_parseinfo cmd[] = {
73 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
74 {.type = CMDARG_INT, .min = 0, .max = ltk_array_len(menu->entries), .optional = 0},
75 };
76 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
77 return 1;
78 int ret;
79 if ((ret = ltk_menu_insert_entry(widget->ltkid, cmd[0].val.widget->ltkid, cmd[1].val.i))) {
80 err->type = ret == 1 ? ERR_WIDGET_IN_CONTAINER : ERR_INVALID_INDEX;
81 err->arg = err->type == ERR_WIDGET_IN_CONTAINER ? 0 : 1;
82 return 1;
83 }
84 return 0;
85 }
86
87 /* menu <menu id> add-entry <entry widget id> */
88 static int
89 ltkd_menu_cmd_add_entry(
90 ltk_widget_id windowid,
91 ltkd_widget *widget,
92 ltkd_cmd_token *tokens,
93 size_t num_tokens,
94 ltkd_error *err) {
95 (void)windowid;
96 ltkd_cmdarg_parseinfo cmd[] = {
97 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
98 };
99 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
100 return 1;
101 if (ltk_menu_add_entry(widget->ltkid, cmd[0].val.widget->ltkid)) {
102 err->type = ERR_WIDGET_IN_CONTAINER;
103 err->arg = 0;
104 return 1;
105 }
106 return 0;
107 }
108
109 /* menu <menu id> remove-entry-index <entry index> */
110 static int
111 ltkd_menu_cmd_remove_entry_index(
112 ltk_widget_id windowid,
113 ltkd_widget *widget,
114 ltkd_cmd_token *tokens,
115 size_t num_tokens,
116 ltkd_error *err) {
117 (void)windowid;
118 ltk_widget *menuw = ltk_get_widget_from_id(widget->ltkid);
119 ltk_menu *menu = LTK_CAST_MENU(menuw);
120 ltkd_cmdarg_parseinfo cmd[] = {
121 {.type = CMDARG_INT, .min = 0, .max = ltk_array_len(menu->entries) - 1, .optional = 0},
122 };
123 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
124 return 1;
125 ltk_widget_id ret = ltk_menu_remove_entry_index(widget->ltkid, cmd[0].val.i);
126 if (LTK_WIDGET_ID_IS_NONE(ret)) {
127 err->type = ERR_WIDGET_NOT_IN_CONTAINER;
128 err->arg = 0;
129 return 1;
130 }
131 return 0;
132 }
133
134 /* menu <menu id> remove-entry-id <entry id> */
135 static int
136 ltkd_menu_cmd_remove_entry_id(
137 ltk_widget_id windowid,
138 ltkd_widget *widget,
139 ltkd_cmd_token *tokens,
140 size_t num_tokens,
141 ltkd_error *err) {
142 (void)windowid;
143 ltkd_cmdarg_parseinfo cmd[] = {
144 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
145 };
146 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
147 return 1;
148 if (!ltk_menu_remove_entry(widget->ltkid, cmd[0].val.widget->ltkid)) {
149 err->type = ERR_WIDGET_NOT_IN_CONTAINER;
150 err->arg = 0;
151 return 1;
152 }
153 return 0;
154 }
155
156 /* menu <menu id> remove-all-entries */
157 static int
158 ltkd_menu_cmd_remove_all_entries(
159 ltk_widget_id windowid,
160 ltkd_widget *widget,
161 ltkd_cmd_token *tokens,
162 size_t num_tokens,
163 ltkd_error *err) {
164 (void)windowid;
165 (void)tokens;
166 (void)num_tokens;
167 (void)err;
168 ltk_menu_remove_all_entries(widget->ltkid);
169 return 0;
170 }
171
172 static int
173 ltkd_menuentry_press(ltk_widget *widget_unused, ltk_callback_arglist args, ltk_callback_arg arg) {
174 (void)widget_unused;
175 (void)args;
176 ltkd_widget *widget = LTK_CAST_ARG_VOIDP(arg);
177 return ltkd_widget_queue_specific_event(widget, "menuentry", LTKD_PWEVENTMASK_MENUENTRY_PRESS, "press");
178 }
179
180 static ltkd_event_handler entry_handlers[] = {
181 {<kd_menuentry_press, LTK_MENUENTRY_SIGNAL_PRESSED},
182 };
183
184 /* menuentry <id> create <text> */
185 static int
186 ltkd_menuentry_cmd_create(
187 ltk_widget_id windowid,
188 ltkd_widget *widget_unneeded,
189 ltkd_cmd_token *tokens,
190 size_t num_tokens,
191 ltkd_error *err) {
192 (void)widget_unneeded;
193 ltkd_cmdarg_parseinfo cmd[] = {
194 {.type = CMDARG_STRING, .optional = 0},
195 {.type = CMDARG_STRING, .optional = 0},
196 {.type = CMDARG_IGNORE, .optional = 0},
197 {.type = CMDARG_STRING, .optional = 0},
198 };
199 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
200 return 1;
201 ltk_widget_id e = ltk_menuentry_create(windowid, cmd[3].val.str);
202 if (!ltkd_widget_create(e, cmd[1].val.str, entry_handlers, LENGTH(entry_handlers), err)) {
203 ltk_widget_id_destroy(e, 1);
204 err->arg = 1;
205 return 1;
206 }
207 return 0;
208 }
209
210 /* menuentry <menuentry id> attach-submenu <submenu id> */
211 static int
212 ltkd_menuentry_cmd_attach_submenu(
213 ltk_widget_id windowid,
214 ltkd_widget *widget,
215 ltkd_cmd_token *tokens,
216 size_t num_tokens,
217 ltkd_error *err) {
218 (void)windowid;
219 ltkd_cmdarg_parseinfo cmd[] = {
220 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENU, .optional = 0},
221 };
222 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
223 return 1;
224 int ret;
225 if ((ret = ltk_menuentry_attach_submenu(widget->ltkid, cmd[0].val.widget->ltkid))) {
226 /* FIXME: allow setting err->arg to arg before the args given to function */
227 /*err->arg = err->type == ERR_MENU_NOT_SUBMENU ? 0 : -2;*/
228 err->type = ret == 1 ? ERR_MENU_NOT_SUBMENU : ERR_MENU_ENTRY_CONTAINS_SUBMENU;
229 err->arg = 0;
230 return 1;
231 }
232 return 0;
233 }
234
235 /* menuentry <menuentry id> detach-submenu */
236 static int
237 ltkd_menuentry_cmd_detach_submenu(
238 ltk_widget_id windowid,
239 ltkd_widget *widget,
240 ltkd_cmd_token *tokens,
241 size_t num_tokens,
242 ltkd_error *err) {
243 (void)windowid;
244 (void)tokens;
245 (void)num_tokens;
246 (void)err;
247 ltk_menuentry_detach_submenu(widget->ltkid);
248 return 0;
249 }
250
251 /* FIXME: sort out menu/submenu - it's weird right now */
252 /* FIXME: distinguish between menu/submenu in commands other than create? */
253
254 static ltkd_cmd_info menu_cmds[] = {
255 {"add-entry", <kd_menu_cmd_add_entry, 0},
256 {"create", <kd_menu_cmd_create, 1},
257 {"insert-entry", <kd_menu_cmd_insert_entry, 0},
258 {"remove-all-entries", <kd_menu_cmd_remove_all_entries, 0},
259 {"remove-entry-index", <kd_menu_cmd_remove_entry_index, 0},
260 {"remove-entry-id", <kd_menu_cmd_remove_entry_id, 0},
261 };
262
263 static ltkd_cmd_info menuentry_cmds[] = {
264 {"attach-submenu", <kd_menuentry_cmd_attach_submenu, 0},
265 {"create", <kd_menuentry_cmd_create, 1},
266 {"detach-submenu", <kd_menuentry_cmd_detach_submenu, 0},
267 };
268
269 GEN_CMD_HELPERS(ltkd_menu_cmd, LTK_WIDGET_MENU, menu_cmds)
270 GEN_CMD_HELPERS(ltkd_menuentry_cmd, LTK_WIDGET_MENUENTRY, menuentry_cmds)