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