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