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/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 (8150B)
---
1 /*
2 * Copyright (c) 2022-2024 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
30 /* [sub]menu <menu id> create */
31 static int
32 ltkd_menu_cmd_create(
33 ltk_window *window,
34 ltkd_widget *widget_unneeded,
35 ltkd_cmd_token *tokens,
36 size_t num_tokens,
37 ltkd_error *err) {
38 (void)widget_unneeded;
39 ltkd_cmdarg_parseinfo cmd[] = {
40 {.type = CMDARG_STRING, .optional = 0},
41 {.type = CMDARG_STRING, .optional = 0},
42 {.type = CMDARG_IGNORE, .optional = 0},
43 };
44 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
45 return 1;
46 ltk_menu *menu;
47 if (!strcmp(cmd[0].val.str, "menu")) {
48 menu = ltk_menu_create(window);
49 } else {
50 menu = ltk_submenu_create(window);
51 }
52 if (!ltkd_widget_create(LTK_CAST_WIDGET(menu), cmd[1].val.str, NULL, 0, err)) {
53 ltk_widget_destroy(LTK_CAST_WIDGET(menu), 1);
54 err->arg = 1;
55 return 1;
56 }
57 return 0;
58 }
59
60 /* menu <menu id> insert-entry <entry widget id> <index> */
61 static int
62 ltkd_menu_cmd_insert_entry(
63 ltk_window *window,
64 ltkd_widget *widget,
65 ltkd_cmd_token *tokens,
66 size_t num_tokens,
67 ltkd_error *err) {
68 (void)window;
69 ltk_menu *menu = LTK_CAST_MENU(widget->widget);
70 ltkd_cmdarg_parseinfo cmd[] = {
71 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
72 {.type = CMDARG_INT, .min = 0, .max = menu->num_entries, .optional = 0},
73 };
74 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
75 return 1;
76 int ret;
77 if ((ret = ltk_menu_insert_entry(menu, LTK_CAST_MENUENTRY(cmd[0].val.widget->widget), cmd[1].val.i))) {
78 err->type = ret == 1 ? ERR_WIDGET_IN_CONTAINER : ERR_INVALID_INDEX;
79 err->arg = err->type == ERR_WIDGET_IN_CONTAINER ? 0 : 1;
80 return 1;
81 }
82 return 0;
83 }
84
85 /* menu <menu id> add-entry <entry widget id> */
86 static int
87 ltkd_menu_cmd_add_entry(
88 ltk_window *window,
89 ltkd_widget *widget,
90 ltkd_cmd_token *tokens,
91 size_t num_tokens,
92 ltkd_error *err) {
93 (void)window;
94 ltk_menu *menu = LTK_CAST_MENU(widget->widget);
95 ltkd_cmdarg_parseinfo cmd[] = {
96 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
97 };
98 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
99 return 1;
100 if (ltk_menu_add_entry(menu, LTK_CAST_MENUENTRY(cmd[0].val.widget->widget))) {
101 err->type = ERR_WIDGET_IN_CONTAINER;
102 err->arg = 0;
103 return 1;
104 }
105 return 0;
106 }
107
108 /* menu <menu id> remove-entry-index <entry index> */
109 static int
110 ltkd_menu_cmd_remove_entry_index(
111 ltk_window *window,
112 ltkd_widget *widget,
113 ltkd_cmd_token *tokens,
114 size_t num_tokens,
115 ltkd_error *err) {
116 (void)window;
117 ltk_menu *menu = LTK_CAST_MENU(widget->widget);
118 ltkd_cmdarg_parseinfo cmd[] = {
119 {.type = CMDARG_INT, .min = 0, .max = menu->num_entries - 1, .optional = 0},
120 };
121 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
122 return 1;
123 if (!ltk_menu_remove_entry_index(menu, cmd[0].val.i)) {
124 err->type = ERR_WIDGET_NOT_IN_CONTAINER;
125 err->arg = 0;
126 return 1;
127 }
128 return 0;
129 }
130
131 /* menu <menu id> remove-entry-id <entry id> */
132 static int
133 ltkd_menu_cmd_remove_entry_id(
134 ltk_window *window,
135 ltkd_widget *widget,
136 ltkd_cmd_token *tokens,
137 size_t num_tokens,
138 ltkd_error *err) {
139 (void)window;
140 ltk_menu *menu = LTK_CAST_MENU(widget->widget);
141 ltkd_cmdarg_parseinfo cmd[] = {
142 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENUENTRY, .optional = 0},
143 };
144 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
145 return 1;
146 ltk_menuentry *entry = LTK_CAST_MENUENTRY(cmd[0].val.widget->widget);
147 if (!ltk_menu_remove_entry(menu, entry)) {
148 err->type = ERR_WIDGET_NOT_IN_CONTAINER;
149 err->arg = 0;
150 return 1;
151 }
152 return 0;
153 }
154
155 /* menu <menu id> remove-all-entries */
156 static int
157 ltkd_menu_cmd_remove_all_entries(
158 ltk_window *window,
159 ltkd_widget *widget,
160 ltkd_cmd_token *tokens,
161 size_t num_tokens,
162 ltkd_error *err) {
163 (void)window;
164 (void)tokens;
165 (void)num_tokens;
166 (void)err;
167 ltk_menu *menu = LTK_CAST_MENU(widget->widget);
168 ltk_menu_remove_all_entries(menu);
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_window *window,
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_menuentry *e = ltk_menuentry_create(window, cmd[3].val.str);
202 if (!ltkd_widget_create(LTK_CAST_WIDGET(e), cmd[1].val.str, entry_handlers, LENGTH(entry_handlers), err)) {
203 ltk_widget_destroy(LTK_CAST_WIDGET(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_window *window,
214 ltkd_widget *widget,
215 ltkd_cmd_token *tokens,
216 size_t num_tokens,
217 ltkd_error *err) {
218 (void)window;
219 ltk_menuentry *e = LTK_CAST_MENUENTRY(widget->widget);
220 ltkd_cmdarg_parseinfo cmd[] = {
221 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_MENU, .optional = 0},
222 };
223 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err))
224 return 1;
225 int ret;
226 if ((ret = ltk_menuentry_attach_submenu(e, LTK_CAST_MENU(cmd[0].val.widget->widget)))) {
227 /* FIXME: allow setting err->arg to arg before the args given to function */
228 /*err->arg = err->type == ERR_MENU_NOT_SUBMENU ? 0 : -2;*/
229 err->type = ret == 1 ? ERR_MENU_NOT_SUBMENU : ERR_MENU_ENTRY_CONTAINS_SUBMENU;
230 err->arg = 0;
231 return 1;
232 }
233 return 0;
234 }
235
236 /* menuentry <menuentry id> detach-submenu */
237 static int
238 ltkd_menuentry_cmd_detach_submenu(
239 ltk_window *window,
240 ltkd_widget *widget,
241 ltkd_cmd_token *tokens,
242 size_t num_tokens,
243 ltkd_error *err) {
244 (void)window;
245 (void)tokens;
246 (void)num_tokens;
247 (void)err;
248 ltk_menuentry *e = LTK_CAST_MENUENTRY(widget->widget);
249 ltk_menuentry_detach_submenu(e);
250 return 0;
251 }
252
253 /* FIXME: sort out menu/submenu - it's weird right now */
254 /* FIXME: distinguish between menu/submenu in commands other than create? */
255
256 static ltkd_cmd_info menu_cmds[] = {
257 {"add-entry", <kd_menu_cmd_add_entry, 0},
258 {"create", <kd_menu_cmd_create, 1},
259 {"insert-entry", <kd_menu_cmd_insert_entry, 0},
260 {"remove-all-entries", <kd_menu_cmd_remove_all_entries, 0},
261 {"remove-entry-index", <kd_menu_cmd_remove_entry_index, 0},
262 {"remove-entry-id", <kd_menu_cmd_remove_entry_id, 0},
263 };
264
265 static ltkd_cmd_info menuentry_cmds[] = {
266 {"attach-submenu", <kd_menuentry_cmd_attach_submenu, 0},
267 {"create", <kd_menuentry_cmd_create, 1},
268 {"detach-submenu", <kd_menuentry_cmd_detach_submenu, 0},
269 };
270
271 GEN_CMD_HELPERS(ltkd_menu_cmd, LTK_WIDGET_MENU, menu_cmds)
272 GEN_CMD_HELPERS(ltkd_menuentry_cmd, LTK_WIDGET_MENUENTRY, menuentry_cmds)