URI: 
       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         {&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)