diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apoint.c | 10 | ||||
-rw-r--r-- | src/args.c | 4 | ||||
-rw-r--r-- | src/calcurse.c | 105 | ||||
-rw-r--r-- | src/calcurse.h | 51 | ||||
-rw-r--r-- | src/config.c | 28 | ||||
-rw-r--r-- | src/custom.c | 76 | ||||
-rw-r--r-- | src/day.c | 66 | ||||
-rw-r--r-- | src/dmon.c | 2 | ||||
-rw-r--r-- | src/event.c | 2 | ||||
-rw-r--r-- | src/getstring.c | 4 | ||||
-rw-r--r-- | src/help.c | 6 | ||||
-rw-r--r-- | src/hooks.c | 2 | ||||
-rw-r--r-- | src/htable.h | 2 | ||||
-rw-r--r-- | src/ical.c | 19 | ||||
-rw-r--r-- | src/io.c | 178 | ||||
-rw-r--r-- | src/keys.c | 335 | ||||
-rw-r--r-- | src/listbox.c | 2 | ||||
-rw-r--r-- | src/llist.c | 2 | ||||
-rw-r--r-- | src/llist.h | 2 | ||||
-rw-r--r-- | src/llist_ts.h | 2 | ||||
-rw-r--r-- | src/mem.c | 2 | ||||
-rw-r--r-- | src/note.c | 2 | ||||
-rw-r--r-- | src/notify.c | 2 | ||||
-rw-r--r-- | src/pcal.c | 6 | ||||
-rw-r--r-- | src/queue.c | 2 | ||||
-rw-r--r-- | src/recur.c | 22 | ||||
-rw-r--r-- | src/sha1.c | 3 | ||||
-rw-r--r-- | src/sha1.h | 4 | ||||
-rw-r--r-- | src/sigs.c | 2 | ||||
-rw-r--r-- | src/strings.c | 2 | ||||
-rw-r--r-- | src/todo.c | 2 | ||||
-rw-r--r-- | src/ui-calendar.c | 123 | ||||
-rw-r--r-- | src/ui-day.c | 2 | ||||
-rw-r--r-- | src/ui-todo.c | 23 | ||||
-rw-r--r-- | src/utf8.c | 2 | ||||
-rw-r--r-- | src/utils.c | 38 | ||||
-rw-r--r-- | src/vars.c | 5 | ||||
-rw-r--r-- | src/vector.c | 2 | ||||
-rw-r--r-- | src/vector.h | 2 | ||||
-rw-r--r-- | src/wins.c | 16 |
40 files changed, 670 insertions, 490 deletions
diff --git a/src/apoint.c b/src/apoint.c index 4cb77f6..e138e5e 100644 --- a/src/apoint.c +++ b/src/apoint.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,8 @@ #include "calcurse.h" #include "sha1.h" +#define APPT_TIME_LENGTH 25 + llist_ts_t alist_p; void apoint_free(struct apoint *apt) @@ -134,16 +136,14 @@ void apoint_sec2str(struct apoint *o, time_t day, char *start, char *end) } else { t = o->start; localtime_r(&t, <); - snprintf(start, HRMIN_SIZE, "%02u:%02u", lt.tm_hour, - lt.tm_min); + strftime(start, APPT_TIME_LENGTH, conf.timefmt, <); } if (o->start + o->dur > day + DAYLEN(day)) { strncpy(end, "..:..", 6); } else { t = o->start + o->dur; localtime_r(&t, <); - snprintf(end, HRMIN_SIZE, "%02u:%02u", lt.tm_hour, - lt.tm_min); + strftime(end, APPT_TIME_LENGTH, conf.timefmt, <); } } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -112,7 +112,7 @@ static void version_arg(void) { printf(_("calcurse %s -- text-based organizer\n"), VERSION); putchar('\n'); - printf("%s\n", _("Copyright (c) 2004-2020 calcurse Development Team.")); + printf("%s\n", _("Copyright (c) 2004-2023 calcurse Development Team.")); printf("%s\n", _("This is free software; see the source for copying conditions.")); } diff --git a/src/calcurse.c b/src/calcurse.c index cd143d6..c89d1dd 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,37 +41,6 @@ #define HANDLE_KEY(key, fn) case key: fn(); break; int count, reg; -/* - * 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) -{ - int pre_sel; - /* - * Save the selected item before rebuilding the day vector - - * unless a preselection is already set. - */ - if (!(pre_sel = 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_days()); - /* The APP listbox. */ - ui_day_load_items(); - - if (day_changed && !pre_sel) - ui_day_sel_reset(); - else - ui_day_find_sel(); - - day_set_sel_data(&empty_day); -} static inline void key_generic_change_view(void) { @@ -80,6 +49,13 @@ static inline void key_generic_change_view(void) wins_update(FLAG_ALL); } +static inline void key_generic_prev_view(void) +{ + wins_reset_status_page(); + wins_slctd_prev(); + wins_update(FLAG_ALL); +} + static inline void key_generic_other_cmd(void) { wins_other_status_page(); @@ -91,7 +67,7 @@ static inline void key_generic_goto(void) wins_erase_status_bar(); ui_calendar_set_current_date(); ui_calendar_change_day(conf.input_datefmt); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } @@ -100,7 +76,7 @@ static inline void key_generic_goto_today(void) wins_erase_status_bar(); ui_calendar_set_current_date(); ui_calendar_goto_today(); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } @@ -118,14 +94,14 @@ static inline void key_generic_config_menu(void) wins_erase_status_bar(); wins_reset_status_page(); custom_config_main(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_ALL); } static inline void key_generic_add_appt(void) { ui_day_item_add(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } @@ -141,7 +117,7 @@ static inline void key_add_item(void) case APP: case CAL: ui_day_item_add(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); break; case TOD: @@ -157,7 +133,7 @@ static inline void key_edit_item(void) { if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_edit(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } else if (wins_slctd() == TOD) { ui_todo_edit(); @@ -169,7 +145,7 @@ static inline void key_del_item(void) { if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_delete(reg); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } else if (wins_slctd() == TOD) { ui_todo_delete(); @@ -187,7 +163,7 @@ static inline void key_generic_paste(void) { if (wins_slctd() == APP) { ui_day_item_paste(reg); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP); } } @@ -196,7 +172,7 @@ static inline void key_repeat_item(void) { if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_item_repeat(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_CAL | FLAG_APP | FLAG_STA); } } @@ -205,7 +181,7 @@ static inline void key_flag_item(void) { if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_flag(); - do_storage(0); + day_do_storage(0); wins_update(FLAG_APP); } else if (wins_slctd() == TOD) { ui_todo_flag(); @@ -244,7 +220,7 @@ static inline void key_edit_note(void) { if (wins_slctd() == APP && !event_dummy(ui_day_get_sel())) { ui_day_edit_note(); - do_storage(0); + day_do_storage(0); } else if (wins_slctd() == TOD) { ui_todo_edit_note(); } @@ -284,7 +260,7 @@ static inline void key_generic_save(void) if (ret == IO_SAVE_RELOAD) { ui_todo_load_items(); ui_todo_sel_reset(); - do_storage(0); + day_do_storage(0); notify_check_next_app(1); ui_calendar_monthly_view_cache_set_invalid(); } @@ -319,7 +295,7 @@ static inline void key_generic_reload(void) ret == IO_RELOAD_MERGE) { ui_todo_load_items(); ui_todo_sel_reset(); - do_storage(0); + day_do_storage(0); notify_check_next_app(1); ui_calendar_monthly_view_cache_set_invalid(); } @@ -349,7 +325,7 @@ static inline void key_generic_import(void) wins_erase_status_bar(); io_import_data(IO_IMPORT_ICAL, NULL, NULL, NULL, NULL, NULL, NULL); ui_calendar_monthly_view_cache_set_invalid(); - do_storage(0); + day_do_storage(0); ui_todo_load_items(); wins_update(FLAG_ALL); } @@ -374,14 +350,14 @@ static inline void key_generic_export() break; } - do_storage(0); + day_do_storage(0); wins_update(FLAG_ALL); } static inline void key_generic_prev_day(void) { ui_calendar_move(DAY_PREV, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } @@ -394,7 +370,7 @@ static inline void key_move_left(void) static inline void key_generic_next_day(void) { ui_calendar_move(DAY_NEXT, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } @@ -407,7 +383,7 @@ static inline void key_move_right(void) static inline void key_generic_prev_week(void) { ui_calendar_move(WEEK_PREV, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } @@ -418,7 +394,7 @@ static inline void key_move_up(void) } else if (wins_slctd() == APP) { if (!ui_day_sel_move(-1)) { ui_calendar_move(DAY_PREV, 1); - do_storage(1); + day_do_storage(1); ui_day_sel_dayend(); } wins_update(FLAG_APP | FLAG_CAL); @@ -431,7 +407,7 @@ static inline void key_move_up(void) static inline void key_generic_next_week(void) { ui_calendar_move(WEEK_NEXT, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } @@ -442,7 +418,7 @@ static inline void key_move_down(void) } else if (wins_slctd() == APP) { if (!ui_day_sel_move(1)) { ui_calendar_move(DAY_PREV, day_get_days() - 2); - do_storage(1); + day_do_storage(1); ui_day_sel_daybegin(day_get_days() - 1); } wins_update(FLAG_APP | FLAG_CAL); @@ -455,28 +431,28 @@ static inline void key_move_down(void) static inline void key_generic_prev_month(void) { ui_calendar_move(MONTH_PREV, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } static inline void key_generic_next_month(void) { ui_calendar_move(MONTH_NEXT, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } static inline void key_generic_prev_year(void) { ui_calendar_move(YEAR_PREV, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } static inline void key_generic_next_year(void) { ui_calendar_move(YEAR_NEXT, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } @@ -484,7 +460,7 @@ static inline void key_start_of_week(void) { if (wins_slctd() == CAL) { ui_calendar_move(WEEK_START, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } } @@ -493,7 +469,7 @@ static inline void key_end_of_week(void) { if (wins_slctd() == CAL) { ui_calendar_move(WEEK_END, count); - do_storage(1); + day_do_storage(1); wins_update(FLAG_CAL | FLAG_APP); } } @@ -650,7 +626,7 @@ static inline void key_generic_cmd(void) item->order = next; ui_calendar_set_slctd_day(sec2date(next)); day_set_sel_data(item); - do_storage(1); + day_do_storage(1); valid = 1; } @@ -695,7 +671,7 @@ static inline void key_generic_cmd(void) item->order = prev; ui_calendar_set_slctd_day(sec2date(prev)); day_set_sel_data(item); - do_storage(1); + day_do_storage(1); valid = 1; } @@ -805,7 +781,7 @@ int main(int argc, char **argv) */ wins_wrefresh(win[KEY].p); ui_calendar_monthly_view_cache_set_invalid(); - do_storage(1); + day_do_storage(1); ui_todo_load_items(); ui_todo_sel_reset(); wins_update(FLAG_ALL); @@ -825,7 +801,7 @@ int main(int argc, char **argv) que_show(); if (conf.systemevents) { que_save(); - do_storage(0); + day_do_storage(0); } wins_update(FLAG_ALL); que_rem(); @@ -835,7 +811,7 @@ int main(int argc, char **argv) resize = 0; wins_reset(); if (conf.multiple_days) { - do_storage(0); + day_do_storage(0); wins_update(FLAG_APP); } } @@ -851,6 +827,7 @@ int main(int argc, char **argv) wtimeout(win[KEY].p, -1); switch (key) { HANDLE_KEY(KEY_GENERIC_CHANGE_VIEW, key_generic_change_view); + HANDLE_KEY(KEY_GENERIC_PREV_VIEW, key_generic_prev_view); HANDLE_KEY(KEY_GENERIC_OTHER_CMD, key_generic_other_cmd); HANDLE_KEY(KEY_GENERIC_GOTO, key_generic_goto); HANDLE_KEY(KEY_GENERIC_GOTO_TODAY, key_generic_goto_today); diff --git a/src/calcurse.h b/src/calcurse.h index d5ba355..8322416 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,9 +111,6 @@ #define STATUSHEIGHT 2 #define MAX_NOTESIZ 40 -/* Format for appointment hours is: HH:MM */ -#define HRMIN_SIZE 6 - /* Maximum number of colors available. */ #define NBUSERCOLORS 6 @@ -155,7 +152,7 @@ * The argument (d) is the "Sunday"-numbering of member tm_wday in struct tm. */ #define WDAY(d) \ - (ui_calendar_week_begins_on_monday() ? ((d ? d : WEEKINDAYS) - 1) : d) + (modify_wday(d, -ui_calendar_get_wday_start())) /* Key definitions. */ #define CTRLVAL 0x1F @@ -306,9 +303,11 @@ struct conf { int input_datefmt; /* format for reading date */ enum pos heading_pos; /* left/center/right for heading in appts panel */ char day_heading[BUFSIZ]; /* format for displaying heading in appts panel */ + char timefmt[BUFSIZ]; /* format for displaying time in appts panel*/ }; #define EMPTY_DAY_DEFAULT "--" +#define EMPTY_EVENT_DESC_DEFAULT _("(empty description)") /* Daemon-related configuration. */ struct dmon_conf { @@ -338,6 +337,9 @@ enum datefmt { /* Day heading default format. */ #define DAY_HEADING_DEFAULT "%B %e, %Y" +/* Appointment time default format. */ +#define APPT_TIME_DEFAULT "%H:%M" + /* * Calcurse representation of the date of a day in the calendar. * When time_t is a 32-bit signed integer, the year range is 1902 - 2037. @@ -515,8 +517,8 @@ struct io_file { char *name; }; -/* Available keys. */ -enum key { +/* Virtual keys. */ +enum vkey { KEY_GENERIC_CANCEL, KEY_GENERIC_SELECT, KEY_GENERIC_CREDITS, @@ -527,6 +529,7 @@ enum key { KEY_GENERIC_COPY, KEY_GENERIC_PASTE, KEY_GENERIC_CHANGE_VIEW, + KEY_GENERIC_PREV_VIEW, KEY_GENERIC_IMPORT, KEY_GENERIC_EXPORT, KEY_GENERIC_GOTO, @@ -566,7 +569,7 @@ enum key { KEY_RAISE_PRIORITY, KEY_LOWER_PRIORITY, - NBKEYS, + NBVKEYS, KEY_UNDEF, /* Non-configurable, context sensitive key bindings. */ @@ -809,7 +812,7 @@ void ui_calendar_set_current_date(void); struct date *ui_calendar_get_today(void); void ui_calendar_set_first_day_of_week(enum wday); void ui_calendar_change_first_day_of_week(void); -unsigned ui_calendar_week_begins_on_monday(void); +int ui_calendar_get_wday_start(void); void ui_calendar_store_current_date(struct date *); void ui_calendar_init_slctd_day(void); struct date *ui_calendar_get_slctd_day(void); @@ -855,6 +858,7 @@ void day_display_item_date(struct day_item *, WINDOW *, int, time_t, int, int); void day_display_item(struct day_item *, WINDOW *, int, int, int, int); void day_write_stdout(time_t, const char *, const char *, const char *, const char *, int *); +void day_do_storage(int day_changed); void day_popup_item(struct day_item *); int day_check_if_item(struct date); unsigned day_chk_busy_slices(struct date, int, int *); @@ -946,24 +950,26 @@ int io_get_modified(void); void keys_init(void); void keys_free(void); void keys_dump_defaults(char *); -const char *keys_get_label(enum key); -enum key keys_get_action(int); +const char *keys_get_label(enum vkey); +const char *keys_get_binding(enum vkey); +enum vkey keys_get_action(int); int keys_wgetch(WINDOW *); void keys_wait_for_any_key(WINDOW *); -enum key keys_get(WINDOW *, int *, int *); -int keys_assign_binding(int, enum key); -void keys_remove_binding(int, enum key); +enum vkey keys_get(WINDOW * win, int *, int *); +int keys_assign_binding(int, enum vkey); +void keys_remove_binding(int, enum vkey); int keys_str2int(const char *); char *keys_int2str(int); -int keys_action_count_keys(enum key); -const char *keys_action_firstkey(enum key); -const char *keys_action_nkey(enum key, int); -char *keys_action_allkeys(enum key); +int keys_action_count_keys(enum vkey); +const char *keys_action_firstkey(enum vkey); +const char *keys_action_nkey(enum vkey, int); +char *keys_action_allkeys(enum vkey); void keys_display_bindings_bar(WINDOW *, int *, int, int, int); -void keys_popup_info(enum key); +void keys_popup_info(enum vkey); void keys_save_bindings(FILE *); -int keys_check_missing_bindings(void); -void keys_fill_missing(void); +int keys_check_missing(void); +int keys_check_undefined(void); +int keys_fill_missing(void); /* listbox.c */ void listbox_init(struct listbox *, int, int, int, int, const char *, @@ -1230,6 +1236,8 @@ time_t date_sec_change(time_t, int, int); time_t update_time_in_date(time_t, unsigned, unsigned); time_t get_sec_date(struct date); long min2sec(unsigned); +int modify_wday(int,int); +char *get_wday_default_string(int); void draw_scrollbar(struct scrollwin *, int); void item_in_popup(const char *, const char *, const char *, const char *); time_t get_today(void); @@ -1325,6 +1333,7 @@ void wins_sbar_wdec(void); enum win wins_slctd(void); void wins_slctd_set(enum win); void wins_slctd_next(void); +void wins_slctd_prev(void); void wins_init(void); void wins_scrollwin_init(struct scrollwin *, int, int, int, int, const char *); void wins_scrollwin_resize(struct scrollwin *, int, int, int, int); diff --git a/src/config.c b/src/config.c index f621320..4e0f7db 100644 --- a/src/config.c +++ b/src/config.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,8 @@ #include <ctype.h> #include <unistd.h> +#include <string.h> +#include <strings.h> #include "calcurse.h" @@ -109,6 +111,7 @@ static const struct confvar confmap[] = { {"format.inputdate", config_parse_input_datefmt, config_serialize_input_datefmt, NULL}, {"format.notifydate", CONFIG_HANDLER_STR(nbar.datefmt)}, {"format.notifytime", CONFIG_HANDLER_STR(nbar.timefmt)}, + {"format.appointmenttime", CONFIG_HANDLER_STR(conf.timefmt)}, {"format.outputdate", config_parse_output_datefmt, config_serialize_output_datefmt, NULL}, {"format.dayheading", CONFIG_HANDLER_STR(conf.day_heading)}, {"general.autogc", CONFIG_HANDLER_BOOL(conf.auto_gc)}, @@ -260,14 +263,16 @@ static int config_parse_default_panel(void *dummy, const char *val) static int config_parse_first_day_of_week(void *dummy, const char *val) { - if (!strcmp(val, "monday")) - ui_calendar_set_first_day_of_week(MONDAY); - else if (!strcmp(val, "sunday")) - ui_calendar_set_first_day_of_week(SUNDAY); - else - return 0; + int i; - return 1; + for (i = 0; i < WEEKINDAYS; i++) { + if(!strcasecmp(val, get_wday_default_string(i))) { + ui_calendar_set_first_day_of_week(i); + return 1; + } + } + + return 0; } static int config_parse_color_theme(void *dummy, const char *val) @@ -467,10 +472,9 @@ static int config_serialize_default_panel(char **buf, void *dummy) static int config_serialize_first_day_of_week(char **buf, void *dummy) { - if (ui_calendar_week_begins_on_monday()) - *buf = mem_strdup("monday"); - else - *buf = mem_strdup("sunday"); + *buf = mem_strdup(get_wday_default_string(ui_calendar_get_wday_start())); + /* now stores string with uppercase first letter, changing to lower */ + **buf = tolower(**buf); return 1; } diff --git a/src/custom.c b/src/custom.c index 0e5e554..2cd385c 100644 --- a/src/custom.c +++ b/src/custom.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ #include <stdlib.h> #include <math.h> #include <ctype.h> +#include <langinfo.h> #include "calcurse.h" @@ -545,6 +546,7 @@ enum { INPUT_DATE_FMT, HEADING_POS, DAY_HEADING_FMT, + APPOINTMENT_TIME_FMT, NB_OPTIONS }; @@ -573,7 +575,8 @@ static void print_general_option(int i, WINDOW *win, int y, int hilt, void *cb_d "format.outputdate = ", "format.inputdate = ", "appearance.headingposition = ", - "format.dayheading = " + "format.dayheading = ", + "format.appointmenttime = " }; const char *panel; const char *position; @@ -700,8 +703,7 @@ static void print_general_option(int i, WINDOW *win, int y, int hilt, void *cb_d case FIRST_DAY_OF_WEEK: custom_apply_attr(win, ATTR_HIGHEST); mvwaddstr(win, y, XPOS + strlen(opt[FIRST_DAY_OF_WEEK]), - ui_calendar_week_begins_on_monday()? _("Monday") : - _("Sunday")); + nl_langinfo(DAY_1 + ui_calendar_get_wday_start())); custom_remove_attr(win, ATTR_HIGHEST); mvwaddstr(win, y + 1, XPOS, _("(specifies the first day of week in the calendar view)")); @@ -746,6 +748,14 @@ static void print_general_option(int i, WINDOW *win, int y, int hilt, void *cb_d mvwaddstr(win, y + 1, XPOS, _("(Format of the date displayed in the appointments panel)")); break; + case APPOINTMENT_TIME_FMT: + custom_apply_attr(win, ATTR_HIGHEST); + mvwaddstr(win, y, XPOS + strlen(opt[APPOINTMENT_TIME_FMT]), + conf.timefmt); + custom_remove_attr(win, ATTR_HIGHEST); + mvwaddstr(win, y + 1, XPOS, + _("(Format of the time displayed in the appointments panel)")); + break; } if (hilt) @@ -771,6 +781,8 @@ static void general_option_edit(int i) _("Enter a text string (an empty string for the default text)"); const char *output_datefmt_str = _("Enter the date format (see 'man 3 strftime' for possible formats) "); + const char *output_timefmt_str = + _("Enter the time format (see 'man 3 strftime' for possible formats) "); const char *input_datefmt_prefix = _("Enter the date format: "); const char *periodic_save_str = _("Enter the delay, in minutes, between automatic saves (0 to disable) "); @@ -893,6 +905,15 @@ static void general_option_edit(int i) conf.day_heading[BUFSIZ - 1] = '\0'; } break; + case APPOINTMENT_TIME_FMT: + status_mesg(output_timefmt_str, ""); + strncpy(buf, conf.timefmt, BUFSIZ); + buf[BUFSIZ - 1] = '\0'; + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + strncpy(conf.timefmt, buf, BUFSIZ); + conf.timefmt[BUFSIZ - 1] = '\0'; + } + break; } mem_free(buf); @@ -975,10 +996,11 @@ print_keys_bindings(WINDOW * win, int selected_row, int selected_elm, const int XPOS = 1; const int EQUALPOS = 23; const int KEYPOS = 25; - int noelm, action, y; + int noelm, action, y, pos; + const char *key = NULL; noelm = y = 0; - for (action = 0; action < NBKEYS; action++) { + for (action = 0; action < NBVKEYS; action++) { char *actionstr; int nbkeys; @@ -990,18 +1012,15 @@ print_keys_bindings(WINDOW * win, int selected_row, int selected_elm, mem_free(actionstr); mvwaddstr(win, y, EQUALPOS, "="); if (nbkeys == 0) - mvwaddstr(win, y, KEYPOS, _("undefined")); + mvwaddstr(win, y, KEYPOS, _("UNDEFINED")); if (action == selected_row) custom_remove_attr(win, ATTR_HIGHEST); if (nbkeys > 0) { if (action == selected_row) { - const char *key; - int pos; - + /* Elements may have been added or deleted. */ + wclrtoeol(win); pos = KEYPOS; - while ((key = - keys_action_nkey(action, - noelm)) != NULL) { + while ((key = keys_action_nkey(action, noelm))) { if (noelm == selected_elm) print_key_incolor(win, key, y, pos); @@ -1012,8 +1031,9 @@ print_keys_bindings(WINDOW * win, int selected_row, int selected_elm, pos += utf8_strwidth((char *)key) + 1; } } else { - mvwaddstr(win, y, KEYPOS, - keys_action_allkeys(action)); + key = keys_action_allkeys(action); + mvwaddstr(win, y, KEYPOS, key); + mem_free((char *)key); } } y += yoff; @@ -1045,9 +1065,11 @@ void custom_keys_config(void) const int LABELLINES = 3; clear(); - nbdisplayed = ((notify_bar() ? row - 3 : row - 2) - LABELLINES) / LINESPERKEY; - wins_scrollwin_init(&kwin, 0, 0, notify_bar() ? row - 3 : row - 2, col, _("keys configuration")); - wins_scrollwin_set_pad(&kwin, NBKEYS * LINESPERKEY); + nbdisplayed = ((notify_bar() ? row - 3 : row - 2) - + LABELLINES) / LINESPERKEY; + wins_scrollwin_init(&kwin, 0, 0, notify_bar() ? row - 3 : row - 2, col, + _("keys configuration")); + wins_scrollwin_set_pad(&kwin, NBVKEYS * LINESPERKEY); wins_scrollwin_draw_deco(&kwin, 0); custom_keys_config_bar(); selrow = selelm = 0; @@ -1072,7 +1094,7 @@ void custom_keys_config(void) } break; case KEY_MOVE_DOWN: - if (selrow < NBKEYS - 1) { + if (selrow < NBVKEYS - 1) { selrow++; selelm = 0; if (selrow == lastrow) { @@ -1103,7 +1125,7 @@ void custom_keys_config(void) keys_get_label(selrow), 0); for (;;) { ch = keys_wgetch(grabwin); - enum key action = keys_get_action(ch); + enum vkey action = keys_get_action(ch); /* Is the key already used by this action? */ if (action == selrow) break; @@ -1142,10 +1164,8 @@ void custom_keys_config(void) selelm--; break; case KEY_GENERIC_QUIT: - if (keys_check_missing_bindings() != 0) { - WARN_MSG(_("Some actions do not have any associated " - "key bindings!")); - } + if (keys_check_undefined()) + WARN_MSG(_("Some actions are left undefined!")); wins_scrollwin_delete(&kwin); return; } @@ -1222,7 +1242,7 @@ void custom_config_main(void) old_layout = wins_layout(); custom_layout_config(); if (wins_layout() != old_layout) - wins_reset(); + wins_resize(); break; case 'G': case 'g': @@ -1248,7 +1268,11 @@ void custom_config_main(void) resize = 0; wins_reset(); } - + + /* needed to update app list */ + day_do_storage(0); + + /* wins_update(FLAG_ALL), but with custom bindings */ wins_set_bindings(bindings, ARRAY_SIZE(bindings)); wins_update_border(FLAG_ALL); wins_update_panels(FLAG_ALL); @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,7 +58,7 @@ 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(). + * Public function used to override the setting in day_do_storage(). */ int day_set_sel_data(struct day_item *d) { @@ -198,7 +198,8 @@ static void day_add_item(int type, time_t start, time_t order, union aptev_ptr i /* Get the message of an item. */ char *day_item_get_mesg(struct day_item *day) { - switch (day->type) { + switch (day->type) + { case APPT: return day->item.apt->mesg; case EVNT: @@ -212,6 +213,15 @@ char *day_item_get_mesg(struct day_item *day) } } +/* Get the display message of an item. */ +char *day_item_get_display_mesg(struct day_item *day) +{ + char *msg = day_item_get_mesg(day); + if (msg[0] == '\0') + return EMPTY_EVENT_DESC_DEFAULT; + return msg; +} + /* Get the note attached to an item. */ char *day_item_get_note(struct day_item *day) { @@ -529,7 +539,7 @@ day_display_item(struct day_item *day, WINDOW *win, int incolor, int width, if (width <= 0) return; - char *mesg = day_item_get_mesg(day); + char *mesg = day_item_get_display_mesg(day); ch_recur = (day->type == RECUR_EVNT) ? '*' : ' '; ch_note = day_item_get_note(day) ? '>' : ' '; @@ -578,6 +588,38 @@ void day_write_stdout(time_t date, const char *fmt_apt, const char *fmt_rapt, } } +/* + * 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. + */ +void day_do_storage(int day_changed) +{ + int pre_sel; + /* + * Save the selected item before rebuilding the day vector - + * unless a preselection is already set. + */ + if(!(pre_sel = 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_days()); + /* The APP listbox. */ + ui_day_load_items(); + + if (day_changed && !pre_sel) + ui_day_sel_reset(); + else + ui_day_find_sel(); + + day_set_sel_data(&empty_day); +} + /* Display an item inside a popup window. */ void day_popup_item(struct day_item *day) { @@ -592,15 +634,19 @@ void day_popup_item(struct day_item *day) asprintf(¬epath, "%s%s", path_notes, day_item_get_note(day)); fp = fopen(notepath, "r"); + if (fp == NULL) { + item_in_popup(NULL, NULL, day_item_get_mesg(day), _("Event:")); + return; + } note_read_contents(note, note_size, fp); fclose(fp); mem_free(notepath); - asprintf(&msg, "%s\n\n%s\n%s", day_item_get_mesg(day), note_heading, note); + asprintf(&msg, "%s\n\n%s\n%s", day_item_get_display_mesg(day), note_heading, note); item_in_popup(NULL, NULL, msg, _("Event:")); mem_free(msg); } else { - item_in_popup(NULL, NULL, day_item_get_mesg(day), _("Event:")); + item_in_popup(NULL, NULL, day_item_get_display_mesg(day), _("Event:")); } } else if (day->type == APPT || day->type == RECUR_APPT) { char a_st[100], a_end[100]; @@ -619,15 +665,19 @@ void day_popup_item(struct day_item *day) asprintf(¬epath, "%s%s", path_notes, day_item_get_note(day)); fp = fopen(notepath, "r"); + if (fp == NULL) { + item_in_popup(a_st, a_end, day_item_get_mesg(day), _("Appointment:")); + return; + } note_read_contents(note, note_size, fp); fclose(fp); mem_free(notepath); - asprintf(&msg, "%s\n\n%s\n%s", day_item_get_mesg(day), note_heading, note); + asprintf(&msg, "%s\n\n%s\n%s", day_item_get_display_mesg(day), note_heading, note); item_in_popup(a_st, a_end, msg, _("Appointment:")); mem_free(msg); } else { - item_in_popup(a_st, a_end, day_item_get_mesg(day), _("Appointment:")); + item_in_popup(a_st, a_end, day_item_get_display_mesg(day), _("Appointment:")); } } else { EXIT(_("unknown item type")); @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/event.c b/src/event.c index e0da4c1..7c371e4 100644 --- a/src/event.c +++ b/src/event.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/getstring.c b/src/getstring.c index 7cdb84e..8ea5df5 100644 --- a/src/getstring.c +++ b/src/getstring.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -241,9 +241,11 @@ enum getstr getstring(WINDOW * win, char *str, int l, int x, int y) st.len = st.pos; break; case CTRL('A'): /* go to beginning of string */ + case KEY_HOME: st.pos = 0; break; case CTRL('E'): /* go to end of string */ + case KEY_END: st.pos = st.len; break; case KEY_LEFT: /* move one char backward */ @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,7 +105,7 @@ int display_help(const char *topic) if (!io_file_exists(path)) { int ch = keys_str2int(topic); - enum key action = keys_get_action(ch); + enum vkey action = keys_get_action(ch); if (ch > 0 && action > 0 && action != KEY_UNDEF) { topic = keys_get_label(action); mem_free(path); @@ -134,6 +134,8 @@ int display_help(const char *topic) topic = "copy-paste"; else if (!strcmp(topic, "generic-change-view")) topic = "tab"; + else if (!strcmp(topic, "generic-prev-view")) + topic = "tab"; else if (!strcmp(topic, "generic-import")) topic = "import"; else if (!strcmp(topic, "generic-export")) diff --git a/src/hooks.c b/src/hooks.c index 7bfd548..f649076 100644 --- a/src/hooks.c +++ b/src/hooks.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/htable.h b/src/htable.h index 5266213..92be6e2 100644 --- a/src/htable.h +++ b/src/htable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -520,6 +520,10 @@ ical_store_event(char *mesg, char *note, time_t day, time_t end, struct event *ev; struct recur_event *rev; + if (!mesg) + mesg = mem_strdup(_("(empty)")); + EXIT_IF(!mesg, _("ical_store_event: out of memory")); + /* * Repeating event. The end day is ignored, and the event becomes * one-day even if multi-day. @@ -572,6 +576,10 @@ ical_store_apoint(char *mesg, char *note, time_t start, long dur, struct recur_apoint *rapt; time_t day; + if (!mesg) + mesg = mem_strdup(_("(empty)")); + EXIT_IF(!mesg, _("ical_store_event: out of memory")); + if (has_alarm) state |= APOINT_NOTIFY; if (rpt) { @@ -1331,12 +1339,9 @@ static char *ical_read_summary(char *line, unsigned *noskipped, } /* An event summary is one line only. */ - if (strchr(summary, '\n')) { - ical_log(log, item_type, itemline, _("line break in summary.")); - (*noskipped)++; - mem_free(summary); - summary = NULL; - } + for (p = summary; *p; p++) + if (*p == '\n') + *p = ' '; leave: return summary; } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,8 +50,8 @@ struct ht_keybindings_s { const char *label; - enum key key; - HTABLE_ENTRY(ht_keybindings_s); + enum vkey key; + HTABLE_ENTRY(ht_keybindings_s); }; static void load_keys_ht_getkey(struct ht_keybindings_s *, const char **, @@ -940,16 +940,6 @@ load_keys_ht_compare(struct ht_keybindings_s *data1, } /* - * isblank(3) is protected by the __BSD_VISIBLE macro and this fails to be - * visible in some specific cases. Thus replace it by the following is_blank() - * function. - */ -static int is_blank(int c) -{ - return c == ' ' || c == '\t'; -} - -/* * Load user-definable keys from file. * A hash table is used to speed up loading process in avoiding string * comparisons. @@ -958,21 +948,21 @@ static int is_blank(int c) */ void io_load_keys(const char *pager) { - struct ht_keybindings_s keys[NBKEYS]; + struct ht_keybindings_s virt_keys[NBVKEYS], *ht_elm, ht_entry; FILE *keyfp; - char buf[BUFSIZ]; + char buf[BUFSIZ], key_label[BUFSIZ], key_str[BUFSIZ]; + char *p, *msg; struct io_file *log; - int i, skipped, loaded, line; - const int MAX_ERRORS = 5; + int i, n, skipped, loaded, line, assigned, undefined, key; keys_init(); struct ht_keybindings ht_keys = HTABLE_INITIALIZER(&ht_keys); - for (i = 0; i < NBKEYS; i++) { - keys[i].key = (enum key)i; - keys[i].label = keys_get_label((enum key)i); - HTABLE_INSERT(ht_keybindings, &ht_keys, &keys[i]); + for (i = 0; i < NBVKEYS; i++) { + virt_keys[i].key = (enum vkey)i; + virt_keys[i].label = keys_get_label((enum vkey)i); + HTABLE_INSERT(ht_keybindings, &ht_keys, &virt_keys[i]); } keyfp = fopen(path_keys, "r"); @@ -981,111 +971,97 @@ void io_load_keys(const char *pager) log = io_log_init(); skipped = loaded = line = 0; while (fgets(buf, BUFSIZ, keyfp) != NULL) { - char key_label[BUFSIZ], *p; - struct ht_keybindings_s *ht_elm, ht_entry; - const int AWAITED = 1; - int assigned; - line++; - if (skipped > MAX_ERRORS) { - const char *too_many = - _("\nToo many errors while reading configuration file!\n" - "Please backup your keys file, remove it from directory, " - "and launch calcurse again.\n"); - - io_log_print(log, line, too_many); - break; - } - for (p = buf; is_blank((int)*p); p++) ; - if (p != buf) - memmove(buf, p, strlen(p)); - if (buf[0] == '#' || buf[0] == '\n') + p = buf; + while (*p == ' ' || *p == '\t') p++; + if (*p == '#' || *p == '\n') continue; - if (sscanf(buf, "%s", key_label) != AWAITED) { + /* Find the virtual key by key label. */ + if (sscanf(p, "%s", key_label) != 1) { skipped++; io_log_print(log, line, _("Could not read key label")); continue; } - - /* Skip legacy entries. */ - if (strcmp(key_label, "generic-cut") == 0) - continue; - + p += strlen(key_label); ht_entry.label = key_label; - p = buf + strlen(key_label) + 1; - ht_elm = - HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry); + ht_elm = HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry); if (!ht_elm) { skipped++; - io_log_print(log, line, - _("Key label not recognized")); + asprintf(&msg, + _("Key label not recognized: \"%s\""), + key_label); + io_log_print(log, line, msg); + mem_free(msg); continue; } - assigned = 0; - for (;;) { - char key_ch[BUFSIZ], tmpbuf[BUFSIZ]; - - while (*p == ' ') - p++; - (void)strncpy(tmpbuf, p, BUFSIZ); - tmpbuf[BUFSIZ - 1] = '\0'; - if (sscanf(tmpbuf, "%s", key_ch) == AWAITED) { - int ch; - - if ((ch = keys_str2int(key_ch)) < 0) { - char *unknown_key; + /* Assign keyboard keys to the virtual key. */ + assigned = undefined = 0; + for (;;) { + if (sscanf(p, "%s%n", key_str, &n) != 1) { + if (assigned || undefined) + loaded++; + else { skipped++; - asprintf(&unknown_key, - _("Error reading key: \"%s\""), - key_ch); - io_log_print(log, line, unknown_key); - mem_free(unknown_key); - } else { - int used; - - used = - keys_assign_binding(ch, - ht_elm-> - key); - if (used) { - char *already_assigned; - - skipped++; - asprintf(&already_assigned, - _("\"%s\" assigned multiple times!"), - key_ch); - io_log_print(log, line, - already_assigned); - mem_free(already_assigned); - } else { - assigned++; - } + asprintf(&msg, + _("No keys assigned to " + "\"%s\"."), + key_label); + io_log_print(log, line, msg); + mem_free(msg); } - p += strlen(key_ch) + 1; - } else { - if (assigned) - loaded++; break; } + p += n; + if (!strcmp(key_str, "UNDEFINED")) { + undefined++; + keys_assign_binding(-1, ht_elm->key); + } else if ((key = keys_str2int(key_str)) < 0) { + skipped++; + asprintf(&msg, + _("Keyname not recognized: \"%s\""), + key_str); + io_log_print(log, line, msg); + mem_free(msg); + } else if (keys_assign_binding(key, ht_elm->key)) { + skipped++; + asprintf(&msg, + _("\"%s\" assigned twice: \"%s\"."), + key_str, key_label); + io_log_print(log, line, msg); + mem_free(msg); + } else + assigned++; } } file_close(keyfp, __FILE_POS__); + if (loaded < NBVKEYS && (i = keys_fill_missing()) < 1) { + skipped++; + strcpy(key_label, keys_get_label((enum vkey)(-i))); + strcpy(key_str, keys_get_binding((enum vkey)(-i))); + asprintf(&msg, _("Action \"%s\" absent, but default key \"%s\" " + "assigned to another action."), + key_label, key_str); + io_log_print(log, line, msg); + mem_free(msg); + } file_close(log->fd, __FILE_POS__); if (skipped > 0) { - const char *view_log = - _("There were some errors when loading keys file."); - io_log_display(log, view_log, pager); + msg = _("Errors in the keys file."); + io_log_display(log, msg, pager); + WARN_MSG(_("Remove offending line(s) from the keys file, " + "aborting...")); + exit_calcurse(EXIT_FAILURE); } io_log_free(log); - EXIT_IF(skipped > MAX_ERRORS, - _("Too many errors while reading keys file, aborting...")); - if (loaded < NBKEYS) - keys_fill_missing(); - if (keys_check_missing_bindings()) - WARN_MSG(_("Some actions do not have any associated key bindings!")); + /* Default keys were inserted. */ + if (loaded < NBVKEYS) + io_save_keys(); + /* Should never occur. */ + EXIT_IF(keys_check_missing(), + _("Some actions do not have any associated key bindings!")); } int io_check_dir(const char *dir) @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,26 +39,73 @@ #include "calcurse.h" -#define MAXKEYVAL KEY_MAX /* ncurses defines KEY_MAX as maximum key value */ - -struct keydef_s { - const char *label; - const char *binding; - const char *sb_label; -}; +/* + * The interactive calcurse interface is controlled by "virtual keys", aka + * actions or commands. The virtual keys are defined by the type 'enum vkey', + * see calcurse.h. To each virtual key is assigned (or bound) zero or more + * keyboard keys/characters. A character (generated by a keyboard key) may be + * either an ordinary character or a pseudo-character. [An ordinary character + * is either a singlebyte ASCII character or a multibyte, UTF-8 encoded + * character; a pseudo-character (as supported by curses) is an escape sequence + * generated by a key.] A keyboard key/character is uniquely identified by its + * keyname (a character string) or by an integer (the Unicode code point of the + * character with a slight modification to accomodate the range of curses + * pseudo-characters). Mapping between the two forms is performed by the + * functions keys_str2int() and keys_int2str(). + */ -static llist_t keys[NBKEYS]; -static enum key actions[MAXKEYVAL]; +/* + * Assignment of keys to virtual keys is held in the tabel keys[]. The entry for + * each virtual key is a linked list of keyboard keys (bindings); each list + * element is the keyname as returned by keys_int2str(). + * + * At the very first run default keys are assigned to all virtual keys from a + * built-in table keydef[] and saved to disk in the calcurse config directory. + * Later the user may edit the key configuration and change the key bindings by + * adding/removing keys. If all keys are removed, the virtual key is left + * undefined. This state is also saved in the configuration file. The linked + * list for an undefined virtual key contains a single element with a null + * pointer as data. + */ +static llist_t keys[NBVKEYS]; +/* + * To cater for the other direction (which virtual key is a keyboard key + * assigned to), two constructions are needed: a table actions[] for the + * keyboard keys in the curses range, and a linked list actions_ext for + * multi-byte UTF-8 encoded keyboard characters. + * + * For each keyboard key (integer) in the curses key range, the virtual key + * (action) it is assigned to or, if not assigned, KEY_UNDEF. + */ +static enum vkey actions[KEY_MAX]; +/* + * For the millions of possible keyboard keys above the curses range, a linked + * list of keys which are actually bound to a virtual key. + * Each list element is a key_ext structure. + */ +llist_t actions_ext; struct key_ext { - int ch; - enum key action; + int key; + enum vkey action; }; -llist_t actions_ext; +/* + * Assigning a keyboard key to a virtual key is accomplished by + * 1) either inserting the virtual key in the actions[] entry for the keyboard key + * or adding the pair (key, virtual key) to the list actions_ext + * 2) adding it in keys[] to the list for the virtual key + * See keys_assign_binding() below. + */ +/* The default key bindings for the virtual keys. */ +struct keydef_s { + const char *label; /* Name of the virtual key (action). */ + const char *binding; /* String of space-separated keynames bound to it. */ + const char *sb_label; /* Display name in the status bar menu. */ +}; #define gettext_noop(s) s -static struct keydef_s keydef[NBKEYS] = { +static struct keydef_s keydef[NBVKEYS] = { { "generic-cancel", "ESC", gettext_noop("Cancel") }, { "generic-select", "SPC", gettext_noop("Select") }, { "generic-credits", "@", gettext_noop("Credits") }, @@ -69,6 +116,7 @@ static struct keydef_s keydef[NBKEYS] = { { "generic-copy", "c", gettext_noop("Copy") }, { "generic-paste", "p ^V", gettext_noop("Paste") }, { "generic-change-view", "TAB", gettext_noop("Chg Win") }, + { "generic-prev-view", "KEY_BTAB", gettext_noop("Prev Win") }, { "generic-import", "i I", gettext_noop("Import") }, { "generic-export", "x X", gettext_noop("Export") }, { "generic-goto", "g G", gettext_noop("Go to") }, @@ -132,10 +180,11 @@ void keys_init(void) int i; const char *cp; - for (i = 0; i < MAXKEYVAL; i++) + /* All keys unassigned. */ + for (i = 0; i < KEY_MAX; i++) actions[i] = KEY_UNDEF; LLIST_INIT(&actions_ext); - for (i = 0; i < NBKEYS; i++) + for (i = 0; i < NBVKEYS; i++) LLIST_INIT(&keys[i]); /* Initialization of the keynames table. */ @@ -146,7 +195,7 @@ void keys_init(void) for (i = 1; i < 128; i++) if ((cp = keyname(i))) keynames[i] = mem_strdup(cp); - /* ... and for the ncurses escape keys (pseudokeys). */ + /* ... and for the ncurses pseudo-characters. */ for (i = KEY_MIN; i < KEY_MAX; i++) if ((cp = keyname(i))) keynames[i] = mem_strdup(cp); @@ -189,7 +238,7 @@ void keys_free(void) { int i; - for (i = 0; i < NBKEYS; i++) { + for (i = 0; i < NBVKEYS; i++) { LLIST_FREE_INNER(&keys[i], key_free); LLIST_FREE(&keys[i]); } @@ -205,31 +254,40 @@ void keys_dump_defaults(char *file) _("FATAL ERROR: could not create default keys file.")); dump_intro(fd); - for (i = 0; i < NBKEYS; i++) + for (i = 0; i < NBVKEYS; i++) fprintf(fd, "%s %s\n", keydef[i].label, keydef[i].binding); file_close(fd, __FILE_POS__); } -const char *keys_get_label(enum key key) +const char *keys_get_label(enum vkey key) { EXIT_IF(key < 0 - || key > NBKEYS, + || key > NBVKEYS, _("FATAL ERROR: key value out of bounds")); return keydef[key].label; } +const char *keys_get_binding(enum vkey key) +{ + EXIT_IF(key < 0 + || key > NBVKEYS, + _("FATAL ERROR: key value out of bounds")); + + return keydef[key].binding; +} + static int key_ext_hasch(struct key_ext *k, void *cbdata) { - return (k->ch == *((int *)cbdata)); + return (k->key == *((int *)cbdata)); } -enum key keys_get_action(int pressed) +enum vkey keys_get_action(int pressed) { if (pressed < 0) { return -1; - } else if (pressed > MAXKEYVAL) { + } else if (pressed > KEY_MAX) { llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &pressed, key_ext_hasch); if (!i) @@ -274,7 +332,7 @@ void keys_wait_for_any_key(WINDOW *win) keys_wgetch(win); } -enum key keys_get(WINDOW *win, int *count, int *reg) +enum vkey keys_get(WINDOW *win, int *count, int *reg) { int ch = '0'; @@ -312,60 +370,89 @@ enum key keys_get(WINDOW *win, int *count, int *reg) } } -static void add_key_str(enum key action, int key) +static void add_if_undefined(enum vkey action) { - if (action > NBKEYS) - return; + /* If list is empty, mark action as UNDEFINED. */ + if (!keys[action].head) + LLIST_ADD(&keys[action], NULL); +} - LLIST_ADD(&keys[action], keys_int2str(key)); +static void del_if_undefined(enum vkey action) +{ + /* Action UNDEFINED? */ + if (!LLIST_GET_DATA(LLIST_FIRST(&keys[action]))) + LLIST_REMOVE(&keys[action], keys[action].head); } -int keys_assign_binding(int key, enum key action) +static void free_key_str(char *str) { - if (key < 0) - return 1; - if (key > KEY_MAX) { - llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &key, key_ext_hasch); - if (i) - return 1; - struct key_ext *k = mem_malloc(sizeof(struct key_ext)); - k->ch = key; - k->action = action; - LLIST_ADD(&actions_ext, k); - } else { - if (actions[key] != KEY_UNDEF) - return 1; - actions[key] = action; - } - add_key_str(action, key); - return 0; + mem_free(str); } -static void del_key_str(enum key action, int key) +static void add_key_str(enum vkey action, int key) +{ + if (action > NBVKEYS) + return; + + del_if_undefined(action); + LLIST_ADD(&keys[action], keys_int2str(key)); +} + +static void del_key_str(enum vkey action, int key) { llist_item_t *i; - char *oldstr = keys_int2str(key);; + char *oldstr = keys_int2str(key), *j; - if (action > NBKEYS) + if (action > NBVKEYS) return; LLIST_FOREACH(&keys[action], i) { - if (strcmp(LLIST_GET_DATA(i), oldstr) == 0) { + if (strcmp((j = LLIST_GET_DATA(i)), oldstr) == 0) { LLIST_REMOVE(&keys[action], i); + free_key_str(j); goto cleanup; } } cleanup: + add_if_undefined(action); mem_free(oldstr); } -void keys_remove_binding(int key, enum key action) +/* + * Assign keyboard key "key" to virtual key "action" by + * + * - marking keyboard key "key" as used for virtual key "actual" + * - adding "key" to the list of assigned keys for "action" in the tabel keys[] + * + * The former is done by either inserting "action" in the "key" entry of tabel + * actions[], or for keys above the curses range, inserting (key, action) in the + * list actions_ext. + */ +int keys_assign_binding(int key, enum vkey action) +{ + if (key > KEY_MAX) { + if (LLIST_FIND_FIRST(&actions_ext, &key, key_ext_hasch)) + return 1; + struct key_ext *k = mem_malloc(sizeof(struct key_ext)); + k->key = key; + k->action = action; + LLIST_ADD(&actions_ext, k); + } else if (key > -1) { + if (actions[key] != KEY_UNDEF) + return 1; + actions[key] = action; + } + add_key_str(action, key); + return 0; +} + +void keys_remove_binding(int key, enum vkey action) { if (key < 0) return; - if (key <= MAXKEYVAL) { + if (key <= KEY_MAX) { actions[key] = KEY_UNDEF; } else { llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &key, @@ -410,6 +497,8 @@ char *keys_int2str(int key) { char *res; + if (key == -1) + return NULL; if (key < KEY_MAX) { if (strcmp(keynames[key], "") == 0) return NULL; @@ -421,50 +510,44 @@ char *keys_int2str(int key) } } -int keys_action_count_keys(enum key action) +int keys_action_count_keys(enum vkey action) { llist_item_t *i; int n = 0; + /* Action UNDEFINED? */ + if (!LLIST_GET_DATA(LLIST_FIRST(&keys[action]))) + return 0; + LLIST_FOREACH(&keys[action], i) - n++; + n++; return n; } -const char *keys_action_firstkey(enum key action) +const char *keys_action_firstkey(enum vkey action) { const char *s = LLIST_GET_DATA(LLIST_FIRST(&keys[action])); return (s != NULL) ? s : "XXX"; } -const char *keys_action_nkey(enum key action, int keynum) +const char *keys_action_nkey(enum vkey action, int keynum) { return LLIST_GET_DATA(LLIST_NTH(&keys[action], keynum)); } -char *keys_action_allkeys(enum key action) +char *keys_action_allkeys(enum vkey action) { llist_item_t *i; - static char keystr[BUFSIZ]; - int keystrlen = 0; - int entrylen; - - if (!LLIST_FIRST(&keys[action])) - return NULL; - - keystr[0] = '\0'; - LLIST_FOREACH(&keys[action], i) { - entrylen = strlen(LLIST_GET_DATA(i)) + 1; - if (keystrlen + entrylen >= BUFSIZ) - break; - memcpy(keystr + keystrlen, LLIST_GET_DATA(i), entrylen - 1); - keystr[keystrlen + entrylen - 1] = ' '; - keystrlen += entrylen; - } - - keystr[keystrlen] = '\0'; - return keystr; + struct string keystr; + + string_init(&keystr); + if (!LLIST_GET_DATA(LLIST_FIRST(&keys[action]))) + string_catf(&keystr, "%s", "UNDEFINED"); + else + LLIST_FOREACH(&keys[action], i) + string_catf(&keystr, "%s ", LLIST_GET_DATA(i)); + return string_buf(&keystr); } /* Need this to display keys properly inside status bar. */ @@ -509,7 +592,7 @@ keys_display_bindings_bar(WINDOW * win, int *bindings, int count, const char *label; - if (binding_key < NBKEYS) { + if (binding_key < NBVKEYS) { strncpy(key, keys_action_firstkey(binding_key), UTF8_MAXLEN); key[UTF8_MAXLEN] = '\0'; label = gettext(keydef[binding_key].sb_label); @@ -561,9 +644,9 @@ keys_display_bindings_bar(WINDOW * win, int *bindings, int count, * Display information about the given key. * (could not add the keys descriptions to keydef variable, because of i18n). */ -void keys_popup_info(enum key key) +void keys_popup_info(enum vkey key) { - char *info[NBKEYS]; + char *info[NBVKEYS]; WINDOW *infowin; info[KEY_GENERIC_CANCEL] = _("Cancel the ongoing action."); @@ -582,6 +665,8 @@ void keys_popup_info(enum key key) _("Paste an item at the current position."); info[KEY_GENERIC_CHANGE_VIEW] = _("Select next panel in calcurse main screen."); + info[KEY_GENERIC_PREV_VIEW] = + _("Select previous panel in calcurse main screen."); info[KEY_GENERIC_IMPORT] = _("Import data from an external file."); info[KEY_GENERIC_EXPORT] = _("Export data to a new file format."); info[KEY_GENERIC_GOTO] = _("Select the day to go to."); @@ -651,7 +736,7 @@ void keys_popup_info(enum key key) info[KEY_LOWER_PRIORITY] = _("Lower a task priority inside the todo panel."); - if (key > NBKEYS) + if (key > NBVKEYS) return; #define WINROW 10 @@ -668,59 +753,75 @@ void keys_popup_info(enum key key) void keys_save_bindings(FILE * fd) { int i; - char *action; + char *keys; EXIT_IF(fd == NULL, _("FATAL ERROR: null file pointer.")); dump_intro(fd); - for (i = 0; i < NBKEYS; i++) { - action = keys_action_allkeys(i); - if (action) - fprintf(fd, "%s %s\n", keydef[i].label, action); + for (i = 0; i < NBVKEYS; i++) { + if ((keys = keys_action_allkeys(i))) + fprintf(fd, "%s %s\n", keydef[i].label, keys); } + mem_free(keys); } -int keys_check_missing_bindings(void) +int keys_check_undefined(void) { int i; - for (i = 0; i < NBKEYS; i++) { - if (!LLIST_FIRST(&keys[i])) + for (i = 0; i < NBVKEYS; i++) { + if (!LLIST_GET_DATA(LLIST_FIRST(&keys[i]))) return 1; } return 0; } -void keys_fill_missing(void) +int keys_check_missing(void) { int i; - for (i = 0; i < NBKEYS; i++) { - if (!LLIST_FIRST(&keys[i])) { - char *p, tmpbuf[BUFSIZ]; - - strncpy(tmpbuf, keydef[i].binding, BUFSIZ); - tmpbuf[BUFSIZ - 1] = '\0'; - p = tmpbuf; - for (;;) { - char key_ch[BUFSIZ]; - - while (*p == ' ') - p++; - if (sscanf(p, "%s", key_ch) == 1) { - int ch, used; - - ch = keys_str2int(key_ch); - used = keys_assign_binding(ch, i); - if (used) - WARN_MSG(_("When adding default key for \"%s\", " - "\"%s\" was already assigned!"), - keydef[i].label, - key_ch); - p += strlen(key_ch); - } else { - break; - } - } + for (i = 0; i < NBVKEYS; i++) { + if (!LLIST_FIRST(&keys[i])) + return 1; + } + return 0; +} + +/* + * Insert default keybindings for missing actions. + * Return either the number of actions assigned to (on success) or, if default + * keys could not be assigned, the negative index into the keydef[] table of the + * failing action. + */ +int keys_fill_missing(void) +{ + int i, ch, assign, assigned; + char *p, key_ch[BUFSIZ]; + + for (i = assigned = 0; i < NBVKEYS; i++) { + if (LLIST_FIRST(&keys[i])) + continue; + + p = (char *)keydef[i].binding; + for (assign = 0;;) { + while (*p == ' ') + p++; + if (sscanf(p, "%s", key_ch) == 1) { + ch = keys_str2int(key_ch); + if (keys_assign_binding(ch, i)) + return -i; + else + assign = 1; + p += strlen(key_ch); + } else + break; } + assigned += assign; + } + + if (assigned) { + p = (assigned == 1) ? "": "s"; + WARN_MSG(_("Default key(s) assigned to %d action%s."), + assigned, p); } + return assigned; } diff --git a/src/listbox.c b/src/listbox.c index 2b39aa8..d86f540 100644 --- a/src/listbox.c +++ b/src/listbox.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/llist.c b/src/llist.c index 04f16a1..d31f004 100644 --- a/src/llist.c +++ b/src/llist.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/llist.h b/src/llist.h index 1f7f419..0dd15bf 100644 --- a/src/llist.h +++ b/src/llist.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/llist_ts.h b/src/llist_ts.h index 1604d3e..a4b6184 100644 --- a/src/llist_ts.h +++ b/src/llist_ts.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/notify.c b/src/notify.c index 3491e8e..6eda361 100644 --- a/src/notify.c +++ b/src/notify.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -102,8 +102,8 @@ static void pcal_export_header(FILE * stream) { fputs("# calcurse pcal export\n", stream); fputs("\n# =======\n# options\n# =======\n", stream); - fprintf(stream, "opt -A -K -l -m -F %s\n", - ui_calendar_week_begins_on_monday()? "Monday" : "Sunday"); + fprintf(stream, "opt -A -K -l -m -F %s\n", get_wday_default_string( + ui_calendar_get_wday_start())); fputs("# Display week number (i.e. 1-52) on every Monday\n", stream); fprintf(stream, "all monday in all week %%w\n"); diff --git a/src/queue.c b/src/queue.c index a00ebad..41cb69b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/recur.c b/src/recur.c index 72cb40f..12f76b8 100644 --- a/src/recur.c +++ b/src/recur.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1003,14 +1003,20 @@ static int find_occurrence(time_t start, long dur, struct rpt *rpt, llist_t *exc if (rpt->until && t >= NEXTDAY(rpt->until)) return 0; - /* Does it span the given day? */ - if (t + DUR(t) < day) + /* Does it span the given day? + * + * NOTE: An appointment ending at 00:00 is not considered to span the + * given day, unless the appointment is an appointment without + * specified end time, which is internally treated as appointment with + * duration 0. + */ + if (t + DUR(t) >= day || (t == day && dur == 0)) { + if (occurrence) + *occurrence = t; + return 1; + } else { return 0; - - if (occurrence) - *occurrence = t; - - return 1; + } } #undef DUR @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ #include <stdlib.h> #include <string.h> +#include "config.h" #include "sha1.h" #define rol(val, n) (((val) << (n)) | ((val) >> (32 - (n)))) @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,6 +52,6 @@ typedef struct { void sha1_init(sha1_ctx_t *); void sha1_update(sha1_ctx_t *, const uint8_t *, unsigned int); -void sha1_final(sha1_ctx_t *, uint8_t *); +void sha1_final(sha1_ctx_t *, uint8_t[SHA1_DIGESTLEN]); void sha1_digest(const char *, char *); void sha1_stream(FILE *, char *); @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/strings.c b/src/strings.c index b3dc1c4..45c9310 100644 --- a/src/strings.c +++ b/src/strings.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/ui-calendar.c b/src/ui-calendar.c index 4a8ef44..c1719d8 100644 --- a/src/ui-calendar.c +++ b/src/ui-calendar.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,14 +45,14 @@ #include "calcurse.h" static struct date today, slctd_day; -static unsigned ui_calendar_view, week_begins_on_monday; +static unsigned ui_calendar_view; +static int wday_start; /* this is used in signed arithmetic */ static pthread_mutex_t date_thread_mutex = PTHREAD_MUTEX_INITIALIZER; -static void draw_monthly_view(struct scrollwin *, struct date *, unsigned); -static void draw_weekly_view(struct scrollwin *, struct date *, unsigned); -static void (*draw_calendar[CAL_VIEWS]) (struct scrollwin *, struct date *, - unsigned) = { -draw_monthly_view, draw_weekly_view}; +static void draw_monthly_view(struct scrollwin *, struct date *); +static void draw_weekly_view(struct scrollwin *, struct date *); +static void (*draw_calendar[CAL_VIEWS]) (struct scrollwin *, + struct date *) = {draw_monthly_view, draw_weekly_view}; /* Six weeks cover a month. */ static int monthly_view_cache[WEEKINDAYS * 6]; @@ -148,30 +148,26 @@ struct date *ui_calendar_get_today(void) /* Needed to display sunday or monday as the first day of week in calendar. */ void ui_calendar_set_first_day_of_week(enum wday first_day) { - switch (first_day) { - case SUNDAY: - week_begins_on_monday = 0; - break; - case MONDAY: - week_begins_on_monday = 1; - break; - default: + if (first_day >= 0 && first_day <= 6) + wday_start = first_day; + else { ERROR_MSG(_("ERROR setting first day of week")); - week_begins_on_monday = 0; - /* NOTREACHED */ + wday_start = 0; } } /* Swap first day of week in calendar. */ void ui_calendar_change_first_day_of_week(void) { - week_begins_on_monday = !week_begins_on_monday; + wday_start++; + if(wday_start >= WEEKINDAYS) + wday_start = 0; } /* Return 1 if week begins on monday, 0 otherwise. */ -unsigned ui_calendar_week_begins_on_monday(void) +int ui_calendar_get_wday_start(void) { - return week_begins_on_monday; + return wday_start; } /* Fill in the given variable with the current date. */ @@ -219,18 +215,14 @@ void ui_calendar_monthly_view_cache_set_invalid(void) monthly_view_cache_valid = 0; } -static int weeknum(const struct tm *t, int firstweekday) +static int weeknum(const struct tm *t, int wday_start) { int wday, wnum; wday = t->tm_wday; - if (firstweekday == MONDAY) { - if (wday == SUNDAY) - wday = 6; - else - wday--; - } - wnum = ((t->tm_yday + WEEKINDAYS - wday) / WEEKINDAYS); + wnum = ((t->tm_yday + WEEKINDAYS + -modify_wday(wday, -wday_start)) + / WEEKINDAYS); + if (wnum < 0) wnum = 0; @@ -296,7 +288,7 @@ static int ISO8601weeknum(const struct tm *t) * Return the tm structure for the first day of the first week * (containing a day) of the selected month. */ -static struct tm get_first_day(unsigned sunday_first) +static struct tm get_first_day(int wday_start) { struct tm t; struct date d; @@ -308,26 +300,20 @@ static struct tm get_first_day(unsigned sunday_first) t = date2tm(d, 0, 0); mktime(&t); /* get the first day of the week */ - date_change(&t, 0, - -(sunday_first ? - t.tm_wday : - (t.tm_wday + WEEKINDAYS - 1) % WEEKINDAYS)); + date_change(&t, 0, -modify_wday(t.tm_wday, -wday_start)); + return t; } -static struct tm get_first_weekday(unsigned sunday_first) +static struct tm get_first_weekday(int wday_start) { - int c_wday, days_to_remove; + int c_wday; struct tm t; c_wday = ui_calendar_get_wday(&slctd_day); - if (sunday_first) - days_to_remove = c_wday; - else - days_to_remove = c_wday == 0 ? WEEKINDAYS - 1 : c_wday - 1; - t = date2tm(slctd_day, 0, 0); - date_change(&t, 0, -days_to_remove); + + date_change(&t, 0, -modify_wday(c_wday, -wday_start)); return t; } @@ -346,8 +332,7 @@ static void draw_week_number(struct scrollwin *sw, struct tm t) /* Draw the monthly view inside calendar panel. */ static void -draw_monthly_view(struct scrollwin *sw, struct date *current_day, - unsigned sunday_first) +draw_monthly_view(struct scrollwin *sw, struct date *current_day) { struct date c_day; int slctd, w_day, numdays, j, week = 0; @@ -373,7 +358,7 @@ draw_monthly_view(struct scrollwin *sw, struct date *current_day, * Step forward by week until past the last day of the month. * The first day of the first week may belong to the previous month. */ - t = t_first = get_first_day(sunday_first); + t = t_first = get_first_day(wday_start); t.tm_mday += WEEKINDAYS; mktime(&t); last_day += WEEKINDAYS; @@ -423,7 +408,7 @@ draw_monthly_view(struct scrollwin *sw, struct date *current_day, custom_apply_attr(sw->inner, ATTR_HIGHEST); for (j = 0; j < WEEKINDAYS; j++) { mvwaddstr(sw->inner, ofs_y, ofs_x + weekw + 4 * j, - nl_langinfo(ABDAY_1 + (1 + j - sunday_first) % WEEKINDAYS)); + nl_langinfo(ABDAY_1 + modify_wday(j, wday_start))); } custom_remove_attr(sw->inner, ATTR_HIGHEST); WINS_CALENDAR_UNLOCK; @@ -449,11 +434,9 @@ draw_monthly_view(struct scrollwin *sw, struct date *current_day, if (j == first_day || (mo == 1 && j == WEEKINDAYS) || (mo == 12 && j >= 4 * WEEKINDAYS)) { - if (sunday_first) - date_change(&t, 0, 1); + date_change(&t, 0, WDAY(MONDAY)); week = ISO8601weeknum(&t); - if (sunday_first) - date_change(&t, 0, -1); + date_change(&t, 0, -WDAY(MONDAY)); } else week++; } @@ -506,8 +489,7 @@ draw_monthly_view(struct scrollwin *sw, struct date *current_day, /* Draw the weekly view inside calendar panel. */ static void -draw_weekly_view(struct scrollwin *sw, struct date *current_day, - unsigned sunday_first) +draw_weekly_view(struct scrollwin *sw, struct date *current_day) { #define DAYSLICESNO 6 const int WCALWIDTH = 28; @@ -520,14 +502,14 @@ draw_weekly_view(struct scrollwin *sw, struct date *current_day, OFFX = (wins_sbar_width() - 2 - WCALWIDTH) / 2; /* Print the week number, calculated from monday. */ - t = get_first_weekday(0); + t = get_first_weekday(MONDAY); draw_week_number(sw, t); /* Now draw calendar view. */ for (j = 0; j < WEEKINDAYS; j++) { /* get next day */ if (j == 0) - t = get_first_weekday(sunday_first); + t = get_first_weekday(wday_start); else date_change(&t, 0, 1); @@ -538,7 +520,7 @@ draw_weekly_view(struct scrollwin *sw, struct date *current_day, /* print the day names, with regards to the first day of the week */ custom_apply_attr(sw->inner, ATTR_HIGHEST); mvwaddstr(sw->inner, OFFY, OFFX + 4 * j, - nl_langinfo(ABDAY_1 + (1 + j - sunday_first) % WEEKINDAYS)); + nl_langinfo(ABDAY_1 + modify_wday(j, wday_start))); custom_remove_attr(sw->inner, ATTR_HIGHEST); /* Check if the day to be printed has an item or not. */ @@ -578,9 +560,8 @@ draw_weekly_view(struct scrollwin *sw, struct date *current_day, if (j != WEEKINDAYS - 1 && i != DAYSLICESNO - 1) { WINS_CALENDAR_LOCK; - mvwhline(sw->inner, OFFY + 2 + i, - OFFX + 3 + 4 * j, ACS_S9, - 2); + mvwaddstr(sw->inner, OFFY + 2 + i, + OFFX + 3 + 4 * j, "__"); WINS_CALENDAR_UNLOCK; } if (slices[i]) { @@ -611,9 +592,9 @@ draw_weekly_view(struct scrollwin *sw, struct date *current_day, /* Draw marks to indicate midday on the sides of the calendar. */ WINS_CALENDAR_LOCK; custom_apply_attr(sw->inner, ATTR_HIGHEST); - mvwhline(sw->inner, OFFY + 1 + DAYSLICESNO / 2, OFFX, ACS_S9, 1); - mvwhline(sw->inner, OFFY + 1 + DAYSLICESNO / 2, - OFFX + WCALWIDTH - 1, ACS_S9, 1); + mvwaddch(sw->inner, OFFY + 1 + DAYSLICESNO / 2, OFFX, '<'); + mvwaddch(sw->inner, OFFY + 1 + DAYSLICESNO / 2, + OFFX + WCALWIDTH - 1, '>'); custom_remove_attr(sw->inner, ATTR_HIGHEST); WINS_CALENDAR_UNLOCK; @@ -624,11 +605,9 @@ draw_weekly_view(struct scrollwin *sw, struct date *current_day, void ui_calendar_update_panel(void) { struct date current_day; - unsigned sunday_first; ui_calendar_store_current_date(¤t_day); - sunday_first = !ui_calendar_week_begins_on_monday(); - draw_calendar[ui_calendar_view] (&sw_cal, ¤t_day, sunday_first); + draw_calendar[ui_calendar_view] (&sw_cal, ¤t_day); wins_scrollwin_display(&sw_cal, NOHILT); } @@ -728,28 +707,14 @@ void ui_calendar_move(enum move move, int count) ret = date_change(&t, count * YEARINMONTHS, 0); break; case WEEK_START: - /* Normalize struct tm to get week day number. */ mktime(&t); - if (ui_calendar_week_begins_on_monday()) - days_to_remove = - ((t.tm_wday == - 0) ? WEEKINDAYS - 1 : t.tm_wday - 1); - else - days_to_remove = - ((t.tm_wday == 0) ? 0 : t.tm_wday); + days_to_remove = WDAY(t.tm_wday); days_to_remove += (count - 1) * WEEKINDAYS; ret = date_change(&t, 0, -days_to_remove); break; case WEEK_END: mktime(&t); - if (ui_calendar_week_begins_on_monday()) - days_to_add = - ((t.tm_wday == - 0) ? 0 : WEEKINDAYS - t.tm_wday); - else - days_to_add = ((t.tm_wday == 0) ? - WEEKINDAYS - 1 : WEEKINDAYS - 1 - - t.tm_wday); + days_to_add = modify_wday(-t.tm_wday, wday_start - 1); days_to_add += (count - 1) * WEEKINDAYS; ret = date_change(&t, 0, days_to_add); break; diff --git a/src/ui-day.c b/src/ui-day.c index 0bd82bb..6a038fa 100644 --- a/src/ui-day.c +++ b/src/ui-day.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/ui-todo.c b/src/ui-todo.c index cad89fd..46933b3 100644 --- a/src/ui-todo.c +++ b/src/ui-todo.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -207,14 +207,16 @@ void ui_todo_draw(int n, WINDOW *win, int y, int hilt, void *cb_data) if (hilt) custom_apply_attr(win, ATTR_HIGHEST); - if (utf8_strwidth(todo->mesg) < width) { - mesg = todo->mesg; - } else { + mesg = todo->mesg; + if (mesg[0] == '\0') + mesg = EMPTY_EVENT_DESC_DEFAULT; + + if (utf8_strwidth(mesg) >= width) { width -= 3; - 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]; + for (j = 0; mesg[j] && width > 0; j++) { + if (!UTF8_ISCONT(mesg[j])) + width -= utf8_width(&mesg[j]); + buf[j] = mesg[j]; } if (j) { buf[j - 1] = '.'; @@ -325,6 +327,11 @@ void ui_todo_popup_item(void) asprintf(¬epath, "%s%s", path_notes, item->note); fp = fopen(notepath, "r"); + if (fp == NULL) { + item_in_popup(NULL, NULL, item->mesg, _("TODO:")); + return; + } + note_read_contents(note, note_size, fp); fclose(fp); mem_free(notepath); @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/utils.c b/src/utils.c index 1a480df..2d30bfc 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -626,6 +626,42 @@ long min2sec(unsigned minutes) return minutes * MININSEC; } +int modify_wday(int wday, int shift) +{ + return (WEEKINDAYS + wday + shift) % WEEKINDAYS; +} + +/* returns char* representing a wday, used for internal functions */ +char *get_wday_default_string(int wday) +{ + switch(wday) { + case MONDAY: + return "Monday"; + break; + case TUESDAY: + return "Tuesday"; + break; + case WEDNESDAY: + return "Wednesday"; + break; + case THURSDAY: + return "Thursday"; + break; + case FRIDAY: + return "Friday"; + break; + case SATURDAY: + return "Saturday"; + break; + case SUNDAY: + return "Sunday"; + break; + default: + return "Sunday"; + break; + } +} + /* * Display a scroll bar when there are so many items that they * can not be displayed inside the corresponding panel. @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -140,6 +140,7 @@ void vars_init(void) conf.input_datefmt = 1; conf.heading_pos = RIGHT; strcpy(conf.day_heading, DAY_HEADING_DEFAULT); + strcpy(conf.timefmt, APPT_TIME_DEFAULT); datefmt_str[0] = _("mm/dd/yyyy"); datefmt_str[1] = _("dd/mm/yyyy"); @@ -174,6 +175,8 @@ void vars_init(void) ui_calendar_set_first_day_of_week(MONDAY); + wins_set_sbar_width(col * SBARMINWIDTH / 100); + /* Pad structure to scroll text inside the appointment panel */ apad.length = 1; apad.first_onscreen = 0; diff --git a/src/vector.c b/src/vector.c index fd468ab..796ef8e 100644 --- a/src/vector.c +++ b/src/vector.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/vector.h b/src/vector.h index 86cb3b8..7648df2 100644 --- a/src/vector.h +++ b/src/vector.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -229,7 +229,7 @@ void wins_sbar_winc(void) void wins_sbar_wdec(void) { - if (sbarwidth_perc > 0) + if (col * sbarwidth_perc / 100 > SBARMINWIDTH) sbarwidth_perc--; } @@ -254,6 +254,15 @@ void wins_slctd_next(void) slctd_win++; } +/* Shift-TAB key was hit in the interface, need to select previous window. */ +void wins_slctd_prev(void) +{ + if (slctd_win == CAL) + slctd_win = TOD; + else + slctd_win--; +} + static void wins_init_panels(void) { wins_scrollwin_init(&sw_cal, win[CAL].y, win[CAL].x, @@ -651,6 +660,7 @@ void wins_update_bindings(void) static int bindings_cal[] = { KEY_GENERIC_HELP, KEY_GENERIC_QUIT, KEY_GENERIC_SAVE, KEY_GENERIC_RELOAD, KEY_GENERIC_CHANGE_VIEW, + KEY_GENERIC_PREV_VIEW, KEY_GENERIC_SCROLL_DOWN, KEY_GENERIC_SCROLL_UP, KEY_MOVE_UP, KEY_MOVE_DOWN, KEY_MOVE_LEFT, KEY_MOVE_RIGHT, KEY_GENERIC_GOTO, KEY_GENERIC_IMPORT, KEY_GENERIC_EXPORT, KEY_START_OF_WEEK, @@ -666,6 +676,7 @@ void wins_update_bindings(void) static int bindings_apoint[] = { KEY_GENERIC_HELP, KEY_GENERIC_QUIT, KEY_GENERIC_SAVE, KEY_GENERIC_RELOAD, KEY_GENERIC_CHANGE_VIEW, + KEY_GENERIC_PREV_VIEW, KEY_GENERIC_IMPORT, KEY_GENERIC_EXPORT, KEY_ADD_ITEM, KEY_DEL_ITEM, KEY_EDIT_ITEM, KEY_VIEW_ITEM, KEY_PIPE_ITEM, KEY_GENERIC_REDRAW, KEY_REPEAT_ITEM, KEY_FLAG_ITEM, @@ -682,6 +693,7 @@ void wins_update_bindings(void) static int bindings_todo[] = { KEY_GENERIC_HELP, KEY_GENERIC_QUIT, KEY_GENERIC_SAVE, KEY_GENERIC_RELOAD, KEY_GENERIC_CHANGE_VIEW, + KEY_GENERIC_PREV_VIEW, KEY_GENERIC_SCROLL_DOWN, KEY_GENERIC_SCROLL_UP, KEY_GENERIC_IMPORT, KEY_GENERIC_EXPORT, KEY_ADD_ITEM, KEY_DEL_ITEM, KEY_EDIT_ITEM, KEY_VIEW_ITEM, KEY_PIPE_ITEM, |