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