diff options
author | Frederic Culot <calcurse@culot.org> | 2006-07-31 21:00:02 +0000 |
---|---|---|
committer | Frederic Culot <calcurse@culot.org> | 2006-07-31 21:00:02 +0000 |
commit | ac36e94341ca73d581f0df39f1c7bbf2138b2845 (patch) | |
tree | 47de561cd962ff8f47f6d811109907f15b9ff989 /src | |
download | calcurse-ac36e94341ca73d581f0df39f1c7bbf2138b2845.zip |
Initial revision
Diffstat (limited to 'src')
-rwxr-xr-x | src/Makefile.am | 14 | ||||
-rwxr-xr-x | src/apoint.c | 235 | ||||
-rwxr-xr-x | src/apoint.h | 56 | ||||
-rwxr-xr-x | src/args.c | 431 | ||||
-rwxr-xr-x | src/args.h | 41 | ||||
-rwxr-xr-x | src/calcurse.1 | 158 | ||||
-rwxr-xr-x | src/calcurse.c | 1156 | ||||
-rwxr-xr-x | src/calendar.c | 227 | ||||
-rwxr-xr-x | src/calendar.h | 41 | ||||
-rwxr-xr-x | src/custom.c | 178 | ||||
-rwxr-xr-x | src/custom.h | 42 | ||||
-rwxr-xr-x | src/day.c | 362 | ||||
-rwxr-xr-x | src/day.h | 66 | ||||
-rwxr-xr-x | src/event.c | 135 | ||||
-rwxr-xr-x | src/event.h | 48 | ||||
-rwxr-xr-x | src/help.c | 375 | ||||
-rwxr-xr-x | src/help.h | 41 | ||||
-rwxr-xr-x | src/i18n.h | 54 | ||||
-rwxr-xr-x | src/io.c | 484 | ||||
-rwxr-xr-x | src/io.h | 42 | ||||
-rwxr-xr-x | src/recur.c | 355 | ||||
-rwxr-xr-x | src/recur.h | 87 | ||||
-rwxr-xr-x | src/todo.c | 80 | ||||
-rwxr-xr-x | src/todo.h | 41 | ||||
-rwxr-xr-x | src/utils.c | 614 | ||||
-rwxr-xr-x | src/utils.h | 55 | ||||
-rwxr-xr-x | src/vars.c | 85 | ||||
-rwxr-xr-x | src/vars.h | 69 |
28 files changed, 5572 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100755 index 0000000..1614db1 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,14 @@ +# $calcurse: Makefile.am,v 1.1 2006/07/31 21:00:02 culot Exp $ + +AUTOMAKE_OPTIONS= gnu +bin_PROGRAMS= calcurse +calcurse_SOURCES= calcurse.c apoint.c event.c todo.c utils.c\ + calendar.c vars.c io.c help.c custom.c args.c\ + day.c recur.c\ + apoint.h event.h todo.h utils.h calendar.h\ + vars.h io.h help.h custom.h args.h i18n.h\ + day.h recur.h +LIBS= -lncurses -lm +LDADD= @LTLIBINTL@ +man_MANS= calcurse.1 +EXTRA_DIST= calcurse.1 diff --git a/src/apoint.c b/src/apoint.c new file mode 100755 index 0000000..5cbc62e --- /dev/null +++ b/src/apoint.c @@ -0,0 +1,235 @@ +/* $calcurse: apoint.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "i18n.h" +#include "vars.h" +#include "event.h" +#include "apoint.h" +#include "day.h" +#include "custom.h" +#include "utils.h" + +struct apoint_s *apointlist; + +struct apoint_s *apoint_new(char *mesg, long start, long dur) +{ + struct apoint_s *o, **i; + o = (struct apoint_s *) malloc(sizeof(struct apoint_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->start = start; + o->dur = dur; + i = &apointlist; + for (;;) { + if (*i == 0 || (*i)->start > start) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +unsigned apoint_inday(struct apoint_s *i, long start) +{ + if (i->start <= start + 3600 * 24 && i->start + i->dur > start) { + return 1; + } + return 0; +} + +void apoint_sec2str(struct apoint_s *o, int type, long day, char *start, char *end) +{ + struct tm *lt; + time_t t; + + if (o->start < day && type == APPT) { + strcpy(start, "..:.."); + } else { + t = o->start; + lt = localtime(&t); + snprintf(start, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, + lt->tm_min); + } + if (o->start + o->dur > day + 24 * 3600 && type == APPT) { + strcpy(end, "..:.."); + } else { + t = o->start + o->dur; + lt = localtime(&t); + snprintf(end, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, + lt->tm_min); + } +} + +void apoint_write(struct apoint_s *o, FILE * f) +{ + struct tm *lt; + time_t t; + + t = o->start; + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u @ %02u:%02u", + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, + lt->tm_hour, lt->tm_min); + + t = o->start + o->dur; + lt = localtime(&t); + fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u |%s\n", + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, + lt->tm_hour, lt->tm_min, o->mesg); +} + +struct apoint_s *apoint_scan(FILE * f, struct tm start, struct tm end) +{ + struct tm *lt; + char buf[MESG_MAXSIZE], *nl; + time_t tstart, tend, t; + + t = time(NULL); + lt = localtime(&t); + + /* Read the appointment description */ + fgets(buf, MESG_MAXSIZE, f); + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + + start.tm_sec = end.tm_sec = 0; + start.tm_isdst = end.tm_isdst = -1; + start.tm_year -= 1900; + start.tm_mon--; + end.tm_year -= 1900; + end.tm_mon--; + + tstart = mktime(&start); + tend = mktime(&end); + if (tstart == -1 || tend == -1 || tstart > tend) { + fputs(_("FATAL ERROR in apoint_scan: date error in the appointment\n"), stderr); + exit(EXIT_FAILURE); + } + return apoint_new(buf, tstart, tend - tstart); +} + +void apoint_delete_bynum(long start, unsigned num) +{ + unsigned n; + struct apoint_s *i, **iptr; + + n = 0; + iptr = &apointlist; + for (i = apointlist; i != 0; i = i->next) { + if (apoint_inday(i, start)) { + if (n == num) { + *iptr = i->next; + free(i->mesg); + free(i); + return; + } + n++; + } + iptr = &i->next; + } + /* NOTREACHED */ + fputs(_("FATAL ERROR in apoint_delete_bynum: no such appointment\n"), stderr); + exit(EXIT_FAILURE); +} + +/* + * Print an item date in the appointment panel. + */ +void display_item_date(WINDOW *win, int incolor, struct apoint_s *i, + int type, long date, int y, int x) +{ + char a_st[100], a_end[100]; + + apoint_sec2str(i, type, date, a_st, a_end); + + if (incolor == 0) + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, x, " - %s -> %s", a_st, a_end); + if (incolor == 0) + custom_remove_attr(awin, ATTR_HIGHEST); +} + +/* + * Return the line number of an item (either an appointment or an event) in + * the appointment panel. This is to help the appointment scroll function + * to place beggining of the pad correctly. + */ +int get_item_line(int item_nb, int nb_events_inday) +{ + int separator = 2; + int line = 0; + + if (item_nb <= nb_events_inday) + line = item_nb - 1; + else + line = nb_events_inday + separator + + (item_nb - (nb_events_inday + 1))*3 - 1; + return line; +} + +/* + * Update (if necessary) the first displayed pad line to make the + * appointment panel scroll down next time pnoutrefresh is called. + */ +void scroll_pad_down(int item_nb, int nb_events_inday, int win_length) +{ + int pad_last_line = 0; + int item_first_line = 0, item_last_line = 0; + int borders = 6; + int awin_length = win_length - borders; + + item_first_line = get_item_line(item_nb, nb_events_inday); + if (item_nb < nb_events_inday) + item_last_line = item_first_line; + else + item_last_line = item_first_line + 1; + pad_last_line = apad->first_onscreen + awin_length; + if (item_last_line >= pad_last_line) + apad->first_onscreen = item_last_line - awin_length; +} + +/* + * Update (if necessary) the first displayed pad line to make the + * appointment panel scroll up next time pnoutrefresh is called. + */ +void scroll_pad_up(int item_nb, int nb_events_inday) +{ + int item_first_line = 0; + + item_first_line = get_item_line(item_nb, nb_events_inday); + if (item_first_line < apad->first_onscreen) + apad->first_onscreen = item_first_line; +} diff --git a/src/apoint.h b/src/apoint.h new file mode 100755 index 0000000..e9dbe82 --- /dev/null +++ b/src/apoint.h @@ -0,0 +1,56 @@ +/* $calcurse: apoint.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_APOINT_H +#define CALCURSE_APOINT_H + +#include <ncurses.h> + +#define HRMIN_SIZE 6 +#define MESG_MAXSIZE 256 + +struct apoint_s { + struct apoint_s *next; + long start; /* seconds since 1 jan 1970 */ + long dur; /* duration of the appointment in seconds */ + char *mesg; +}; + +extern struct apoint_s *apointlist; + +struct apoint_s *apoint_new(char *, long, long); +unsigned apoint_inday(struct apoint_s *o, long start); +void apoint_sec2str(struct apoint_s *o, int type, long day, char *start, char *end); +void apoint_write(struct apoint_s *o, FILE * f); +struct apoint_s *apoint_scan(FILE * f, struct tm start, struct tm end); +void apoint_delete_bynum(long start, unsigned num); +void display_item_date(WINDOW *win, int color, struct apoint_s *i, + int type, long date, int y, int x); +int get_item_line(int item_nb, int nb_events_inday); +void scroll_pad_down(int item_nb, int nb_events_inday, int win_length); +void scroll_pad_up(int item_nb, int nb_events_inday); + +#endif /* CALCURSE_APOINT_H */ diff --git a/src/args.c b/src/args.c new file mode 100755 index 0000000..2261640 --- /dev/null +++ b/src/args.c @@ -0,0 +1,431 @@ +/* $calcurse: args.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdbool.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + +#include "i18n.h" +#include "utils.h" +#include "args.h" +#include "vars.h" +#include "event.h" +#include "apoint.h" +#include "recur.h" +#include "day.h" +#include "todo.h" +#include "io.h" + +/* + * Parse the command-line arguments and call the appropriate + * routines to handle those arguments. Also initialize the data paths. + */ +int parse_args(int argc, char **argv, int colr) +{ + int ch, add_line = 0; + int unknown_flag = 0, app_found = 0; + int aflag = 0, cflag = 0, dflag = 0, vflag = 0, hflag = 0, tflag = 0; + int non_interactive = 0, multiple_flag = 0, load_data = 0; + int no_file = 1; + char *ddate = "", *cfile = NULL; + + while ((ch = getopt(argc, argv, "hvtad:c:")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + multiple_flag++; + load_data++; + break; + case 'd': + dflag = 1; + multiple_flag++; + load_data++; + ddate = optarg; + break; + case 'c': + cflag = 1; + multiple_flag++; + load_data++; + cfile = optarg; + break; + case 'h': + hflag = 1; + break; + case 't': + tflag = 1; + multiple_flag++; + load_data++; + add_line = 1; + break; + case 'v': + vflag = 1; + break; + default: + usage(); + usage_try(); + unknown_flag = 1; + non_interactive = 1; + } + } + argc -= optind; + argv += optind; + if (argc >= 1) { /* incorrect arguments */ + usage(); + usage_try(); + return 1; + } else { + if (unknown_flag) { + non_interactive = 1; + } else if (hflag) { + help_arg(); + non_interactive = 1; + } else if (vflag) { + version_arg(); + non_interactive = 1; + } else if (multiple_flag) { + if (load_data) { + io_init(cfile); + no_file = check_data_files(); + if (dflag || aflag) + load_app(colr); + } + if (tflag) { + todo_arg(colr); + non_interactive = 1; + } + if (dflag) { + date_arg(ddate, add_line); + non_interactive = 1; + } else if (aflag) { + app_found = app_arg(add_line,0,0,0,0); + non_interactive = 1; + } + } else { + non_interactive = 0; + io_init(cfile); + no_file = check_data_files(); + } + return non_interactive; + } +} + +/* + * Print Calcurse version with a short copyright text and exit. + */ +void version_arg() +{ + char vtitle[50]; + char *vtext = + _("\nCopyright (c) 2004-2006 Frederic Culot.\n" + "This is free software; see the source for copying conditions.\n"); + + sprintf(vtitle, _("Calcurse %s - text-based organizer\n"), VERSION); + fputs(vtitle, stdout); + fputs(vtext, stdout); +} + +/* + * Print the command line options and exit. + */ +void help_arg() +{ + char htitle[50]; + char *htext = + _("\nMiscellaneous:\n" + " -h print this help and exit.\n" + " -v print calcurse version and exit.\n" + "\nOptions:\n" + " -c <file> specify the calendar <file> to use.\n" + "\nNon-interactive:\n" + " -a print events and appointments for current day and exit.\n" + " -d <date|num> print events and appointments for <date> " + "or <num> upcoming\n\t\tdays and exit. Possible formats are: " + "'mm/dd/yyyy' or 'n'.\n" + " -t print todo list and exit.\n" + "\nFor more information, type '?' from within Calcurse, " + "or read the manpage.\n" + "Mail bug reports and suggestions to <calcurse@culot.org>.\n"); + + sprintf(htitle, _("Calcurse %s - text-based organizer\n"), VERSION); + fputs(htitle, stdout); + usage(); + fputs(htext, stdout); +} + +/* + * Print todo list and exit. + */ +void todo_arg(int colr) +{ + struct todo_s *i; + int nb_tod; + + nb_tod = load_todo(colr); + fputs(_("to do:\n"),stdout); + for (i = todolist; i != 0; i = i->next) { + fputs(" - ",stdout); + fputs(i->mesg,stdout); + fputs("\n",stdout); + } +} + +/* + * Print appointments for given day and exit. + * If no year, month, and day is given, the given date is used. + * If there is also no date given, current date is considered. + */ +int app_arg(int add_line, int year, int month, int day, long date) +{ + struct recur_event_s *re; + struct event_s *j; + struct recur_apoint_s *ra; + struct apoint_s *i; + long today; + bool print_date = true; + int app_found = 0; + char apoint_start_time[100]; + char apoint_end_time[100]; + + if (date == 0) { + today = get_sec_date(year, month, day); + } else today = date; + + /* + * Calculate and print the selected date if there is an event for + * that date and it is the first one, and then print all the events for + * that date. + */ + for (re = recur_elist; re != 0; re = re->next) { + if (recur_item_inday(re->day, re->rpt->type, re->rpt->freq, + re->rpt->until, today)) { + app_found = 1; + if (add_line) { + fputs("\n", stdout); + add_line = 0; + } + if (print_date) { + arg_print_date(today); + print_date = false; + } + fputs(" o ", stdout); + fputs(re->mesg, stdout); fputs("\n", stdout); + } + } + + for (j = eventlist; j != 0; j = j->next) { + if (event_inday(j, today)) { + app_found = 1; + if (add_line) { + fputs("\n",stdout); + add_line = 0; + } + if (print_date) { + arg_print_date(today); + print_date = false; + } + fputs(" o ",stdout); + fputs(j->mesg,stdout); fputs("\n",stdout); + } + } + + /* Same process is performed but this time on the appointments. */ + for (ra = recur_alist; ra != 0; ra = ra->next) { + if (recur_item_inday(ra->start, ra->rpt->type, ra->rpt->freq, + ra->rpt->until, today)) { + app_found = 1; + if (add_line) { + fputs("\n",stdout); + add_line = 0; + } + if (print_date) { + arg_print_date(today); + print_date = false; + } + apoint_sec2str(recur_apoint_s2apoint_s(ra), + RECUR_APPT, today, apoint_start_time, + apoint_end_time); + fputs(" - ",stdout); + fputs(apoint_start_time,stdout); + fputs(" -> ",stdout); + fputs(apoint_end_time,stdout); fputs("\n\t",stdout); + fputs(ra->mesg,stdout); fputs("\n",stdout); + } + } + + for (i = apointlist; i != 0; i = i->next) { + if (apoint_inday(i, today)) { + app_found = 1; + if (add_line) { + fputs("\n",stdout); + add_line = 0; + } + if (print_date) { + arg_print_date(today); + print_date = false; + } + apoint_sec2str(i, APPT, today, apoint_start_time, + apoint_end_time); + fputs(" - ",stdout); + fputs(apoint_start_time,stdout); + fputs(" -> ",stdout); + fputs(apoint_end_time,stdout); fputs("\n\t",stdout); + fputs(i->mesg,stdout); fputs("\n",stdout); + } + } + return app_found; +} + +/* + * Print appointment for the given date or for the given n upcoming + * days. + */ +void date_arg(char *ddate, int add_line) +{ + int i; + int year = 0, month = 0, day = 0; + int numdays = 0, num_digit = 0; + int arg_len = 0, app_found = 0; + int date_valid = 0; + long today, ind; + int sec_in_day = 86400; + + /* + * Check (with the argument length) if a date or a number of days + * was entered, and then call app_arg() to print appointments + */ + arg_len = strlen(ddate); + if (arg_len <= 4) { /* a number of days was entered */ + for (i = 0; i <= arg_len-1; i++) { + if (isdigit(ddate[i])) num_digit++; + } + if (num_digit == arg_len) numdays = atoi(ddate); + + /* + * Get current date, and print appointments for each day + * in the chosen interval. app_found and add_line are used + * to format the output correctly. + */ + today = get_sec_date(year, month, day); + ind = today; + for (i = 0; i < numdays; i++) { + app_found = app_arg(add_line, 0, 0, 0, ind); + add_line = app_found; + ind = ind + sec_in_day; + } + } else { /* a date was entered */ + date_valid = check_date(ddate); + if (date_valid) { + sscanf(ddate, "%d / %d / %d", &month, &day, &year); + app_found = app_arg(add_line, year, month, day, 0); + } else { + fputs(_("Argument to the '-d' flag is not valid\n"),stdout); + fputs(_("Possible argument formats are : 'mm/dd/yyyy' or 'n'\n"),stdout); + fputs(_("\nFor more information, type '?' from within Calcurse, or read the manpage.\n"),stdout); + fputs + (_("Mail bug reports and suggestions to <calcurse@culot.org>.\n"), + stdout); + } + } +} + +/* + * Check if the entered date is of a valid format. + * First check the format by itself, and then check the + * numbers correctness. + */ +int +check_date(char *date) +{ + int ok = 0; + char month[] = " "; + char day[] = " "; + char year[] = " "; + if ( + (strlen(date) == 10) & + (isdigit(date[0]) != 0) & + (isdigit(date[1]) != 0) & + (date[2] == '/') & + (isdigit(date[3]) != 0) & + (isdigit(date[4]) != 0) & + (date[5] == '/') & + (isdigit(date[6])!=0) & (isdigit(date[7])!=0) & + (isdigit(date[8])!=0) & (isdigit(date[9])!=0) + ) { + strncpy(month, date, 2); + strncpy(day, date + 3, 2); + strncpy(year, date + 6, 4); + if ( (atoi(month) <= 12) & + (atoi(month) >= 1) & + (atoi(day) <= 31) & + (atoi(day) >= 1) & + (atoi(year) <= 9999) & + (atoi(year) > 1)) + ok = 1; + } + return ok; +} + +/* + * Print the date on stdout. + */ +void arg_print_date(long date) +{ + char date_str[30]; + time_t t; + struct tm *lt; + + t = date; + lt = localtime(&t); + sprintf(date_str,"%02u/%02u/%04u",lt->tm_mon+1, + lt->tm_mday, 1900+lt->tm_year); + fputs(date_str,stdout); + fputs(":\n",stdout); +} + +/* + * Print Calcurse usage and exit. + */ +void usage() +{ + char *arg_usage = + _("Usage: calcurse [-h | -v] [-at] [-d date|num] [-c file]\n"); + + fputs(arg_usage, stdout); +} + +void usage_try() +{ + char *arg_usage_try = + _("Try 'calcurse -h' for more information.\n"); + + fputs(arg_usage_try, stdout); +} diff --git a/src/args.h b/src/args.h new file mode 100755 index 0000000..995cc20 --- /dev/null +++ b/src/args.h @@ -0,0 +1,41 @@ +/* $calcurse: args.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_ARGS_H +#define CALCURSE_ARGS_H + +void usage(); +void usage_try(); +int parse_args(int argc, char **argv, int colr); +void version_arg(); +void help_arg(); +void todo_arg(int colr); +int app_arg(int add_line, int year, int month, int day, long date); +void date_arg(char *ddate, int add_line); +int check_date(char *date); +void arg_print_date(long date); + +#endif /* CALCURSE_ARGS_H */ diff --git a/src/calcurse.1 b/src/calcurse.1 new file mode 100755 index 0000000..5ae929c --- /dev/null +++ b/src/calcurse.1 @@ -0,0 +1,158 @@ +.\" $calcurse: calcurse.1,v 1.1 2006/07/31 21:00:03 culot Exp $ +.\" +.\" Copyright (c) 2004-2006 Frederic Culot +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 59 Temple Place - Suite 330, +.\" Boston, MA 02111-1307, USA. +.\" +.TH CALCURSE 1 "May 07, 2006" "Version 1.4" "Calcurse Manual" +.SH NAME +Calcurse \- text-based organizer +.PP +.SH SYNOPSIS +.B "calcurse " +[ +.B "-h " +| +.B "-v " +] [ +.B "-at " +] [ +.B "-d " +\fIdate\fP|\fInum\fP ] [ +.B "-c " +\fIfile\fP ] +.PP +.SH DESCRIPTION +Calcurse is a text-based personal organizer which helps keeping track of +events and everyday tasks. It contains a calendar, a 'todo' list, and +puts your appointments in order. The user interface is configurable, +and one can choose between different color schemes and layouts. +All of the commands are documented within an online help system. +.PP +.SH OPTIONS +The following options are supported: +.TP +.B \-a +Print the appointments and events for the current day and exit. +.br +\fINote:\fP the calendar from which to read the appointments can be specified using +the '\-c' flag. +.TP +.B \-c +Specify the calendar file to use. The default calendar is +.B "'~/.calcurse/apts'" +(see section \fIFILES\fP below). +.TP +.B \-d +Print the appointments and events for the given date or for +the given number of upcoming days, depending on the argument format. +Two possible formats are supported: +.RS 9 +.TP 2 +\(bu a date of the form 'mm/dd/yyyy'. +.TP 2 +\(bu a number 'n'. +.RE +.RS 7 +.LP +In the first case, the appointments and events list for the specified +date will be returned, while in the second case the appointments and events +list for the 'n' upcoming days will be returned. +.br +As an example, typing 'calcurse -d 3' will display your appointments +and events for today, tomorrow, and the day after tomorrow. +.br +\fINote:\fP as for the '-a' flag, the calendar from which to read the +appointments can be specified using the '\-c' flag. +.RE +.TP +.B \-h +Print a short help text describing the supported command-line options, +and then exit. +.TP +.B \-t +Print the 'todo' list and exit. +.TP +.B \-v +Display calcurse version and exit. +.SH NOTES +Calcurse interface contains three different panels (calendar, +appointment list, and todo list) on which you can perform different +actions. All the possible actions, together with their associated +keystrokes, are listed on the status bar. This status bar +takes place at the bottom of the screen. +.PP +At any time, the built-in help system can be invoked by pressing the '?' +key. Once viewing the help screens, informations on a specific command +can be accessed by pressing the keystroke corresponding to that command. +.PP +.SH CONFIGURATION +The calcurse options can be changed from the configuration menu (shown +when 'C' is hit). Three possible categories are to be chosen from : the +color scheme, the layout (the location of the three panels on the +screen), and more general options (such as automatic save before +quitting). All of these options are detailed in the configuration menu. +.PP +.SH FILES +The following structure is created in your $HOME directory the first +time calcurse is run : +.PP +.HP 10 +$HOME/.calcurse/ +.br +|___conf +.br +|___apts +.br +|___todo +.PP +The \fIconf\fP file contains the user configuration. The \fIapts\fP +file contains all of the user's appointments, and the \fItodo\fP +file contains the todo list. +.PP +.SH LICENCE +Copyright (c) 2004-2006 by Frederic Culot. +.br +This software is released under the GNU General Public License. Please +read the COPYING file for more information. +.PP +.SH BUGS +Incorrect highlighting of items appear when using calcurse black and +white theme together with a \fB$TERM\fP variable set to +\fIxterm-color\fP. +To fix this bug, and as advised by Thomas E. Dickey (xterm maintainer), +\fIxterm-xfree86\fP should be used instead of \fIxterm-color\fP to set +the \fB$TERM\fP variable: + "The xterm-color value for $TERM is a bad choice for XFree86 + xterm because it is commonly used for a terminfo entry which + happens to not support bce. Use the xterm-xfree86 entry + which is distributed with XFree86 xterm (or the similar one + distributed with ncurses)." +.PP +If you find other bugs, please send a report to calcurse@culot.org or to the +author, below. +.PP +.SH AUTHOR +\fBFrederic Culot\fP <frederic@culot.org>. +.PP +.SH SEE ALSO +ncurses(3), gettext(3) +.br +Calcurse home page : http://culot.org/calcurse/ +.br +Calcurse manual found in the doc/ directory of the source package, or +at: +http://culot.org/calcurse/manual.html diff --git a/src/calcurse.c b/src/calcurse.c new file mode 100755 index 0000000..7432daf --- /dev/null +++ b/src/calcurse.c @@ -0,0 +1,1156 @@ +/* $calcurse: calcurse.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <ncurses.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <math.h> +#include <locale.h> + +#include "i18n.h" +#include "io.h" +#include "help.h" +#include "calendar.h" +#include "custom.h" +#include "utils.h" +#include "vars.h" +#include "day.h" +#include "apoint.h" +#include "event.h" +#include "todo.h" +#include "args.h" + + +/* Variables for calendar */ +struct tm *ptrtime; +time_t timer; +char current_day[3]; +char current_month[3]; +char current_year[5]; +char current_time[15]; +char cal_date[30]; +int year, month, day; +int sel_year, sel_month, sel_day; + +/* Variables for appointments */ +int number_apoints_inday; +int number_events_inday; +int first_app_onscreen = 0; +int hilt_app = 0, sav_hilt_app; + +/* Variables for todo list */ +int nb_tod = 0, hilt_tod = 0, sav_hilt_tod; +int first_todo_onscreen = 1; +char *saved_t_mesg; + +/* Variables for user configuration */ +int colr = 1, layout = 1; +int no_data_file = 1; +int really_quit = 0; +bool confirm_quit; +bool confirm_delete; +bool auto_save; +bool skip_system_dialogs; +bool skip_progress_bar; +bool week_begins_on_monday; + +/* + * Variables to handle calcurse windows + */ +int x_cal, y_cal, x_app, y_app, x_tod, y_tod, x_bar, y_bar; +int nl_cal, nc_cal, nl_app, nc_app, nl_tod, nc_tod, nl_bar, nc_bar; +int which_pan = 0; +enum window_number {CALENDAR, APPOINTMENT, TODO}; + +/* External functions */ +void get_date(void); +void init_vars(int colr); +void init_wins(void), reinit_wins(void); +void add_item(void); +void add_todo(void); +void load_conf(void); +bool fill_config_var(char *string); +void update_todo_panel(void); +void update_app_panel(int yeat, int month, int day); +void store_day(int year, int month, int day, bool day_changed); +void get_screen_config(void); +void update_windows(int surrounded_window); +void general_config(void); +void print_general_options(WINDOW *win); +void print_option_incolor(WINDOW *win, bool option, int pos_x, int pos_y); +void del_apoint(void); + +/* + * Calcurse is a text-based personal organizer which helps keeping track + * of events and everyday tasks. It contains a calendar, a 'todo' list, + * and puts your appointments in order. The user interface is configurable, + * and one can choose between different color schemes and layouts. + * All of the commands are documented within an online help system. + */ +int main(int argc, char **argv) +{ + int ch; + int non_interactive; + bool do_storage = false; + bool day_changed = false; + char *no_color_support = + _("Sorry, colors are not supported by your terminal\n" + "(Press [ENTER] to continue)"); + char *quit_message = _("Do you really want to quit ?"); + char choices[] = "[y/n] "; + +#if ENABLE_NLS + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif /* ENABLE_NLS */ + + /* + * Begin by parsing and handling command line arguments. + * The data path is also initialized here. + */ + non_interactive = parse_args(argc, argv, colr); + if (non_interactive) return EXIT_SUCCESS; + + /* Begin of interactive mode with ncurses interface. */ + initscr(); /* start the curses mode */ + cbreak(); /* control chars generate a signal */ + noecho(); /* controls echoing of typed chars */ + curs_set(0); /* make cursor invisible */ + get_date(); + get_screen_config(); + + /* Check if terminal supports color. */ + if (has_colors()) { + colorize = true; + start_color(); + + /* Color assignment */ + init_pair(1, COLOR_RED, COLOR_BLACK); + init_pair(2, COLOR_GREEN, COLOR_BLACK); + init_pair(3, COLOR_BLUE, COLOR_BLACK); + init_pair(4, COLOR_CYAN, COLOR_BLACK); + init_pair(5, COLOR_YELLOW, COLOR_BLACK); + init_pair(6, COLOR_BLACK, COLOR_GREEN); + init_pair(7, COLOR_BLACK, COLOR_YELLOW); + init_pair(8, COLOR_RED, COLOR_BLUE); + init_pair(9, COLOR_WHITE, COLOR_BLACK); + } else { + colorize = false; + use_default_colors(); + } + + init_vars(colr); + init_wins(); + update_windows(which_pan); + + /* + * Read the data from files : first the user + * configuration (the display is then updated), and then + * the todo list, appointments and events. + */ + no_data_file = check_data_files(); + load_conf(); + custom_init_attr(colr); + nb_tod = load_todo(colr); + load_app(); + get_screen_config(); + reinit_wins(); + startup_screen(skip_system_dialogs, no_data_file, colr); + store_day(year, month, day, day_changed); + update_windows(CALENDAR); + + /* User input */ + for (;;) { + + /* Check terminal size. */ + getmaxyx(stdscr, row, col); + if ((col < 80) | (row < 24)) { + endwin(); + fputs(_("Please resize your terminal screen\n" + "(to at least 80x24),\n" + "and restart calcurse.\n"), stderr); + return EXIT_FAILURE; + } + + /* Get user input. */ + ch = wgetch(swin); + switch (ch) { + + case 9: /* The TAB key was hit. */ + /* Save previously highlighted event. */ + if (which_pan == TODO) { + sav_hilt_tod = hilt_tod; + hilt_tod = 0; + } + if (which_pan == APPOINTMENT) { + sav_hilt_app = hilt_app; + hilt_app = 0; + } + /* Switch to the selected panel. */ + if (which_pan == TODO) which_pan = CALENDAR; + else ++which_pan; + + /* Select the event to highlight. */ + if (which_pan == APPOINTMENT) { + if ((sav_hilt_app == 0) + & ( (number_events_inday + + number_apoints_inday) != 0)) + hilt_app = 1; + else + hilt_app = sav_hilt_app; + } else if (which_pan == TODO) { + if ((sav_hilt_tod == 0) & (nb_tod != 0)) + hilt_tod = 1; + else + hilt_tod = sav_hilt_tod; + } + break; + + case 'R': + case 'r': + reinit_wins(); + break; + + case 'G': + case 'g': /* Goto function */ + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + get_date(); + goto_day(colr, day, month, year, + &sel_day, &sel_month, &sel_year); + do_storage = true; + day_changed = true; + break; + + case 'V': + case 'v': /* View function */ + if ((which_pan == APPOINTMENT) & (hilt_app != 0)) + day_popup_item(); + else if ((which_pan == TODO) & (hilt_tod != 0)) + item_in_popup(NULL, NULL, saved_t_mesg, + _("To do :")); + break; + + case 'C': + case 'c': /* Configuration menu */ + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + config_bar(); + while ((ch = wgetch(swin)) != 'q') { + switch (ch) { + case 'C': + case 'c': + if (has_colors()) { + colorize = true; + colr = color_config(colr); + custom_init_attr(colr); + } else { + colorize = false; + erase_window_part(swin, 0, 0, + nc_bar, + nl_bar); + mvwprintw(swin, 0, 0, + _(no_color_support)); + wgetch(swin); + } + break; + case 'L': + case 'l': + layout = layout_config(layout, colr); + break; + case 'G': + case 'g': + general_config(); + break; + } + reinit_wins(); + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + config_bar(); + } + update_windows(which_pan); + break; + + case 'A': + case 'a': /* Add an item */ + if (which_pan == APPOINTMENT) { + add_item(); + do_storage = true; + } + if (which_pan == TODO) add_todo(); + break; + + case 'D': + case 'd': /* Delete an item */ + del_apoint(); + do_storage = true; + break; + + case '?': /* Online help system */ + status_bar(which_pan, colr, nc_bar, nl_bar); + help_screen(which_pan, colr); + break; + + case 'S': + case 's': /* Save function */ + save_cal(auto_save, confirm_quit, + confirm_delete, skip_system_dialogs, + skip_progress_bar, week_begins_on_monday, + colr, layout); + break; + + case (261): /* right arrow */ + case ('L'): + case ('l'): + if (which_pan == CALENDAR) { + do_storage = true; + day_changed = true; + if ((sel_day == 31) & (sel_month == 12)) + { /* goto next year */ + sel_day = 0; + sel_month = 1; + sel_year++; + } + if (sel_day == days[sel_month - 1]) + { /* goto next month */ + sel_month = sel_month + 1; + sel_day = 1; + } else + sel_day = sel_day + 1; + } + break; + + case (260): /* left arrow */ + case ('H'): + case ('h'): + if (which_pan == CALENDAR) { + do_storage = true; + day_changed = true; + if ((sel_day == 1) & (sel_month == 1)) + { /* goto previous year */ + sel_day = 32; + sel_month = 12; + sel_year--; + } + if (sel_day == 1) + { /* goto previous month */ + sel_day = days[sel_month - 2]; + sel_month = sel_month - 1; + } else + sel_day = sel_day - 1; + } + break; + + case (259): /* up arrow */ + case ('K'): + case ('k'): + if (which_pan == CALENDAR) { + do_storage = true; + day_changed = true; + if ((sel_day <= 7) & (sel_month == 1)) + { /* goto previous year */ + sel_day = 31 - (7 - sel_day); + sel_month = 12; + sel_year--; + break; + } + if (sel_day <= 7) + { /* goto previous month */ + sel_day = days[sel_month - 2] - + (7 - sel_day); + sel_month = sel_month - 1; + } else /* previous week */ + sel_day = sel_day - 7; + } else { + if ((which_pan == APPOINTMENT) & (hilt_app > 1)) { + hilt_app--; + scroll_pad_up(hilt_app, + number_events_inday); + } + if ((which_pan == TODO) & (hilt_tod > 1)) { + hilt_tod--; + if (hilt_tod < first_todo_onscreen) + first_todo_onscreen--; + } + } + break; + + case (258): /* down arrow */ + case ('J'): + case ('j'): + if (which_pan == CALENDAR) { + do_storage = true; + day_changed = true; + if ((sel_day > days[sel_month - 1] - 7) & + (sel_month == 12)) + { /* next year */ + sel_day = (7 - (31 - sel_day)); + sel_month = 1; + sel_year++; + break; + } + if (sel_day > days[sel_month - 1] - 7) + { /* next month */ + sel_day = (7 - (days[sel_month - 1] - + sel_day)); + sel_month = sel_month + 1; + } else /* next week */ + sel_day = sel_day + 7; + } else { + if ((which_pan == APPOINTMENT) & (hilt_app < number_events_inday + number_apoints_inday)) + { + hilt_app++; + scroll_pad_down(hilt_app, + number_events_inday, + nl_app); + } + if ((which_pan == TODO) & (hilt_tod < nb_tod)) { + ++hilt_tod; + if (hilt_tod - first_todo_onscreen == + nl_tod - 4) + ++first_todo_onscreen; + } + } + break; + + case ('Q'): /* Quit calcurse :-( */ + case ('q'): + if (auto_save) + save_cal(auto_save,confirm_quit, + confirm_delete, skip_system_dialogs, + skip_progress_bar, + week_begins_on_monday, + colr, layout); + if (confirm_quit) { + status_mesg(_(quit_message), choices); + ch = wgetch(swin); + if ( ch == 'y' ) { + endwin(); + erase(); + return EXIT_SUCCESS; + } else { + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + break; + } + } else { + endwin(); + erase(); + return EXIT_SUCCESS; + } + break; + + } /* end case statement */ + if (do_storage) { + store_day(sel_year, sel_month, sel_day, day_changed); + do_storage = !do_storage; + if (day_changed) { + sav_hilt_app = 0; + day_changed = !day_changed; + } + } + update_windows(which_pan); + } +} /* end of interactive mode */ + +/* + * EXTERNAL FUNCTIONS + */ + +/* + * Variables init + */ +void init_vars(int colr) +{ + // Variables for user configuration + confirm_quit = true; + confirm_delete = true; + auto_save = true; + skip_system_dialogs = false; + skip_progress_bar = false; + week_begins_on_monday = true; + + // Pad structure for scrolling text inside the appointment panel + apad = (struct pad_s *) malloc(sizeof(struct pad_s)); + apad->width = nc_app - 3; + apad->length = 1; + apad->first_onscreen = 0; + apad->ptrwin = newpad(apad->length, apad->width); + + // Attribute definitions for color and non-color terminals + custom_init_attr(colr); +} + +/* + * Update all of the three windows and put a border around the + * selected window. + */ +void update_windows(int surrounded_window) +{ + if (surrounded_window == CALENDAR) { + border_color(cwin, colr); + border_nocolor(awin); + border_nocolor(twin); + } else if (surrounded_window == APPOINTMENT) { + border_color(awin, colr); + border_nocolor(cwin); + border_nocolor(twin); + } else if (surrounded_window == TODO) { + border_color(twin, colr); + border_nocolor(awin); + border_nocolor(cwin); + } else { + /* NOTREACHED */ + fputs(_("FATAL ERROR in update_windows: no window selected\n"),stderr); + exit(EXIT_FAILURE); + } + update_app_panel(sel_year, sel_month, sel_day); + update_todo_panel(); + update_cal_panel(cwin, nl_cal, nc_cal, sel_month, + sel_year, sel_day, day, month, year, + week_begins_on_monday); + status_bar(surrounded_window, colr, nc_bar, nl_bar); + wmove(swin, 0, 0); + doupdate(); +} + +/* + * Get the screen size and recalculate the windows configurations. + */ +void get_screen_config(void) +{ + /* Get the screen configuration */ + getmaxyx(stdscr, row, col); + + /* window size definition */ + nl_cal = 12; + nc_cal = 30; + nc_app = col - nc_cal; + nl_app = row - 2; + nc_tod = nc_cal; + nl_tod = row - (nl_cal + 2); + nl_app = row - 2; + nl_bar = 2; y_bar = row - 2; + nc_bar = col; x_bar = 0; + + /* defining the layout */ + switch (layout) { + case 1: + y_app = 0; x_app = 0; y_cal = 0; + x_tod = nc_app; y_tod = nl_cal; x_cal = nc_app; + break; + case 2: + y_app = 0; x_app = 0; y_tod = 0; + x_tod = nc_app; x_cal = nc_app; y_cal = nl_tod; + break; + case 3: + y_app = 0; x_tod = 0; x_cal = 0; y_cal = 0; + x_app = nc_cal; y_tod = nl_cal; + break; + case 4: + y_app = 0; x_tod = 0; y_tod = 0; x_cal = 0; + x_app = nc_cal; y_cal = nl_tod; + break; + } +} + + + +/* Get current date */ +void get_date(void) +{ + timer = time(NULL); + ptrtime = localtime(&timer); + strftime(current_time, 15, "%H:%M%p", ptrtime); + strftime(cal_date, 30, "%a %B %Y", ptrtime); + strftime(current_day, 3, "%d", ptrtime); + strftime(current_month, 3, "%m", ptrtime); + strftime(current_year, 5, "%Y", ptrtime); + month = atoi(current_month); + day = atoi(current_day); + year = atoi(current_year); + sel_year = year; + sel_month = month; + sel_day = day; +} + +/* Create all the windows */ +void init_wins(void) +{ + char label[80]; + + /* Create the three main windows plus the status bar. */ + cwin = newwin(nl_cal, nc_cal, y_cal, x_cal); + sprintf(label, _("Calendar")); + win_show(cwin, label); + awin = newwin(nl_app, nc_app, y_app, x_app); + sprintf(label, _("Appointments")); + win_show(awin, label); + twin = newwin(nl_tod, nc_tod, y_tod, x_tod); + sprintf(label, _("ToDo")); + win_show(twin, label); + swin = newwin(nl_bar, nc_bar, y_bar, x_bar); + + /* Enable function keys (i.e. arrow keys) in those windows */ + keypad(swin, TRUE); + keypad(twin, TRUE); + keypad(awin, TRUE); + keypad(cwin, TRUE); +} + +/* + * Delete the existing windows and recreate them with their new + * size and placement. + */ +void reinit_wins(void) +{ + clear(); + delwin(swin); + delwin(cwin); + delwin(awin); + delwin(twin); + get_screen_config(); + init_wins(); + update_windows(which_pan); +} + +/* General configuration */ +void general_config(void) +{ + WINDOW *conf_win; + char label[80]; + char *number_str = _("Enter an option number to change its value [Q to quit] "); + int ch; + + clear(); + conf_win = newwin(row - 2, col, 0, 0); + box(conf_win, 0, 0); + sprintf(label, _("CalCurse %s | general options"), VERSION); + win_show(conf_win, label); + status_mesg(number_str, ""); + print_general_options(conf_win); + while ((ch = wgetch(swin)) != 'q') { + switch (ch) { + case '1': + auto_save = !auto_save; + break; + case '2': + confirm_quit = !confirm_quit; + break; + case '3': + confirm_delete = !confirm_delete; + break; + case '4': + skip_system_dialogs = + !skip_system_dialogs; + break; + case '5': + skip_progress_bar = + !skip_progress_bar; + break; + case '6': + week_begins_on_monday = + !week_begins_on_monday; + break; + } + print_general_options(conf_win); + } + delwin(conf_win); +} + +/* prints the general options */ +void print_general_options(WINDOW *win) +{ + int x_pos, y_pos; + char *option1 = _("auto_save = "); + char *option2 = _("confirm_quit = "); + char *option3 = _("confirm_delete = "); + char *option4 = _("skip_system_dialogs = "); + char *option5 = _("skip_progress_bar = "); + char *option6 = _("week_begins_on_monday = "); + + x_pos = 3; + y_pos = 4; + + mvwprintw(win, y_pos, x_pos, "[1] %s ", option1); + print_option_incolor(win, auto_save, y_pos, + x_pos + 4 + strlen(option1)); + mvwprintw(win, y_pos + 1, x_pos, + _("(if set to YES, automatic save is done when quitting)")); + + mvwprintw(win, y_pos + 3, x_pos, "[2] %s ", option2); + print_option_incolor(win, confirm_quit, y_pos + 3, + x_pos + 4 + strlen(option2)); + mvwprintw(win, y_pos + 4, x_pos, + _("(if set to YES, confirmation is required before quitting)")); + + mvwprintw(win, y_pos + 6, x_pos, "[3] %s ", option3); + print_option_incolor(win, confirm_delete, y_pos + 6, + x_pos + 4 + strlen(option3)); + mvwprintw(win, y_pos + 7, x_pos, + _("(if set to YES, confirmation is required before deleting an event)")); + + mvwprintw(win, y_pos + 9, x_pos, "[4] %s ", option4); + print_option_incolor(win, skip_system_dialogs, y_pos + 9, + x_pos + 4 + strlen(option4)); + mvwprintw(win, y_pos + 10, x_pos, + _("(if set to YES, messages about loaded and saved data will not be displayed)")); + + mvwprintw(win, y_pos + 12, x_pos, "[5] %s ", option5); + print_option_incolor(win, skip_progress_bar , y_pos + 12, + x_pos + 4 + strlen(option5)); + mvwprintw(win, y_pos + 13, x_pos, + _("(if set to YES, progress bar will not be displayed when saving data)")); + + mvwprintw(win, y_pos + 15, x_pos, "[6] %s ", option6); + print_option_incolor(win, week_begins_on_monday , y_pos + 15, + x_pos + 4 + strlen(option6)); + mvwprintw(win, y_pos + 16, x_pos, + _("(if set to YES, monday is the first day of the week, else it is sunday)")); + + wmove(swin, 1, 0); + wnoutrefresh(win); + doupdate(); +} + +/* print the option value with appropriate color */ +void print_option_incolor(WINDOW *win, bool option, int pos_y, int pos_x) +{ + int color; + char *option_value; + + if (option == true) { + color = ATTR_TRUE; + option_value = _("yes"); + } else if (option == false) { + color = ATTR_FALSE; + option_value = _("no"); + } else { + erase_window_part(win, 0, 0, col, row - 2); + mvwprintw(win, 1, 1, + _("option not defined - Problem in print_option_incolor()")); + wnoutrefresh(win); + doupdate(); + wgetch(win); + exit(EXIT_FAILURE); + } + custom_apply_attr(win, color); + mvwprintw(win, pos_y, pos_x, "%s", option_value); + custom_remove_attr(win, color); + wnoutrefresh(win); + doupdate(); +} + + /* Delete an event from the ToDo or Appointment lists */ +void del_apoint(void) +{ + char *choices = "[y/n] "; + char *del_app_str = _("Do you really want to delete this item ?"); + char *del_todo_str = _("Do you really want to delete this task ?"); + long date; + int nb_items = number_apoints_inday + number_events_inday; + bool go_for_deletion = false; + bool go_for_todo_del = false; + int to_be_removed = 0; + int answer = 0; + + /* delete an appointment */ + if (which_pan == APPOINTMENT && hilt_app != 0) { + date = date2sec(sel_year, sel_month, sel_day, 0, 0); + + if (confirm_delete) { + status_mesg(del_app_str, choices); + answer = wgetch(swin); + if ( (answer == 'y') && (nb_items != 0) ) + go_for_deletion = true; + else { + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + return; + } + } else + if (nb_items != 0) + go_for_deletion = true; + + if (go_for_deletion) { + if (nb_items != 0) { + if (hilt_app <= number_events_inday) { + event_delete_bynum(date, hilt_app - 1); + number_events_inday--; + to_be_removed = 1; + } else { + apoint_delete_bynum(date, + hilt_app - + number_events_inday - 1); + number_apoints_inday--; + to_be_removed = 3; + } + if (hilt_app > 1) --hilt_app; + if (apad->first_onscreen >= to_be_removed) + apad->first_onscreen = + apad->first_onscreen - + to_be_removed; + } + } + + /* delete a todo */ + } else if (which_pan == TODO && hilt_tod != 0) { + if (confirm_delete) { + status_mesg(del_todo_str, choices); + answer = wgetch(swin); + if ( (answer == 'y') && (nb_tod > 0) ) { + go_for_todo_del = true; + } else { + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + return; + } + } else + if (nb_tod > 0) + go_for_todo_del = true; + + if (go_for_todo_del) { + todo_delete_bynum(hilt_tod - 1); + nb_tod--; + if (hilt_tod > 1) hilt_tod--; + } + } +} + + /* Add an item in the ToDo list */ +void add_todo(void) +{ + char *mesg = _("Enter the new ToDo item : "); + char todo_input[500]; + + status_mesg(mesg, ""); + getstring(swin, colr, todo_input, 0, 1); + if (strlen(todo_input) != 0) { + todo_insert(todo_input); + ++nb_tod; + update_todo_panel(); + } + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + status_bar(which_pan, colr, nc_bar, nl_bar); + doupdate(); +} + +/* + * Add an item in either the appointment or the event list, + * depending if the start time is entered or not. + */ +void add_item(void) +{ + char *mesg_1 = _("Enter start time ([hh:mm] or [h:mm]), leave blank for an all-day event : "); + char *mesg_2 = _("Enter end time ([hh:mm] or [h:mm]) or duration (in minutes) : "); + char *mesg_3 = _("Enter description :"); + char *format_message_1 = _("You entered an invalid start time, should be [h:mm] or [hh:mm]"); + char *format_message_2 = _("You entered an invalid end time, should be [h:mm] or [hh:mm] or [mm]"); + char *enter_str = _("Press [Enter] to continue"); + int Id; + char item_time[500]; + char item_mesg[500]; + long apoint_duration; + struct apoint_s *apoint_pointeur; + struct event_s *event_pointeur; + unsigned heures, minutes; + unsigned end_h, end_m; + int is_appointment = 1; + + /* Get the starting time */ + strcpy(item_time, " "); + while (check_time(item_time) == 0) { + status_mesg(mesg_1, ""); + getstring(swin, colr, item_time, 0, 1); + if (strlen(item_time) == 0){ + is_appointment = 0; + break; + } else if (check_time(item_time) != 1) { + status_mesg(format_message_1, enter_str); + wgetch(swin); + } else + sscanf(item_time, "%u:%u", &heures, &minutes); + } + /* + * Check if an event or appointment is entered, + * depending on the starting time, and record the + * corresponding item. + */ + if (is_appointment){ /* Get the appointment duration */ + strcpy(item_time, " "); + while (check_time(item_time) == 0) { + status_mesg(mesg_2, ""); + getstring(swin, colr, item_time, 0, 1); + if (strlen(item_time) == 0) + return; //nothing entered, cancel adding of event + else if (check_time(item_time) == 0) { + status_mesg(format_message_2, enter_str); + wgetch(swin); + } else { + if (check_time(item_time) == 2) + apoint_duration = atoi(item_time); + else if (check_time(item_time) == 1) { + sscanf(item_time, "%u:%u", + &end_h, &end_m); + if (end_h < heures){ + apoint_duration = + (60 - minutes + end_m) + + (24 + end_h - (heures + 1))*60; + } else { + apoint_duration = + (60 - minutes + end_m) + + (end_h - (heures + 1))*60; + } + } + } + } + } else { /* Insert the event Id */ + Id = 1; + } + // get the item description + status_mesg(mesg_3, ""); + getstring(swin, colr, item_mesg, 0, 1); + if (strlen(item_mesg) != 0) { + if (is_appointment){ + // insert the appointment in list + apoint_pointeur = + apoint_new(item_mesg, + date2sec(sel_year, sel_month, sel_day, + heures, minutes), + min2sec(apoint_duration)); + // insert the event in list + } else { + event_pointeur = event_new(item_mesg, date2sec( + sel_year, + sel_month, + sel_day, + 12, 0), + Id); + } + update_app_panel(sel_year, sel_month, sel_day); + } + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + status_bar(which_pan, colr, nc_bar, nl_bar); + doupdate(); +} + +/* Updates the ToDo panel */ +void update_todo_panel(void) +{ + struct todo_s *i; + int len = nc_tod - 5; + int num_todo = 0; + int y_offset = 3, x_offset = 1; + int t_realpos = -1; + int title_lines = 3; + int todo_lines = 1; + int max_items = nl_tod - 4; + int incolor = -1; + + /* Print todo item in the panel. */ + erase_window_part(twin, 1, title_lines, nc_tod - 2, nl_tod - 2); + for (i = todolist; i != 0; i = i->next) { + num_todo++; + t_realpos = num_todo - first_todo_onscreen; + incolor = num_todo - hilt_tod; + if (incolor == 0) saved_t_mesg = i->mesg; + if (t_realpos >= 0 && t_realpos < max_items) { + display_item(twin, incolor, i->mesg, + len, y_offset, x_offset); + y_offset = y_offset + todo_lines; + } + } + + /* Draw the scrollbar if necessary. */ + if (nb_tod > max_items){ + float ratio = ((float) max_items) / ((float) nb_tod); + int sbar_length = (int) (ratio * (max_items + 1)); + int highend = (int) (ratio * first_todo_onscreen); + bool hilt_bar = (which_pan == TODO) ? true : false; + int sbar_top = highend + title_lines; + + if ((sbar_top + sbar_length) > nl_tod - 1) + sbar_length = nl_tod - 1 - sbar_top; + draw_scrollbar(twin, sbar_top, nc_tod - 2, + sbar_length, title_lines, nl_tod - 1, hilt_bar); + } + + wnoutrefresh(twin); +} + +/* Updates the Appointment panel */ +void update_app_panel(int year, int month, int day) +{ + int title_xpos; + int bordr = 1; + int title_lines = 3; + int app_width = nc_app - bordr; + int app_length = nl_app - bordr - title_lines; + long date; + + /* variable inits */ + title_xpos = nc_app - (strlen(_(monthnames[sel_month - 1])) + 11); + if (sel_day < 10) title_xpos++; + date = date2sec(year, month, day, 0, 0); + day_write_pad(date, app_width, app_length, hilt_app, colr); + + /* Print current date in the top right window corner. */ + erase_window_part(awin, 1, title_lines, nc_app - 2, nl_app - 2); + custom_apply_attr(awin, ATTR_HIGHEST); + mvwprintw(awin, title_lines, title_xpos, "%s %d, %d", + _(monthnames[sel_month - 1]), sel_day, sel_year); + custom_remove_attr(awin, ATTR_HIGHEST); + + /* Draw the scrollbar if necessary. */ + if ((apad->length >= app_length)||(apad->first_onscreen > 0)) { + float ratio = ((float) app_length) / ((float) apad->length); + int sbar_length = (int) (ratio * app_length); + int highend = (int) (ratio * apad->first_onscreen); + bool hilt_bar = (which_pan == APPOINTMENT) ? true : false; + int sbar_top = highend + title_lines + 1; + + if ((sbar_top + sbar_length) > nl_app - 1) + sbar_length = nl_app - 1 - sbar_top; + draw_scrollbar(awin, sbar_top, nc_app - 2, sbar_length, + title_lines + 1, nl_app - 1, hilt_bar); + } + + wnoutrefresh(awin); + pnoutrefresh(apad->ptrwin, apad->first_onscreen, 0, + y_app + title_lines + 1, x_app + bordr, + y_app + nl_app - 2*bordr, x_app + nc_app - 2*bordr); +} + +/* + * Store the events and appointments for the selected day, and write + * those items in a pad. + * This is useful to speed up the appointment panel update. + */ +void store_day(int year, int month, int day, bool day_changed) +{ + long date; + date = date2sec(year, month, day, 0, 0); + + /* Inits */ + if (apad->length != 0) + delwin(apad->ptrwin); + + /* Store the events and appointments (recursive and normal items). */ + apad->length = day_store_items(date, + &number_events_inday, &number_apoints_inday); + + /* Create the new pad with its new length. */ + if (day_changed) apad->first_onscreen = 0; + apad->ptrwin = newpad(apad->length, apad->width); +} + +/* Load the user configuration */ +void load_conf(void) +{ + FILE *data_file; + char *mesg_line1 = _("Failed to open config file"); + char *mesg_line2 = _("Press [ENTER] to continue"); + char buf[100], e_conf[100]; + int var; + + data_file = fopen(path_conf, "r"); + if (data_file == NULL) { + status_mesg(mesg_line1, mesg_line2); + wnoutrefresh(swin); + doupdate(); + wgetch(swin); + } + var = 0; + for (;;) { + if (fgets(buf, 99, data_file) == NULL) { + break; + } + extract_data(e_conf, buf, strlen(buf)); + if (var == 1) { + auto_save = + fill_config_var(e_conf); + var = 0; + } else if (var == 2) { + confirm_quit = + fill_config_var(e_conf); + var = 0; + } else if (var == 3) { + confirm_delete = + fill_config_var(e_conf); + var = 0; + } else if (var == 4) { + skip_system_dialogs = + fill_config_var(e_conf); + var = 0; + } else if (var == 5) { + skip_progress_bar = + fill_config_var(e_conf); + var = 0; + } else if (var == 6) { + week_begins_on_monday = + fill_config_var(e_conf); + var = 0; + } else if (var == 7) { + colr = atoi(e_conf); + if (colr == 0) colorize = false; + var = 0; + } else if (var == 8) { + layout = atoi(e_conf); + var = 0; + } + if (strncmp(e_conf, "auto_save=", 10) == 0) + var = 1; + else if (strncmp(e_conf, "confirm_quit=", 13) == 0) + var = 2; + else if (strncmp(e_conf, "confirm_delete=", 15) == 0) + var = 3; + else if (strncmp(e_conf, "skip_system_dialogs=", 20) == 0) + var = 4; + else if (strncmp(e_conf, "skip_progress_bar=", 18) == 0) + var = 5; + else if (strncmp(e_conf, "week_begins_on_monday=", 23) == 0) + var = 6; + else if (strncmp(e_conf, "color-theme=", 12) == 0) + var = 7; + else if (strncmp(e_conf, "layout=", 7) == 0) + var = 8; + } + fclose(data_file); + erase_window_part(swin, 0, 0, nc_bar, nl_bar); +} + +bool fill_config_var (char *string) { + if (strncmp(string, "yes", 3) == 0) + return true; + else if (strncmp(string, "no", 2) == 0) + return false; + else { + fputs(_("FATAL ERROR in fill_config_var: " + "wrong configuration variable format.\n"), stderr); + return EXIT_FAILURE; + } +} diff --git a/src/calendar.c b/src/calendar.c new file mode 100755 index 0000000..c147e47 --- /dev/null +++ b/src/calendar.c @@ -0,0 +1,227 @@ +/* $calcurse: calendar.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "i18n.h" +#include "day.h" +#include "apoint.h" +#include "event.h" +#include "calendar.h" +#include "custom.h" +#include "vars.h" +#include "utils.h" + +static unsigned months_to_days(unsigned); +static long years_to_days(unsigned); + + /* Load the calendar */ +void +update_cal_panel(WINDOW *cwin, int nl_cal, + int nc_cal, int sel_month, int sel_year, int sel_day, + int day, int month, int year, + bool monday_first) +{ + int c_day, c_day_1, day_1_sav, numdays, j; + unsigned yr, mo; + int ofs_x, ofs_y; + int item_this_day = 0; + int title_lines = 3; + int sunday_first = 0; + + // Inits + erase_window_part(cwin, 1, title_lines, nc_cal - 2, nl_cal - 2); + mo = sel_month; + yr = sel_year; + if (!monday_first) sunday_first = 1; + + // Offset for centering calendar in window + ofs_y = 2 + (nl_cal - 9) / 2; + ofs_x = (nc_cal - 27) / 2; + + + //checking the number of days in february + numdays = days[mo - 1]; + if (2 == mo && isBissextile(yr)) + ++numdays; + + //the first calendar day will be monday or sunday, depending on the + //value of week_begins_on_monday + c_day_1 = (int) ((ymd_to_scalar(yr, mo, 1 + sunday_first) + - (long) 1) % 7L); + + //Write the current month and year on top of the calendar + custom_apply_attr(cwin, ATTR_HIGH); + mvwprintw(cwin, ofs_y, + (nc_cal - (strlen(_(monthnames[mo - 1])) + 5)) / 2, + "%s %d", _(monthnames[mo - 1]), sel_year); + custom_remove_attr(cwin, ATTR_HIGH); + ++ofs_y; + + //prints the days, with regards to the first day of the week + custom_apply_attr(cwin, ATTR_HIGH); + for (j = 0; j < 7; j++) { + mvwprintw(cwin, ofs_y, ofs_x + 4 * j, "%s", + _(daynames[1 + j - sunday_first])); + } + custom_remove_attr(cwin, ATTR_HIGH); + + day_1_sav = (c_day_1 + 1) * 3 + c_day_1 - 7; + + for (c_day = 1; c_day <= numdays; ++c_day, ++c_day_1, c_day_1 %= 7) { + //check if the day contains an event or an appointment + item_this_day = day_check_if_item(sel_year, sel_month, c_day); + + /* Go to next line, the week is over. */ + if (!c_day_1 && 1 != c_day) { + ++ofs_y; + ofs_x = 2 - day_1_sav - 4 * c_day - 1; + } + /* This is today, so print it in yellow. */ + if (c_day == day && month == sel_month + && year == sel_year && day != sel_day) + { + custom_apply_attr(cwin, ATTR_LOWEST); + mvwprintw(cwin, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", + c_day); + custom_remove_attr(cwin, ATTR_LOWEST); + } else if (c_day == sel_day && ( (day != sel_day) | + (month != sel_month) | (year != sel_year) )) + /* This is the selected day, print it in red. */ + { + custom_apply_attr(cwin, ATTR_MIDDLE); + mvwprintw(cwin, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", + c_day); + custom_remove_attr(cwin, ATTR_MIDDLE); + } else if (c_day == sel_day && day == sel_day && month == sel_month && year == sel_year) //today is the selected day + { + custom_apply_attr(cwin, ATTR_MIDDLE); + mvwprintw(cwin, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", + c_day); + custom_remove_attr(cwin, ATTR_MIDDLE); + } else if (item_this_day) { + custom_apply_attr(cwin, ATTR_LOW); + mvwprintw(cwin, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", + c_day); + custom_remove_attr(cwin, ATTR_LOW); + } + + else // otherwise, print normal days in black + mvwprintw(cwin, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", + c_day); + + } + wnoutrefresh(cwin); +} + +int isBissextile(unsigned annee) +{ + return annee % 400 == 0 || (annee % 4 == 0 && annee % 100 != 0); +} + +// convertion functions +unsigned months_to_days(unsigned mois) +{ + return (mois * 3057 - 3007) / 100; +} + + +long years_to_days(unsigned annee) +{ + return annee * 365L + annee / 4 - annee / 100 + annee / 400; +} + +long ymd_to_scalar(unsigned annee, unsigned mois, unsigned jour) +{ + long scalaire; + scalaire = jour + months_to_days(mois); + if (mois > 2) + scalaire -= isBissextile(annee) ? 1 : 2; + annee--; + scalaire += years_to_days(annee); + return scalaire; +} + +/* + * Ask for a date to jump to, then check the correctness of that date + * and jump to it. + * If the entered date is empty, automatically jump to the current date. + * day, month, year are the current day given to that routine, and + * sel_day, sel_month and sel_year represent the day given back. + */ +void +goto_day(int colr, int day, int month, int year, + int *sel_day, int *sel_month, int *sel_year) +{ + char selected_day[50] = ""; + int dday, dmonth, dyear; + int wrong_day = 0; + char *mesg_line1 = _("The day you entered is not valid"); + char *mesg_line2 = _("Press [ENTER] to continue"); + char *request_date = _("Enter the day to go to [ENTER for today] : dd/mm/yyyy"); + + while (wrong_day != 1) { + status_mesg(request_date, ""); + getstring(swin, colr, selected_day, 0, 1); + if (strlen(selected_day) == 0) // go to today + { + *sel_day = day; + *sel_month = month; + *sel_year = year; + break; + } else { + sscanf(selected_day, "%u/%u/%u", &dday, &dmonth, + &dyear); + //check if the entered day is correct + if ((dday <= 0) | (dday >= 32)) + wrong_day = 1; + if ((dmonth <= 0) | (dmonth >= 13)) + wrong_day = 1; + if ((dyear <= 0) | (dyear >= 3000)) + wrong_day = 1; + //go to chosen day + if (wrong_day != 1) { + *sel_day = dday; + *sel_month = dmonth; + *sel_year = dyear; + } else { + status_mesg(mesg_line1, mesg_line2); + wgetch(swin); + } + break; + } + } + return; +} diff --git a/src/calendar.h b/src/calendar.h new file mode 100755 index 0000000..a8cb3ea --- /dev/null +++ b/src/calendar.h @@ -0,0 +1,41 @@ +/* $calcurse: calendar.h,v 1.1 2006/07/31 21:00:02 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_CALENDAR_H +#define CALCURSE_CALENDAR_H + +#include <stdbool.h> + +void update_cal_panel(WINDOW *cwin, int nl_cal, + int nc_cal, int sel_month, int sel_year, int sel_day, + int day, int month, int year, + bool monday_first); +int isBissextile(unsigned); +long ymd_to_scalar(unsigned, unsigned, unsigned); +void goto_day(int colr, int day, int month, int year, + int *sel_day, int *sel_month, int *sel_year); + +#endif /* CALCURSE_CALENDAR_H */ diff --git a/src/custom.c b/src/custom.c new file mode 100755 index 0000000..4a2ea72 --- /dev/null +++ b/src/custom.c @@ -0,0 +1,178 @@ +/* $calcurse: custom.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> + +#include "i18n.h" +#include "utils.h" +#include "custom.h" +#include "vars.h" + +static struct attribute_s attr; + +/* + * Define window attributes (for both color and non-color terminals): + * ATTR_HIGHEST are for window titles + * ATTR_HIGH are for month and days names + * ATTR_MIDDLE are for the selected day inside calendar panel + * ATTR_LOW are for days inside calendar panel which contains an event + * ATTR_LOWEST are for current day inside calendar panel + */ +void custom_init_attr(int colr) +{ + attr.color[ATTR_HIGHEST] = COLOR_PAIR(colr); + attr.color[ATTR_HIGH] = COLOR_PAIR(6); + attr.color[ATTR_MIDDLE] = COLOR_PAIR(1); + attr.color[ATTR_LOW] = COLOR_PAIR(4); + attr.color[ATTR_LOWEST] = COLOR_PAIR(5); + attr.color[ATTR_TRUE] = COLOR_PAIR(2); + attr.color[ATTR_FALSE] = COLOR_PAIR(1); + + attr.nocolor[ATTR_HIGHEST] = A_BOLD; + attr.nocolor[ATTR_HIGH] = A_REVERSE; + attr.nocolor[ATTR_MIDDLE] = A_REVERSE; + attr.nocolor[ATTR_LOW] = A_UNDERLINE; + attr.nocolor[ATTR_LOWEST] = A_BOLD; + attr.nocolor[ATTR_TRUE] = A_BOLD; + attr.nocolor[ATTR_FALSE] = A_DIM; +} + +/* Apply window attribute */ +void custom_apply_attr(WINDOW *win, int attr_num) +{ + if (colorize) + wattron(win, attr.color[attr_num]); + else + wattron(win, attr.nocolor[attr_num]); +} + +/* Remove window attribute */ +void custom_remove_attr(WINDOW *win, int attr_num) +{ + if (colorize) + wattroff(win, attr.color[attr_num]); + else + wattroff(win, attr.nocolor[attr_num]); +} + +/* Draws the configuration bar */ +void config_bar() +{ + int smlspc, spc; + + smlspc = 2; + spc = 15; + + custom_apply_attr(swin, ATTR_HIGHEST); + mvwprintw(swin, 0, 2, "Q"); + mvwprintw(swin, 1, 2, "G"); + mvwprintw(swin, 0, 2 + spc, "L"); + mvwprintw(swin, 1, 2 + spc, "C"); + custom_remove_attr(swin, ATTR_HIGHEST); + + mvwprintw(swin, 0, 2 + smlspc, _("Exit")); + mvwprintw(swin, 1, 2 + smlspc, _("General")); + mvwprintw(swin, 0, 2 + spc + smlspc, _("Layout")); + mvwprintw(swin, 1, 2 + spc + smlspc, _("Color")); + + wnoutrefresh(swin); + wmove(swin, 0, 0); + doupdate(); +} + +/* Choose the layout */ +int layout_config(int layout, int colr) +{ + int ch, old_layout; + char *layout_mesg = _("Pick the desired layout on next screen [press ENTER]"); + char *choice_mesg = _("('A'= Appointment panel, 'c'= calendar panel, 't'= todo panel)"); + char *layout_up_mesg = _(" |Ac| |At| |cA| |tA|"); + char *layout_down_mesg = _("[1]|At| [2]|Ac| [3]|tA| [4]|cA|"); + + old_layout = layout; + status_mesg(layout_mesg, choice_mesg); + wgetch(swin); + status_mesg(layout_up_mesg, layout_down_mesg); + wnoutrefresh(swin); + doupdate(); + while ((ch = wgetch(swin)) != 'q') { + switch (ch) { + case '1': + layout = 1; + return layout; + case '2': + layout = 2; + return layout; + case '3': + layout = 3; + return layout; + case '4': + layout = 4; + return layout; + } + } + layout = old_layout; + return layout; +} + +/* Choose the color theme */ +int color_config(int colr) +{ + int ascii2dec = 48; + int i, ch, old_colr; + int max_colors = 9; + int spc = 6; + char *choose_color = _("Pick the number corresponding to the color scheme " + "(Q to exit) :"); + + old_colr = colr; + erase_window_part(swin, 0, 0, col, 2); + for (i = 1; i < max_colors; i++) { + wattron(swin, COLOR_PAIR(i)); + mvwprintw(swin, 1, (i - 1) * spc, "[>%d<]", i); + wattroff(swin, COLOR_PAIR(i)); + } + mvwprintw(swin, 1, 50, _("([>0<] for black & white)")); + custom_apply_attr(swin, ATTR_HIGHEST); + mvwprintw(swin, 0, 0, choose_color); + custom_remove_attr(swin, ATTR_HIGHEST); + wnoutrefresh(swin); + doupdate(); + while ((ch = wgetch(swin)) != 'q') { + ch = ch - ascii2dec; + if ( (ch > 0) && (ch <= max_colors) ) { + colorize = true; + return ch; + } else if (ch == 0) { + colorize = false; + return 0; + } else { + colr = old_colr; + } + } + if (colr == 0) colorize = false; + return colr; +} diff --git a/src/custom.h b/src/custom.h new file mode 100755 index 0000000..a7f133b --- /dev/null +++ b/src/custom.h @@ -0,0 +1,42 @@ +/* $calcurse: custom.h,v 1.1 2006/07/31 21:00:02 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_CUSTOM_H +#define CALCURSE_CUSTOM_H + +struct attribute_s { + int color[7]; + int nocolor[7]; +}; + +void custom_init_attr(int colr); +void custom_apply_attr(WINDOW *win, int attr_num); +void custom_remove_attr(WINDOW *win, int attr_num); +void config_bar(); +int layout_config(int layout, int colr); +int color_config(int colr); + +#endif /* CALCURSE_CUSTOM_H */ diff --git a/src/day.c b/src/day.c new file mode 100755 index 0000000..8fd7981 --- /dev/null +++ b/src/day.c @@ -0,0 +1,362 @@ +/* $calcurse: day.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <stdbool.h> +#include <time.h> + +#include "i18n.h" +#include "utils.h" +#include "apoint.h" +#include "event.h" +#include "recur.h" +#include "day.h" +#include "vars.h" + +static struct day_item_s *day_items_ptr; +static struct day_saved_item_s *day_saved_item = NULL; + +/* + * Store all of the items to be displayed for the selected day. + * Items are of four types: recursive events, normal events, + * recursive appointments and normal appointments. + * The items are stored in the linked list pointed by *day_items_ptr + * and the length of the new pad to write is returned. + * The number of events and appointments in the current day are also updated. + */ +int day_store_items(long date, int *pnb_events, int *pnb_apoints) +{ + int pad_length; + int nb_events, nb_recur_events; + int nb_apoints, nb_recur_apoints; + + pad_length = nb_events = nb_apoints = 0; + nb_recur_events = nb_recur_apoints = 0; + + if (day_items_ptr != 0) + day_free_list(); + nb_recur_events = day_store_recur_events(date); + nb_events = day_store_events(date); + *pnb_events = nb_events; + nb_recur_apoints = day_store_recur_apoints(date); + nb_apoints = day_store_apoints(date); + *pnb_apoints = nb_apoints; + pad_length = nb_recur_events + nb_events + 1 + + 3*(nb_recur_apoints + nb_apoints); + *pnb_apoints += nb_recur_apoints; + *pnb_events += nb_recur_events; + + return pad_length; +} + +/* Free the current day linked list containing the events and appointments. */ +void day_free_list(void) +{ + struct day_item_s *p, *q; + + for (p = day_items_ptr; p != 0; p = q) { + q = p->next; + free(p->mesg); + free(p); + } + day_items_ptr = NULL; +} + +/* + * Store the recurrent events for the selected day in structure pointed + * by day_items_ptr. This is done by copying the recurrent events + * from the general structure pointed by recur_elist to the structure + * dedicated to the selected day. + * Returns the number of recurrent events for the selected day. + */ +int day_store_recur_events(long date) +{ + struct recur_event_s *j; + struct day_item_s *ptr; + int e_nb = 0; + + for (j = recur_elist; j != 0; j = j->next) { + if (recur_item_inday(j->day, j->rpt->type, j->rpt->freq, + j->rpt->until, date)) { + e_nb++; + ptr = day_add_event(RECUR_EVNT, j->mesg, j->day, j->id); + } + } + + return e_nb; +} + +/* + * Store the events for the selected day in structure pointed + * by day_items_ptr. This is done by copying the events + * from the general structure pointed by eventlist to the structure + * dedicated to the selected day. + * Returns the number of events for the selected day. + */ +int day_store_events(long date) +{ + struct event_s *j; + struct day_item_s *ptr; + int e_nb = 0; + + for (j = eventlist; j != 0; j = j->next) { + if (event_inday(j, date)) { + e_nb++; + ptr = day_add_event(EVNT, j->mesg, j->day, j->id); + } + } + + return e_nb; +} + +/* + * Store the recurrent apoints for the selected day in structure pointed + * by day_items_ptr. This is done by copying the appointments + * from the general structure pointed by recur_alist to the structure + * dedicated to the selected day. + * Returns the number of recurrent appointments for the selected day. + */ +int day_store_recur_apoints(long date) +{ + struct recur_apoint_s *j; + struct day_item_s *ptr; + int a_nb = 0; + + for (j = recur_alist; j != 0; j = j->next) { + if (recur_item_inday(j->start, j->rpt->type, j->rpt->freq, + j->rpt->until, date)) { + a_nb++; + ptr = day_add_apoint(RECUR_APPT, j->mesg, j->start, j->dur); + } + } + + return a_nb; +} + +/* + * Store the apoints for the selected day in structure pointed + * by day_items_ptr. This is done by copying the appointments + * from the general structure pointed by apointlist to the structure + * dedicated to the selected day. + * Returns the number of appointments for the selected day. + */ +int day_store_apoints(long date) +{ + struct apoint_s *j; + struct day_item_s *ptr; + int a_nb = 0; + + for (j = apointlist; j != 0; j = j->next) { + if (apoint_inday(j, date)) { + a_nb++; + ptr = day_add_apoint(APPT, j->mesg, j->start, j->dur); + } + } + + return a_nb; +} + +/* Add an event in the current day list */ +struct day_item_s *day_add_event(int type, char *mesg, long day, int id) +{ + struct day_item_s *o, **i; + o = (struct day_item_s *) malloc(sizeof(struct day_item_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->type = type; + o->appt_dur = 0; + o->start = day; + o->evnt_id = id; + i = &day_items_ptr; + for (;;) { + if (*i == 0 || (*i)->start > day) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +/* Add an appointment in the current day list. */ +struct day_item_s *day_add_apoint(int type, char *mesg, long start, long dur) +{ + struct day_item_s *o, **i; + o = (struct day_item_s *) malloc(sizeof(struct day_item_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->start = start; + o->appt_dur = dur; + o->type = type; + o->evnt_id = 0; + i = &day_items_ptr; + for (;;) { + if (*i == 0 || (*i)->start > start) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +/* + * Write the appointments and events for the selected day in a pad. + * An horizontal line is drawn between events and appointments, and the + * item selected by user is highlighted. This item is also saved inside + * structure (pointed by day_saved_item), to be later displayed in a + * popup window if requested. + */ +void day_write_pad(long date, int width, int length, int incolor, int colr) +{ + struct day_item_s *p; + int line, item_number, max_pos; + const int x_pos = 0; + bool draw_line = true; + + line = item_number = 0; + max_pos = length; + + /* Initialize the structure used to store highlited item. */ + if (day_saved_item == NULL) { + day_saved_item = (struct day_saved_item_s *) + malloc(sizeof(struct day_saved_item_s)); + day_saved_item->mesg = (char *) malloc(1); + } + + for (p = day_items_ptr; p != 0; p = p->next) { + + /* First print the events for current day. */ + if (p->type < RECUR_APPT) { + item_number++; + if (item_number - incolor == 0) { + day_saved_item->type = p->type; + day_saved_item->mesg = (char *) + realloc(day_saved_item->mesg, + strlen(p->mesg) + 1); + day_saved_item->mesg = p->mesg; + } + display_item(apad->ptrwin, item_number - incolor, p->mesg, + width - 4, line, x_pos); + line++; + } else { + /* Draw a line between events and appointments. */ + if (line > 0 && draw_line){ + wmove(apad->ptrwin, line, x_pos); + whline(apad->ptrwin, 0, width); + draw_line = false; + } + + /* Last print the appointments for current day. */ + item_number++; + if (item_number - incolor == 0) { + day_saved_item->type = p->type; + day_saved_item->mesg = (char *) + realloc(day_saved_item->mesg, + strlen(p->mesg) + 1); + day_saved_item->mesg = p->mesg; + apoint_sec2str(day_item_s2apoint_s(p), + p->type, date, + day_saved_item->start, + day_saved_item->end); + } + display_item_date(apad->ptrwin, item_number - incolor, + day_item_s2apoint_s(p), p->type, date, + line + 1, x_pos); + display_item(apad->ptrwin, item_number - incolor, p->mesg, + width - 6, line + 2, x_pos + 2); + line = line + 3; + } + } +} + +/* Returns a structure of type apoint_s given a structure of type day_item_s */ +struct apoint_s *day_item_s2apoint_s(struct day_item_s *p) +{ + struct apoint_s *a; + + a = (struct apoint_s *) malloc(sizeof(struct apoint_s)); + a->mesg = (char *) malloc(strlen(p->mesg) + 1); + a->start = p->start; + a->dur = p->appt_dur; + a->mesg = p->mesg; + return a; +} + +/* Display an item inside a popup window. */ +void day_popup_item(void) +{ + char *error = + _("FATAL ERROR in day_popup_item: unknown item type\n"); + + if (day_saved_item->type == EVNT || day_saved_item->type == RECUR_EVNT) + item_in_popup(NULL, NULL, day_saved_item->mesg, _("Event :")); + else if (day_saved_item->type == APPT || + day_saved_item->type == RECUR_APPT) + item_in_popup(day_saved_item->start, day_saved_item->end, + day_saved_item->mesg, _("Appointment :")); + else { /* NOT REACHED */ + fputs(error, stderr); + exit(EXIT_FAILURE); + } +} + +/* + * Need to know if there is an item for the current selected day inside + * calendar. This is used to put the correct colors inside calendar panel. + */ + int day_check_if_item(int year, int month, int day) { + struct recur_event_s *re; + struct recur_apoint_s *ra; + struct event_s *e; + struct apoint_s *a; + const long date = date2sec(year, month, day, 0, 0); + + for (re = recur_elist; re != 0; re = re->next) + if (recur_item_inday(re->day, re->rpt->type, re->rpt->freq, + re->rpt->until, date)) + return 1; + + for (ra = recur_alist; ra != 0; ra = ra->next) + if (recur_item_inday(ra->start, ra->rpt->type, ra->rpt->freq, + ra->rpt->until, date)) + return 1; + + for (e = eventlist; e != 0; e = e->next) + if (event_inday(e, date)) + return 1; + + for (a = apointlist; a != 0; a = a->next) + if (apoint_inday(a, date)) + return 1; + + return 0; +} diff --git a/src/day.h b/src/day.h new file mode 100755 index 0000000..8426704 --- /dev/null +++ b/src/day.h @@ -0,0 +1,66 @@ +/* $calcurse: day.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_DAY_H +#define CALCURSE_DAY_H + +#include "apoint.h" + +#define RECUR_EVNT 1 +#define EVNT 2 +#define RECUR_APPT 3 +#define APPT 4 + +struct day_item_s { + struct day_item_s *next; + int type; /* (recursive or normal) event or appointment */ + long start; /* seconds since 1 jan 1970 */ + char *mesg; /* item description */ + int evnt_id; /* event identifier */ + long appt_dur; /* appointment duration in seconds */ +}; + +struct day_saved_item_s { + int type ; + char *mesg; + char start[100]; + char end[100]; +}; + +int day_store_items(long date, int *pnb_events, int *pnb_apoints); +void day_free_list(void); +int day_store_recur_events(long date); +int day_store_events(long date); +int day_store_recur_apoints(long date); +int day_store_apoints(long date); +struct day_item_s *day_add_event(int type, char *mesg, long day, int id); +struct day_item_s *day_add_apoint(int type, char *mesg, long start, long dur); +void day_write_pad(long date, int width, int length, int incolor, int colr); +struct apoint_s *day_item_s2apoint_s(struct day_item_s *p); +void day_popup_item(void); +int day_check_if_item(int year, int month, int day); + +#endif /* CALCURSE_DAY_H */ diff --git a/src/event.c b/src/event.c new file mode 100755 index 0000000..4cf3953 --- /dev/null +++ b/src/event.c @@ -0,0 +1,135 @@ +/* $calcurse: event.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "i18n.h" +#include "event.h" +#include "utils.h" + +struct event_s *eventlist; + +/* Create a new event */ +struct event_s *event_new(char *mesg, long day, int id) +{ + struct event_s *o, **i; + o = (struct event_s *) malloc(sizeof(struct event_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->day = day; + o->id = id; + i = &eventlist; + for (;;) { + if (*i == 0 || (*i)->day > day) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +/* Check if the event belongs to the selected day */ +unsigned event_inday(struct event_s *i, long start) +{ + if (i->day <= start + 3600 * 24 && i->day > start) { + return 1; + } + return 0; +} + +/* Write to file the event in user-friendly format */ +void event_write(struct event_s *o, FILE * f) +{ + struct tm *lt; + time_t t; + + t = o->day; + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u [%d] %s\n", + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, o->id, o->mesg); +} + +/* Load the events from file */ +struct event_s *event_scan(FILE * f, struct tm start, int id) +{ + struct tm *lt; + char buf[MESG_MAXSIZE], *nl; + time_t tstart, t; + + t = time(NULL); + lt = localtime(&t); + + /* Read the event description */ + fgets(buf, MESG_MAXSIZE, f); + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + start.tm_hour = 12; + start.tm_min = 0; + start.tm_sec = 0; + start.tm_isdst = -1; + start.tm_year -= 1900; + start.tm_mon--; + + tstart = mktime(&start); + if (tstart == -1) { + fputs(_("FATAL ERROR in event_scan: date error in the event\n"), stderr); + exit(EXIT_FAILURE); + } + return event_new(buf, tstart, id); +} + +/* Delete an event from the list */ +void event_delete_bynum(long start, unsigned num) +{ + unsigned n; + struct event_s *i, **iptr; + + n = 0; + iptr = &eventlist; + for (i = eventlist; i != 0; i = i->next) { + if (event_inday(i, start)) { + if (n == num) { + *iptr = i->next; + free(i->mesg); + free(i); + return; + } + n++; + } + iptr = &i->next; + } + /* NOTREACHED */ + fputs(_("FATAL ERROR in event_delete_bynum: no such event\n"), stderr); + exit(EXIT_FAILURE); +} diff --git a/src/event.h b/src/event.h new file mode 100755 index 0000000..6e06691 --- /dev/null +++ b/src/event.h @@ -0,0 +1,48 @@ +/* $calcurse: event.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_EVENT_H +#define CALCURSE_EVENT_H + +#define HRMIN_SIZE 6 +#define MESG_MAXSIZE 256 + +struct event_s { + struct event_s *next; + int id; /* event identifier */ + long day; /* seconds since 1 jan 1970 */ + char *mesg; +}; + +extern struct event_s *eventlist; + +struct event_s *event_new(char *, long, int); +unsigned event_inday(struct event_s *o, long start); +void event_write(struct event_s *o, FILE * f); +struct event_s *event_scan(FILE * f, struct tm start, int id); +void event_delete_bynum(long start, unsigned num); + +#endif /* CALCURSE_EVENT_H */ diff --git a/src/help.c b/src/help.c new file mode 100755 index 0000000..f586e74 --- /dev/null +++ b/src/help.c @@ -0,0 +1,375 @@ +/* $calcurse: help.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <sys/types.h> + +#include "i18n.h" +#include "help.h" +#include "custom.h" +#include "vars.h" +#include "utils.h" + +/* + * Write the desired help text inside the help pad, and return the number + * of lines that were written. + * */ +int write_help_pad(WINDOW *win, char *title, char *text, int pad_width) +{ + int nl_title = 0; + int nl_text = 0; + + nl_text = get_help_lines(text); + nl_title = get_help_lines(title); + erase_window_part(win, 0, 0, MAX_LENGTH, pad_width); + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, 0, 0, "%s", title); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, nl_title, 0, "%s", text); + return nl_text + nl_title; +} + +int get_help_lines(char *text) +{ + int i; + int nl = 0; + + for (i = 0; text[i]; i++) { + if (text[i] == '\n') nl++; + } + return nl + 1; +} + +/* Draws the help screen */ +void help_screen(int which_pan, int colr) +{ + WINDOW *help_win = NULL; + WINDOW *help_pad = NULL; + char label[80]; + int ch = '?'; + int help_row = row - 2; //size of the help window + int help_col = col; + int title_lines = 3; + int pad_offset = 4; + int text_lines = help_row - (pad_offset + 1); + int pad_width = help_col - 2*pad_offset + 1; + int first_line = 0, nl = 0; + + help_page_t help_main; + help_page_t help_redraw; + help_page_t help_save; + help_page_t help_displacement; + help_page_t help_view; + help_page_t help_tab; + help_page_t help_goto; + help_page_t help_delete; + help_page_t help_add; + help_page_t help_config; + help_page_t help_credits; + + help_main.title = + _(" Welcome to Calcurse. This is the main help screen.\n"); + help_main.text = + _(" Moving around: Press CTRL-P or CTRL-N to scroll text upward or\n" + " downward inside help screens, if necessary.\n\n" + " Exit help: When finished, press 'Q' to exit help and go back\n" + " to the main Calcurse screen.\n\n" + " Help topic: At the bottom of this screen you can see a panel\n" + " with different fields, represented by a letter and\n" + " a short title. This panel contains all the available\n" + " actions you can perform when using Calcurse.\n" + " By pressing one of the letters appearing in this\n" + " panel, you will be shown a short description of the\n" + " corresponding action.\n\n" + " Credits: Press '@' for credits."); + + help_redraw.title = _("Redraw:\n"); + help_redraw.text = + _("Pressing 'R' redraws the Calcurse panels.\n\n" + "You might want to use this function when you resize your terminal\n" + "screen for example, and you want Calcurse to take into account the new\n" + "size of the terminal.\n\n" + "This function can also be useful when garbage appears in the display,\n" + "and you want to clean it."); + + help_save.title = _("Save:\n"); + help_save.text = + _("Pressing 'S' saves the Calcurse data.\n\n" + "The data is splitted into three different files which contains :" + "\n\n" + " / ~/.calcurse/conf -> the user configuration\n" + " | (layout, color, general options)\n" + " | ~/.calcurse/apts -> the data related to the appointments\n" + " \\ ~/.calcurse/todo -> the data related to the todo list\n" + "\nIn the config menu, you can choose to save the Calcurse data\n" + "automatically before quitting."); + + help_displacement.title = _("Displacement keys:\n"); + help_displacement.text = + _("You can use either 'H','J','K','L' or the arrow keys '<','v','^','>'\n" + "to move into the calendar.\n\n" + "The following scheme explains how :\n\n" + " move to previous week\n" + " K ^ \n" + " move to previous day H < > L move to next day\n" + " J v \n" + " move to next week\n" + "\nWhen the Appointment or ToDo panel is selected, the up and down keys\n" + "(respectively K or up arrow, and J or down arrow) allows you to select\n" + "an item from those lists."); + + help_view.title = _("View:\n"); + help_view.text = + _("Pressing 'V' allows you to view the item you select in either the ToDo\n" + "or Appointment panel.\n" + "\nThis is usefull when an event description is longer than the available\n" + "space to display it. If that is the case, the description will be\n" + "shortened and its end replaced by '...'. To be able to read the entire\n" + "description, just press 'V' and a popup window will appear, containing\n" + "the whole event.\n" + "\nPress any key to close the popup window and go back to the main\n" + "Calcurse screen."); + + help_tab.title = _("Tab:\n"); + help_tab.text = + _("Pressing 'Tab' allows you to switch between panels.\n" + "The panel currently in use has its border colorized.\n" + "\nSome actions are possible only if the right panel is selected.\n" + "For example, if you want to add a task in the TODO list, you need first\n" + "to press the 'Tab' key to get the TODO panel selected. Then you can\n" + "press 'A' to add your item.\n" + "\nNotice that at the bottom of the screen the list of possible actions\n" + "change while pressing 'Tab', so you always know what action can be\n" + "performed on the selected panel."); + + help_goto.title = _("Goto:\n"); + help_goto.text = + _("Pressing 'G' allows you to jump to a specific day in the calendar.\n" + "\nUsing this command, you do not need to travel to that day using\n" + "the displacement keys inside the calendar panel.\n" + "If you hit [ENTER] without specifying any date, Calcurse checks the\n" + "system current date and you will be taken to that date."); + + help_delete.title = _("Delete:\n"); + help_delete.text = + _("Pressing 'D' deletes an element in the ToDo or Appointment list.\n" + "\nDepending on which panel is selected when you press the delete key,\n" + "the hilighted item of either the ToDo or Appointment list will be \n" + "removed from this list.\n" + "\nIf the general option 'confirm_delete' is set to 'YES', then you will\n" + "be asked for confirmation before deleting the selected event.\n" + "Do not forget to save the calendar data to retrieve the modifications\n" + "next time you launch Calcurse."); + + help_add.title = _("Add:\n"); + help_add.text = + _("Pressing 'A' allows you to add an item in either the ToDo or Appointment\n" + "list, depending on which panel is selected when you press 'A'.\n" + "\nTo enter a new item in the TODO list, you only need to enter the\n" + "description of this new item.\n" + "\nIf the APPOINTMENT panel is selected while pressing 'A', you will be\n" + "able to enter either a new appointment or a new all-day long event.\n" + "To enter a new event, press [ENTER] instead of the item start time, and\n" + "just fill in the event description.\n" + "To enter a new appointment to be added in the APPOINTMENT list, you\n" + "will need to enter successively the time at which the appointment\n" + "begins, the appointment length (either by specifying the duration in\n" + "minutes, or the end time in [hh:mm] or [h:mm] format), and the\n" + "description of the event.\n" + "\nThe day at which occurs the event or appointment is the day currently\n" + "selected in the calendar, so you need to move to the desired day before\n" + "pressing 'A'.\n" + "\nNotes:\n" + " o if an appointment lasts for such a long time that it continues\n" + " on the next days, this event will be indicated on all the\n" + " corresponding days, and the beginning or ending hour will be\n" + " replaced by '..' if the event does not begin or end on the day.\n" + " o if you only press [ENTER] at the APPOINTMENT or TODO event\n" + " description prompt, without any description, no item will be\n" + " added.\n" + " o do not forget to save the calendar data to retrieve the new\n" + " event next time you launch Calcurse."); + + help_config.title = _("Config:\n"); + help_config.text = + _("Pressing 'C' leads to the configuration submenu, from which you can\n" + "select between color, layout, and general options.\n" + "\nThe color submenu lets you choose the color theme.\n" + "\nThe layout submenu lets you choose the Calcurse screen layout, in other\n" + "words where to place the three different panels on the screen.\n" + "\nThe general options submenu brings a screen with the different options\n" + "which modifies the way Calcurse interacts with the user.\n" + "\nDo not forget to save the calendar data to retrieve your configuration\n" + "next time you launch Calcurse."); + + help_credits.title = _("Calcurse - text-based organizer"); + help_credits.text = + _("Copyright (c) 2004-2006 Frederic Culot\n" + "\n" + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\nThis program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n\n" + "Send your feedback or comments to : calcurse@culot.org\n" + "Calcurse home page : http://culot.org/calcurse"); + + /* + * Create the help window and panel. The panel is used to make + * the scrolling faster. + */ + help_win = newwin(help_row, help_col, 0, 0); + help_pad = newpad(MAX_LENGTH, pad_width); + box(help_win, 0, 0); + sprintf(label, _("CalCurse %s | help"), VERSION); + win_show(help_win, label); + + /* Display the main help screen. */ +/* nl = write_help_pad(help_pad, help_main.title, help_main.text, pad_width); + status_bar(which_pan, colr, col, 2); + wmove(swin, 0, 0); + wnoutrefresh(help_win); + pnoutrefresh(help_pad, first_line, 0, pad_offset, pad_offset, + help_row - 2, help_col - pad_offset); + doupdate(); +*/ + + /* Display the help screen related to user input. */ + while ( ch != 'q' ) { + erase_window_part(help_win, 1, title_lines, + help_col - 2, help_row - 2); + + switch (ch) { + + case CTRL('N') : + if (nl > first_line + text_lines) first_line++; + break; + + case CTRL('P') : + if (first_line > 0) first_line--; + break; + + case '?': + first_line = 0; + nl = write_help_pad(help_pad, help_main.title, + help_main.text, pad_width); + break; + case 'r': + first_line = 0; + nl = write_help_pad(help_pad, help_redraw.title, + help_redraw.text, pad_width); + break; + case 's': + first_line = 0; + nl = write_help_pad(help_pad, help_save.title, + help_save.text, pad_width); + break; + case 'h': + case 'l': + case 'j': + case 'k': + case 259: + case 258: + case 260: + case 261: + first_line = 0; + nl = write_help_pad(help_pad, help_displacement.title, + help_displacement.text, pad_width); + break; + + case 'a': + first_line = 0; + nl = write_help_pad(help_pad, help_add.title, + help_add.text, pad_width); + break; + + case 'g': + first_line = 0; + nl = write_help_pad(help_pad, help_goto.title, + help_goto.text, pad_width); + break; + + case 'd': + first_line = 0; + nl = write_help_pad(help_pad, help_delete.title, + help_delete.text, pad_width); + break; + + case 'c': + first_line = 0; + nl = write_help_pad(help_pad, help_config.title, + help_config.text, pad_width); + break; + + case 'v': + first_line = 0; + nl = write_help_pad(help_pad, help_view.title, + help_view.text, pad_width); + break; + + case 9: + first_line = 0; + nl = write_help_pad(help_pad, help_tab.title, + help_tab.text, pad_width); + break; + + case '@': + first_line = 0; + nl = write_help_pad(help_pad, help_credits.title, + help_credits.text, pad_width); + break; + } + + /* Draw the scrollbar if necessary. */ + if (nl > text_lines){ + float ratio = ((float) text_lines + 1) / ((float) nl); + int sbar_length = (int) (ratio * text_lines); + int highend = (int) (ratio * first_line); + int sbar_top = highend + title_lines + 1; + + draw_scrollbar(help_win, sbar_top, help_col - 2, + sbar_length, title_lines + 1, + help_row - 1, true); + } + + wmove(swin, 0, 0); + wnoutrefresh(help_win); + pnoutrefresh(help_pad, first_line, 0, + pad_offset, pad_offset, + help_row - 2, help_col - pad_offset); + doupdate(); + ch = wgetch(swin); + } + delwin(help_pad); + delwin(help_win); +} diff --git a/src/help.h b/src/help.h new file mode 100755 index 0000000..5aa830f --- /dev/null +++ b/src/help.h @@ -0,0 +1,41 @@ +/* $calcurse: help.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_HELP_H +#define CALCURSE_HELP_H + +#include <ncurses.h> + +typedef struct { + char *title; + char *text; +} help_page_t; + +int write_help_pad(WINDOW *win, char *title, char *text, int pad_width); +int get_help_lines(char *text); +void help_screen(int which_pan, int colr); + +#endif /* CALCURSE_HELP_H */ diff --git a/src/i18n.h b/src/i18n.h new file mode 100755 index 0000000..454a084 --- /dev/null +++ b/src/i18n.h @@ -0,0 +1,54 @@ +/* $calcurse: i18n.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_I18N_H +#define CALCURSE_I18N_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#if ENABLE_NLS + #include <libintl.h> + #undef _ + #define _(String) gettext(String) + #ifdef gettext_noop + #define N_(String) gettext_noop(String) + #else + #define N_(String) (String) + #endif +#else /* NLS disabled */ + #define _(String) (String) + #define N_(String) (String) + #define textdomain(String) (String) + #define gettext(String) (String) + #define dgettext(String) (String) + #define dcgettext(String) (String) + #define bindtextdomain(String) (String) + #define bind_textdomain_codeset(Domain,Codeset) (Codeset) +#endif /* ENABLE_NLS */ + +#endif /* CALCURSE_I18N_H */ diff --git a/src/io.c b/src/io.c new file mode 100755 index 0000000..35c5802 --- /dev/null +++ b/src/io.c @@ -0,0 +1,484 @@ +/* $calcurse: io.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <math.h> +#include <unistd.h> + +#include "i18n.h" +#include "utils.h" +#include "custom.h" +#include "todo.h" +#include "event.h" +#include "apoint.h" +#include "recur.h" +#include "io.h" +#include "vars.h" + +/* + * Initialization of data paths. The argument cfile is the variable + * which contains the calendar file. If none is given, then the default + * one (~/.calcurse/apts) is taken. If the one given does not exist, it + * is created. + */ +void +io_init(char *cfile) +{ + FILE *data_file; + char *home; + char apts_file[MAX_LENGTH] = ""; + int ch; + + home = getenv("HOME"); + if (home == NULL) { + home = "."; + } + snprintf(path_dir, MAX_LENGTH, "%s/" DIR_NAME, home); + snprintf(path_todo, MAX_LENGTH, "%s/" TODO_PATH, home); + snprintf(path_conf, MAX_LENGTH, "%s/" CONF_PATH, home); + if (cfile == NULL) { + snprintf(path_apts, MAX_LENGTH, "%s/" APTS_PATH, home); + } else { + snprintf(apts_file, MAX_LENGTH, "%s", cfile); + strncpy(path_apts, apts_file, MAX_LENGTH); + /* check if the file exists, otherwise create it */ + data_file = fopen(path_apts, "r"); + if (data_file == NULL) { + printf(_("%s does not exist, create it now [y or n] ? "), path_apts); + ch = getchar(); + switch (ch) { + case 'N': + case 'n': + printf(_("aborting...\n")); + exit(EXIT_FAILURE); + break; + + case 'Y': + case 'y': + data_file = fopen(path_apts, "w"); + if (data_file == NULL) { + perror(path_apts); + exit(EXIT_FAILURE); + } else { + printf(_("%s successfully created\n"),path_apts); + printf(_("starting interactive mode...\n")); + } + break; + + default: + printf(_("aborting...\n")); + exit(EXIT_FAILURE); + break; + } + } + fclose(data_file); + } +} + + /* get data from file */ +void extract_data(char *dst_data, const char *org, int len) +{ + for (;;) { + if (*org == '\n' || *org == '\0') + break; + *dst_data++ = *org++; + } + *dst_data = '\0'; +} + +/* Save the calendar data */ +void +save_cal(bool auto_save, bool confirm_quit, + bool confirm_delete, bool skip_system_dialogs, + bool skip_progress_bar, bool week_begins_on_monday, + int colr, int layout) +{ + FILE *data_file; + struct event_s *k; + struct apoint_s *j; + struct todo_s *i; + char *access_pb = _("Problems accessing data file ..."); + char *config_txt = + "#\n# Calcurse configuration file\n#\n# This file sets the configuration options used by Calcurse. These\n# options are usually set from within Calcurse. A line beginning with \n# a space or tab is considered to be a continuation of the previous line.\n# For a variable to be unset its value must be blank.\n# To set a variable to the empty string its value should be \"\".\n# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n"; + char *save_success = _("The data files were successfully saved"); + char *enter = _("Press [ENTER] to continue"); + bool save = true, show_bar = false; + + if (!skip_progress_bar) show_bar = true; + + /* Save the user configuration. */ + + if (show_bar) progress_bar(save, 1); + data_file = fopen(path_conf, "w"); + if (data_file == (FILE *) 0) + status_mesg(access_pb, ""); + else { + fprintf(data_file, "%s\n", config_txt); + + fprintf(data_file, + "# If this option is set to yes, automatic save is done when quitting\n"); + fprintf(data_file, "auto_save=\n"); + fprintf(data_file, "%s\n", + (auto_save) ? "yes" : "no"); + + fprintf(data_file, + "\n# If this option is set to yes, confirmation is required before quitting\n"); + fprintf(data_file, "confirm_quit=\n"); + fprintf(data_file, "%s\n", + (confirm_quit) ? "yes" : "no"); + + fprintf(data_file, + "\n# If this option is set to yes, confirmation is required before deleting an event\n"); + fprintf(data_file, "confirm_delete=\n"); + fprintf(data_file, "%s\n", + (confirm_delete) ? "yes" : "no"); + + fprintf(data_file, + "\n# If this option is set to yes, messages about loaded and saved data will not be displayed\n"); + fprintf(data_file, "skip_system_dialogs=\n"); + fprintf(data_file, "%s\n", + (skip_system_dialogs) ? "yes" : "no"); + + fprintf(data_file, + "\n# If this option is set to yes, progress bar appearing when saving data will not be displayed\n"); + fprintf(data_file, "skip_progress_bar=\n"); + fprintf(data_file, "%s\n", + (skip_progress_bar) ? "yes" : "no"); + + fprintf(data_file, + "\n# If this option is set to yes, monday is the first day of the week, else it is sunday\n"); + fprintf(data_file, "week_begins_on_monday=\n"); + fprintf(data_file, "%s\n", + (week_begins_on_monday) ? "yes" : "no"); + + fprintf(data_file, + "\n# This is the color theme used for menus (1 to 8) :\n"); + fprintf(data_file, "color-theme=\n"); + fprintf(data_file, "%d\n", colr); + + fprintf(data_file, + "\n# This is the layout of the calendar (1 to 4) :\n"); + fprintf(data_file, "layout=\n"); + fprintf(data_file, "%d\n", layout); + fclose(data_file); + } + + /* Save the todo data file. */ + if (show_bar) progress_bar(save, 2); + data_file = fopen(path_todo, "w"); + if (data_file == (FILE *) 0) + status_mesg(access_pb, ""); + else { + for (i = todolist; i != 0; i = i->next) + fprintf(data_file, "%s\n", i->mesg); + fclose(data_file); + } + + /* + * Save the apts data file, which contains the + * appointments first, and then the events. + * Recursive items are written first. + */ + if (show_bar) progress_bar(save, 3); + data_file = fopen(path_apts, "w"); + if (data_file == (FILE *) 0) + status_mesg(access_pb, ""); + else { + recur_save_data(data_file); + for (j = apointlist; j != 0; j = j->next) + apoint_write(j, data_file); + for (k = eventlist; k != 0; k = k->next) + event_write(k, data_file); + fclose(data_file); + } + + + /* Print a message telling data were saved */ + if (!skip_system_dialogs){ + status_mesg(save_success, enter); + wgetch(swin); + } +} + +/* + * Check what type of data is written in the appointment file, + * and then load either: a new appointment, a new event, or a new + * recursive item (which can also be either an event or an appointment). + */ +void load_app() +{ + FILE *data_file; + int c, is_appointment, is_event, is_recursive; + struct tm start, end, until, *lt; + time_t t; + int id = 0; + int freq; + char type; + char *error = + _("FATAL ERROR in load_app: wrong format in the appointment or event\n"); + + t = time(NULL); + lt = localtime(&t); + start = end = until = *lt; + + data_file = fopen(path_apts, "r"); + for (;;) { + is_appointment = is_event = is_recursive = 0; + c = getc(data_file); + if (c == EOF) + break; + ungetc(c, data_file); + + /* Read the date first: it is common to both events + * and appointments. + */ + if (fscanf(data_file, "%u / %u / %u ", + &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) { + fputs(_("FATAL ERROR in load_app: " + "syntax error in the item date\n"), stderr); + exit(EXIT_FAILURE); + } + + /* Read the next character : if it is an '@' then we have + * an appointment, else if it is an '[' we have en event. + */ + c = getc(data_file); + + if (c == '@') + is_appointment = 1; + else if (c == '[') + is_event = 1; + else { + fputs(_("FATAL ERROR in load_app: " + "no event nor appointment found\n"), stderr); + exit(EXIT_FAILURE); + } + ungetc(c, data_file); + + /* Read the remaining informations. */ + if (is_appointment) { + fscanf(data_file, "@ %u : %u -> %u / %u / %u @ %u : %u ", + &start.tm_hour, &start.tm_min, + &end.tm_mon, &end.tm_mday, &end.tm_year, + &end.tm_hour, &end.tm_min); + } else if (is_event) { + fscanf(data_file, "[%d] ", &id); + } else { /* NOT REACHED */ + fputs(error, stderr); + exit(EXIT_FAILURE); + } + + /* Check if we have a recursive item. */ + c = getc(data_file); + + if (c == '{') { + ungetc(c, data_file); + is_recursive = 1; + fscanf(data_file, "{ %d%c ", &freq, &type); + /* Check if we have an endless recurrent item. */ + c = getc(data_file); + if (c == '}') { + ungetc(c, data_file); + fscanf(data_file, "} "); + until.tm_year = 0; + if (is_appointment) + c = getc(data_file); // useless '|' + } else if (c == '-') { + ungetc(c, data_file); + fscanf(data_file, " -> %u / %u / %u } ", + &until.tm_mon, &until.tm_mday, + &until.tm_year); + if (is_appointment) + c = getc(data_file); // useless '|' + } else { /* NOT REACHED */ + fputs(error, stderr); + exit(EXIT_FAILURE); + } + } else { + if (is_event) // if appointment we have a useless '|' + ungetc(c, data_file); + } + + /* + * Last: read the item description and load it into its + * corresponding linked list, depending on the item type. + */ + if (is_appointment) { + if (is_recursive) { + recur_apoint_scan(data_file, start, end, + type, freq, until); + } else { + apoint_scan(data_file, start, end); + } + } else if (is_event) { + if (is_recursive) { + recur_event_scan(data_file, start, id, + type, freq, until); + } else { + event_scan(data_file, start, id); + } + } else { /* NOT REACHED */ + fputs(error, stderr); + exit(EXIT_FAILURE); + } + } + fclose(data_file); +} + +/* Load the todo data */ +int +load_todo(int colr) +{ + FILE *data_file; + char *mesg_line1 = _("Failed to open todo file"); + char *mesg_line2 = _("Press [ENTER] to continue"); + int nb_tod = 0; + char buf[100], e_todo[100]; + + data_file = fopen(path_todo, "r"); + if (data_file == NULL) { + status_mesg(mesg_line1, mesg_line2); + wgetch(swin); + } + for (;;) { + if (fgets(buf, 99, data_file) == NULL) { + break; + } + extract_data(e_todo, buf, strlen(buf)); + todo_add(e_todo); + ++nb_tod; + } + fclose(data_file); + return nb_tod; +} + +/* Checks if data files exist. If not, create them */ +int check_data_files() +{ + FILE *data_file; + int no_data_file; + + no_data_file = 0; + /* Create the calcurse repertory if not present. */ + mkdir(path_dir, 0700); + + data_file = fopen(path_todo, "r"); + if (data_file == NULL) { + no_data_file++; + data_file = fopen(path_todo, "w"); + if (data_file == NULL) { + perror(path_todo); + return no_data_file; + } + } + fclose(data_file); + + data_file = fopen(path_apts, "r"); + if (data_file == NULL) { + no_data_file++; + data_file = fopen(path_apts, "w"); + if (data_file == NULL) { + perror(path_apts); + return no_data_file; + } + } + fclose(data_file); + + data_file = fopen(path_conf, "r"); + if (data_file == NULL) { + no_data_file++; + data_file = fopen(path_conf, "w"); + if (data_file == NULL) { + perror(path_conf); + return no_data_file; + } + } + fclose(data_file); + return no_data_file; +} + +/* Draw the startup screen */ +void startup_screen(bool skip_dialogs, int no_data_file, int colr) +{ + char *welcome_mesg = _("Welcome to Calcurse. Missing data files were created."); + char *data_mesg = _("Data files found. Data will be loaded now."); + char *enter = _("Press [ENTER] to continue"); + + if (no_data_file != 0) { + status_mesg(welcome_mesg, enter); + wgetch(swin); + } else if (!skip_dialogs){ + status_mesg(data_mesg, enter); + wgetch(swin); + } +} + +/* Draw a progress bar while saving or loading data. */ +void progress_bar(bool save, int progress) +{ + int i, nbd = 4; + char *mesg_sav = _("Saving..."); + char *mesg_load = _("Loading..."); + char *barchar = "|"; + char *data[4] = { + "[ ]", + "[ conf ]", + "[ todo ]", + "[ apts ]"}; + int ipos = strlen(data[1]) + 2; + int epos[4]; + int sleep_time = 125000; + + /* progress bar length init. */ + epos[0] = floor(col / nbd); + epos[1] = 2*epos[0]; + epos[2] = 3*epos[0]; + epos[3] = col - 2; + + /* Display which data is being saved. */ + if (save) + status_mesg(mesg_sav, data[progress]); + else + status_mesg(mesg_load, data[progress]); + + /* Draw the progress bar. */ + mvwprintw(swin, 1, ipos, barchar); + mvwprintw(swin, 1, epos[nbd - 1], barchar); + custom_apply_attr(swin, ATTR_HIGHEST); + for (i = ipos + 1; i < epos[progress]; i++) + mvwaddch(swin, 1, i, ' ' | A_REVERSE); + custom_remove_attr(swin, ATTR_HIGHEST); + wmove(swin, 0, 0); + wrefresh(swin); + usleep(sleep_time); +} diff --git a/src/io.h b/src/io.h new file mode 100755 index 0000000..8cc7788 --- /dev/null +++ b/src/io.h @@ -0,0 +1,42 @@ +/* $calcurse: io.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_IO_H +#define CALCURSE_IO_H + +void io_init(char *cfile); +void extract_data(char *dst_data, const char *org, int len); +void save_cal(bool auto_save, bool confirm_quit, + bool confirm_delete, bool skip_system_dialogs, + bool skip_progress_bar, bool week_begins_on_monday, + int colr, int layout); +void load_app(); +int load_todo(int colr); +int check_data_files(); +void startup_screen(bool skip_dialogs, int no_data_file, int colr); +void progress_bar(bool save, int progress); + +#endif /* CALCURSE_IO_H */ diff --git a/src/recur.c b/src/recur.c new file mode 100755 index 0000000..d0629aa --- /dev/null +++ b/src/recur.c @@ -0,0 +1,355 @@ +/* $calcurse: recur.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "i18n.h" +#include "utils.h" +#include "apoint.h" +#include "event.h" +#include "recur.h" + +struct recur_apoint_s *recur_alist; +struct recur_event_s *recur_elist; + +/* Insert a new recursive appointment in the general linked list */ +struct recur_apoint_s *recur_apoint_new(char *mesg, long start, long dur, + int type, int freq, long until) +{ + struct recur_apoint_s *o, **i; + o = (struct recur_apoint_s *) malloc(sizeof(struct recur_apoint_s)); + o->rpt = (struct rpt_s *) malloc(sizeof(struct rpt_s)); + o->exc = (struct days_s *) malloc(sizeof(struct days_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->start = start; + o->dur = dur; + o->rpt->type = type; + o->rpt->freq = freq; + o->rpt->until = until; + i = &recur_alist; + for (;;) { + if (*i == 0 || (*i)->start > start) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +/* Insert a new recursive event in the general linked list */ +struct recur_event_s *recur_event_new(char *mesg, long day, int id, + int type, int freq, long until) +{ + struct recur_event_s *o, **i; + o = (struct recur_event_s *) malloc(sizeof(struct recur_event_s)); + o->rpt = (struct rpt_s *) malloc(sizeof(struct rpt_s)); + o->exc = (struct days_s *) malloc(sizeof(struct days_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->day = day; + o->id = id; + o->rpt->type = type; + o->rpt->freq = freq; + o->rpt->until = until; + i = &recur_elist; + for (;;) { + if (*i == 0 || (*i)->day > day) { + o->next = *i; + *i = o; + break; + } + i = &(*i)->next; + } + return o; +} + +/* + * Correspondance between the defines on recursive type, + * and the letter to be written in file. + */ +char recur_def2char(int define){ + char recur_char; + + switch (define) { + case 1: + recur_char = 'D'; + break; + case 2: + recur_char = 'W'; + break; + case 3: + recur_char = 'M'; + break; + case 4: + recur_char = 'Y'; + break; + } + return recur_char; +} + +/* + * Correspondance between the letters written in file and the defines + * concerning the recursive type. + */ +int recur_char2def(char type){ + int recur_def; + + switch (type) { + case 'D': + recur_def = RECUR_DAILY; + break; + case 'W': + recur_def = RECUR_WEEKLY; + break; + case 'M': + recur_def = RECUR_MONTHLY; + break; + case 'Y': + recur_def = RECUR_YEARLY; + break; + } + return recur_def; +} + +/* Writting of a recursive appointment into file. */ +void recur_apoint_write(struct recur_apoint_s *o, FILE *f) +{ + struct tm *lt; + time_t t; + + t = o->start; + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u @ %02u:%02u", + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, + lt->tm_hour, lt->tm_min); + + t = o->start + o->dur; + lt = localtime(&t); + fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u", + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, + lt->tm_hour, lt->tm_min); + + t = o->rpt->until; + if (t == 0) { /* We have an endless recurrent appointment. */ + fprintf(f, " {%d%c} |%s\n", o->rpt->freq, + recur_def2char(o->rpt->type), o->mesg); + } else { + lt = localtime(&t); + fprintf(f, " {%d%c -> %02u/%02u/%04u} |%s\n", + o->rpt->freq, recur_def2char(o->rpt->type), + lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, + o->mesg); + } +} + +/* Writting of a recursive event into file. */ +void recur_event_write(struct recur_event_s *o, FILE *f) +{ + struct tm *lt; + time_t t; + int st_mon, st_day, st_year; + int end_mon, end_day, end_year; + + t = o->day; + lt = localtime(&t); + st_mon = lt->tm_mon + 1; + st_day = lt->tm_mday; + st_year = lt->tm_year + 1900; + t = o->rpt->until; + if (t == 0) { /* We have an endless recurrent event. */ + fprintf(f, "%02u/%02u/%04u [%d] {%d%c} %s\n", + st_mon, st_day, st_year, o->id, o->rpt->freq, + recur_def2char(o->rpt->type), o->mesg); + } else { + lt = localtime(&t); + end_mon = lt->tm_mon + 1; + end_day = lt->tm_mday; + end_year = lt->tm_year + 1900; + fprintf(f, "%02u/%02u/%04u [%d] {%d%c -> %02u/%02u/%04u} %s\n", + st_mon, st_day, st_year, o->id, + o->rpt->freq, recur_def2char(o->rpt->type), + end_mon, end_day, end_year, o->mesg); + } +} + +/* Load the recursive appointment description */ +struct recur_apoint_s *recur_apoint_scan(FILE * f, struct tm start, + struct tm end, char type, int freq, struct tm until) +{ + struct tm *lt; + char buf[MESG_MAXSIZE], *nl; + time_t tstart, tend, t, tuntil; + + t = time(NULL); + lt = localtime(&t); + + /* Read the appointment description */ + fgets(buf, MESG_MAXSIZE, f); + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + + start.tm_sec = end.tm_sec = 0; + start.tm_isdst = end.tm_isdst = -1; + start.tm_year -= 1900; + start.tm_mon--; + end.tm_year -= 1900; + end.tm_mon--; + tstart = mktime(&start); + tend = mktime(&end); + + if (until.tm_year != 0) { + until.tm_hour = 12; + until.tm_min = 0; + until.tm_sec = 0; + until.tm_isdst = -1; + until.tm_year -= 1900; + until.tm_mon--; + tuntil = mktime(&until); + } else { + tuntil = 0; + } + + if (tstart == -1 || tend == -1 || tstart > tend || tuntil == -1) { + fputs(_("FATAL ERROR in apoint_scan: date error in the appointment\n"), stderr); + exit(EXIT_FAILURE); + } + + return recur_apoint_new(buf, tstart, tend - tstart, + recur_char2def(type), freq, tuntil); +} + +/* Load the recursive events from file */ +struct recur_event_s *recur_event_scan(FILE * f, struct tm start, int id, + char type, int freq, struct tm until) +{ + struct tm *lt; + char buf[MESG_MAXSIZE], *nl; + time_t tstart, t, tuntil; + + t = time(NULL); + lt = localtime(&t); + + /* Read the event description */ + fgets(buf, MESG_MAXSIZE, f); + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + + start.tm_hour = until.tm_hour = 12; + start.tm_min = until.tm_min = 0; + start.tm_sec = until.tm_sec = 0; + start.tm_isdst = until.tm_isdst = -1; + start.tm_year -= 1900; + start.tm_mon--; + if (until.tm_year != 0) { + until.tm_year -= 1900; + until.tm_mon--; + tuntil = mktime(&until); + } else { + tuntil = 0; + } + tstart = mktime(&start); + if ( (tstart == -1) || (tuntil == -1) ) { + fputs(_("FATAL ERROR in recur_event_scan: date error in the event\n"), stderr); + exit(EXIT_FAILURE); + } + + return recur_event_new(buf, tstart, id, recur_char2def(type), freq, tuntil); +} + +/* Write recursive items to file. */ +void recur_save_data(FILE *f) +{ + struct recur_event_s *re; + struct recur_apoint_s *ra; + + for (re = recur_elist; re != 0; re = re->next) + recur_event_write(re, f); + for (ra = recur_alist; ra != 0; ra = ra->next) + recur_apoint_write(ra, f); +} + +/* Check if the recurrent item belongs to the selected day. */ +unsigned recur_item_inday(long item_start, int rpt_type, int rpt_freq, + long rpt_until, long day_start) +{ + const int DAYINSEC = 86400; + long day_end = day_start + DAYINSEC; + int inday = 0; + struct tm *lt; + time_t t; + char *error = + _("FATAL ERROR in recur_item_inday: unknown item type\n"); + + if (rpt_until == 0) /* we have an endless recurrent item */ + rpt_until = day_end; + while (item_start <= day_end && item_start <= rpt_until) { + if (item_start < day_end && item_start >= day_start) { + inday = 1; + break; + } + t = item_start; + lt = localtime(&t); + if (rpt_type == RECUR_DAILY) { + lt->tm_mday += rpt_freq; + } else if (rpt_type == RECUR_WEEKLY) { + lt->tm_mday += rpt_freq * 7; + } else if (rpt_type == RECUR_MONTHLY) { + lt->tm_mon += rpt_freq; + } else if (rpt_type == RECUR_YEARLY) { + lt->tm_year += rpt_freq; + } else { /* NOT REACHED */ + fputs(error, stderr); + exit(EXIT_FAILURE); + } + item_start = date2sec(lt->tm_year + 1900, lt->tm_mon + 1, + lt->tm_mday, 0, 0); + } + return inday; +} + +/* Returns a structure of type apoint_s given a structure of type recur_apoint_s */ +struct apoint_s *recur_apoint_s2apoint_s(struct recur_apoint_s *p) +{ + struct apoint_s *a; + + a = (struct apoint_s *) malloc(sizeof(struct apoint_s)); + a->mesg = (char *) malloc(strlen(p->mesg) + 1); + a->start = p->start; + a->dur = p->dur; + a->mesg = p->mesg; + return a; +} diff --git a/src/recur.h b/src/recur.h new file mode 100755 index 0000000..611197c --- /dev/null +++ b/src/recur.h @@ -0,0 +1,87 @@ +/* $calcurse: recur.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_RECUR_H +#define CALCURSE_RECUR_H + +#include "apoint.h" + +#define RECUR_NO 0 +#define RECUR_DAILY 1 +#define RECUR_WEEKLY 2 +#define RECUR_MONTHLY 3 +#define RECUR_YEARLY 4 + +struct days_s { + struct days_s *next; + long st; /* beggining of the considered day, in seconds */ +}; + +struct rpt_s { + int type; /* repetition type, see RECUR_* defines */ + int freq; /* repetition frequence */ + long until; /* ending date for repeated event */ +}; + +struct recur_apoint_s { + struct recur_apoint_s *next; + struct rpt_s *rpt; /* information about repetition */ + struct days_s *exc; /* days when the item should not be repeated */ + long start; /* beggining of the appointment */ + long dur; /* duration of the appointment */ + char *mesg; /* appointment description */ +}; + +struct recur_event_s { + struct recur_event_s *next; + struct rpt_s *rpt; /* information about repetition */ + struct days_s *exc; /* days when the item should not be repeated */ + int id; /* event type */ + long day; /* day at which event occurs */ + char *mesg; /* event description */ +}; + +extern struct recur_apoint_s *recur_alist; +extern struct recur_event_s *recur_elist; + +struct recur_apoint_s *recur_apoint_new(char *mesg, long start, long duration, + int type, int freq, long until); +struct recur_event_s *recur_event_new(char *mesg, long day, int id, + int type, int freq, long until); +char recur_def2char(int define); +int recur_char2def(char type); +void recur_apoint_write(struct recur_apoint_s *o, FILE * f); +void recur_event_write(struct recur_event_s *o, FILE * f); +struct recur_apoint_s *recur_apoint_scan(FILE * f, struct tm start, + struct tm end, char type, int freq, struct tm until); +struct recur_event_s *recur_event_scan(FILE * f, struct tm start, int id, + char type, int freq, struct tm until); +void recur_save_data(FILE *f); +unsigned recur_item_inday(long item_start, int rpt_type, int rpt_freq, + long rpt_until, long day_start); +struct apoint_s *recur_apoint_s2apoint_s(struct recur_apoint_s *p); + +#endif /* CALCURSE_RECUR_H */ diff --git a/src/todo.c b/src/todo.c new file mode 100755 index 0000000..b9419ec --- /dev/null +++ b/src/todo.c @@ -0,0 +1,80 @@ +/* $calcurse: todo.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "i18n.h" +#include "todo.h" + +struct todo_s *todolist; + +struct todo_s *todo_insert(char *mesg) +{ + struct todo_s *o; + o = (struct todo_s *) malloc(sizeof(struct todo_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + o->next = todolist; + todolist = o; + return o; +} + +struct todo_s *todo_add(char *mesg) +{ + struct todo_s *o, **i; + o = (struct todo_s *) malloc(sizeof(struct todo_s)); + o->mesg = (char *) malloc(strlen(mesg) + 1); + strcpy(o->mesg, mesg); + for (i = &todolist; *i != 0; i = &(*i)->next) { + } + o->next = *i; + *i = o; + return o; +} + +void todo_delete_bynum(unsigned num) +{ + unsigned n; + struct todo_s *i, **iptr; + + n = 0; + iptr = &todolist; + for (i = todolist; i != 0; i = i->next) { + if (n == num) { + *iptr = i->next; + free(i->mesg); + free(i); + return; + } + iptr = &i->next; + n++; + } + /* not reached */ + fputs(_("FATAL ERROR in todo_delete_bynum: no such todo\n"), stderr); + exit(EXIT_FAILURE); +} diff --git a/src/todo.h b/src/todo.h new file mode 100755 index 0000000..9e2af31 --- /dev/null +++ b/src/todo.h @@ -0,0 +1,41 @@ +/* $calcurse: todo.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_TODO_H +#define CALCURSE_TODO_H + +struct todo_s { + struct todo_s *next; + char *mesg; +}; + +extern struct todo_s *todolist; + +struct todo_s *todo_insert(char *mesg); +struct todo_s *todo_add(char *mesg); +void todo_delete_bynum(unsigned num); + +#endif /* CALCURSE_TODO_H */ diff --git a/src/utils.c b/src/utils.c new file mode 100755 index 0000000..ded00fb --- /dev/null +++ b/src/utils.c @@ -0,0 +1,614 @@ +/* $calcurse: utils.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include <ncurses.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdbool.h> +#include <sys/types.h> +#include <math.h> + +#include "i18n.h" +#include "utils.h" +#include "custom.h" +#include "vars.h" + + +/* + * Print a message in the status bar. + * Message texts for first line and second line are to be provided. + */ + +void status_mesg(char *mesg_line1, char *mesg_line2) +{ + erase_window_part(swin, 0, 0, col, 2); + custom_apply_attr(swin, ATTR_HIGHEST); + mvwprintw(swin, 0, 0, mesg_line1); + mvwprintw(swin, 1, 0, mesg_line2); + custom_remove_attr(swin, ATTR_HIGHEST); +} + +/* + * Erase part of a window + */ +void erase_window_part(WINDOW *win, int first_col, int first_row, + int last_col, int last_row) +{ + int c, r; + + for (r = first_row; r <= last_row; r++){ + for (c = first_col; c <= last_col; c++){ + mvwprintw(win, r, c, " "); + } + } + wnoutrefresh(win); +} + +/* draws a popup window */ +WINDOW * popup(int pop_row, int pop_col, + int pop_y, int pop_x, char *pop_lab) +{ + char *txt_pop = _("Press any key to continue..."); + char label[80]; + WINDOW *popup_win; + + popup_win = newwin(pop_row, pop_col, pop_y, pop_x); + custom_apply_attr(popup_win, ATTR_HIGHEST); + box(popup_win, 0, 0); + sprintf(label, "%s", pop_lab); + win_show(popup_win, label); + mvwprintw(popup_win, pop_row - 2, pop_col - (strlen(txt_pop) + 1), "%s", + txt_pop); + custom_remove_attr(popup_win, ATTR_HIGHEST); + wnoutrefresh(popup_win); + doupdate(); + return popup_win; +} + +/* prints in middle of a panel */ +void +print_in_middle(WINDOW * win, int starty, int startx, int width, char *string) +{ + int length, x, y; + float temp; + + if (win == NULL) + win = stdscr; + getyx(win, y, x); + if (startx != 0) + x = startx; + if (starty != 0) + y = starty; + if (width == 0) + width = 80; + + length = strlen(string); + temp = (width - length) / 2; + x = startx + (int) temp; + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, x, "%s", string); + custom_remove_attr(win, ATTR_HIGHEST); +} + +/* + * Getstring allows to get user input and to print it on a window, + * even if noecho() is on. + */ +void getstring(win, colr, string, start_x, start_y) +WINDOW *win; +int colr; +char *string; +int start_x, start_y; +{ + int ch; + int charcount = 0; + + custom_apply_attr(win, ATTR_HIGHEST); + if (start_x != -1) + wmove(win, start_y, start_x); + + while ((ch = wgetch(win)) != '\n') { + if ((ch == KEY_BACKSPACE) || + (ch == 330) || + (ch == 263) || + (ch == 127) || + (ch == CTRL('H')) ) { + if (charcount > 0) { + string--; + charcount--; + wmove(win, start_y, start_x + charcount); + waddch(win, ' '); + wmove(win, start_y, start_x + charcount); + } + } else { + *string++ = ch; + charcount++; + waddch(win, ch); + } + doupdate(); + } + *string = 0; + custom_remove_attr(win, ATTR_HIGHEST); + return; +} + +/* checks if a string is only made of digits */ +int is_all_digit(char *string) +{ + int digit, i; + int all_digit; + + digit = 0; + all_digit = 0; + + for (i = 0; i <= strlen(string); i++) + if (isdigit(string[i]) != 0) + digit++; + if (digit == strlen(string)) + all_digit = 1; + return all_digit; +} + +/* draw panel border in color */ +void border_color(WINDOW * window, int bcolr) +{ + int color_attr = A_BOLD; + int no_color_attr = A_BOLD; + + if (colorize) { + wattron(window, color_attr | COLOR_PAIR(bcolr)); + box(window, 0, 0); + } else { + wattron(window, no_color_attr); + box(window, 0, 0); + } + + if (colorize) { + wattroff(window, color_attr | COLOR_PAIR(bcolr)); + } else { + wattroff(window, no_color_attr); + } + + wnoutrefresh(window); +} + +/* draw panel border without any color */ +void border_nocolor(WINDOW * window) +{ + int colr = 9; + int color_attr = A_BOLD; + int no_color_attr = A_DIM; + + if (colorize) { + wattron(window, color_attr | COLOR_PAIR(colr)); + } else { + wattron(window, no_color_attr); + } + + box(window, 0, 0); + + if (colorize) { + wattroff(window, color_attr | COLOR_PAIR(colr)); + } else { + wattroff(window, no_color_attr); + } + + wnoutrefresh(window); +} + + /* prints and scroll text in a window */ +void scroller(WINDOW *win, char *mesg, int x, int y, int nb_row, int nb_col) +{ + int x_offset = 3; + int y_offset = 3; + int text_len = nb_col - 2 * x_offset; + int text_max_row = nb_row - 3; + int nlin, i, j, k; + int last_blank_i, last_blank_j; + char buf[] = " "; + char *next_mesg = _("-- Press 'N' for next page --"); + char *prev_mesg = _("-- Press 'P' for previous page --"); + int ch; + int which_page; //first page : 0, second page : 1 + + i = 0; //position in the message + j = 0; //x position on the current line + nlin = 1; //line number + last_blank_j = 0; + last_blank_i = 0; + which_page = 0; + + while (i <= strlen(mesg)) { + if ((i == strlen(mesg)) & (which_page == 1)) { + // we have finished writing text and we are on second page + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, nb_row - 2, + nb_col - (strlen(prev_mesg) + 2), "%s", + prev_mesg); + custom_remove_attr(win, ATTR_HIGHEST); + wmove(swin, 0, 0); + wnoutrefresh(win); + wnoutrefresh(swin); + doupdate(); + ch = wgetch(win); + if ( (ch == 'P') | (ch == 'p') ) { + erase_window_part(win, y + 1, x + 3, nb_col - 2, nb_row - 2); + nlin = 1; + j = 0; + i = 0; + which_page = 0; + } else { //erase last line and exit next-prev page mode + for (k = 1; k < nb_col - 2; k++) + mvwprintw(win, nb_row - 2, k, " "); + break; + } + } + if (nlin == text_max_row - 2) { // we reach the last line + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, nb_row - 2, + nb_col - (strlen(next_mesg) + 2), "%s", + next_mesg); + custom_remove_attr(win, ATTR_HIGHEST); + wmove(swin, 0, 0); + wnoutrefresh(win); + wnoutrefresh(swin); + doupdate(); + ch = wgetch(win); + if ( (ch == 'N') | (ch == 'n') ) { + erase_window_part(win, y + 1, x + 3, nb_col - 2, nb_row - 2); + nlin = 1; + j = 0; + which_page = 1; + } else { + for (k = 1; k < nb_col - 2; k++) + mvwprintw(win, nb_row - 2, k, " "); + break; + } + } + //write text + strncpy(buf, mesg + i, 1); + i++; + j++; + if ((strncmp(buf, "§", 1) == 0)) { //§ is the character for a new line + buf[0] = '\0'; + mvwprintw(win, x + x_offset + nlin, y + y_offset + j, + "%s", buf); + nlin++; + j = 0; + } else { + if (j == text_len - 1) { // if we reach the terminal border + for (k = last_blank_j; k <= text_len - 1; + k++) + mvwprintw(win, x + x_offset + nlin, + y + y_offset + k, " "); + nlin++; + i = last_blank_i; + j = 0; + } else { + if ((strncmp(buf, " ", 1) == 0)) //space between words + { + last_blank_j = j; //save position + last_blank_i = i; + } + mvwprintw(win, x + x_offset + nlin, + y + y_offset + j, "%s", buf); + } + } + } + wmove(swin, 0, 0); + wnoutrefresh(win); + wnoutrefresh(swin); +} + +/* Draws the status bar */ +void status_bar(int which_pan, int colr, int nc_bar, int nl_bar) +{ + int nb_item_cal, nb_item_oth; + int len_let, len_des, spc_lad; + int spc_bet_cal_itm, spc_bet_oth_itm; + int len_cal_itm, len_oth_itm; + + nb_item_cal = 10; /* max item number to display in status bar */ + nb_item_cal = ceil(nb_item_cal / 2); /* two lines to display items */ + nb_item_oth = 12; + nb_item_oth = ceil(nb_item_oth / 2); + len_let = 3; + len_des = 8; + spc_lad = 1; + + spc_bet_cal_itm = + floor((col - + nb_item_cal * (len_let + len_des + + spc_lad)) / nb_item_cal); + spc_bet_oth_itm = + floor((col - + nb_item_oth * (len_let + len_des + + spc_lad)) / nb_item_oth); + len_cal_itm = len_let + spc_lad + len_des + spc_bet_cal_itm; + len_oth_itm = len_let + spc_lad + len_des + spc_bet_oth_itm; + + erase_window_part(swin, 0, 0, nc_bar, nl_bar); + if (which_pan == 0) { + custom_apply_attr(swin, ATTR_HIGHEST); + mvwprintw(swin, 0, 0, " ?"); + mvwprintw(swin, 1, 0, " Q"); + mvwprintw(swin, 0, len_cal_itm, " R"); + mvwprintw(swin, 1, len_cal_itm, " S"); + mvwprintw(swin, 0, 2 * len_cal_itm, "H/L"); + mvwprintw(swin, 1, 2 * len_cal_itm, "J/K"); + mvwprintw(swin, 0, 3 * len_cal_itm, " G"); + mvwprintw(swin, 1, 3 * len_cal_itm, "Tab"); + mvwprintw(swin, 0, 4 * len_cal_itm, " C"); + custom_remove_attr(swin, ATTR_HIGHEST); + wnoutrefresh(swin); + + mvwprintw(swin, 0, len_let + spc_lad, _("Help")); + mvwprintw(swin, 1, len_let + spc_lad, _("Quit")); + mvwprintw(swin, 0, len_cal_itm + len_let + spc_lad, + _("Redraw")); + mvwprintw(swin, 1, len_cal_itm + len_let + spc_lad, _("Save")); + mvwprintw(swin, 0, 2 * len_cal_itm + len_let + spc_lad, + _("-/+1 Day")); + mvwprintw(swin, 1, 2 * len_cal_itm + len_let + spc_lad, + _("-/+1 Week")); + mvwprintw(swin, 0, 3 * len_cal_itm + len_let + spc_lad, + _("GoTo")); + mvwprintw(swin, 1, 3 * len_cal_itm + len_let + spc_lad, + _("Chg View")); + mvwprintw(swin, 0, 4 * len_cal_itm + len_let + spc_lad, + _("Config")); + } else { + custom_apply_attr(swin, ATTR_HIGHEST); + mvwprintw(swin, 0, 0, " ?"); + mvwprintw(swin, 1, 0, " Q"); + mvwprintw(swin, 0, len_oth_itm, " R"); + mvwprintw(swin, 1, len_oth_itm, " S"); + mvwprintw(swin, 0, 2 * len_oth_itm, "J/K"); + mvwprintw(swin, 1, 2 * len_oth_itm, "Tab"); + mvwprintw(swin, 0, 3 * len_oth_itm, " A"); + mvwprintw(swin, 1, 3 * len_oth_itm, " D"); + mvwprintw(swin, 0, 4 * len_oth_itm, " G"); + mvwprintw(swin, 1, 4 * len_oth_itm, " V"); + mvwprintw(swin, 0, 5 * len_oth_itm, " C"); + custom_remove_attr(swin, ATTR_HIGHEST); + wnoutrefresh(swin); + + mvwprintw(swin, 0, len_let + spc_lad, _("Help")); + mvwprintw(swin, 1, len_let + spc_lad, _("Quit")); + mvwprintw(swin, 0, len_oth_itm + len_let + spc_lad, + _("Redraw")); + mvwprintw(swin, 1, len_oth_itm + len_let + spc_lad, _("Save")); + mvwprintw(swin, 0, 2 * len_oth_itm + len_let + spc_lad, + _("Up/Down")); + mvwprintw(swin, 1, 2 * len_oth_itm + len_let + spc_lad, + _("Chg View")); + mvwprintw(swin, 0, 3 * len_oth_itm + len_let + spc_lad, + _("Add Item")); + mvwprintw(swin, 1, 3 * len_oth_itm + len_let + spc_lad, + _("Del Item")); + mvwprintw(swin, 0, 4 * len_oth_itm + len_let + spc_lad, + _( "GoTo")); + mvwprintw(swin, 1, 4 * len_oth_itm + len_let + spc_lad, + _("View")); + mvwprintw(swin, 0, 5 * len_oth_itm + len_let + spc_lad, + _("Config")); + } + wnoutrefresh(swin); +} + +long date2sec(unsigned year, unsigned month, unsigned day, unsigned hour, + unsigned min) +{ + struct tm start, *lt; + time_t tstart, t; + + t = time(NULL); + lt = localtime(&t); + start = *lt; + + start.tm_mon = month; + start.tm_mday = day; + start.tm_year = year; + start.tm_hour = hour; + start.tm_min = min; + start.tm_sec = 0; + start.tm_isdst = -1; + start.tm_year -= 1900; + start.tm_mon--; + tstart = mktime(&start); + if (tstart == -1) { + fputs(_("FATAL ERROR in date2sec: failure in mktime\n"), stderr); + fprintf(stderr, "%u %u %u %u %u\n", year, month, day, hour, min); + exit(EXIT_FAILURE); + } + return tstart; +} + +/* + * Returns the date in seconds from year 1900. + * If no date is entered, current date is chosen. + */ +long +get_sec_date(int year, int month, int day) +{ + struct tm *ptrtime; + time_t timer; + long long_date; + char current_day[3], current_month[3] ,current_year[5]; + + if (year == 0 && month == 0 && day == 0) { + timer = time(NULL); + ptrtime = localtime(&timer); + strftime(current_day, 3, "%d", ptrtime); + strftime(current_month, 3, "%m", ptrtime); + strftime(current_year, 5, "%Y", ptrtime); + month = atoi(current_month); + day = atoi(current_day); + year = atoi(current_year); + + } + long_date = date2sec(year, month, day, 0, 0); + return long_date; +} + +long min2sec(unsigned minutes) +{ + return minutes * 60; +} + +/* + * Checks if a time has a good format. + * The format could be either HH:MM or H:MM or MM, and we should have: + * 0 <= HH <= 24 and 0 <= MM < 999. + * This function returns 1 if the entered time is correct and in + * [h:mm] or [hh:mm] format, and 2 if the entered time is correct and entered + * in [mm] format. + */ +int check_time(char *string) +{ + int ok = 0; + char hour[] = " "; + char minutes[] = " "; + + if ( // format test [MM] + ((strlen(string) == 2) || (strlen(string) == 3)) & + (isdigit(string[0]) != 0) & + (isdigit(string[1]) != 0) + ) { // check if we have a valid time + strncpy(minutes, string, 2); + if ( atoi(minutes) >= 0) + ok = 2; + } + + else if ( // format test [H:MM] + (strlen(string) == 4) & + (isdigit(string[0]) != 0) & + (isdigit(string[2]) != 0) & + (isdigit(string[3]) != 0) & (string[1] == ':') + ) { // check if we have a valid time + strncpy(hour, string, 1); + strncpy(minutes, string + 2, 2); + if ((atoi(hour) <= 24) & (atoi(hour) >= + 0) & (atoi(minutes) < + 60) & (atoi(minutes) >= 0)) + ok = 1; + } + + else if ( //format test [HH:MM] + (strlen(string) == 5) & + (isdigit(string[0]) != 0) & + (isdigit(string[1]) != 0) & + (isdigit(string[3]) != 0) & + (isdigit(string[4]) != 0) & (string[2] == ':') + ) { // check if we have a valid time + strncpy(hour, string, 2); + strncpy(minutes, string + 3, 2); + if ((atoi(hour) <= 24) & (atoi(hour) >= + 0) & (atoi(minutes) < + 60) & (atoi(minutes) >= 0)) + ok = 1; + } + + return ok; +} + +/* + * Display a scroll bar when there are so many items that they + * can not be displayed inside the corresponding panel. + */ +void draw_scrollbar(WINDOW *win, int y, int x, int length, + int bar_top, int bar_bottom, bool hilt) +{ + mvwvline(win, bar_top, x, ACS_VLINE, bar_bottom - bar_top); + if (hilt) + custom_apply_attr(win, ATTR_HIGHEST); + wattron(win, A_REVERSE); + mvwvline(win, y, x, ' ', length); + wattroff(win, A_REVERSE); + if (hilt) + custom_remove_attr(win, ATTR_HIGHEST); +} + +/* + * Print an item (either an appointment, event, or todo) in a + * popup window. This is useful if an item description is too + * long to fit in its corresponding panel window. + */ +void item_in_popup(char *saved_a_start, char *saved_a_end, char *msg, + char *pop_title) +{ + WINDOW *popup_win; + + popup_win = popup(row - 4, col - 2, 1, 1, pop_title); + if (strncmp(pop_title, _("Appointment"), 11) == 0) { + mvwprintw(popup_win, 4, 4, " - %s -> %s", + saved_a_start, saved_a_end); + } + scroller(popup_win, msg, 1, 1, row - 4, col - 2); + wmove(swin, 0, 0); + doupdate(); + wgetch(popup_win); + delwin(popup_win); +} + +/* Show the window with a border and a label */ +void win_show(WINDOW * win, char *label) +{ + int startx, starty, height, width; + + getbegyx(win, starty, startx); + getmaxyx(win, height, width); + + box(win, 0, 0); + mvwaddch(win, 2, 0, ACS_LTEE); + mvwhline(win, 2, 1, ACS_HLINE, width - 2); + mvwaddch(win, 2, width - 1, ACS_RTEE); + + print_in_middle(win, 1, 0, width, label); +} + +/* + * Print an item description in the corresponding panel window. + */ +void display_item(WINDOW *win, int incolor, char *msg, int len, + int y, int x) +{ + char buf[len]; + + if (incolor == 0) + custom_apply_attr(win, ATTR_HIGHEST); + if (strlen(msg) < len) { + mvwprintw(win, y, x, "%s", msg); + } else { + strncpy(buf, msg, len - 1); + buf[len - 1] = '\0'; + mvwprintw(win, y, x, "%s...", buf); + } + if (incolor == 0) + custom_remove_attr(win, ATTR_HIGHEST); +} diff --git a/src/utils.h b/src/utils.h new file mode 100755 index 0000000..e7bdeff --- /dev/null +++ b/src/utils.h @@ -0,0 +1,55 @@ +/* $calcurse: utils.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_UTILS_H +#define CALCURSE_UTILS_H + +void status_mesg(char *mesg_line1, char *mesg_line2); +void erase_window_part(WINDOW *win, int first_col, int first_row, + int last_col, int last_row); +WINDOW *popup(int pop_row, int pop_col, + int pop_y, int pop_x, char *pop_lab); +void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string); +void getstring(WINDOW *win, int colr, char *string, int start_x, int start_y); +int is_all_digit(char *string); +void border_color(WINDOW *window, int bcolr); +void border_nocolor(WINDOW *window); +void scroller(WINDOW *win, char *, int x, int y, int nb_row, int nb_col); +void status_bar(int which_pan, int colr, int nc_bar, int nl_bar); +long date2sec(unsigned year, unsigned month, unsigned day, unsigned hour, + unsigned min); +long get_sec_date(int year, int month, int day); +long min2sec(unsigned minutes); +int check_time(char *string); +void draw_scrollbar(WINDOW *win, int y, int x, int length, + int bar_top, int bar_bottom, bool hilt); +void item_in_popup(char *saved_a_start, char *saved_a_end, char *msg, + char *pop_title); +void win_show(WINDOW * win, char *label); +void display_item(WINDOW *win, int incolor, char *msg, + int len, int y, int x); + +#endif /* CALCURSE_UTILS_H */ diff --git a/src/vars.c b/src/vars.c new file mode 100755 index 0000000..524d944 --- /dev/null +++ b/src/vars.c @@ -0,0 +1,85 @@ +/* $calcurse: vars.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#include "i18n.h" +#include "vars.h" + +/* + * variables to store window size + */ +int col = 0, row = 0; + +/* variable to tell if the terminal supports color */ +bool colorize = false; + +/* + * variables to store calendar names + */ +int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +char *monthnames[12] = + { N_("January"), + N_("February"), + N_("March"), + N_("April"), + N_("May"), + N_("June"), + N_("July"), + N_("August"), + N_("September"), + N_("October"), + N_("November"), + N_("December") }; + +char *daynames[8] = + { N_("Sun"), + N_("Mon"), + N_("Tue"), + N_("Wed"), + N_("Thu"), + N_("Fri"), + N_("Sat"), + N_("Sun") }; + +/* + * variables to store data path names, which are initialized in + * io_init() + */ +char path_dir[] = ""; +char path_todo[] = ""; +char path_apts[] = ""; +char path_conf[] = ""; + +/* + * Variables to handle calcurse windows: + * cwin = calendar window + * awin = appointment window + * twin = todo window + * swin = status bar window + */ +WINDOW *awin = NULL, *cwin = NULL, *twin = NULL, *swin = NULL; + +/* Variable to handle pads. */ +struct pad_s *apad; diff --git a/src/vars.h b/src/vars.h new file mode 100755 index 0000000..d9bb13e --- /dev/null +++ b/src/vars.h @@ -0,0 +1,69 @@ +/* $calcurse: vars.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */ + +/* + * Calcurse - text-based organizer + * Copyright (c) 2004-2006 Frederic Culot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Send your feedback or comments to : calcurse@culot.org + * Calcurse home page : http://culot.org/calcurse + * + */ + +#ifndef CALCURSE_VARS_H +#define CALCURSE_VARS_H + +#include <ncurses.h> +#include <stdbool.h> + +#define DIR_NAME ".calcurse" +#define TODO_PATH ".calcurse/todo" +#define APTS_PATH ".calcurse/apts" +#define CONF_PATH ".calcurse/conf" + +#define MAX_LENGTH 512 + +#define CTRL(x) ((x) & 0x1f) + +#define ATTR_FALSE 0 +#define ATTR_TRUE 1 +#define ATTR_LOWEST 2 +#define ATTR_LOW 3 +#define ATTR_MIDDLE 4 +#define ATTR_HIGH 5 +#define ATTR_HIGHEST 6 + +struct pad_s { + int width; + int length; + int first_onscreen; /* first line to be displayed inside window */ + WINDOW *ptrwin; /* pointer to the pad window */ +}; + +extern int col, row; +extern bool colorize; +extern int days[12]; +extern char *monthnames[12]; +extern char *daynames[8]; +extern char path_dir[MAX_LENGTH]; +extern char path_todo[MAX_LENGTH]; +extern char path_apts[MAX_LENGTH]; +extern char path_conf[MAX_LENGTH]; +extern WINDOW *awin, *cwin, *twin, *swin; +extern struct pad_s *apad; + +#endif /* CALCURSE_VARS_H */ |