From 655218b7df40b3e159119933a4fa18efca2ff940 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 15 May 2014 14:37:49 +0200 Subject: ui-todo: Large-scale refactoring This is a complete overhaul of the TODO list user interface. The new implementation uses the generic list box panel. Signed-off-by: Lukas Fleischer --- src/ui-todo.c | 274 ++++++++++++++++++++++++---------------------------------- 1 file changed, 113 insertions(+), 161 deletions(-) (limited to 'src/ui-todo.c') diff --git a/src/ui-todo.c b/src/ui-todo.c index 60838af..930b595 100644 --- a/src/ui-todo.c +++ b/src/ui-todo.c @@ -36,11 +36,6 @@ #include "calcurse.h" -static int hilt = 0; -static int todos = 0; -static int first = 1; -static char *msgsav; - /* Request user to enter a new todo item. */ void ui_todo_add(void) { @@ -58,7 +53,8 @@ void ui_todo_add(void) ch = wgetch(win[KEY].p); } todo_add(todo_input, ch - '0', NULL); - ui_todo_set_nb(ui_todo_nb() + 1); + ui_todo_sel_move(1); + ui_todo_load_items(); } } @@ -74,34 +70,28 @@ void ui_todo_delete(void) const int nb_erase_choice = 2; int answer; - if ((ui_todo_nb() <= 0) || + if (!LLIST_FIRST(&todolist) || (conf.confirm_delete && (status_ask_bool(del_todo_str) != 1))) { wins_erase_status_bar(); return; } - /* This todo item doesn't have any note associated. */ - if (todo_get_item(ui_todo_hilt())->note == NULL) - answer = 1; + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + + if (item->note) + answer = status_ask_choice(erase_warning, erase_choice, + nb_erase_choice); else - answer = - status_ask_choice(erase_warning, erase_choice, - nb_erase_choice); + answer = 1; switch (answer) { case 1: - todo_delete(todo_get_item(ui_todo_hilt())); - ui_todo_set_nb(ui_todo_nb() - 1); - if (ui_todo_hilt() > 1) - ui_todo_hilt_decrease(1); - if (ui_todo_nb() == 0) - ui_todo_hilt_set(0); - if (ui_todo_hilt_pos() < 0) - ui_todo_first_decrease(1); + todo_delete(item); + ui_todo_load_items(); break; case 2: - todo_delete_note(todo_get_item(ui_todo_hilt())); + todo_delete_note(item); break; default: wins_erase_status_bar(); @@ -112,12 +102,14 @@ void ui_todo_delete(void) /* Edit the description of an already existing todo item. */ void ui_todo_edit(void) { - struct todo *i; + if (!LLIST_FIRST(&todolist)) + return; + + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); const char *mesg = _("Enter the new TODO description:"); status_mesg(mesg, ""); - i = todo_get_item(ui_todo_hilt()); - updatestring(win[STA].p, &i->mesg, 0, 1); + updatestring(win[STA].p, &item->mesg, 0, 1); } /* Pipe a todo item to an external program. */ @@ -128,7 +120,11 @@ void ui_todo_pipe(void) int pout; int pid; FILE *fpout; - struct todo *todo; + + if (!LLIST_FIRST(&todolist)) + return; + + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); status_mesg(_("Pipe item to external command:"), ""); if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID) @@ -137,10 +133,7 @@ void ui_todo_pipe(void) wins_prepare_external(); if ((pid = shell_exec(NULL, &pout, *arg, arg))) { fpout = fdopen(pout, "w"); - - todo = todo_get_item(ui_todo_hilt()); - todo_write(todo, fpout); - + todo_write(item, fpout); fclose(fpout); child_wait(NULL, &pout, pid); press_any_key(); @@ -148,171 +141,130 @@ void ui_todo_pipe(void) wins_unprepare_external(); } -/* Sets which todo is highlighted. */ -void ui_todo_hilt_set(int highlighted) +/* Display todo items in the corresponding panel. */ +void ui_todo_draw(int n, WINDOW *win, int y, int hilt, void *cb_data) { - hilt = highlighted; -} + llist_item_t *i = *((llist_item_t **)cb_data); + struct todo *todo = LLIST_TS_GET_DATA(i); + int mark[2]; + int width = lb_todo.sw.w; + char buf[width * UTF8_MAXLEN]; + int j; -void ui_todo_hilt_decrease(int n) -{ - hilt -= n; -} + mark[0] = todo->id > 0 ? '0' + todo->id : 'X'; + mark[1] = todo->note ? '>' : '.'; -void ui_todo_hilt_increase(int n) -{ - hilt += n; -} + if (hilt) + custom_apply_attr(win, ATTR_HIGHEST); -/* Return which todo is highlighted. */ -int ui_todo_hilt(void) -{ - return hilt; -} + if (utf8_strwidth(todo->mesg) < width) { + mvwprintw(win, y, 0, "%c%c %s", mark[0], mark[1], todo->mesg); + } else { + for (j = 0; todo->mesg[j] && width > 0; j++) { + if (!UTF8_ISCONT(todo->mesg[j])) + width -= utf8_width(&todo->mesg[j]); + buf[j] = todo->mesg[j]; + } + if (j) + buf[j - 1] = 0; + else + buf[0] = 0; + mvwprintw(win, y, 0, "%c%c %s...", mark[0], mark[1], buf); + } -/* Set the number of todos. */ -void ui_todo_set_nb(int nb) -{ - todos = nb; -} + if (hilt) + custom_remove_attr(win, ATTR_HIGHEST); -/* Set which one is the first todo to be displayed. */ -void ui_todo_set_first(int nb) -{ - first = nb; + *((llist_item_t **)cb_data) = i->next; } -void ui_todo_first_increase(int n) +int ui_todo_height(int n, void *cb_data) { - first += n; + return 1; } -void ui_todo_first_decrease(int n) +void ui_todo_load_items(void) { - first -= n; + int n = 0; + llist_item_t *i; + + /* TODO: Optimize this by keeping the list size in a variable. */ + LLIST_FOREACH(&todolist, i) + n++; + + listbox_load_items(&lb_todo, n); } -/* - * Return the position of the hilghlighted item, relative to the first one - * displayed. - */ -int ui_todo_hilt_pos(void) +void ui_todo_sel_move(int delta) { - return hilt - first; + listbox_sel_move(&lb_todo, delta); } -/* Return the number of todos. */ -int ui_todo_nb(void) +/* Updates the TODO panel. */ +void ui_todo_update_panel(int which_pan) { - return todos; + /* + * This is used and modified by display_todo_item() to avoid quadratic + * running time. + */ + llist_item_t *p = LLIST_FIRST(&todolist); + + listbox_set_cb_data(&lb_todo, &p); + listbox_display(&lb_todo); } -/* Return the last visited todo. */ -char *ui_todo_saved_mesg(void) +/* Change an item priority by pressing '+' or '-' inside TODO panel. */ +void ui_todo_chg_priority(int diff) { - return msgsav; + if (!LLIST_FIRST(&todolist)) + return; + + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + int id = item->id + diff; + struct todo *item_new; + + if (id < 1) + id = 1; + else if (id > 9) + id = 9; + + item_new = todo_add(item->mesg, id, item->note); + todo_delete(item); + listbox_set_sel(&lb_todo, todo_get_position(item_new)); } -/* Display todo items in the corresponding panel. */ -static void -display_todo_item(int incolor, char *msg, int prio, int note, int width, - int y, int x) +void ui_todo_popup_item(void) { - WINDOW *w; - int ch_note; - char buf[width * UTF8_MAXLEN], priostr[2]; - int i; - - w = win[TOD].p; - ch_note = (note) ? '>' : '.'; - if (prio > 0) - snprintf(priostr, sizeof priostr, "%d", prio); - else - strncpy(priostr, "X", sizeof priostr); + if (!LLIST_FIRST(&todolist)) + return; - if (incolor == 0) - custom_apply_attr(w, ATTR_HIGHEST); - if (utf8_strwidth(msg) < width) { - mvwprintw(w, y, x, "%s%c %s", priostr, ch_note, msg); - } else { - for (i = 0; msg[i] && width > 0; i++) { - if (!UTF8_ISCONT(msg[i])) - width -= utf8_width(&msg[i]); - buf[i] = msg[i]; - } - if (i) - buf[i - 1] = 0; - else - buf[0] = 0; - mvwprintw(w, y, x, "%s%c %s...", priostr, ch_note, buf); - } - if (incolor == 0) - custom_remove_attr(w, ATTR_HIGHEST); + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + item_in_popup(NULL, NULL, item->mesg, _("TODO:")); } -/* Updates the TODO panel. */ -void ui_todo_update_panel(int which_pan) +void ui_todo_flag(void) { - llist_item_t *i; - int len = win[TOD].w - 8; - int num_todo = 0; - int title_lines = conf.compact_panels ? 1 : 3; - int y_offset = title_lines, x_offset = 1; - int t_realpos = -1; - int todo_lines = 1; - int max_items = win[TOD].h - 4; - int incolor = -1; - - if ((int)win[TOD].h < 4) + if (!LLIST_FIRST(&todolist)) return; - /* Print todo item in the panel. */ - erase_window_part(win[TOD].p, 1, title_lines, win[TOD].w - 2, - win[TOD].h - 2); - LLIST_FOREACH(&todolist, i) { - struct todo *todo = LLIST_TS_GET_DATA(i); - num_todo++; - t_realpos = num_todo - first; - incolor = (which_pan == TOD) ? num_todo - hilt : num_todo; - if (incolor == 0) - msgsav = todo->mesg; - if (t_realpos >= 0 && t_realpos < max_items) { - display_todo_item(incolor, todo->mesg, todo->id, - (todo->note != NULL) ? 1 : 0, - len, y_offset, x_offset); - y_offset = y_offset + todo_lines; - } - } + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + todo_flag(item); +} - /* Draw the scrollbar if necessary. */ - if (todos > max_items) { - int sbar_length = max_items * (max_items + 1) / todos; - int highend = max_items * first / todos; - unsigned hilt_bar = (which_pan == TOD) ? 1 : 0; - int sbar_top = highend + title_lines; - - if ((sbar_top + sbar_length) > win[TOD].h - 1) - sbar_length = win[TOD].h - 1 - sbar_top; - draw_scrollbar(win[TOD].p, sbar_top, win[TOD].w - 2, - sbar_length, title_lines, win[TOD].h - 1, - hilt_bar); - } +void ui_todo_view_note(void) +{ + if (!LLIST_FIRST(&todolist)) + return; - wnoutrefresh(win[TOD].p); + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + todo_view_note(item, conf.pager); } -/* Change an item priority by pressing '+' or '-' inside TODO panel. */ -void ui_todo_chg_priority(struct todo *todo, int diff) +void ui_todo_edit_note(void) { - int id = todo->id + diff; - struct todo *todo_new; - - if (id < 1) - id = 1; - else if (id > 9) - id = 9; + if (!LLIST_FIRST(&todolist)) + return; - todo_new = todo_add(todo->mesg, id, todo->note); - todo_delete(todo); - hilt = todo_get_position(todo_new); + struct todo *item = todo_get_item(listbox_get_sel(&lb_todo)); + todo_edit_note(item, conf.editor); } -- cgit v1.2.3-54-g00ecf