From 1ccfe128cce8d670d12c350326bb13fbc0276d0a Mon Sep 17 00:00:00 2001 From: Lars Henriksen Date: Wed, 19 Dec 2018 08:59:05 +0100 Subject: Redesign selected-item implementation for the APP panel The day vector, day_items, is displayed in the appointments panel; the selected day_item object is highlighted (when the panel has the focus). When items are inserted, edited, moved etc., and when the day is changed, the day vector is rebuilt and displayed anew. Problem: How shall the selection be set automatically in the context of the new day vector? In previous versions all of the above is mostly handled by the function do_storage() in calcurse.c The function saves data about the selection as needed, rebuilds the day vector, loads the listbox and sets the selection from the saved selection data. This works well in "single day" calcurse in cases where the selected item is present in the day vector both before and after the rebuild, or when the item ordering in the listbox is unaffected by the changes. But when a new item is added the selection cannot be set to the new object by do_storage(). Instead the necessary operations are performed by ui_day_item_add(), and do_storage() is bypassed. In general, when an item cannot be found in the new vector, the item which occupies the old place in the list gets selected, e.g. when an item is deleted. When an item is turned into a repeating one, the old item is deleted and a new is created. Here the new selection is not always the affected item, but in any case not far away. Generally, with only one day in the panel an erronous selection might not be noticed or be accurate by chance. In "multiple day" calcurse the existing scheme works less well; in addition the day vector may now contain more than one object that refer to the same event or appointment (recurrent items or multi-day appointments). The scheme has therefore been modified. The do_storage() function is no longer bypassed, but handles day vector rebuild, load of listbox and item selection exclusively. To make that possible, data about the selected item is no longer saved in a local automatic variable, private to do_storage(), but in an external static variable in day.c, which may be set not only by do_storage(). The variable is declared as static struct day_item sel_data; and used as follows: 1. On startup sel_data is initialized to empty (i.e. no selection). 2. In any operation involving the appointments panel: 2.1 Do the work and if necessary set sel_data. This is the case when deleting, adding or pasting an item, and when turning an ordinary item into a recurrent one. 2.2 Call do_storage(). 3. In do_storage(): 3.1 If sel_data is empty, set it to the current selection. 3.2 Rebuild the day vector. 3.3 Set the selection from sel_data. 3.4 Set sel_data to empty. Further remarks --------------- The selection is found in the new day vector by searching for the saved (order, item.) pair. Previously the item. alone sufficed and in some cases it still does. In case the item cannot be found, the selection stays in the same day as before the rebuild. An attempt at more consistently named APP-related functions has led to: ui_day_sel_date() replaces ui_day_sel_day() ui_day_get_sel() replaces ui_day_selitem() Signed-off-by: Lars Henriksen Signed-off-by: Lukas Fleischer --- src/calcurse.c | 51 +++++++++++++++++++++--------------- src/calcurse.h | 16 ++++++----- src/day.c | 83 +++++++++++++++++++++++++++++++++++++++++++--------------- src/ui-day.c | 79 +++++++++++++++++++++++++++++-------------------------- 4 files changed, 144 insertions(+), 85 deletions(-) diff --git a/src/calcurse.c b/src/calcurse.c index 757b3cd..b99f210 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -41,26 +41,35 @@ #define HANDLE_KEY(key, fn) case key: fn(); break; int count, reg; - /* - * Store the events and appointments for the selected day and reset the - * appointment highlight pointer if a new day was selected. + * Store events and appointments for a range of days in the day vector - + * beginning with the selected day - and load them into the APP listbox. If no + * day-change occurs, reset the selected APP item and with it the selected day, + * thereby storing and loading the same range of days. */ static void do_storage(int day_changed) { - /* * Save the selected item before rebuilding the day vector. */ - struct day_item *day = ui_day_selitem(); - union aptev_ptr item; - if (day) - item = day->item; + /* + * Save the selected item before rebuilding the day vector - + * unless already set. + */ + if (!day_check_sel_data()) + day_set_sel_data(ui_day_get_sel()); + + if (!day_changed) + ui_day_sel_reset(); + /* The day_items vector. */ day_store_items(get_slctd_day(), 1, day_get_nb()); + /* The APP listbox. */ ui_day_load_items(); if (day_changed) ui_day_sel_reset(); - else if (day) - ui_day_set_selitem_by_aptev_ptr(item); + else + ui_day_find_sel(); + + day_set_sel_data(&empty_day); } static inline void key_generic_change_view(void) @@ -115,6 +124,7 @@ static inline void key_generic_config_menu(void) static inline void key_generic_add_appt(void) { ui_day_item_add(); + do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } @@ -130,6 +140,7 @@ static inline void key_add_item(void) case APP: case CAL: ui_day_item_add(); + do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); break; case TOD: @@ -143,7 +154,7 @@ static inline void key_add_item(void) static inline void key_edit_item(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) { + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_edit(); do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); @@ -155,7 +166,7 @@ static inline void key_edit_item(void) static inline void key_del_item(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) { + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_delete(reg); do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); @@ -167,11 +178,8 @@ static inline void key_del_item(void) static inline void key_generic_copy(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) { + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) ui_day_item_copy(reg); - do_storage(0); - wins_update(FLAG_CAL | FLAG_APP); - } } static inline void key_generic_paste(void) @@ -185,15 +193,16 @@ static inline void key_generic_paste(void) static inline void key_repeat_item(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_repeat(); - do_storage(0); - wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); + do_storage(0); + wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); + } } static inline void key_flag_item(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) { + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_flag(); do_storage(0); wins_update(FLAG_APP); @@ -232,7 +241,7 @@ static inline void key_lower_priority(void) static inline void key_edit_note(void) { - if (wins_slctd() == APP && !event_dummy(ui_day_selitem())) { + if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_edit_note(); do_storage(0); } else if (wins_slctd() == TOD) { diff --git a/src/calcurse.h b/src/calcurse.h index 3ee0900..333e1b9 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -762,6 +762,9 @@ void apoint_paste_item(struct apoint *, time_t); int parse_args(int, char **); /* calendar.c */ +extern struct day_item empty_day; + +/* ui_calendar.c */ void ui_calendar_view_next(void); void ui_calendar_view_prev(void); void ui_calendar_set_view(int); @@ -801,6 +804,9 @@ 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); void day_free_vector(void); char *day_item_get_mesg(struct day_item *); char *day_item_get_note(struct day_item *); @@ -819,8 +825,6 @@ int day_check_if_item(struct date); unsigned day_chk_busy_slices(struct date, int, int *); struct day_item *day_cut_item(time_t, int); int day_paste_item(struct day_item *, time_t); -int day_get_position_by_aptev_ptr(union aptev_ptr); -int day_get_position(struct day_item *); struct day_item *day_get_item(int); unsigned day_item_count(int); void day_edit_note(struct day_item *, const char *); @@ -1097,10 +1101,6 @@ void todo_init_list(void); void todo_free_list(void); /* ui-day.c */ -struct day_item *ui_day_selitem(void); -time_t ui_day_selday(void); -void ui_day_set_selitem_by_aptev_ptr(union aptev_ptr); -void ui_day_set_selitem(struct day_item *); void ui_day_item_add(void); void ui_day_item_delete(unsigned); void ui_day_item_edit(void); @@ -1110,7 +1110,11 @@ void ui_day_item_cut_free(unsigned); void ui_day_item_copy(unsigned); void ui_day_item_paste(unsigned); void ui_day_load_items(void); +void ui_day_find_sel(void); +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); void ui_day_draw(int, WINDOW *, int, int, void *); enum listbox_row_type ui_day_row_type(int, void *); diff --git a/src/day.c b/src/day.c index e480732..4c6e1a1 100644 --- a/src/day.c +++ b/src/day.c @@ -46,6 +46,67 @@ static unsigned day_nb = 7; static vector_t day_items; static unsigned day_items_nb = 0; +struct day_item empty_day = { 0, 0, 0, {NULL}}; + +/* + * The day vector, day_items, is continuously rebuilt for display as the + * selected day changes, items are added, edited or deleted etc. To keep track + * of the selected item of the day vector across rebuilds, data are saved in + * here that may later be used to refind the item in the rebuilt day + * vector. + */ +static struct day_item sel_data = { 0, 0, 0, {NULL}}; + +/* + * Save the item to become the selected APP item. + * Public function used to override the setting in do_storage(). + */ +int day_set_sel_data(struct day_item *d) +{ + if (!d) + return 0; + + sel_data = *d; + return 1; +} + +/* + * Return selection data if available. + */ +int day_check_sel_data() +{ + return (sel_data.order || sel_data.item.apt) ? 1 : 0; +} + +/* + * Return the position of the saved selection in the day vector. + */ +int day_sel_index(void) +{ + int i = 0; + struct day_item *p; + + VECTOR_FOREACH(&day_items, i) { + p = VECTOR_NTH(&day_items, i); + if (p->order == sel_data.order && + p->item.apt == sel_data.item.apt) + return i; + } + /* Needed as long as ui_day_item_paste() does not set order. */ + VECTOR_FOREACH(&day_items, i) { + p = VECTOR_NTH(&day_items, i); + if (p->item.apt == sel_data.item.apt) + return i; + } + /* If still not found, stay on the same day. */ + VECTOR_FOREACH(&day_items, i) { + p = VECTOR_NTH(&day_items, i); + if (p->order == update_time_in_date(sel_data.order, 0, 0)) + return i; + } + return -1; +} + int day_get_nb(void) { return day_nb; @@ -510,7 +571,7 @@ void day_popup_item(struct day_item *day) struct apoint apt_tmp; apt_tmp.start = day->start; apt_tmp.dur = day_item_get_duration(day); - apoint_sec2str(&apt_tmp, ui_day_selday(), a_st, a_end); + apoint_sec2str(&apt_tmp, ui_day_sel_date(), a_st, a_end); item_in_popup(a_st, a_end, day_item_get_mesg(day), _("Appointment:")); } else { @@ -734,26 +795,6 @@ int day_paste_item(struct day_item *p, time_t date) return p->type; } -/* Returns the position corresponding to a given item. */ -int day_get_position_by_aptev_ptr(union aptev_ptr aptevp) -{ - int n = 0; - - VECTOR_FOREACH(&day_items, n) { - struct day_item *p = VECTOR_NTH(&day_items, n); - /* Compare pointers. */ - if (p->item.ev == aptevp.ev) - return n; - } - - return -1; -} - -int day_get_position(struct day_item *needle) -{ - return day_get_position_by_aptev_ptr(needle->item); -} - /* Returns a structure containing the selected item. */ struct day_item *day_get_item(int item_number) { diff --git a/src/ui-day.c b/src/ui-day.c index 32e12bf..4b37a90 100644 --- a/src/ui-day.c +++ b/src/ui-day.c @@ -39,34 +39,35 @@ struct day_item day_cut[38] = { {0, 0, 0, {NULL}} }; /* - * Return the selected item in the APP panel. + * Return the selected APP item. + * This is a pointer into the day vector and invalid after a day vector rebuild, + * but the (order, item) data may be used to refind the object. */ -struct day_item *ui_day_selitem(void) +struct day_item *ui_day_get_sel(void) { if (day_item_count(0) <= 0) - return NULL; + return &empty_day; return day_get_item(listbox_get_sel(&lb_apt)); } /* - * Return the day (midnight) of the selected item in the APP panel. + * Set the selected item from the saved day_item. */ -time_t ui_day_selday(void) +void ui_day_find_sel(void) { - return update_time_in_date(ui_day_selitem()->order, 0, 0); -} + int n; -void ui_day_set_selitem_by_aptev_ptr(union aptev_ptr p) -{ - int n = day_get_position_by_aptev_ptr(p); - if (n >= 0) + if ((n = day_sel_index()) != -1) listbox_set_sel(&lb_apt, n); } -void ui_day_set_selitem(struct day_item *day) +/* + * Return the date (midnight) of the selected item in the APP panel. + */ +time_t ui_day_sel_date(void) { - ui_day_set_selitem_by_aptev_ptr(day->item); + return update_time_in_date(ui_day_get_sel()->order, 0, 0); } /* @@ -406,7 +407,7 @@ void ui_day_item_edit(void) if (day_item_count(0) <= 0) return; - struct day_item *p = ui_day_selitem(); + struct day_item *p = ui_day_get_sel(); switch (p->type) { case RECUR_EVNT: @@ -534,7 +535,7 @@ void ui_day_item_pipe(void) if (day_item_count(0) <= 0) return; - struct day_item *p = ui_day_selitem(); + struct day_item *p = ui_day_get_sel(); status_mesg(_("Pipe item to external command:"), ""); if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID) @@ -590,7 +591,7 @@ void ui_day_item_add(void) const char *enter_str = _("Press [Enter] to continue"); char item_time[LTIME] = ""; char item_mesg[BUFSIZ] = ""; - time_t start = ui_day_selday(), end, saved = start; + time_t start = ui_day_sel_date(), end, saved = start; unsigned dur; int is_appointment = 1; union aptev_ptr item; @@ -683,9 +684,11 @@ void ui_day_item_add(void) item.ev = event_new(item_mesg, 0L, start, 1); } io_set_modified(); - day_store_items(get_slctd_day(), 1, day_get_nb()); - ui_day_load_items(); - ui_day_set_selitem_by_aptev_ptr(item); + /* Set the selected APP item. */ + struct day_item d = empty_day; + d.order = start; + d.item = item; + day_set_sel_data(&d); } ui_calendar_monthly_view_cache_set_invalid(); @@ -715,7 +718,7 @@ void ui_day_item_delete(unsigned reg) if (day_item_count(0) <= 0) return; - struct day_item *p = ui_day_selitem(); + struct day_item *p = ui_day_get_sel(); if (conf.confirm_delete) { if (status_ask_bool(del_app_str) != 1) { @@ -745,12 +748,10 @@ void ui_day_item_delete(unsigned reg) break; case 2: if (p->type == RECUR_EVNT) { - date = get_slctd_day(); - day_item_add_exc(p, date); + day_item_add_exc(p, ui_day_sel_date()); } else { - date = update_time_in_date(p->start, 0, 0); recur_apoint_find_occurrence(p->item.rapt, - date, + ui_day_sel_date(), &occurrence); day_item_add_exc(p, occurrence); } @@ -900,21 +901,25 @@ void ui_day_item_repeat(void) } date = get_slctd_day(); + /* Set the selected APP item. */ + struct day_item d = empty_day; if (p->type == EVNT) { struct event *ev = p->item.ev; - recur_event_new(ev->mesg, ev->note, ev->day, ev->id, type, - freq, until, NULL); + d.item.rev = recur_event_new(ev->mesg, ev->note, ev->day, + ev->id, type, freq, until, NULL); } else if (p->type == APPT) { struct apoint *apt = p->item.apt; - ra = recur_apoint_new(apt->mesg, apt->note, apt->start, - apt->dur, apt->state, type, freq, - until, NULL); + d.item.rapt = ra = recur_apoint_new(apt->mesg, apt->note, + apt->start, apt->dur, + apt->state, type, freq, + until, NULL); if (notify_bar()) notify_check_repeated(ra); } else { EXIT(_("wrong item type")); /* NOTREACHED */ } + day_set_sel_data(&d); ui_day_item_cut_free(REG_BLACK_HOLE); p = day_cut_item(date, item_nb); @@ -960,7 +965,7 @@ void ui_day_item_copy(unsigned reg) if (day_item_count(0) <= 0 || reg == REG_BLACK_HOLE) return; - struct day_item *item = ui_day_selitem(); + struct day_item *item = ui_day_get_sel(); ui_day_item_cut_free(reg); day_item_fork(item, &day_cut[reg]); } @@ -968,15 +973,15 @@ void ui_day_item_copy(unsigned reg) /* Paste a previously cut item. */ void ui_day_item_paste(unsigned reg) { - struct day_item day; + struct day_item day = empty_day; if (reg == REG_BLACK_HOLE || !day_cut[reg].type) return; day_item_fork(&day_cut[reg], &day); - day_paste_item(&day, ui_day_selday()); + day_paste_item(&day, ui_day_sel_date()); + day_set_sel_data(&day); io_set_modified(); - ui_calendar_monthly_view_cache_set_invalid(); } @@ -1071,7 +1076,7 @@ void ui_day_popup_item(void) if (day_item_count(0) <= 0) return; - struct day_item *item = ui_day_selitem(); + struct day_item *item = ui_day_get_sel(); day_popup_item(item); } @@ -1080,7 +1085,7 @@ void ui_day_flag(void) if (day_item_count(0) <= 0) return; - struct day_item *item = ui_day_selitem(); + struct day_item *item = ui_day_get_sel(); day_item_switch_notify(item); io_set_modified(); } @@ -1090,7 +1095,7 @@ void ui_day_view_note(void) if (day_item_count(0) <= 0) return; - struct day_item *item = ui_day_selitem(); + struct day_item *item = ui_day_get_sel(); day_view_note(item, conf.pager); } @@ -1099,7 +1104,7 @@ void ui_day_edit_note(void) if (day_item_count(0) <= 0) return; - struct day_item *item = ui_day_selitem(); + struct day_item *item = ui_day_get_sel(); day_edit_note(item, conf.editor); io_set_modified(); } -- cgit v1.2.3-70-g09d2