From 4284ca91bc0fd04851a34c67dae1068f3c1defc9 Mon Sep 17 00:00:00 2001 From: Lars Henriksen Date: Sat, 16 Mar 2019 08:27:45 +0100 Subject: Implement scrolling in the appointments panel With multiple days in the APP panel, up/down movements should change behaviour at the top and bottom of the list displayed, and load the previous/next lot of days. This requires that the move function returns the result of the operation. Furthermore, the ability to move the selection to the beginning of a day is needed when moving down (in order to move from the first day to the last day). For this reason a DAY_SEPARATOR has been inserted also after the last day of a lot. Appointments have a listbox height of three to separate them clearly when there is more than one in a day. This leaves a spurious empty line at the end of a day with appointments. The DAY_SEPARATOR height is reduced from two to one, and a new EMPTY_SEPARATOR of height one is inserted in any day with only events. When scrolling up the DAY_HEADING becomes visible when the selection reaches the first item of the day. The length of the separator (between events and appointments) is adjusted to leave a space to the window border at both ends, thereby making it a part of the day, not a separation between days. The dummy event must also be recognisable when not the selected item and is only inserted in interactive mode. The test for a saved selection must also recognise caption items which have item pointer NULL. The function day_get_nb() has been renamed day_get_days(). Signed-off-by: Lars Henriksen Signed-off-by: Lukas Fleischer --- src/calcurse.c | 16 +++++++-- src/calcurse.h | 9 ++++-- src/day.c | 17 ++++++---- src/ui-day.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 121 insertions(+), 21 deletions(-) diff --git a/src/calcurse.c b/src/calcurse.c index b99f210..6313818 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -60,7 +60,7 @@ static void do_storage(int day_changed) ui_day_sel_reset(); /* The day_items vector. */ - day_store_items(get_slctd_day(), 1, day_get_nb()); + day_store_items(get_slctd_day(), 1, day_get_days()); /* The APP listbox. */ ui_day_load_items(); @@ -414,7 +414,12 @@ static inline void key_move_up(void) if (wins_slctd() == CAL) { key_generic_prev_week(); } else if (wins_slctd() == APP) { - ui_day_sel_move(-1); + if (!ui_day_sel_move(-1)) { + ui_calendar_move(DAY_PREV, 1); + do_storage(1); + ui_day_sel_dayend(); + wins_update(FLAG_CAL); + } wins_update(FLAG_APP); } else if (wins_slctd() == TOD) { ui_todo_sel_move(-1); @@ -434,7 +439,12 @@ static inline void key_move_down(void) if (wins_slctd() == CAL) { key_generic_next_week(); } else if (wins_slctd() == APP) { - ui_day_sel_move(1); + if (!ui_day_sel_move(1)) { + ui_calendar_move(DAY_NEXT, 1); + do_storage(1); + ui_day_sel_daybegin(day_get_days() - 1); + wins_update(FLAG_CAL); + } wins_update(FLAG_APP); } else if (wins_slctd() == TOD) { ui_todo_sel_move(1); diff --git a/src/calcurse.h b/src/calcurse.h index 333e1b9..e4cfe79 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -421,6 +421,7 @@ enum day_item_type { EVNT_SEPARATOR, RECUR_APPT, APPT, + EMPTY_SEPARATOR, DAY_SEPARATOR }; @@ -764,7 +765,7 @@ int parse_args(int, char **); /* calendar.c */ extern struct day_item empty_day; -/* ui_calendar.c */ +/* ui-calendar.c */ void ui_calendar_view_next(void); void ui_calendar_view_prev(void); void ui_calendar_set_view(int); @@ -803,10 +804,10 @@ void custom_keys_config(void); void custom_config_main(void); /* day.c */ -int day_get_nb(void); int day_set_sel_data(struct day_item *); int day_check_sel_data(void); int day_sel_index(void); +int day_get_days(void); void day_free_vector(void); char *day_item_get_mesg(struct day_item *); char *day_item_get_note(struct day_item *); @@ -1115,7 +1116,9 @@ struct day_item *ui_day_get_sel(void); time_t ui_day_sel_date(void); void ui_day_sel_reset(void); void ui_day_set_sel(struct day_item *); -void ui_day_sel_move(int); +int ui_day_sel_move(int); +void ui_day_sel_daybegin(int); +void ui_day_sel_dayend(void); void ui_day_draw(int, WINDOW *, int, int, void *); enum listbox_row_type ui_day_row_type(int, void *); int ui_day_height(int, void *); diff --git a/src/day.c b/src/day.c index 4c6e1a1..c340988 100644 --- a/src/day.c +++ b/src/day.c @@ -42,7 +42,7 @@ #include "calcurse.h" -static unsigned day_nb = 7; +static unsigned day_days = 5; static vector_t day_items; static unsigned day_items_nb = 0; @@ -107,9 +107,9 @@ int day_sel_index(void) return -1; } -int day_get_nb(void) +int day_get_days(void) { - return day_nb; + return day_days; } static void day_free(struct day_item *day) @@ -397,6 +397,7 @@ static int day_store_recur_apoints(time_t date) { llist_item_t *i; union aptev_ptr p; + time_t occurrence; int a_nb = 0; LLIST_TS_LOCK(&recur_alist_p); @@ -404,8 +405,6 @@ static int day_store_recur_apoints(time_t date) struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); p.rapt = rapt; - - time_t occurrence; /* As for appointments */ if (recur_apoint_find_occurrence(rapt, date, &occurrence)) { day_add_item(RECUR_APPT, @@ -451,7 +450,7 @@ day_store_items(time_t date, int include_captions, int n) day_items_nb += events + apts; - if (events == 0 && apts == 0) { + if (include_captions && events == 0 && apts == 0) { /* Insert dummy event. */ d.ev = &dummy; dummy.mesg = _("(none)"); @@ -459,8 +458,12 @@ day_store_items(time_t date, int include_captions, int n) day_items_nb++; } - if (include_captions && i < n - 1) + if (include_captions) { + /* Two empty lines between days. */ + if (apts == 0) + day_add_item(EMPTY_SEPARATOR, 0, ENDOFDAY(date), p); day_add_item(DAY_SEPARATOR, 0, ENDOFDAY(date), p); + } } VECTOR_SORT(&day_items, day_cmp); diff --git a/src/ui-day.c b/src/ui-day.c index 4b37a90..ab4e7d9 100644 --- a/src/ui-day.c +++ b/src/ui-day.c @@ -70,6 +70,45 @@ time_t ui_day_sel_date(void) return update_time_in_date(ui_day_get_sel()->order, 0, 0); } +/* + * If possible, move the selection to the beginning + * of previous, current or next day. + */ +static void daybegin(int dir) +{ + dir = dir > 0 ? 1 : (dir < 0 ? -1 : 0); + int sel = listbox_get_sel(&lb_apt); + + switch (dir) { + case -1: + while (day_get_item(sel)->type != DAY_HEADING) + sel--; + if (sel == 0) + goto leave; + sel--; + while (day_get_item(sel)->type != DAY_HEADING) + sel--; + break; + case 0: + while (day_get_item(sel)->type != DAY_HEADING) + sel--; + break; + case 1: + while (day_get_item(sel)->type != DAY_SEPARATOR) + sel++; + if (sel == lb_apt.item_count - 1) { + while (day_get_item(sel)->type != DAY_HEADING) + sel--; + goto leave; + } else + sel++; + break; + } + leave: + listbox_set_sel(&lb_apt, sel); + listbox_item_in_view(&lb_apt, sel); +} + /* * Request the user to enter a new start time. * Input: start time and duration in seconds. @@ -758,6 +797,10 @@ void ui_day_item_delete(unsigned reg) io_set_modified(); ui_calendar_monthly_view_cache_set_invalid(); + /* Keep the selection on the same day. */ + day_set_sel_data( + day_get_item(listbox_get_sel(&lb_apt) - 1) + ); return; default: return; @@ -768,7 +811,8 @@ void ui_day_item_delete(unsigned reg) p = day_cut_item(date, listbox_get_sel(&lb_apt)); day_cut[reg].type = p->type; day_cut[reg].item = p->item; - + /* Keep the selection on the same day. */ + day_set_sel_data(day_get_item(listbox_get_sel(&lb_apt) - 1)); io_set_modified(); ui_calendar_monthly_view_cache_set_invalid(); } @@ -993,11 +1037,51 @@ void ui_day_load_items(void) void ui_day_sel_reset(void) { listbox_set_sel(&lb_apt, 0); + /* Make the day visible. */ + if (lb_apt.item_sel) + listbox_item_in_view(&lb_apt, lb_apt.item_sel - 1); +} + +int ui_day_sel_move(int delta) +{ + int ret; + + ret = listbox_sel_move(&lb_apt, delta); + /* When moving up, make the line above visible. */ + if (delta < 0 && ret && lb_apt.item_sel) + listbox_item_in_view(&lb_apt, lb_apt.item_sel - 1); + return ret; } -void ui_day_sel_move(int delta) +/* + * Move the selection to the beginning of the current day or + * the day n days before or after. + */ +void ui_day_sel_daybegin(int n) +{ + if (n == 0) { + daybegin(0); + return; + } + int dir = n > 0 ? 1 : -1; + n = dir * n; + for (int i = 0; i < n; i++) + daybegin(dir); +} + +/* + * Move the selection to the end of the current day. + */ +void ui_day_sel_dayend(void) { - listbox_sel_move(&lb_apt, delta); + int sel = listbox_get_sel(&lb_apt); + + while (day_get_item(sel)->type != DAY_SEPARATOR) + sel++; + while (lb_apt.type[sel] != LISTBOX_ROW_TEXT) + sel--; + listbox_set_sel(&lb_apt, sel); + listbox_item_in_view(&lb_apt, sel); } static char *fmt_day_heading(time_t date) @@ -1036,8 +1120,8 @@ void ui_day_draw(int n, WINDOW *win, int y, int hilt, void *cb_data) custom_remove_attr(win, ATTR_HIGHEST); mem_free(buf); } else if (item->type == EVNT_SEPARATOR) { - wmove(win, y, 0); - whline(win, 0, width); + wmove(win, y, 1); + whline(win, 0, width - 2); } } @@ -1047,6 +1131,7 @@ enum listbox_row_type ui_day_row_type(int n, void *cb_data) if (item->type == DAY_HEADING || item->type == EVNT_SEPARATOR || + item->type == EMPTY_SEPARATOR || item->type == DAY_SEPARATOR) return LISTBOX_ROW_CAPTION; else @@ -1057,10 +1142,9 @@ int ui_day_height(int n, void *cb_data) { struct day_item *item = day_get_item(n); - if (item->type == APPT || item->type == RECUR_APPT) + if (item->type == APPT || + item->type == RECUR_APPT) return 3; - else if (item->type == DAY_SEPARATOR) - return 2; else return 1; } -- cgit v1.2.3-54-g00ecf