⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calendar.c

📁 This version of dialog, formerly known as cdialog is based on the Debian package for dialog 0.9a (se
💻 C
字号:
/* * $Id: calendar.c,v 1.35 2003/11/26 18:47:49 tom Exp $ * *  calendar.c -- implements the calendar box * * Copyright 2001-2002,2003	Thomas E. Dickey * *  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., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "dialog.h"#include <time.h>#define ONE_DAY  (60 * 60 * 24)#define MON_WIDE 4#define DAY_HIGH 5#define DAY_WIDE (8 * MON_WIDE)#define HDR_HIGH 1#define BTN_HIGH 2#define MIN_HIGH (DAY_HIGH + HDR_HIGH + BTN_HIGH + (6 * MARGIN))#define MIN_WIDE (DAY_WIDE + (4 * MARGIN))typedef enum {    sMONTH = -3    ,sYEAR = -2    ,sDAY = -1} STATES;struct _box;typedef int (*BOX_DRAW) (struct _box *, struct tm *);typedef struct _box {    WINDOW *parent;    WINDOW *window;    int x;    int y;    int width;    int height;    BOX_DRAW box_draw;} BOX;static intdays_in_month(struct tm *current, int offset /* -1, 0, 1 */ ){    static const int nominal[] =    {	31, 28, 31, 30, 31, 30,	31, 31, 30, 31, 30, 31    };    int year = current->tm_year;    int month = current->tm_mon + offset;    int result;    while (month < 0) {	month += 12;	year -= 1;    }    while (month >= 12) {	month -= 12;	year += 1;    }    result = nominal[month];    if (month == 1)	result += ((year % 4) == 0);    return result;}static intdays_in_year(struct tm *current, int offset /* -1, 0, 1 */ ){    int year = current->tm_year + 1900 + offset;    return ((year % 4) == 0) ? 366 : 365;}static intday_cell_number(struct tm *current){    int cell;    cell = current->tm_mday - ((6 + current->tm_mday - current->tm_wday) % 7);    if ((current->tm_mday - 1) % 7 != current->tm_wday)	cell += 6;    else	cell--;    return cell;}static intnext_or_previous(int key, int two_d){    int result = 0;    switch (key) {    case M_EVENT + KEY_PPAGE:    case KEY_PPAGE:    case KEY_PREVIOUS:    case KEY_UP:	result = two_d ? -7 : -1;	break;    case KEY_LEFT:    case CHR_PREVIOUS:    case CHR_BACKSPACE:	result = -1;	break;    case M_EVENT + KEY_NPAGE:    case KEY_NPAGE:    case KEY_DOWN:	result = two_d ? 7 : 1;	break;    case KEY_RIGHT:    case CHR_NEXT:    case KEY_NEXT:	result = 1;	break;    default:	/*	 * We're already using the left/right arrow keys for traversal.  Use	 * vi-style for navigating around the days of the month.	 */	if (two_d) {	    switch (key) {	    case 'h':		result = -1;		break;	    case 'j':		result = 7;		break;	    case 'k':		result = -7;		break;	    case 'l':		result = 1;		break;	    }	} else {	    beep();	}	break;    }    return result;}/* * Draw the day-of-month selection box */static intdraw_day(BOX * data, struct tm *current){#ifdef ENABLE_NLS    char *of_week[] =    {	nl_langinfo(ABDAY_1),	nl_langinfo(ABDAY_2),	nl_langinfo(ABDAY_3),	nl_langinfo(ABDAY_4),	nl_langinfo(ABDAY_5),	nl_langinfo(ABDAY_6),	nl_langinfo(ABDAY_7)    };#else    static const char *const of_week[] =    {	"Sunday",	"Monday",	"Tuesday",	"Wednesday",	"Thursday",	"Friday",	"Saturday"    };#endif    int cell_wide = MON_WIDE;    int y, x, this_x = 0;    int save_y = 0, save_x = 0;    int day = current->tm_mday;    int mday;    int week;    int last = days_in_month(current, 0);    int prev = days_in_month(current, -1);    werase(data->window);    dlg_draw_box(data->parent,		 data->y - MARGIN, data->x - MARGIN,		 data->height + (2 * MARGIN), data->width + (2 * MARGIN),		 border_attr, dialog_attr);    wattrset(data->window, item_selected_attr);    for (x = 0; x < 7; x++) {	mvwprintw(data->window,		  0, (x + 1) * cell_wide, "%*.*s ",		  cell_wide - 1,		  cell_wide - 1,		  of_week[x]);    }    wattrset(data->window, item_attr);    mday = ((6 + current->tm_mday - current->tm_wday) % 7) - 7;    if (mday <= -7)	mday += 7;    /* mday is now in the range -6 to 0. */    week = (current->tm_yday + 6 + mday - current->tm_mday) / 7;    for (y = 1; mday < last; y++) {	wattrset(data->window, item_selected_attr);	mvwprintw(data->window,		  y, 0,		  "%*d ",		  cell_wide - 1,		  ++week);	for (x = 0; x < 7; x++) {	    this_x = 1 + (x + 1) * cell_wide;	    ++mday;	    if (wmove(data->window, y, this_x) == ERR)		continue;	    wattrset(data->window, item_attr);	    if (mday == day) {		wattrset(data->window, item_selected_attr);		save_y = y;		save_x = this_x;	    }	    if (mday > 0) {		if (mday <= last) {		    wprintw(data->window, "%*d", cell_wide - 2, mday);		} else if (mday == day) {		    wprintw(data->window, "%*d", cell_wide - 2, mday - last);		}	    } else if (mday == day) {		wprintw(data->window, "%*d", cell_wide - 2, mday + prev);	    }	    wattrset(data->window, item_attr);	}	wmove(data->window, save_y, save_x);    }    dlg_draw_arrows(data->parent, TRUE, TRUE,		    data->x + 5,		    data->y - 1,		    data->y + data->height);    return 0;}/* * Draw the month-of-year selection box */static intdraw_month(BOX * data, struct tm *current){#ifdef ENABLE_NLS    char *months[] =    {	nl_langinfo(MON_1),	nl_langinfo(MON_2),	nl_langinfo(MON_3),	nl_langinfo(MON_4),	nl_langinfo(MON_5),	nl_langinfo(MON_6),	nl_langinfo(MON_7),	nl_langinfo(MON_8),	nl_langinfo(MON_9),	nl_langinfo(MON_10),	nl_langinfo(MON_11),	nl_langinfo(MON_12)    };#else    static const char *const months[] =    {	"January",	"February",	"March",	"April",	"May",	"June",	"July",	"August",	"September",	"October",	"November",	"December"    };#endif    int month;    month = current->tm_mon + 1;    wattrset(data->parent, dialog_attr);    (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Month"));    dlg_draw_box(data->parent,		 data->y - 1, data->x - 1,		 data->height + 2, data->width + 2,		 border_attr, dialog_attr);    mvwprintw(data->window, 0, 0, "%s", months[month - 1]);    wmove(data->window, 0, 0);    return 0;}/* * Draw the year selection box */static intdraw_year(BOX * data, struct tm *current){    int year = current->tm_year + 1900;    wattrset(data->parent, dialog_attr);    (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Year"));    dlg_draw_box(data->parent,		 data->y - 1, data->x - 1,		 data->height + 2, data->width + 2,		 border_attr, dialog_attr);    mvwprintw(data->window, 0, 0, "%4d", year);    wmove(data->window, 0, 0);    return 0;}static intinit_object(BOX * data,	    WINDOW *parent,	    int x, int y,	    int width, int height,	    BOX_DRAW box_draw,	    int code){    data->parent = parent;    data->x = x;    data->y = y;    data->width = width;    data->height = height;    data->box_draw = box_draw;    data->window = derwin(data->parent,			  data->height, data->width,			  data->y, data->x);    if (data->window == 0)	return -1;    (void) keypad(data->window, TRUE);    dlg_mouse_setbase(getbegx(parent), getbegy(parent));    if (code == 'D') {	dlg_mouse_mkbigregion(y + 1, x + MON_WIDE, height - 1, width - MON_WIDE,			      KEY_MAX, 1, MON_WIDE, 3);    } else {	dlg_mouse_mkregion(y, x, height, width, code);    }    return 0;}#define DrawObject(data) (data)->box_draw(data, &current)/* * Display a dialog box for entering a date */intdialog_calendar(const char *title,		const char *subtitle,		int height,		int width,		int day,		int month,		int year){    BOX dy_box, mn_box, yr_box;    int fkey;    int key = 0;    int key2;    int step;    int button;    int result = DLG_EXIT_UNKNOWN;    WINDOW *dialog;    time_t now_time = time((time_t *) 0);    struct tm current;    STATES state = dlg_defaultno_button();    const char **buttons = dlg_ok_labels();    char *prompt = dlg_strclone(subtitle);    dlg_does_output();    now_time = time((time_t *) 0);    current = *localtime(&now_time);    if (day < 0)	day = current.tm_mday;    if (month < 0)	month = current.tm_mon + 1;    if (year < 0)	year = current.tm_year + 1900;    /* compute a struct tm that matches the day/month/year parameters */    if (((year -= 1900) > 0) && (year < 200)) {	/* ugly, but I'd like to run this on older machines w/o mktime -TD */	for (;;) {	    if (year > current.tm_year) {		now_time += ONE_DAY * days_in_year(&current, 0);	    } else if (year < current.tm_year) {		now_time -= ONE_DAY * days_in_year(&current, -1);	    } else if (month > current.tm_mon + 1) {		now_time += ONE_DAY * days_in_month(&current, 0);	    } else if (month < current.tm_mon + 1) {		now_time -= ONE_DAY * days_in_month(&current, -1);	    } else if (day > current.tm_mday) {		now_time += ONE_DAY;	    } else if (day < current.tm_mday) {		now_time -= ONE_DAY;	    } else {		break;	    }	    current = *localtime(&now_time);	}    }    dlg_auto_size(title, prompt, &height, &width, 0, 0);    height += MIN_HIGH;    if (width < MIN_WIDE)	width = MIN_WIDE;    dlg_print_size(height, width);    dlg_ctl_size(height, width);    /* FIXME: how to make this resizable? */    dialog = dlg_new_window(height, width,			    dlg_box_y_ordinate(height),			    dlg_box_x_ordinate(width));    dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);    dlg_draw_bottom_box(dialog);    dlg_draw_title(dialog, title);    wattrset(dialog, dialog_attr);    dlg_print_autowrap(dialog, prompt, height, width);    /* compute positions of day, month and year boxes */    memset(&dy_box, 0, sizeof(dy_box));    memset(&mn_box, 0, sizeof(mn_box));    memset(&yr_box, 0, sizeof(yr_box));    if (init_object(&dy_box,		    dialog,		    (width - DAY_WIDE) / 2,		    (height - (DAY_HIGH + BTN_HIGH + (4 * MARGIN))),		    DAY_WIDE,		    DAY_HIGH + (2 * MARGIN),		    draw_day,		    'D') < 0	|| DrawObject(&dy_box) < 0)	return DLG_EXIT_ERROR;    if (init_object(&mn_box,		    dialog,		    dy_box.x,		    dy_box.y - (HDR_HIGH + 2 * MARGIN),		    (DAY_WIDE / 2) - MARGIN,		    HDR_HIGH,		    draw_month,		    'M') < 0	|| DrawObject(&mn_box) < 0)	return DLG_EXIT_ERROR;    if (init_object(&yr_box,		    dialog,		    dy_box.x + mn_box.width + 2,		    mn_box.y,		    mn_box.width,		    mn_box.height,		    draw_year,		    'Y') < 0	|| DrawObject(&yr_box) < 0)	return DLG_EXIT_ERROR;    while (result == DLG_EXIT_UNKNOWN) {	BOX *obj = (state == sDAY ? &dy_box		    : (state == sMONTH ? &mn_box :		       (state == sYEAR ? &yr_box : 0)));	button = (state < 0) ? 0 : state;	dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);	if (obj != 0)	    dlg_set_focus(dialog, obj->window);	key = dlg_mouse_wgetch(dialog, &fkey);	if ((key2 = dlg_char_to_button(key, buttons)) >= 0) {	    result = key2;	} else {	    /* handle non-functionkeys */	    if (!fkey) {		fkey = TRUE;		switch (key) {		case ' ':		case '\n':		case '\r':		    key = KEY_ENTER;		    break;		case TAB:		    key = DLGK_NEXT_FIELD;		    break;		case CHR_PREVIOUS:		case CHR_NEXT:		case CHR_BACKSPACE:		case 'h':		case 'j':		case 'k':		case 'l':		    /* treat these as function-keys */		    break;		case ESC:		    result = DLG_EXIT_ESC;		    fkey = FALSE;		    break;		default:		    fkey = FALSE;		    break;		}	    }	    /* handle functionkeys */	    if (fkey) {		switch (key) {		case M_EVENT + 'D':		    state = sDAY;		    break;		case M_EVENT + 'M':		    state = sMONTH;		    break;		case M_EVENT + 'Y':		    state = sYEAR;		    break;		case KEY_ENTER:		    result = dlg_ok_buttoncode(button);		    break;		case DLGK_PREV_FIELD:		case KEY_BTAB:		    state = dlg_prev_ok_buttonindex(state, sMONTH);		    break;		case DLGK_NEXT_FIELD:		    state = dlg_next_ok_buttonindex(state, sMONTH);		    break;		default:		    step = 0;		    key2 = -1;		    if (key >= M_EVENT) {			if ((key2 = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {			    result = key2;			    break;			} else if (key >= (M_EVENT + KEY_MAX)) {			    state = sDAY;			    obj = &dy_box;			    key2 = 1;			    step = (key				    - (M_EVENT + KEY_MAX)				    - day_cell_number(&current));			}		    }		    if (obj != 0) {			if (key2 < 0)			    step = next_or_previous(key, (obj == &dy_box));			if (step != 0) {			    struct tm old = current;			    /* see comment regarding mktime -TD */			    if (obj == &dy_box) {				now_time += ONE_DAY * step;			    } else if (obj == &mn_box) {				if (step > 0)				    now_time += ONE_DAY *					days_in_month(&current, 0);				else				    now_time -= ONE_DAY *					days_in_month(&current, -1);			    } else if (obj == &yr_box) {				if (step > 0)				    now_time += (ONE_DAY						 * days_in_year(&current, 0));				else				    now_time -= (ONE_DAY						 * days_in_year(&current, -1));			    }			    current = *localtime(&now_time);			    if (obj != &dy_box				&& (current.tm_mday != old.tm_mday				    || current.tm_mon != old.tm_mon				    || current.tm_year != old.tm_year))				DrawObject(&dy_box);			    if (obj != &mn_box && current.tm_mon != old.tm_mon)				DrawObject(&mn_box);			    if (obj != &yr_box && current.tm_year != old.tm_year)				DrawObject(&yr_box);			    (void) DrawObject(obj);			}		    } else if (state >= 0) {			if (next_or_previous(key, FALSE) < 0)			    state = dlg_prev_ok_buttonindex(state, sMONTH);			else if (next_or_previous(key, FALSE) > 0)			    state = dlg_next_ok_buttonindex(state, sMONTH);		    }		    break;		}	    }	}    }    dlg_del_window(dialog);    sprintf(dialog_vars.input_result, "%02d/%02d/%0d\n",	    current.tm_mday, current.tm_mon + 1, current.tm_year + 1900);    dlg_mouse_free_regions();    free(prompt);    return result;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -