summaryrefslogblamecommitdiffstats
path: root/src/utils.c
blob: e3ed984100d38b45510584b081ea65b0f8def2cc (plain) (tree)
1
                                                                          

































































































































































































































































































































































                                                                                             


                              


                                                      
                                                       























                                                                               


                                 


                                                      
                                                       




                                                           



                                                           
















                                                                               
                                     
                                                                       
                                    
                                                                       

                                                                       
                                      











                                                           
                                                           
                                                           

                                                           
















                                                                               
                                       


                                                                       

                                                                       

                                      
         
 

































































































































































































                                                                                 
/*	$calcurse: utils.c,v 1.4 2006/08/31 18:50:17 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);
	switch (which_pan) {

	case 0: /* CALENDAR */
		custom_apply_attr(swin, ATTR_HIGHEST);
		mvwprintw(swin, 0, 0, "  ?");
		mvwprintw(swin, 1, 0, "  Q");
		mvwprintw(swin, 0, len_cal_itm, " ^L");
		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"));
		break;

	case 1: /* APPOINTMENT */
		custom_apply_attr(swin, ATTR_HIGHEST);
		mvwprintw(swin, 0, 0, "  ?");
		mvwprintw(swin, 1, 0, "  Q");
		mvwprintw(swin, 0, len_oth_itm, " ^L");
		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, "  R");
		mvwprintw(swin, 1, 4 * len_oth_itm, "  G");
		mvwprintw(swin, 0, 5 * len_oth_itm, "  V");
		mvwprintw(swin, 1, 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,
			_("Repeat"));
		mvwprintw(swin, 1, 4 * len_oth_itm + len_let + spc_lad,
			_( "GoTo"));
		mvwprintw(swin, 0, 5 * len_oth_itm + len_let + spc_lad,
			 _("View"));
		mvwprintw(swin, 1, 5 * len_oth_itm + len_let + spc_lad,
			 _("Config"));
		break;

	case 2: /* TODO */
		custom_apply_attr(swin, ATTR_HIGHEST);
		mvwprintw(swin, 0, 0, "  ?");
		mvwprintw(swin, 1, 0, "  Q");
		mvwprintw(swin, 0, len_oth_itm, " ^L");
		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, "+/-");
		mvwprintw(swin, 1, 4 * len_oth_itm, "  V");
		mvwprintw(swin, 0, 5 * len_oth_itm, "  G");
		mvwprintw(swin, 1, 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,
			_("Priority"));
		mvwprintw(swin, 1, 4 * len_oth_itm + len_let + spc_lad,
			_( "View"));
		mvwprintw(swin, 0, 5 * len_oth_itm + len_let + spc_lad,
			 _("GoTo"));
		mvwprintw(swin, 1, 5 * len_oth_itm + len_let + spc_lad,
			 _("Config"));
		break;
	}

	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);
}