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 <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
parent
1ccfe128cc
commit
4284ca91bc
@ -60,7 +60,7 @@ static void do_storage(int day_changed)
|
|||||||
ui_day_sel_reset();
|
ui_day_sel_reset();
|
||||||
|
|
||||||
/* The day_items vector. */
|
/* 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. */
|
/* The APP listbox. */
|
||||||
ui_day_load_items();
|
ui_day_load_items();
|
||||||
|
|
||||||
@ -414,7 +414,12 @@ static inline void key_move_up(void)
|
|||||||
if (wins_slctd() == CAL) {
|
if (wins_slctd() == CAL) {
|
||||||
key_generic_prev_week();
|
key_generic_prev_week();
|
||||||
} else if (wins_slctd() == APP) {
|
} 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);
|
wins_update(FLAG_APP);
|
||||||
} else if (wins_slctd() == TOD) {
|
} else if (wins_slctd() == TOD) {
|
||||||
ui_todo_sel_move(-1);
|
ui_todo_sel_move(-1);
|
||||||
@ -434,7 +439,12 @@ static inline void key_move_down(void)
|
|||||||
if (wins_slctd() == CAL) {
|
if (wins_slctd() == CAL) {
|
||||||
key_generic_next_week();
|
key_generic_next_week();
|
||||||
} else if (wins_slctd() == APP) {
|
} 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);
|
wins_update(FLAG_APP);
|
||||||
} else if (wins_slctd() == TOD) {
|
} else if (wins_slctd() == TOD) {
|
||||||
ui_todo_sel_move(1);
|
ui_todo_sel_move(1);
|
||||||
|
@ -421,6 +421,7 @@ enum day_item_type {
|
|||||||
EVNT_SEPARATOR,
|
EVNT_SEPARATOR,
|
||||||
RECUR_APPT,
|
RECUR_APPT,
|
||||||
APPT,
|
APPT,
|
||||||
|
EMPTY_SEPARATOR,
|
||||||
DAY_SEPARATOR
|
DAY_SEPARATOR
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -764,7 +765,7 @@ int parse_args(int, char **);
|
|||||||
/* calendar.c */
|
/* calendar.c */
|
||||||
extern struct day_item empty_day;
|
extern struct day_item empty_day;
|
||||||
|
|
||||||
/* ui_calendar.c */
|
/* ui-calendar.c */
|
||||||
void ui_calendar_view_next(void);
|
void ui_calendar_view_next(void);
|
||||||
void ui_calendar_view_prev(void);
|
void ui_calendar_view_prev(void);
|
||||||
void ui_calendar_set_view(int);
|
void ui_calendar_set_view(int);
|
||||||
@ -803,10 +804,10 @@ void custom_keys_config(void);
|
|||||||
void custom_config_main(void);
|
void custom_config_main(void);
|
||||||
|
|
||||||
/* day.c */
|
/* day.c */
|
||||||
int day_get_nb(void);
|
|
||||||
int day_set_sel_data(struct day_item *);
|
int day_set_sel_data(struct day_item *);
|
||||||
int day_check_sel_data(void);
|
int day_check_sel_data(void);
|
||||||
int day_sel_index(void);
|
int day_sel_index(void);
|
||||||
|
int day_get_days(void);
|
||||||
void day_free_vector(void);
|
void day_free_vector(void);
|
||||||
char *day_item_get_mesg(struct day_item *);
|
char *day_item_get_mesg(struct day_item *);
|
||||||
char *day_item_get_note(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);
|
time_t ui_day_sel_date(void);
|
||||||
void ui_day_sel_reset(void);
|
void ui_day_sel_reset(void);
|
||||||
void ui_day_set_sel(struct day_item *);
|
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 *);
|
void ui_day_draw(int, WINDOW *, int, int, void *);
|
||||||
enum listbox_row_type ui_day_row_type(int, void *);
|
enum listbox_row_type ui_day_row_type(int, void *);
|
||||||
int ui_day_height(int, void *);
|
int ui_day_height(int, void *);
|
||||||
|
17
src/day.c
17
src/day.c
@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
#include "calcurse.h"
|
#include "calcurse.h"
|
||||||
|
|
||||||
static unsigned day_nb = 7;
|
static unsigned day_days = 5;
|
||||||
static vector_t day_items;
|
static vector_t day_items;
|
||||||
static unsigned day_items_nb = 0;
|
static unsigned day_items_nb = 0;
|
||||||
|
|
||||||
@ -107,9 +107,9 @@ int day_sel_index(void)
|
|||||||
return -1;
|
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)
|
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;
|
llist_item_t *i;
|
||||||
union aptev_ptr p;
|
union aptev_ptr p;
|
||||||
|
time_t occurrence;
|
||||||
int a_nb = 0;
|
int a_nb = 0;
|
||||||
|
|
||||||
LLIST_TS_LOCK(&recur_alist_p);
|
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);
|
struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
|
||||||
|
|
||||||
p.rapt = rapt;
|
p.rapt = rapt;
|
||||||
|
|
||||||
time_t occurrence;
|
|
||||||
/* As for appointments */
|
/* As for appointments */
|
||||||
if (recur_apoint_find_occurrence(rapt, date, &occurrence)) {
|
if (recur_apoint_find_occurrence(rapt, date, &occurrence)) {
|
||||||
day_add_item(RECUR_APPT,
|
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;
|
day_items_nb += events + apts;
|
||||||
|
|
||||||
if (events == 0 && apts == 0) {
|
if (include_captions && events == 0 && apts == 0) {
|
||||||
/* Insert dummy event. */
|
/* Insert dummy event. */
|
||||||
d.ev = &dummy;
|
d.ev = &dummy;
|
||||||
dummy.mesg = _("(none)");
|
dummy.mesg = _("(none)");
|
||||||
@ -459,9 +458,13 @@ day_store_items(time_t date, int include_captions, int n)
|
|||||||
day_items_nb++;
|
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);
|
day_add_item(DAY_SEPARATOR, 0, ENDOFDAY(date), p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VECTOR_SORT(&day_items, day_cmp);
|
VECTOR_SORT(&day_items, day_cmp);
|
||||||
}
|
}
|
||||||
|
100
src/ui-day.c
100
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);
|
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.
|
* Request the user to enter a new start time.
|
||||||
* Input: start time and duration in seconds.
|
* Input: start time and duration in seconds.
|
||||||
@ -758,6 +797,10 @@ void ui_day_item_delete(unsigned reg)
|
|||||||
|
|
||||||
io_set_modified();
|
io_set_modified();
|
||||||
ui_calendar_monthly_view_cache_set_invalid();
|
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;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@ -768,7 +811,8 @@ void ui_day_item_delete(unsigned reg)
|
|||||||
p = day_cut_item(date, listbox_get_sel(&lb_apt));
|
p = day_cut_item(date, listbox_get_sel(&lb_apt));
|
||||||
day_cut[reg].type = p->type;
|
day_cut[reg].type = p->type;
|
||||||
day_cut[reg].item = p->item;
|
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();
|
io_set_modified();
|
||||||
ui_calendar_monthly_view_cache_set_invalid();
|
ui_calendar_monthly_view_cache_set_invalid();
|
||||||
}
|
}
|
||||||
@ -993,11 +1037,51 @@ void ui_day_load_items(void)
|
|||||||
void ui_day_sel_reset(void)
|
void ui_day_sel_reset(void)
|
||||||
{
|
{
|
||||||
listbox_set_sel(&lb_apt, 0);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_day_sel_move(int delta)
|
int ui_day_sel_move(int delta)
|
||||||
{
|
{
|
||||||
listbox_sel_move(&lb_apt, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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)
|
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);
|
custom_remove_attr(win, ATTR_HIGHEST);
|
||||||
mem_free(buf);
|
mem_free(buf);
|
||||||
} else if (item->type == EVNT_SEPARATOR) {
|
} else if (item->type == EVNT_SEPARATOR) {
|
||||||
wmove(win, y, 0);
|
wmove(win, y, 1);
|
||||||
whline(win, 0, width);
|
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 ||
|
if (item->type == DAY_HEADING ||
|
||||||
item->type == EVNT_SEPARATOR ||
|
item->type == EVNT_SEPARATOR ||
|
||||||
|
item->type == EMPTY_SEPARATOR ||
|
||||||
item->type == DAY_SEPARATOR)
|
item->type == DAY_SEPARATOR)
|
||||||
return LISTBOX_ROW_CAPTION;
|
return LISTBOX_ROW_CAPTION;
|
||||||
else
|
else
|
||||||
@ -1057,10 +1142,9 @@ int ui_day_height(int n, void *cb_data)
|
|||||||
{
|
{
|
||||||
struct day_item *item = day_get_item(n);
|
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;
|
return 3;
|
||||||
else if (item->type == DAY_SEPARATOR)
|
|
||||||
return 2;
|
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user