ltk

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/ltk.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
Log | Files | Refs | README | 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 	{&ltkd_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", &ltkd_menu_cmd_add_entry, 0},
    258 	{"create", &ltkd_menu_cmd_create, 1},
    259 	{"insert-entry", &ltkd_menu_cmd_insert_entry, 0},
    260 	{"remove-all-entries", &ltkd_menu_cmd_remove_all_entries, 0},
    261 	{"remove-entry-index", &ltkd_menu_cmd_remove_entry_index, 0},
    262 	{"remove-entry-id", &ltkd_menu_cmd_remove_entry_id, 0},
    263 };
    264 
    265 static ltkd_cmd_info menuentry_cmds[] = {
    266 	{"attach-submenu", &ltkd_menuentry_cmd_attach_submenu, 0},
    267 	{"create", &ltkd_menuentry_cmd_create, 1},
    268 	{"detach-submenu", &ltkd_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)