1 /*
2  *  This file is part of the XForms library package.
3  *
4  *  XForms is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU Lesser General Public License as
6  *  published by the Free Software Foundation; either version 2.1, or
7  *  (at your option) any later version.
8  *
9  *  XForms is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with XForms.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 /**
20  * \file timer.c
21  *
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  * Forms Object class: TIMER
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <string.h>
34 #include <stdlib.h>
35 #include "include/forms.h"
36 #include "flinternal.h"
37 
38 
39 /* Extra information need for input boxes. */
40 
41 typedef struct
42 {
43     double time_left;       /* the time (sec) left to wait */
44     double timer;           /* total duration              */
45     long sec,               /* start time                  */
46          usec;
47     int on,
48         up;
49     FL_TIMER_FILTER filter;
50 } SPEC;
51 
52 
53 /***************************************
54  ***************************************/
55 
56 static char *
default_filter(FL_OBJECT * ob FL_UNUSED_ARG,double totalsec)57 default_filter( FL_OBJECT * ob  FL_UNUSED_ARG,
58                 double      totalsec )
59 {
60     static char buf[ 32 ];
61     int minutes;
62     double sec;
63 
64     if ( totalsec >= 3600.0 )
65     {
66         int hr = totalsec / 3600.0 + 0.001;
67 
68         minutes = totalsec / 60.0 + 0.001;
69         minutes -= hr * 60;
70         sec = totalsec - 60 * ( minutes + 60 * hr );
71         sprintf( buf, "%d:%02d:%04.1f", hr, minutes, sec );
72     }
73     else if ( totalsec >= 60.0 )
74     {
75         minutes = totalsec / 60.0 + 0.001;
76         sec = totalsec - minutes * 60;
77         sprintf( buf, "%d:%04.1f", minutes, sec );
78     }
79     else
80         sprintf( buf, "%.1f", totalsec );
81 
82     return buf;
83 }
84 
85 
86 /***************************************
87  * draws the timer
88  ***************************************/
89 
90 static void
draw_timer(FL_OBJECT * ob)91 draw_timer( FL_OBJECT * ob )
92 {
93     FL_COLOR col;
94     char *str;
95     SPEC *sp = ob->spec;
96 
97     if ( ob->type == FL_HIDDEN_TIMER )
98         return;
99 
100     if ( ! sp->on || sp->time_left > 0.0 )
101         col = ob->col1;
102     else if ( ( int ) ( sp->time_left / FL_TIMER_BLINKRATE ) % 2 )
103         col = ob->col1;
104     else
105         col = ob->col2;
106 
107     fl_draw_box( ob->boxtype, ob->x, ob->y, ob->w, ob->h, col, ob->bw );
108 
109     if ( ob->type == FL_VALUE_TIMER && sp->time_left > 0.0 )
110     {
111         double time_shown = sp->up ? sp->timer - sp->time_left : sp->time_left;
112 
113         str = ( sp->filter ? sp->filter : default_filter )( ob, time_shown );
114         fl_draw_text( FL_ALIGN_CENTER, ob->x, ob->y, ob->w, ob->h,
115                       ob->lcol, ob->lstyle, ob->lsize, str );
116     }
117 }
118 
119 
120 /***************************************
121  * Handles an event
122  ***************************************/
123 
124 static int
handle_timer(FL_OBJECT * ob,int event,FL_Coord mx FL_UNUSED_ARG,FL_Coord my FL_UNUSED_ARG,int key FL_UNUSED_ARG,void * ev FL_UNUSED_ARG)125 handle_timer( FL_OBJECT * ob,
126               int         event,
127               FL_Coord    mx   FL_UNUSED_ARG,
128               FL_Coord    my   FL_UNUSED_ARG,
129               int         key  FL_UNUSED_ARG,
130               void      * ev   FL_UNUSED_ARG )
131 {
132     SPEC *sp = ob->spec;
133     long sec,
134          usec;
135     double lasttime_left;
136     int ret = FL_RETURN_NONE;
137     static int update_only;
138 
139     switch ( event )
140     {
141         case FL_ATTRIB :
142             if ( ob->type == FL_VALUE_TIMER )
143                 ob->align = fl_to_outside_lalign( ob->align );
144             break;
145 
146         case FL_DRAW:
147             draw_timer( ob );
148             /* fall through */
149 
150         case FL_DRAWLABEL:
151             if (    ob->type == FL_HIDDEN_TIMER
152                  || ( ob->type == FL_VALUE_TIMER && update_only ) )
153                 break;
154             if ( fl_is_outside_lalign( ob->align ) )
155                 fl_draw_text_beside( ob->align, ob->x, ob->y, ob->w, ob->h,
156                                      ob->lcol, ob->lstyle, ob->lsize,
157                                      ob->label );
158             else
159                 fl_draw_text( ob->align, ob->x, ob->y, ob->w, ob->h,
160                               ob->lcol, ob->lstyle, ob->lsize,
161                               ob->label );
162             break;
163 
164         case FL_RELEASE:
165             if ( ob->type != FL_HIDDEN_TIMER && sp->time_left < 0.0 )
166                 fl_set_timer( ob, 0.0 );
167             break;
168 
169         case FL_STEP:
170             if ( ! sp->on )
171                 break;
172             lasttime_left = sp->time_left;
173             fl_gettime( &sec, &usec );
174             sp->time_left = sp->timer - ( sec - sp->sec )
175                             - ( usec - sp->usec ) * 1.0e-6;
176             update_only = 1;
177 
178             /* Don't check for zero, we can overshoot quite a bit. Instead try
179                to split the error by already returning 10 ms too early. */
180 
181             if ( sp->time_left > 0.01 )
182             {
183                 if (    ob->type == FL_VALUE_TIMER
184                      && ( int ) ( 10.0 * sp->time_left ) !=
185                                               ( int ) ( 10.0 * lasttime_left ) )
186                     fl_redraw_object( ob );
187             }
188             else if ( lasttime_left > 0.0 )
189             {
190                 if ( ob->type == FL_HIDDEN_TIMER )
191                     fl_set_timer( ob, 0.0 );
192                 else
193                     fl_redraw_object( ob );
194                 update_only = 0;
195                 ret = FL_RETURN_CHANGED | FL_RETURN_END;
196                 break;
197             }
198             else if ( ( int ) ( lasttime_left / FL_TIMER_BLINKRATE ) !=
199                                 ( int ) ( sp->time_left / FL_TIMER_BLINKRATE ) )
200                 fl_redraw_object( ob );
201 
202             update_only = 0;
203             break;
204 
205         case FL_FREEMEM:
206             fl_free( ob->spec );
207             break;
208     }
209 
210     return ret;
211 }
212 
213 
214 /***************************************
215  * creates an object
216  ***************************************/
217 
218 FL_OBJECT *
fl_create_timer(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * l)219 fl_create_timer( int          type,
220                  FL_Coord     x,
221                  FL_Coord     y,
222                  FL_Coord     w,
223                  FL_Coord     h,
224                  const char * l )
225 {
226     FL_OBJECT *ob;
227     SPEC *sp;
228 
229     ob = fl_make_object( FL_TIMER, type, x, y, w, h, l, handle_timer );
230 
231     ob->boxtype   = FL_TIMER_BOXTYPE;
232     ob->col1      = FL_TIMER_COL1;
233     ob->col2      = FL_TIMER_COL2;
234     if ( type != FL_VALUE_TIMER )
235         ob->align     = FL_TIMER_ALIGN;
236     else
237         ob->align     = FL_ALIGN_LEFT;
238     ob->lcol      = FL_TIMER_LCOL;
239     ob->spec = sp = fl_calloc( 1, sizeof *sp );
240 
241     fl_set_timer( ob, 0.0 );       /* disabled timer */
242     sp->filter = default_filter;
243 
244     return ob;
245 }
246 
247 
248 /***************************************
249  * Adds an object
250  ***************************************/
251 
252 FL_OBJECT *
fl_add_timer(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * l)253 fl_add_timer( int          type,
254               FL_Coord     x,
255               FL_Coord     y,
256               FL_Coord     w,
257               FL_Coord     h,
258               const char * l )
259 {
260     FL_OBJECT *ob= fl_create_timer( type, x, y, w, h, l );
261 
262     fl_add_object( fl_current_form, ob );
263     if ( ob->type == FL_VALUE_TIMER )
264         fl_set_object_dblbuffer( ob, 1 );
265     return ob;
266 }
267 
268 
269 /***************************************
270  * Sets the timer clock to the particular delay. (0.0 to reset)
271  ***************************************/
272 
273 void
fl_set_timer(FL_OBJECT * ob,double total)274 fl_set_timer( FL_OBJECT * ob,
275               double      total )
276 {
277     SPEC *sp = ob->spec;
278 
279     sp->time_left = sp->timer = total;
280     sp->on = total > 0.0;
281     fl_set_object_automatic( ob, sp->on );
282     fl_gettime( &sp->sec, &sp->usec );
283     if ( ob->type != FL_HIDDEN_TIMER )
284         fl_redraw_object( ob );
285 }
286 
287 
288 /***************************************
289  * returns the amount of time left
290  ***************************************/
291 
292 double
fl_get_timer(FL_OBJECT * ob)293 fl_get_timer( FL_OBJECT * ob )
294 {
295     SPEC *sp = ob->spec;
296 
297     return sp->time_left > 0.0 ? sp->time_left : 0.0;
298 }
299 
300 
301 /***************************************
302  ***************************************/
303 
304 void
fl_set_timer_countup(FL_OBJECT * ob,int yes)305 fl_set_timer_countup( FL_OBJECT * ob,
306                       int         yes )
307 {
308     ( ( SPEC * ) ob->spec )->up = yes;
309 }
310 
311 
312 /***************************************
313  ***************************************/
314 
315 FL_TIMER_FILTER
fl_set_timer_filter(FL_OBJECT * ob,FL_TIMER_FILTER filter)316 fl_set_timer_filter( FL_OBJECT       * ob,
317                      FL_TIMER_FILTER   filter )
318 {
319     SPEC *sp = ob->spec;
320     FL_TIMER_FILTER old = sp->filter;
321 
322     if ( filter != sp->filter )
323     {
324         sp->filter = filter;
325         fl_redraw_object( ob );
326     }
327     return old;
328 }
329 
330 
331 /***************************************
332  ***************************************/
333 
334 void
fl_suspend_timer(FL_OBJECT * ob)335 fl_suspend_timer( FL_OBJECT * ob )
336 {
337     ( ( SPEC * ) ob->spec )->on = 0;
338     fl_set_object_automatic( ob, 0 );
339 }
340 
341 
342 /***************************************
343  ***************************************/
344 
345 void
fl_resume_timer(FL_OBJECT * ob)346 fl_resume_timer( FL_OBJECT * ob )
347 {
348     SPEC *sp = ob->spec;
349     long sec, usec;
350     double elapsed;
351 
352     if ( sp->on )
353         return;
354 
355     elapsed = sp->timer - sp->time_left;
356     fl_gettime( &sec, &usec );
357     sp->sec = sec - ( long ) elapsed;
358     sp->usec = usec - ( long ) ( ( elapsed - ( long ) elapsed ) * 1.0e6 );
359     fl_set_object_automatic( ob, 1 );
360     sp->on = 1;
361 }
362 
363 
364 /*
365  * Local variables:
366  * tab-width: 4
367  * indent-tabs-mode: nil
368  * End:
369  */
370