grid.c (5767B)
1 /* 2 * Copyright (c) 2016-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 "ltkd.h" 18 #include "widget.h" 19 #include "cmd.h" 20 21 #include <ltk/ltk.h> 22 #include <ltk/grid.h> 23 24 /* grid <grid id> add <widget id> <row> <column> <row_span> <column_span> [sticky] */ 25 static int 26 ltkd_grid_cmd_add( 27 ltk_widget_id windowid, 28 ltkd_widget *widget, 29 ltkd_cmd_token *tokens, 30 size_t num_tokens, 31 ltkd_error *err) { 32 (void)windowid; 33 ltk_widget *gridw = ltk_get_widget_from_id(widget->ltkid); 34 ltk_grid *grid = LTK_CAST_GRID(gridw); 35 ltkd_cmdarg_parseinfo cmd[] = { 36 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_UNKNOWN, .optional = 0}, 37 {.type = CMDARG_INT, .min = 0, .max = grid->rows - 1, .optional = 0}, 38 {.type = CMDARG_INT, .min = 0, .max = grid->columns - 1, .optional = 0}, 39 {.type = CMDARG_INT, .min = 0, .max = grid->rows, .optional = 0}, 40 {.type = CMDARG_INT, .min = 0, .max = grid->columns, .optional = 0}, 41 {.type = CMDARG_STICKY, .optional = 1}, 42 }; 43 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err)) 44 return 1; 45 int row = cmd[1].val.i, col = cmd[2].val.i; 46 int rowspan = cmd[3].val.i, colspan = cmd[4].val.i; 47 if (row + rowspan > grid->rows) { 48 err->type = ERR_GRID_INVALID_POSITION; 49 err->arg = 1; 50 } 51 if (col + colspan > grid->columns) { 52 err->type = ERR_GRID_INVALID_POSITION; 53 err->arg = 2; 54 } 55 /* FIXME: better error reporting for invalid grid position */ 56 /* FIXME: check if recalculation deals properly with rowspan/columnspan 57 that goes over the edge of the grid */ 58 if (ltk_grid_add( 59 widget->ltkid, cmd[0].val.widget->ltkid, 60 row, col, rowspan, colspan, 61 cmd[5].initialized ? cmd[5].val.sticky : 0)) { 62 err->type = ERR_WIDGET_IN_CONTAINER; 63 err->arg = 0; 64 return 1; 65 } 66 return 0; 67 } 68 69 /* grid <grid id> remove <widget id> */ 70 static int 71 ltkd_grid_cmd_ungrid( 72 ltk_widget_id windowid, 73 ltkd_widget *widget, 74 ltkd_cmd_token *tokens, 75 size_t num_tokens, 76 ltkd_error *err) { 77 (void)windowid; 78 ltkd_cmdarg_parseinfo cmd[] = { 79 {.type = CMDARG_WIDGET, .widget_type = LTK_WIDGET_UNKNOWN, .optional = 0} 80 }; 81 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err)) 82 return 1; 83 if (ltk_grid_remove(widget->ltkid, cmd[0].val.widget->ltkid)) { 84 err->type = ERR_WIDGET_NOT_IN_CONTAINER; 85 err->arg = 0; 86 return 1; 87 } 88 return 0; 89 } 90 91 /* FIXME: max size of 64 is completely arbitrary! */ 92 /* grid <grid id> create <rows> <columns> */ 93 static int 94 ltkd_grid_cmd_create( 95 ltk_widget_id windowid, 96 ltkd_widget *widget_unneeded, 97 ltkd_cmd_token *tokens, 98 size_t num_tokens, 99 ltkd_error *err) { 100 (void)widget_unneeded; 101 ltkd_cmdarg_parseinfo cmd[] = { 102 {.type = CMDARG_IGNORE, .optional = 0}, 103 {.type = CMDARG_STRING, .optional = 0}, 104 {.type = CMDARG_IGNORE, .optional = 0}, 105 {.type = CMDARG_INT, .min = 0, .max = 64, .optional = 0}, 106 {.type = CMDARG_INT, .min = 0, .max = 64, .optional = 0}, 107 }; 108 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err)) 109 return 1; 110 ltk_widget_id grid = ltk_grid_create(windowid, cmd[3].val.i, cmd[4].val.i); 111 if (!ltkd_widget_create(grid, cmd[1].val.str, NULL, 0, err)) { 112 ltk_widget_id_destroy(grid, 1); 113 err->arg = 1; 114 return 1; 115 } 116 117 return 0; 118 } 119 120 /* FIXME: 64 is completely arbitrary */ 121 /* grid <grid id> set-row-weight <row> <weight> */ 122 static int 123 ltkd_grid_cmd_set_row_weight( 124 ltk_widget_id windowid, 125 ltkd_widget *widget, 126 ltkd_cmd_token *tokens, 127 size_t num_tokens, 128 ltkd_error *err) { 129 (void)windowid; 130 ltk_widget *gridw = ltk_get_widget_from_id(widget->ltkid); 131 ltk_grid *grid = LTK_CAST_GRID(gridw); 132 ltkd_cmdarg_parseinfo cmd[] = { 133 {.type = CMDARG_INT, .min = 0, .max = grid->rows - 1, .optional = 0}, 134 {.type = CMDARG_INT, .min = 0, .max = 64, .optional = 0}, 135 }; 136 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err)) 137 return 1; 138 ltk_grid_set_row_weight(widget->ltkid, cmd[0].val.i, cmd[1].val.i); 139 140 return 0; 141 } 142 143 144 /* FIXME: 64 is completely arbitrary */ 145 /* FIXME: check for overflows in various grid calculations (at least when larger values are allowed) */ 146 /* grid <grid id> set-column-weight <column> <weight> */ 147 static int 148 ltkd_grid_cmd_set_column_weight( 149 ltk_widget_id windowid, 150 ltkd_widget *widget, 151 ltkd_cmd_token *tokens, 152 size_t num_tokens, 153 ltkd_error *err) { 154 (void)windowid; 155 ltk_widget *gridw = ltk_get_widget_from_id(widget->ltkid); 156 ltk_grid *grid = LTK_CAST_GRID(gridw); 157 ltkd_cmdarg_parseinfo cmd[] = { 158 {.type = CMDARG_INT, .min = 0, .max = grid->columns - 1, .optional = 0}, 159 {.type = CMDARG_INT, .min = 0, .max = 64, .optional = 0}, 160 }; 161 if (ltkd_parse_cmd(tokens, num_tokens, cmd, LENGTH(cmd), err)) 162 return 1; 163 ltk_grid_set_column_weight(widget->ltkid, cmd[0].val.i, cmd[1].val.i); 164 165 return 0; 166 } 167 168 static ltkd_cmd_info grid_cmds[] = { 169 {"add", <kd_grid_cmd_add, 0}, 170 {"create", <kd_grid_cmd_create, 1}, 171 {"remove", <kd_grid_cmd_ungrid, 0}, 172 {"set-column-weight", <kd_grid_cmd_set_column_weight, 0}, 173 {"set-row-weight", <kd_grid_cmd_set_row_weight, 0}, 174 }; 175 176 GEN_CMD_HELPERS(ltkd_grid_cmd, LTK_WIDGET_GRID, grid_cmds)