aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui/menu.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2023-11-24 01:35:51 -0600
committerLibravatar bigfoot547 <[email protected]>2023-11-24 01:35:51 -0600
commit60e47519d3cd151348000d72811aa7037a01e3f4 (patch)
treefa408db8ee114277c8fac381fd1a683e32160508 /src/ui/menu.c
parentcustom assert macros and other stuff (diff)
menu
Diffstat (limited to 'src/ui/menu.c')
-rw-r--r--src/ui/menu.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/ui/menu.c b/src/ui/menu.c
new file mode 100644
index 0000000..c0e8d58
--- /dev/null
+++ b/src/ui/menu.c
@@ -0,0 +1,118 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "uimenu.internal.h"
+#include "../macros.h"
+
+void uimenu_item_button_init(struct uimenu_item_button *button, unsigned id, const char *text, uimenu_button_action *action)
+{
+ button->header.type = UMPS__MENU_TYPE_BUTTON;
+ button->header.next = button->header.prev = NULL;
+
+ button->id = id;
+ button->text = text ? strdup(text) : NULL;
+ button->enabled = true;
+ button->action = action;
+}
+
+void uimenu_item_menu_init(struct uimenu_item_menu *menu, const char *text)
+{
+ menu->header.type = UMPS__MENU_TYPE_MENU;
+ menu->header.next = menu->header.prev = NULL;
+
+ menu->text = text ? strdup(text) : NULL;
+ menu->head = menu->tail = NULL;
+ menu->nchildren = 0;
+}
+
+struct uimenu_item_header *uimenu__item_menu_spacer_create(void)
+{
+ struct uimenu_item_header *spacer = malloc(sizeof(struct uimenu_item_header));
+ spacer->type = UMPS__MENU_TYPE_SPACER;
+ spacer->next = spacer->prev = NULL;
+ return spacer;
+}
+
+/* menu items will be freed on removal */
+void uimenu_menu_add_spacer(struct uimenu_item_menu *menu, struct uimenu_item_header *where, bool after)
+{
+ struct uimenu_item_header *spc = uimenu__item_menu_spacer_create();
+ uimenu_menu_add(menu, where, spc, after);
+}
+
+void uimenu_menu_add(struct uimenu_item_menu *menu, struct uimenu_item_header *where, struct uimenu_item_header *item, bool after)
+{
+ if (!menu->head) {
+ /* edge case: menu has no children :((((( */
+ menu->head = menu->tail = item;
+ item->next = item->prev = NULL;
+ ++menu->nchildren;
+ return;
+ }
+
+ umps_assert(where);
+
+ if (after) {
+ item->prev = where;
+ item->next = where->next;
+ where->next = item;
+
+ if (!item->next) menu->tail = item;
+ } else {
+ item->next = where;
+ item->prev = where->prev;
+ where->prev = item;
+
+ if (!item->prev) menu->head = item;
+ }
+
+ ++menu->nchildren;
+}
+
+void uimenu__item_free(struct uimenu_item_header *item)
+{
+ switch (item->type) {
+ case UMPS__MENU_TYPE_SPACER:
+ free(item);
+ break;
+ case UMPS__MENU_TYPE_BUTTON: {
+ struct uimenu_item_button *btn = (struct uimenu_item_button *)item;
+ free(btn->text);
+ free(btn);
+ break;
+ }
+ case UMPS__MENU_TYPE_MENU:
+ uimenu_menu_free((struct uimenu_item_menu *)item);
+ break;
+ default:
+ umps_trap;
+ }
+}
+
+void uimenu_menu_remove(struct uimenu_item_menu *menu, struct uimenu_item_header *item)
+{
+ if (item->prev) {
+ item->prev->next = item->next;
+ } else {
+ menu->head = item->next;
+ }
+
+ if (item->next) {
+ item->next->prev = item->prev;
+ } else {
+ menu->tail = item->prev;
+ }
+
+ --menu->nchildren;
+}
+
+/* frees children */
+void uimenu_menu_free(struct uimenu_item_menu *menu)
+{
+ for (struct uimenu_item_header *cur = menu->head, *next; cur; cur = next) {
+ next = cur->next;
+ uimenu__item_free(cur);
+ }
+ free(menu->text);
+ free(menu);
+}