2 #include "headers/render.h"
6 #define POPUP_MENU_PAD_TOP 4
7 #define POPUP_MENU_PAD_BOTTOM 2
8 #define POPUP_MENU_PAD_LEFT 2
9 #define POPUP_MENU_PAD_RIGHT 1
11 int init_tscolors(void);
12 int create_todowin(void);
14 /* menu render callbacks */
15 void render_menuitem(Menu* menu, int item_index, int start_y);
16 int menuitem_height(MenuItem* menuitem);
18 void render_popup_menuitem(Menu* menu, int item_index, int start_y);
19 int popup_menuitem_height(MenuItem* menuitem);
31 /* need to error check this */
32 if (has_colors() == FALSE) {
33 fprintf(stderr, "Your terminal does not support color.\n");
35 /* maybe just return 1 */
36 /* exit_tscurses(); */
57 init_pair(TS_SELECTED, selected_color, COLOR_BLACK);
58 init_pair(TS_NONSELECTED, non_selected_color, COLOR_BLACK);
59 init_pair(TS_MENU_SELECTED, menu_selected_color, COLOR_BLACK);
60 init_pair(TS_MENU_NONSELECTED, menu_non_selected_color, COLOR_BLACK);
61 init_pair(TS_ITEMCOUNT, item_count_color, COLOR_BLACK);
92 create_board_menu(Board* board)
94 BoardMenu* new_boardmenu;
96 new_boardmenu = malloc(sizeof(BoardMenu));
98 new_boardmenu->menu_list = make_menus(board, board->todolist_count);
99 new_boardmenu->menu_count = board->todolist_count;
100 new_boardmenu->selected = 0;
101 new_boardmenu->popupmenu = NULL;
102 new_boardmenu->popup_open = 0;
104 return new_boardmenu;
108 make_menus(Board* board, int todolist_length)
113 menu_list = malloc(todolist_length*sizeof(Menu*));
115 for (int i = 0; i < todolist_length; i++) {
117 /* read from parsed */
118 TodoList* todo_list = board->todolist_list[i];
119 MenuItem** item_list = todolist_to_menuitem(todo_list->item_list, todo_list->item_count);
121 Menu* new_menu = create_menu(todo_list->list_name, item_list);
124 WINDOW* win = newwin(20, MENU_WIDTH, 1, 1+MENU_WIDTH*i);
127 /* some menu settings */
128 set_menu_win(new_menu, win);
129 set_menu_focus(new_menu, i == 0); // make first win focused
131 /* set menu render callbacks */
132 set_menu_renderitem(new_menu, *render_menuitem);
133 set_menu_itemheight(new_menu, *menuitem_height);
139 menu_list[i] = new_menu;
146 render_menuitem(Menu* menu, int item_index, int start_y)
153 curitem = get_menu_item(menu, item_index);
154 menu_win = get_menu_win(menu);
155 item_data = (TodoItem*)get_menuitem_userdata(curitem);
157 /* color selected item */
158 hlcolor = COLOR_PAIR((item_index == get_selected_item(menu) && get_menu_focused(menu) == true) ? TS_SELECTED : TS_NONSELECTED);
159 wattron(menu_win, hlcolor);
160 mvwprintw(menu_win, start_y, 0, get_menuitem_title(curitem));
161 wattroff(menu_win, hlcolor);
164 wmove(menu_win, start_y+1, 0);
165 wattron(menu_win, COLOR_PAIR(TS_ITEMCOUNT));
166 /* display tiny character to indicate item has a descrip */
167 if (strlen(item_data->description) > 0) {
168 wprintw(menu_win, "# ");
170 /* display number of complete tasks */
171 if (item_data->subtask_count > 0) {
172 int tasks_complete = 0;
173 for (int i = 0; i < item_data->subtask_count; i++) {
174 if (item_data->subtask_list[i]->done == SubTaskState_done)
177 wprintw(menu_win, "[%d/%d]", tasks_complete, item_data->subtask_count);
179 wattroff(menu_win, COLOR_PAIR(TS_ITEMCOUNT));
183 menuitem_height(MenuItem* menuitem)
188 item_data = get_menuitem_userdata(menuitem);
190 if (item_data->subtask_count > 0 || strlen(item_data->description) > 0) {
198 todolist_to_menuitem(TodoItem** item_list, int list_length)
202 items = malloc((list_length+1)*sizeof(MenuItem*));
203 for (int i = 0; i < list_length; i++) {
204 MenuItem* new_menuitem;
205 new_menuitem = create_menuitem(item_list[i]->item_name);
206 /* using same struct, careful if it gets freed */
207 set_menuitem_userdata(new_menuitem, item_list[i]);
209 items[i] = new_menuitem;
212 items[list_length] = 0; //null terminate
217 boardmenu_to_board(BoardMenu* boardmenu)
218 { // STRINGS are sharing the same address as the one in MENU
219 // and MENUITEM, this may break something if u free this board
220 // consider copying the string
222 Board* newboard = malloc(sizeof(Board));
223 TodoList** new_todolist_list = malloc(sizeof(TodoList*));
225 for (int i = 0; i < boardmenu->menu_count; i++) {
226 Menu* curmenu = boardmenu->menu_list[i];
228 TodoList* new_todolist = malloc(sizeof(TodoList));
229 TodoItem** new_item_list = malloc(sizeof(TodoItem*));
230 new_todolist->list_name = strdup(get_menu_name(curmenu));
231 new_todolist->item_count = get_menu_length(curmenu);
233 for (int j = 0; j < get_menu_length(curmenu); j++) {
234 MenuItem* curmenuitem = get_menu_item(curmenu, j);
235 TodoItem* itemdata = get_menuitem_userdata(curmenuitem);
237 TodoItem* new_todoitem = malloc(sizeof(TodoItem));
238 SubTask** new_subtask_list = malloc(itemdata->subtask_count*sizeof(SubTask*));
240 new_todoitem->item_name = strdup(get_menuitem_title(curmenuitem));
241 new_todoitem->description = strdup(itemdata->description);
242 new_todoitem->due = strdup(itemdata->due);
243 new_todoitem->subtask_count = itemdata->subtask_count;
244 for (int k = 0; k < itemdata->subtask_count; k++) {
245 SubTask* new_subtask = malloc(sizeof(SubTask));
247 new_subtask->subtask_name = itemdata->subtask_list[k]->subtask_name;
248 new_subtask->done = itemdata->subtask_list[k]->done;
250 new_subtask_list[k] = new_subtask;
253 new_todoitem->subtask_list = new_subtask_list;
255 new_item_list[j] = new_todoitem;
258 new_todolist->item_list = new_item_list;
259 new_todolist_list[i] = new_todolist;
263 newboard->board_name = strdup("");
264 newboard->todolist_list = new_todolist_list;
265 newboard->todolist_count = boardmenu->menu_count;
271 render_board(Board* board)
278 set_selected_menu(BoardMenu* boardmenu, int index)
284 old_menu = boardmenu->menu_list[boardmenu->selected];
285 new_menu = boardmenu->menu_list[index];
287 set_menu_focus(old_menu, false);
288 set_menu_focus(new_menu, true);
290 /* also try to jump to a similar position if possible */
291 /* rn theres a bug if old menu is empty */
292 new_pos = min(get_selected_item(old_menu), get_menu_length(new_menu)-1);
293 if (new_pos < 0) new_pos = 0;
294 set_selected_item(new_menu, new_pos);
296 boardmenu->selected = index;
302 swap_menu(BoardMenu* boardmenu, int src_index, int dest_index)
304 /* reposition menus */
305 mvwin(get_menu_win(boardmenu->menu_list[src_index]),
306 1, 1+MENU_WIDTH*dest_index
308 mvwin(get_menu_win(boardmenu->menu_list[dest_index]),
309 1, 1+MENU_WIDTH*src_index
312 wrefresh(get_menu_win(boardmenu->menu_list[src_index]));
313 wrefresh(get_menu_win(boardmenu->menu_list[dest_index]));
314 /* wclear(get_menu_win(boardmenu->menu_list[src_index])); */
315 /* wclear(get_menu_win(boardmenu->menu_list[dest_index])); */
316 /* touchwin(get_menu_win(boardmenu->menu_list[src_index])); */
317 /* touchwin(get_menu_win(boardmenu->menu_list[dest_index])); */
321 ar_swap_item((void*)boardmenu->menu_list, src_index, dest_index);
328 make_popupmenu(TodoItem* itemdata)
330 PopupMenu* new_popupmenu;
331 MenuItem** subtask_menuitems;
332 Menu* popupmenu_menu;
333 WINDOW* popupmenu_win;
334 WINDOW* popupmenu_menu_win;
336 new_popupmenu = malloc(sizeof(PopupMenu));
338 subtask_menuitems = subtasklist_to_menuitem(itemdata->subtask_list, itemdata->subtask_count);
339 popupmenu_menu = create_menu(strdup(""), subtask_menuitems);
342 int maxheight, maxwidth;
343 getmaxyx(stdscr, maxheight, maxwidth);
344 popupmenu_win = newwin(
345 maxheight-2*POPUP_BORDER,
346 maxwidth-2*2*POPUP_BORDER,
351 int popup_maxheight, popup_maxwidth;
352 getmaxyx(popupmenu_win, popup_maxheight, popup_maxwidth);
353 popupmenu_menu_win = derwin(
355 popup_maxheight-POPUP_MENU_PAD_TOP-POPUP_MENU_PAD_BOTTOM,
356 popup_maxwidth-POPUP_MENU_PAD_LEFT-POPUP_MENU_PAD_RIGHT,
361 set_menu_win(popupmenu_menu, popupmenu_menu_win);
362 set_menu_userdata(popupmenu_menu, itemdata);
363 set_menu_focus(popupmenu_menu, 1);
364 set_menu_renderitem(popupmenu_menu, render_popup_menuitem);
365 set_menu_itemheight(popupmenu_menu, popup_menuitem_height);
366 box(popupmenu_win, 0, 0);
368 /* move this stuff to render phase later? */
369 mvwprintw(popupmenu_win, 1, 2, itemdata->item_name);
370 mvwprintw(popupmenu_win, 2, 2, (strlen(itemdata->description) > 0) ? itemdata->description : "no description");
372 /* don't forget to free popupmenu after */
373 new_popupmenu->win = popupmenu_win;
374 new_popupmenu->menu = popupmenu_menu;
376 return new_popupmenu;
380 render_popup_menuitem(Menu* menu, int item_index, int start_y)
386 curitem = get_menu_item(menu, item_index);
387 menu_win = get_menu_win(menu);
389 /* color selected item */
390 hlcolor = COLOR_PAIR((item_index == get_selected_item(menu) && get_menu_focused(menu) == true) ? TS_SELECTED : TS_NONSELECTED);
391 wattron(menu_win, hlcolor);
393 wmove(menu_win, start_y, 0);
394 /* print subtask done indicator */
395 if (strlen(get_menuitem_title(curitem)) > 0)
398 (((SubTask*)get_menuitem_userdata(curitem))->done == SubTaskState_done) ? "[X] " : "[ ] "
399 /* (((TodoItem*)get_menu_userdata(menu))->subtask_list[item_index]->done == SubTaskState_done) ? "[X] " : "[ ] " */
401 wprintw(menu_win, get_menuitem_title(curitem));
402 /* wprintw(menu_win, ((TodoItem*)get_menu_userdata(menu))->subtask_list[item_index]->subtask_name); */
404 wattroff(menu_win, hlcolor);
408 popup_menuitem_height(MenuItem* menuitem)
410 return 1; // account for wrap later
413 /* save menu state to userdata */
414 /* sorta duct tape rn */
415 /* find a way to tie TodoItem and MenuItem together better in the future */
417 close_popupmenu(Menu* popupmenu_menu)
420 SubTask** updated_subtasklist;
422 item_data = (TodoItem*)get_menu_userdata(popupmenu_menu);
423 updated_subtasklist = menuitem_to_subtasklist(
424 get_menu_itemlist(popupmenu_menu),
425 get_menu_length(popupmenu_menu)
428 /* remember to free old subtask list */
429 item_data->subtask_list = updated_subtasklist;
430 item_data->subtask_count = get_menu_length(popupmenu_menu);
432 /* this is messy but since subtask rendering uses menuitem title instead
433 * of userdata subtask title, this needs to be done :( */
434 /* for (int i = 0; i < get_menu_length(popupmenu_menu); i++) { */
435 /* set_menuitem_title( */
436 /* get_menu_item(popupmenu_menu, i), */
437 /* strdup(item_data->subtask_list[i]->subtask_name) */
442 /* this is copy paste of other, prob abstract */
444 subtasklist_to_menuitem(SubTask** subtask_list, int list_length)
448 items = malloc((list_length+1)*sizeof(MenuItem*));
449 for (int i = 0; i < list_length; i++) {
450 MenuItem* new_menuitem;
451 new_menuitem = create_menuitem(subtask_list[i]->subtask_name);
452 /* using same struct, careful if it gets freed */
453 set_menuitem_userdata(new_menuitem, subtask_list[i]);
455 items[i] = new_menuitem;
458 items[list_length] = 0; //null terminate
463 menuitem_to_subtasklist(MenuItem** menuitem_list, int list_length)
465 SubTask** new_subtasklist;
467 new_subtasklist = malloc(list_length*sizeof(SubTask*));
469 for (int i = 0; i < list_length; i++) {
470 SubTask* cur_subtask;
471 SubTask* new_subtask;
473 cur_subtask = (SubTask*)get_menuitem_userdata(menuitem_list[i]);
474 new_subtask = malloc(sizeof(SubTask));
476 new_subtask->subtask_name = strdup(cur_subtask->subtask_name);
477 new_subtask->done = cur_subtask->done;
479 new_subtasklist[i] = new_subtask;
482 /* new_subtasklist[list_length] = 0; */
484 return new_subtasklist;
492 // ignore null character (it's fine even if strlen = 0)
493 for (int i = strlen(str)-1; i >= 0; i--) {