1 // =====================================================================
2 //
3 // calendar.cxx
4 //
5 // Author: Dave Freese, W1HKJ
6 // Copyright: 2010
7 //
8 // This file is part of FLAMP.
9 //
10 // This is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // This software is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 //
23 // =====================================================================
24 
25 #include <config.h>
26 
27 #include <cstring>
28 #include <cstdio>
29 #include <cstdlib>
30 
31 #include <FL/Fl.H>
32 #include <FL/Fl_Pixmap.H>
33 
34 #include "pixmaps.h"
35 #include "calendar.h"
36 
37 void popcal_cb (Fl_Widget *v, long d);
38 
fl_calendar_button_cb(Fl_Button * a,void * b)39 static void fl_calendar_button_cb (Fl_Button *a, void *b)
40 {
41 	long j=0;
42 	Fl_Calendar *c = (Fl_Calendar *)b;
43 	Fl_Button   *sb;
44 	int numdays = c->daysinmonth () + 1;
45 	for (int i=1; i < numdays; i++) {
46 		sb = c->day_button(i);
47 		sb->color (52);
48 		if (a == sb) {
49 			c->Day (i);
50 			j = i;
51 			sb->color (sb->selection_color());
52 			if (c->target) {
53 				((Fl_Input2 *)(c->target))->value(c->szDate(c->calfmt));
54 				(c->target)->redraw();
55 			}
56 		}
57 	}
58 	c->redraw();
59 	c->do_callback(c, j);
60 }
61 
62 void
setTarget(Fl_Widget * tgt)63 Fl_Calendar_Base::setTarget (Fl_Widget *tgt)
64 {
65 	target = tgt;
66 }
67 
Fl_Calendar_Base(int x,int y,int w,int h,const char * l)68 Fl_Calendar_Base::Fl_Calendar_Base (int x, int y, int w, int h,
69 									const char *l) : Fl_Group (x, y, w, h, l), Date ()
70 {
71 	int i;
72 
73 	for (i = 0; i<(7*6); i++)
74 	{
75 		days[i] = new Fl_Button ((w/7)*(i%7) + x,
76 								 (h/6)*(i/7) + y,
77 								 (w/7),
78 								 (h/6));
79 		days[i]->down_box (FL_THIN_DOWN_BOX);
80 		days[i]->labelsize (10);
81 		days[i]->box (FL_THIN_UP_BOX);
82 		days[i]->color (52);
83 		days[i]->callback ((Fl_Callback*)&fl_calendar_button_cb, (void *)this);
84 	}
85 	calfmt = 0;
86 }
87 
csize(int cx,int cy,int cw,int ch)88 void Fl_Calendar_Base::csize (int cx, int cy, int cw, int ch)
89 {
90 	int i;
91 	for (i = 0; i<(7*6); i++)
92 	{
93 		days[i]->resize ((cw/7)*(i%7) + cx,
94 						 (ch/6)*(i/7) + cy,
95 						 (cw/7),
96 						 (ch/6));
97 	}
98 }
99 
100 
101 void
update()102 Fl_Calendar_Base::update ()
103 {
104 	int dow = dayofweek (Year(), Month(), 1);
105 	int dim = daysinmonth (Month(), isleapyear (Year()));
106 	int i;
107 
108 	for (i=0; i<dow; i++)
109 	{
110 		days[i]->hide ();
111 	}
112 
113 	for (i=(dim+dow); i<(6*7); i++)
114 	{
115 		days[i]->hide ();
116 	}
117 
118 	for (i=dow; i<(dim+dow); i++)
119 	{
120 		char t[8];
121 		snprintf (t, sizeof(t), "%d", (i-dow+1));
122 		days[i]->label (strdup(t));
123 		days[i]->color (52);
124 		if ((i-dow+1) == Day())
125 			days[i]->color (selection_color());
126 		days[i]->show ();
127 	}
128 }
129 
130 Fl_Button *
day_button(int i)131 Fl_Calendar_Base::day_button (int i)
132 {
133 	if ((i > 0) && (i <= daysinmonth ()))
134 		return days[i + dayofweek (Year(), Month(), 1) - 1];
135 	return 0;
136 }
137 
138 
139 
140 static void
fl_calendar_prv_month_cb(Fl_Button *,void * b)141 fl_calendar_prv_month_cb (Fl_Button *, void *b)
142 {
143 	Fl_Calendar *c = (Fl_Calendar *)b;
144 	c->previous_month ();
145 	c->do_callback(c, (long)0);
146 }
147 
148 static void
fl_calendar_nxt_month_cb(Fl_Button *,void * b)149 fl_calendar_nxt_month_cb (Fl_Button *, void *b)
150 {
151 	Fl_Calendar *c = (Fl_Calendar *)b;
152 	c->next_month ();
153 	c->do_callback(c, (long)0);
154 }
155 
156 static void
fl_calendar_prv_year_cb(Fl_Button *,void * b)157 fl_calendar_prv_year_cb (Fl_Button *, void *b)
158 {
159 	Fl_Calendar *c = (Fl_Calendar *)b;
160 	c->previous_year ();
161 	c->do_callback(c, (long)0);
162 }
163 
164 static void
fl_calendar_nxt_year_cb(Fl_Button *,void * b)165 fl_calendar_nxt_year_cb (Fl_Button *, void *b)
166 {
167 	Fl_Calendar *c = (Fl_Calendar *)b;
168 	c->next_year ();
169 	c->do_callback(c, (long)0);
170 }
171 
Fl_Calendar(int x,int y,int w,int h,const char * l)172 Fl_Calendar::Fl_Calendar (int x, int y, int w, int h,
173 						  const char *l) : Fl_Calendar_Base (x, y, w, h, l)
174 {
175 	int i, bw;
176 	for (i = 0; i<7; i++) {
177 		//    weekdays[i] = new Fl_Button ((w/7)*(i%7) + x,
178 		weekdays[i] = new Fl_Box ((w/7)*(i%7) + x,
179 								  (h/8)*((i/7)+1) + y,
180 								  (w/7),
181 								  (h/8));
182 		weekdays[i]->box (FL_THIN_UP_BOX);
183 		weekdays[i]->labelsize (10);
184 		weekdays[i]->color (52);
185 	}
186 
187 	weekdays[SUNDAY]->label ("S");
188 	weekdays[MONDAY]->label ("M");
189 	weekdays[TUESDAY]->label ("T");
190 	weekdays[WEDNESDAY]->label ("W");
191 	weekdays[THURSDAY]->label ("T");
192 	weekdays[FRIDAY]->label ("F");
193 	weekdays[SATURDAY]->label ("S");
194 
195 	bw = w/10 < 16 ? 16 : w/10;
196 	prv_year = new Fl_Button (x, y, bw, (h/8), "@<<");
197 	prv_year->box (FL_THIN_UP_BOX);
198 	prv_year->labeltype (FL_SYMBOL_LABEL);
199 	prv_year->labelsize (10);
200 	prv_year->down_box (FL_THIN_DOWN_BOX);
201 	prv_year->callback ((Fl_Callback*)&fl_calendar_prv_year_cb, (void *)this);
202 
203 	prv_month = new Fl_Button (x + bw, y, bw, (h/8), "@<");
204 	prv_month->box (FL_THIN_UP_BOX);
205 	prv_month->labeltype (FL_SYMBOL_LABEL);
206 	prv_month->labelsize (10);
207 	prv_month->down_box (FL_THIN_DOWN_BOX);
208 	prv_month->callback ((Fl_Callback*)&fl_calendar_prv_month_cb, (void *)this);
209 
210 	nxt_month = new Fl_Button (x + w - 2*bw, y, bw, (h/8), "@>");
211 	nxt_month->box (FL_THIN_UP_BOX);
212 	nxt_month->labeltype (FL_SYMBOL_LABEL);
213 	nxt_month->labelsize (10);
214 	nxt_month->down_box (FL_THIN_DOWN_BOX);
215 	nxt_month->callback ((Fl_Callback*)&fl_calendar_nxt_month_cb, (void *)this);
216 
217 	nxt_year = new Fl_Button (x + w - bw, y, bw, (h/8), "@>>");
218 	nxt_year->box (FL_THIN_UP_BOX);
219 	nxt_year->labeltype (FL_SYMBOL_LABEL);
220 	nxt_year->labelsize (10);
221 	nxt_year->down_box (FL_THIN_DOWN_BOX);
222 	nxt_year->callback ((Fl_Callback*)&fl_calendar_nxt_year_cb, (void *)this);
223 
224 	//  caption = new Fl_Button (x + (w/10)*2, y, (6*w/10), (h/8));
225 	caption = new Fl_Box (x + 2*bw, y, w - 4*bw, (h/8));
226 	caption->box (FL_THIN_UP_BOX);
227 	caption->labeltype (FL_SYMBOL_LABEL);
228 	caption->labelfont (1);
229 	if (bw < 20)
230 		caption->labelsize (9);
231 	else
232 		caption->labelsize (11);
233 	//  caption->down_box (FL_THIN_DOWN_BOX);
234 
235 	Fl_Calendar_Base::csize (x, y + (2*h/8), w, (6*h/8));
236 
237 	target = 0;
238 
239 	update ();
240 }
241 
242 void
csize(int cx,int cy,int cw,int ch)243 Fl_Calendar::csize (int cx, int cy, int cw, int ch)
244 {
245 	int i;
246 	for (i = 0; i<7; i++)
247 	{
248 		//      weekdays[i] = new Fl_Button ((cw/7)*(i%7) + cx,
249 		weekdays[i] = new Fl_Box ((cw/7)*(i%7) + cx,
250 								  (ch/8)*((i/7)+1) + cy,
251 								  (cw/7),
252 								  (ch/8));
253 	}
254 
255 	prv_month->resize (cx + (cw/10), cy, (cw/10), (ch/8));
256 	nxt_month->resize (cx + (cw/10)*8, cy, (cw/10), (ch/8));
257 	prv_year->resize (cx, cy, (cw/10), (ch/8));
258 	nxt_year->resize (cx + (cw/10)*9, cy, (cw/10), (ch/8));
259 	caption->resize (cx + (cw/10)*2, cy, (cw/10)*6, (ch/8));
260 
261 	Fl_Calendar_Base::csize (cx, cy + (2*ch/8), cw, (6*ch/8));
262 }
263 
264 void
update()265 Fl_Calendar::update ()
266 {
267 	int dow = dayofweek (Year(), Month(), 1);
268 	int dim = daysinmonth (Month(), isleapyear (Year()));
269 	int i;
270 
271 	for (i=dow; i<(dim+dow); i++)
272 	{
273 		char t[8];
274 		snprintf (t, sizeof(t), "%d", (i-dow+1));
275 		days[i]->label (strdup(t));
276 	}
277 
278 	char tmp[32];
279 	snprintf (tmp, sizeof(tmp), "%s %d", month_name[Month()-1], Year());
280 	Fl_Calendar_Base::update ();
281 	if (caption->label ())
282 		free ((void *) caption->label ());
283 	caption->label (strdup(tmp));
284 	redraw ();
285 }
286 
today()287 void Fl_Calendar::today ()
288 {
289 	Date::today();
290 	update ();
291 }
292 
previous_month()293 void Fl_Calendar::previous_month ()
294 {
295 	Date::previous_month();
296 	update ();
297 }
298 
299 void
next_month()300 Fl_Calendar::next_month ()
301 {
302 	Date::next_month();
303 	update ();
304 }
305 
306 void
previous_year()307 Fl_Calendar::previous_year ()
308 {
309 	Date::previous_year();
310 	update ();
311 }
312 
next_year()313 void Fl_Calendar::next_year ()
314 {
315 	Date::next_year();
316 	update ();
317 }
318 
setDate(int m,int d,int y)319 void Fl_Calendar::setDate(int m, int d, int y)
320 {
321 	Date::setDate(m,d,y);
322 }
323 
324 int
handle(int event)325 Fl_Calendar::handle (int event)
326 {
327 	int m, d, y, o, md;
328 
329 	switch (event)
330 	{
331 		case FL_FOCUS:
332 		case FL_UNFOCUS:
333 			return 1;
334 
335 		case FL_KEYBOARD:
336 			m = Month ();
337 			d = Day ();
338 			y = Year ();
339 			switch(Fl::event_key ())
340 		{
341 			case FL_Enter:
342 				do_callback(this, d);
343 				return 1;
344 				break;
345 			case FL_Up:
346 				o = -7;
347 				break;
348 			case FL_Down:
349 				o = 7;
350 				break;
351 			case FL_Right:
352 				o = 1;
353 				break;
354 			case FL_Left:
355 				o = -1;
356 				break;
357 			case FL_Page_Up:
358 				previous_month ();
359 				return 1;
360 			case FL_Page_Down:
361 				next_month ();
362 				return 1;
363 			default:
364 				return Fl_Group::handle (event);
365 		}
366 			if (datevalid (y, m, d + o))
367 				setDate (m, d + o, y);
368 			else
369 			{
370 				if (o < 0)
371 				{
372 					previous_month ();
373 					m = Month ();
374 					y = Year ();
375 					md = daysinmonth (m, isleapyear (y));
376 					d = d + o + md;
377 					setDate (m, d, y);
378 				}
379 				else
380 				{
381 					md = daysinmonth (m, isleapyear (y));
382 					next_month ();
383 					m = Month ();
384 					y = Year ();
385 					d = d + o - md;
386 					setDate (m, d, y);
387 				}
388 			}
389 			return 1;
390 	}
391 	return Fl_Group::handle (event);
392 }
393 
394 
395 // Popup Calendar class
396 
Fl_PopCal(int X,int Y,int W,int H,Fl_Input2 * tgt)397 Fl_PopCal::Fl_PopCal (int X, int Y, int W, int H, Fl_Input2 * tgt)
398 : Fl_Window (X, Y, W, H, "")
399 {
400 	target = tgt;
401 	clear_border();
402 	box(FL_UP_BOX);
403 	//  popcal = new Fl_Calendar(2, 2);
404 	popcal = new Fl_Calendar(2, 2, W-4, H-4);
405 	popcal->callback ( (Fl_Callback*)popcal_cb);
406 	end();
407 }
408 
409 
~Fl_PopCal()410 Fl_PopCal::~Fl_PopCal ()
411 {
412 }
413 
popcalfmt(int i)414 void Fl_PopCal::popcalfmt (int i)
415 {
416 	popcalfmt_ = i;
417 }
418 
popcalfmt()419 int Fl_PopCal::popcalfmt ()
420 {
421 	return popcalfmt_;
422 }
423 
setDate(int m,int d,int y)424 void Fl_PopCal::setDate (int m, int d, int y)
425 {
426 	popcal->setDate (m,d,y);
427 	popcal->update();
428 }
429 
handle(int event)430 int Fl_PopCal::handle(int event)
431 {
432 	int ex = Fl::event_x_root(),
433 	ey = Fl::event_y_root();
434 	if (event == FL_PUSH) {
435 		if ( ex < x() || ex > (x() + w()) ||
436 			ey < y() || ey > (y() + h()) ) {
437 			pophide();
438 			return 1;
439 		}
440 	}
441 	if (Fl_Group::handle(event)) return 1;
442 	return 0;
443 }
444 
popposition(int x,int y)445 void Fl_PopCal::popposition (int x, int y)
446 {
447 	position (x, y);
448 }
449 
popshow()450 void Fl_PopCal::popshow ()
451 {
452 	show ();
453 	Fl::grab(this);
454 }
455 
pophide()456 void Fl_PopCal::pophide ()
457 {
458 	hide ();
459 	Fl::release();
460 }
461 
popcal_cb_i(Fl_Widget * v,long d)462 void Fl_PopCal::popcal_cb_i (Fl_Widget *v, long d)
463 {
464 	int ey = Fl::event_y_root();
465 	Fl_PopCal *me = (Fl_PopCal *)(v->parent());
466 	Fl_Input2 *tgt = me->target;
467 	if (ey > me->y() + 40) {
468 		if (d && tgt)
469 			tgt->value (((Fl_Calendar *)v)->szDate (me->popcalfmt_));
470 		me->pophide();
471 	}
472 	return;
473 }
474 
popcal_cb(Fl_Widget * v,long d)475 void popcal_cb (Fl_Widget *v, long d)
476 {
477 	((Fl_PopCal *)(v))->popcal_cb_i (v, d);
478 	return;
479 }
480 
481 void
fl_popcal()482 Fl_DateInput::fl_popcal()
483 {
484 	Fl_Widget *who = this, *parent;
485 	int xpos = who->x(), ypos = who->h() + who->y();
486 	int w = who->w(), h;
487 	int m = 0, d = 0, y = 0;
488 
489 	w = w < 140 ? 140 : w;
490 	w = w - (w % 7);
491 	h = 8*(w/7);
492 	w += 4; h += 4;
493 	parent = who;
494 	while (parent) {
495 		who = parent;
496 		parent = parent->parent();
497 		if (parent == 0) {
498 			xpos += who->x();
499 			ypos += who->y();
500 		}
501 	}
502 	if (!Cal)
503 		//    Cal = new Fl_PopCal(xpos, ypos, 7*20+4, 8*20+4, Input);
504 		Cal = new Fl_PopCal(xpos, ypos, w, h, Input);
505 	else
506 		Cal->popposition(xpos, ypos);
507 
508 	if (popcalfmt_ < 3) {
509 		switch (popcalfmt_) {
510 			case 0:
511 			case 1:
512 				sscanf(Input->value(), "%d/%d/%d", &m, &d, &y);
513 				break;
514 			case 2:
515 			default:
516 				sscanf(Input->value(),"%4d%2d%2d", &y, &m, &d);
517 				break;
518 		}
519 		if (y < 10) y+=2000;
520 		if (y < 100) y+=1900;
521 		Cal->setDate (m,d,y);
522 	}
523 	Cal->popcalfmt (popcalfmt_);
524 
525 	Cal->popshow();
526 	return;
527 }
528 
btnDateInput_cb(Fl_Widget * v,void * d)529 void btnDateInput_cb (Fl_Widget *v, void *d)
530 {
531 	((Fl_DateInput *)(v->parent()))->fl_popcal ();
532 	return;
533 }
534 
535 
Fl_DateInput(int X,int Y,int W,int H,const char * L)536 Fl_DateInput::Fl_DateInput (int X,int Y,int W,int H, const char *L)
537 : Fl_Group (X, Y, W, H, 0)
538 {
539 	Btn = new Fl_Button (X + W - H + 1, Y + 1, H - 2, H - 2);
540 	(new Fl_Pixmap (time_icon))->label (Btn);
541 	Btn->callback ((Fl_Callback *)btnDateInput_cb, 0);
542 	Input = new Fl_Input2 (X, Y, W-H, H, L);
543 
544 	popcalfmt_ = 0;
545 	Cal = 0;
546 	end();
547 }
548 
align(Fl_Align how)549 void Fl_DateInput::align (Fl_Align how)
550 {
551 	Input->align(how);
552 }
553 
554 // DateInput value is contained in the Input widget
555 
value(const char * s)556 void Fl_DateInput::value( const char *s )
557 {
558 	Input->value (s);
559 }
560 
value()561 const char *Fl_DateInput::value()
562 {
563 	return (Input->value ());
564 }
565 
566 
textfont(int tf)567 void Fl_DateInput::textfont(int tf)
568 {
569 	Input->textfont (tf);
570 }
571 
textsize(int sz)572 void Fl_DateInput::textsize(int sz)
573 {
574 	Input->textsize (sz);
575 }
576 
labelfont(int fnt)577 void Fl_DateInput::labelfont(int fnt)
578 {
579 	Input->labelfont(fnt);
580 }
581 
labelsize(int size)582 void Fl_DateInput::labelsize(int size)
583 {
584 	Input->labelsize(size);
585 }
586 
labelcolor(int clr)587 void Fl_DateInput::labelcolor(int clr)
588 {
589 	Input->labelcolor(clr);
590 }
591 
format(int fmt)592 void Fl_DateInput::format (int fmt)
593 {
594 	switch (fmt) {
595 		case 0:
596 		case 1:
597 		case 2:
598 		case 3:
599 		case 4:
600 			popcalfmt_ = fmt;
601 			break;
602 		default :
603 			popcalfmt_ = 0;
604 	}
605 }
606 
take_focus()607 void Fl_DateInput::take_focus() {
608 	Input->take_focus();
609 }
610