more menu controls
[taskasaur.git] / menu.c
1
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <ncurses.h>
6
7 #include "headers/menu.h"
8 #include "headers/render.h"
9 #include "headers/utils.h"
10
11 typedef struct MenuItem {
12     char* contents;
13 } MenuItem;
14
15 typedef struct Menu {
16     MenuItem** menu_items;
17     int menu_length;
18     int selected_item;
19     WINDOW* menu_win;
20     int max_height;
21     int max_width;
22 } Menu;
23
24 int swap_item(Menu* menu, int src_index, int dest_index);
25 int delete_item(Menu* menu, int index);
26
27 MenuItem*
28 create_menuitem(char* contents)
29 {
30     MenuItem* new_menuitem;
31
32     new_menuitem = malloc(sizeof(MenuItem));
33     new_menuitem->contents = contents;
34
35     return new_menuitem;
36 }
37
38 Menu* 
39 create_menu(MenuItem** item_list)
40 {
41     Menu* new_menu;
42
43     new_menu = malloc(sizeof(Menu));
44     new_menu->menu_items = item_list;
45     new_menu->menu_length = array_length(MenuItem*, item_list);
46     new_menu->selected_item = 0;
47     set_menu_win(new_menu, stdscr);
48
49     return new_menu;
50 }
51
52 int
53 set_menu_win(Menu* menu, WINDOW* win)
54 {
55     menu->menu_win = win;
56     getmaxyx(menu->menu_win, menu->max_height, menu->max_width);
57
58     return 0;
59 }
60
61 MenuItem*
62 get_menu_items(Menu* menu)
63 {
64     return NULL;
65 }
66
67 int
68 swap_item(Menu* menu, int src_index, int dest_index)
69 {
70     MenuItem* temp;
71
72     temp = menu->menu_items[dest_index];
73     menu->menu_items[dest_index] = menu->menu_items[src_index];
74     menu->menu_items[src_index] = temp;
75
76     return 0;
77 }
78
79 int
80 delete_item(Menu* menu, int index)
81 {
82     if (index < 0 || index > menu->menu_length-1) return -1;
83
84     int temp_size = (menu->menu_length-index-1)*sizeof(MenuItem*);
85     MenuItem* temp[temp_size];
86
87     /* might break if last item? */
88     memcpy(temp, menu->menu_items[index+1], temp_size);
89     memcpy(menu->menu_items[index], temp, temp_size);
90
91     menu->menu_items = realloc(menu->menu_items, menu->menu_length*sizeof(MenuItem*)); 
92     menu->menu_items[menu->menu_length-1] = 0; // preserve null at end
93
94     menu->menu_length -= 1;
95
96     /* also move the current selected position if it's last */
97     if (menu->selected_item > menu->menu_length-1) {
98         menu->selected_item = menu->menu_length-1;
99     }
100
101     return 0;
102 }
103
104 int
105 menu_driver(Menu* menu, MenuAction action)
106 {
107
108     switch (action) {
109         case MENU_UP:
110             menu->selected_item = menu->selected_item-1 >= 0 ? menu->selected_item-1 : 0;
111             break;
112
113         case MENU_DOWN:
114             menu->selected_item = menu->selected_item+1 <= menu->menu_length-1 ? menu->selected_item+1 : menu->menu_length-1;
115             break;
116
117         case MENU_TOP:
118             menu->selected_item = 0;
119             break;
120
121         case MENU_BOTTOM:
122             menu->selected_item = menu->menu_length-1;
123             break;
124
125         case MENU_MOVE_UP:
126             if (menu->selected_item <= 0) break;
127             swap_item(menu, menu->selected_item, menu->selected_item-1);
128             menu->selected_item -= 1;
129             break;
130
131         case MENU_MOVE_DOWN:
132             if (menu->selected_item >= menu->menu_length-1) break;
133             swap_item(menu, menu->selected_item, menu->selected_item+1);
134             menu->selected_item += 1;
135             break;
136
137         case MENU_DELETE:
138             delete_item(menu, menu->selected_item);
139             wclear(menu->menu_win);
140             break;
141
142         default: // This is here for debug, disable later
143             fprintf(stderr, "Invalid menu action");
144     }
145
146     return 0;
147 }
148
149 int
150 render_menu(Menu* menu)
151 {
152     int cur_line;
153
154     cur_line = 0;
155
156     for (int i = 0; i < menu->menu_length; i++) {
157
158         int wrapped_lines;
159         char* wrapped_text;
160         int text_color;
161         
162         /* wrap text by inserting newlines */
163         wrapped_text = wrap_text(menu->menu_items[i]->contents, menu->max_width, &wrapped_lines);        
164
165         /* color selected item */
166         text_color = (i == menu->selected_item) ? TS_SELECTED : TS_NONSELECTED;
167
168         wattron(menu->menu_win, COLOR_PAIR(text_color));
169         mvwprintw(menu->menu_win, cur_line, 0, wrapped_text);
170         wattroff(menu->menu_win, COLOR_PAIR(text_color));
171
172         cur_line += wrapped_lines;
173
174         free(wrapped_text);
175
176     }
177
178     return 0;
179 }
180
181 int
182 free_menu(Menu* menu)
183 {
184     return 0;
185 }
186