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