pane

Termbox2 based terminal UI library
git clone git://git.dimitrijedobrota.com/pane.git
Log | Files | Refs

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 }