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