menu.c (3515B)
1 #include "menu.h" 2 #include "pane.h" 3 #include "utils.h" 4 5 menu_T menu_new(int item_num, menu_back_f back_f) 6 { 7 menu_T menu = 8 malloc(sizeof(*menu) + item_num * sizeof(struct menuItem_T)); 9 10 menu->items_size = item_num; 11 menu->current = 0; 12 menu->back_f = back_f; 13 14 return menu; 15 } 16 17 int menu_hadleInput(data_T data, struct tb_event ev) 18 { 19 menu_T menu = (menu_T)data->payload; 20 21 if (ev.type == TB_EVENT_KEY) { 22 if (ev.ch == 'k' || ev.ch == 'w') { 23 menu->current--; 24 CLAMP(menu->current, 0, menu->items_size - 1); 25 return 1; 26 } 27 if (ev.ch == 'j' || ev.ch == 's') { 28 menu->current++; 29 CLAMP(menu->current, 0, menu->items_size - 1); 30 return 1; 31 } 32 if (ev.key == TB_KEY_ENTER) { 33 struct menuItem_T *item = menu->items + menu->current; 34 item->select_f(item->name, menu->current); 35 return 1; 36 } 37 if (ev.key == TB_KEY_BACKSPACE || ev.key == TB_KEY_BACKSPACE2) { 38 if (menu->back_f) { 39 menu->back_f(); 40 return 1; 41 } 42 } 43 } 44 45 return 0; 46 } 47 48 void pane_menu(widget_T widget) 49 { 50 size_t i; 51 Pane_T pane = widget->pane; 52 menuInfo_T info = (menuInfo_T)(widget->info); 53 menuStyle_T style = (menuStyle_T)(widget->style); 54 menu_T menu = (menu_T)(widget->data->payload); 55 56 if (!widget->inited) { 57 widget->inited = 1; 58 widget->resized = 1; 59 60 pane_clear(pane, 0); 61 62 int len, maxi = 0; 63 64 for (i = 0; i < menu->items_size; i++) 65 if ((len = strlen(menu->items[i].name)) > maxi) 66 maxi = len; 67 68 info->max_item_len = maxi; 69 info->sep_len = strlen(style->separator); 70 info->start = 0; 71 /* info->end = info->items_num - 1; */ 72 } 73 74 if (widget->resized) { 75 widget->resized = 0; 76 77 int padding = (style->padding * 2 + 1 > pane_height(pane)) ? 78 0 : 79 style->padding; 80 // optimal number of elements to display on the screen 81 int max_items = 82 (pane_height(pane) - padding * 2 + style->spacing) / 83 (style->spacing + 1); 84 // number of items displayed cant exceed actual number of items in the menu 85 info->items_num = ACLAMP(max_items, 0, menu->items_size); 86 87 info->x_sep = centerHorisontal(pane, info->sep_len); 88 info->x = centerHorisontal(pane, info->max_item_len); 89 info->y = centerVertical( 90 pane, info->items_num * (style->spacing + 1) - 91 style->spacing); 92 93 /* info->start = menu->current - in */ 94 /* info->end = info->start + info->items_num - 1; */ 95 if (menu->current >= info->start + info->items_num) 96 info->start += menu->current - info->items_num; 97 } 98 99 /* while (1) { */ 100 pane_clear(pane, 0); 101 102 int relative = menu->current - info->start; 103 if (relative < 0) { 104 info->start--; 105 } else if (relative > 0 && relative > info->items_num - 1) { 106 info->start++; 107 } 108 109 CLAMP(info->start, 0, menu->items_size - info->items_num); 110 /* CLAMP(menu->current, info->start, info->start + info->items_num); */ 111 112 if (!menu->items_size) { 113 char *message = "NOTHING TO DISPLAY HERE!"; 114 int x = centerHorisontal(pane, strlen(message)); 115 tb_print(x, info->y, TB_BLUE, 0, message); 116 return; 117 } 118 119 if (info->items_num != menu->items_size && info->start == 0) 120 tb_print(info->x_sep, info->y - 1, TB_BLUE, 0, 121 style->separator); 122 123 int y = info->y; 124 for (i = info->start; i < info->start + info->items_num; i++) { 125 int color = (i == menu->current) ? TB_RED : TB_BLUE; 126 tb_printf(info->x, y, color, 0, "%.*s", 127 pane_width(widget->pane), menu->items[i].name); 128 y += style->spacing + 1; 129 } 130 131 if (info->items_num != menu->items_size && 132 info->start + info->items_num == menu->items_size) 133 tb_print(info->x_sep, y - style->spacing, TB_BLUE, 0, 134 style->separator); 135 }