1 /*
2 * buttons.c: Draw MWFA player buttons in X11 window
3 *
4 * Written by: Ullrich Hafner
5 *
6 * This file is part of FIASCO (Fractal Image And Sequence COdec)
7 * Copyright (C) 1994-2000 Ullrich Hafner
8 */
9
10 /*
11 * $Date: 2000/06/15 17:23:11 $
12 * $Author: hafner $
13 * $Revision: 5.2 $
14 * $State: Exp $
15 */
16
17 #include "config.h"
18
19 #ifndef X_DISPLAY_MISSING
20
21 #include <X11/Xlib.h>
22 #include <X11/Intrinsic.h>
23 #include <X11/StringDefs.h>
24
25 #if STDC_HEADERS
26 # include <stdlib.h>
27 #endif /* not STDC_HEADERS */
28
29 #include "types.h"
30 #include "macros.h"
31
32 #include "display.h"
33 #include "binerror.h"
34 #include "buttons.h"
35
36 /*****************************************************************************
37
38 local variables
39
40 *****************************************************************************/
41
42 static const int EVENT_MASK = (KeyPressMask | ButtonPressMask |
43 ButtonReleaseMask | ExposureMask);
44
45 /*****************************************************************************
46
47 prototypes
48
49 *****************************************************************************/
50
51 static void
52 draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n,
53 unsigned n_frames);
54 static void
55 draw_button (x11_info_t *xinfo, binfo_t *binfo,
56 buttons_t button, bool_t pressed);
57 static void
58 draw_control_panel (x11_info_t *xinfo, binfo_t *binfo,
59 unsigned n, unsigned n_frames);
60
61 /*****************************************************************************
62
63 public code
64
65 *****************************************************************************/
66
67 binfo_t *
init_buttons(x11_info_t * xinfo,unsigned n,unsigned n_frames,unsigned buttons_height,unsigned progbar_height)68 init_buttons (x11_info_t *xinfo, unsigned n, unsigned n_frames,
69 unsigned buttons_height, unsigned progbar_height)
70 /*
71 * Initialize a toolbar with the typical collection of video player
72 * buttons (pause, play, record, next, etc.) in the window given by 'xinfo'.
73 * 'n' gives the current frame, 'whereas' n_frames is the total number of
74 * frames of the video stream.
75 * The size of the button toolbar is given by 'buttons_height',
76 * the size of the progressbar is given by 'progbar_height'.
77 *
78 * Return value:
79 * struct managing the toolbar and progressbar information
80 */
81 {
82 XGCValues values;
83 XEvent event;
84 Colormap cmap;
85 XColor gray, dgray, lgray, red;
86 XColor graye, dgraye, lgraye, rede;
87 buttons_t button; /* counter */
88 binfo_t *binfo = calloc (1, sizeof (binfo_t));
89
90 if (!binfo)
91 error ("Out of memory.");
92
93 binfo->width = xinfo->ximage->width;
94 binfo->height = buttons_height;
95 binfo->progbar_height = progbar_height;
96 binfo->record_is_rewind = NO;
97
98 /*
99 * Generate sub-window for control panel
100 */
101 binfo->window = XCreateSimpleWindow (xinfo->display, xinfo->window,
102 0, xinfo->ximage->height,
103 binfo->width, binfo->height, 0,
104 BlackPixel (xinfo->display,
105 xinfo->screen),
106 WhitePixel (xinfo->display,
107 xinfo->screen));
108 XSelectInput(xinfo->display, binfo->window, StructureNotifyMask);
109 XMapWindow (xinfo->display, binfo->window);
110 do
111 {
112 XNextEvent (xinfo->display, &event);
113 }
114 while (event.type != MapNotify || event.xmap.event != binfo->window);
115 XSelectInput (xinfo->display, binfo->window, EVENT_MASK);
116
117 /*
118 * Generate graphic contexts for different colors.
119 */
120 cmap = DefaultColormap (xinfo->display, xinfo->screen);
121 XAllocNamedColor (xinfo->display, cmap, "#404040", &dgray, &dgraye);
122 XAllocNamedColor (xinfo->display, cmap, "white", &lgray, &lgraye);
123 XAllocNamedColor (xinfo->display, cmap, "#a8a8a8", &gray, &graye);
124 XAllocNamedColor (xinfo->display, cmap, "red", &red, &rede);
125
126 values.foreground = BlackPixel (xinfo->display, xinfo->screen);
127 values.background = WhitePixel (xinfo->display, xinfo->screen);
128 binfo->gc [BLACK] = XCreateGC (xinfo->display,
129 RootWindow (xinfo->display, xinfo->screen),
130 (GCForeground | GCBackground), &values);
131 values.foreground = BlackPixel (xinfo->display, xinfo->screen);
132 values.background = WhitePixel (xinfo->display, xinfo->screen);
133 values.line_width = 3;
134 values.join_style = JoinRound;
135 binfo->gc [THICKBLACK] = XCreateGC (xinfo->display,
136 RootWindow (xinfo->display,
137 xinfo->screen),
138 (GCForeground | GCBackground
139 | GCLineWidth | GCJoinStyle), &values);
140 values.foreground = gray.pixel;
141 values.background = WhitePixel (xinfo->display, xinfo->screen);
142 binfo->gc [NGRAY] = XCreateGC (xinfo->display,
143 RootWindow (xinfo->display, xinfo->screen),
144 (GCForeground | GCBackground), &values);
145 values.foreground = lgray.pixel;
146 values.background = WhitePixel (xinfo->display, xinfo->screen);
147 binfo->gc [LGRAY] = XCreateGC (xinfo->display,
148 RootWindow (xinfo->display, xinfo->screen),
149 (GCForeground | GCBackground), &values);
150 values.foreground = dgray.pixel;
151 values.background = WhitePixel (xinfo->display, xinfo->screen);
152 binfo->gc [DGRAY] = XCreateGC (xinfo->display,
153 RootWindow (xinfo->display, xinfo->screen),
154 (GCForeground | GCBackground), &values);
155 values.foreground = red.pixel;
156 values.background = WhitePixel (xinfo->display, xinfo->screen);
157 binfo->gc [RED] = XCreateGC (xinfo->display,
158 RootWindow (xinfo->display, xinfo->screen),
159 (GCForeground | GCBackground), &values);
160
161 for (button = 0; button < NO_BUTTON; button++)
162 binfo->pressed [button] = NO;
163
164 draw_control_panel (xinfo, binfo, n, n_frames);
165
166 return binfo;
167 }
168
169 void
wait_for_input(x11_info_t * xinfo)170 wait_for_input (x11_info_t *xinfo)
171 /*
172 * Wait for key press or mouse click in window 'xinfo'.
173 * Redraw 'image' if event other then ButtonPress or KeyPress occurs.
174 * Enlarge or reduce size of image by factor 2^'enlarge_factor'.
175 *
176 * No return value.
177 *
178 * Side effect:
179 * program is terminated after key press or mouse click.
180 */
181 {
182 bool_t leave_loop = NO;
183
184 XSelectInput (xinfo->display, xinfo->window, EVENT_MASK);
185
186 while (!leave_loop)
187 {
188 XEvent event;
189
190 XMaskEvent (xinfo->display, EVENT_MASK, &event);
191 switch (event.type)
192 {
193 case ButtonPress:
194 case KeyPress:
195 leave_loop = YES;
196 break;
197 default:
198 display_image (0, 0, xinfo);
199 break;
200 }
201 }
202 }
203
204 void
check_events(x11_info_t * xinfo,binfo_t * binfo,unsigned n,unsigned n_frames)205 check_events (x11_info_t *xinfo, binfo_t *binfo, unsigned n, unsigned n_frames)
206 /*
207 * Check the X11 event loop. If the PAUSE buttonin the of panel 'binfo'
208 * is activated wait until next event occurs.
209 * Redraw 'image' if event other then ButtonPress or ButtonRelease occurs.
210 * Enlarge or reduce size of image by factor 2^'enlarge_factor'.
211 * 'n' gives the current frame, 'whereas' n_frames is the total number of
212 * frames of the video stream.
213 *
214 * No return values.
215 *
216 * Side effects:
217 * status of buttons (binfo->pressed [button]) is changed accordingly.
218 */
219 {
220 bool_t leave_eventloop;
221
222 leave_eventloop = (!binfo->pressed [PAUSE_BUTTON]
223 && binfo->pressed [PLAY_BUTTON])
224 || (!binfo->pressed [PAUSE_BUTTON]
225 && binfo->record_is_rewind
226 && binfo->pressed [RECORD_BUTTON])
227 || binfo->pressed [RECORD_BUTTON];
228 draw_progress_bar (xinfo, binfo, n, n_frames);
229
230 if (binfo->pressed [PAUSE_BUTTON] && binfo->pressed [PLAY_BUTTON])
231 {
232 XFlush (xinfo->display);
233 draw_button (xinfo, binfo, PLAY_BUTTON, NO); /* clear PLAY mode */
234 XFlush (xinfo->display);
235 }
236 if (binfo->pressed [PAUSE_BUTTON]
237 && binfo->record_is_rewind && binfo->pressed [RECORD_BUTTON])
238 {
239 XFlush (xinfo->display);
240 draw_button (xinfo, binfo, RECORD_BUTTON, NO); /* clear PLAY mode */
241 XFlush (xinfo->display);
242 }
243
244 if (binfo->pressed [STOP_BUTTON])
245 {
246 XFlush (xinfo->display);
247 draw_button (xinfo, binfo, STOP_BUTTON, NO); /* clear STOP button */
248 XFlush (xinfo->display);
249 }
250
251 do
252 {
253 XEvent event;
254 int button;
255 bool_t wait_release = NO;
256
257
258 if (XCheckMaskEvent (xinfo->display, EVENT_MASK, &event))
259 {
260 switch (event.type)
261 {
262 case ButtonPress:
263 wait_release = NO;
264 if (!(binfo->pressed [RECORD_BUTTON] &&
265 !binfo->record_is_rewind))
266 for (button = 0; button < NO_BUTTON; button++)
267 {
268 int x0, y0, x1, y1; /* button coordinates */
269
270 x0 = button * (binfo->width / NO_BUTTON);
271 y0 = binfo->progbar_height;
272 x1 = x0 + binfo->width / NO_BUTTON;
273 y1 = y0 + binfo->height - binfo->progbar_height - 1;
274 if (event.xbutton.x > x0 && event.xbutton.x < x1
275 && event.xbutton.y > y0 && event.xbutton.y < y1)
276 {
277 draw_button (xinfo, binfo, button,
278 !binfo->pressed [button]);
279 wait_release = YES;
280 break;
281 }
282 }
283 break;
284 case ButtonRelease:
285 wait_release = NO;
286 break;
287 default:
288 wait_release = NO;
289 draw_control_panel (xinfo, binfo, n, n_frames);
290 display_image (0, 0, xinfo);
291 break;
292 }
293 leave_eventloop = !wait_release
294 && (binfo->pressed [PLAY_BUTTON]
295 || binfo->pressed [STOP_BUTTON]
296 || binfo->pressed [RECORD_BUTTON]
297 || binfo->pressed [QUIT_BUTTON]);
298 }
299 } while (!leave_eventloop);
300
301 if ((binfo->pressed [RECORD_BUTTON] && !binfo->record_is_rewind)
302 && n == n_frames - 1)
303 {
304 binfo->record_is_rewind = YES;
305 draw_button (xinfo, binfo, RECORD_BUTTON, NO);
306 }
307 }
308
309 /*****************************************************************************
310
311 private code
312
313 *****************************************************************************/
314
315 static void
draw_control_panel(x11_info_t * xinfo,binfo_t * binfo,unsigned n,unsigned n_frames)316 draw_control_panel (x11_info_t *xinfo, binfo_t *binfo,
317 unsigned n, unsigned n_frames)
318 /*
319 * Draw control panel 'binfo' with all buttons and progressbar in
320 * the given 'window'.
321 * 'n' gives the current frame, 'whereas' n_frames is the total number of
322 * frames of the video stream.
323 *
324 * No return value.
325 */
326 {
327 buttons_t button;
328
329 XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
330 0, 0, binfo->width, binfo->height);
331 draw_progress_bar (xinfo, binfo, n, n_frames);
332 for (button = 0; button < NO_BUTTON; button++)
333 draw_button (xinfo, binfo, button, binfo->pressed [button]);
334 }
335
336 static void
draw_progress_bar(x11_info_t * xinfo,binfo_t * binfo,unsigned n,unsigned n_frames)337 draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n,
338 unsigned n_frames)
339 /*
340 * Draw progressbar of control panel 'binfo' in the given 'window'.
341 * 'n' gives the current frame, whereas 'n_frames' is the total number of
342 * frames of the video stream.
343 *
344 * No return value.
345 */
346 {
347 unsigned x, y, width, height;
348
349 x = 2;
350 y = 1;
351 width = binfo->width - 5;
352 height = binfo->progbar_height - 3;
353
354 XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY],
355 x, y, x + width, y);
356 XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY],
357 x, y, x, y + height - 1);
358 XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY],
359 x + width, y + 1, x + width, y + height);
360 XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY],
361 x, y + height, x + width, y + height);
362
363 x++; y++; width -= 2; height -= 2;
364 XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
365 x, y, width, height);
366
367 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
368 x + n * max (1, width / n_frames), y,
369 max (1, width / n_frames), height);
370 }
371
372 static void
draw_button(x11_info_t * xinfo,binfo_t * binfo,buttons_t button,bool_t pressed)373 draw_button (x11_info_t *xinfo, binfo_t *binfo,
374 buttons_t button, bool_t pressed)
375 /*
376 * Draw 'button' of control panel 'binfo' in the given 'window'.
377 * 'pressed' indicates whether the button is pressed or not.
378 *
379 * No return value.
380 */
381 {
382 grayscale_t top, bottom; /* index of GC */
383 unsigned x, y, width, height; /* coordinates of button */
384
385 x = button * (binfo->width / NO_BUTTON);
386 y = binfo->progbar_height;
387 width = binfo->width / NO_BUTTON;
388 height = binfo->height - binfo->progbar_height - 1;
389
390 if (width < 4 || height < 4)
391 return;
392
393 if (pressed)
394 {
395 top = DGRAY;
396 bottom = LGRAY;
397 }
398 else
399 {
400 top = LGRAY;
401 bottom = DGRAY;
402 }
403
404 x += 2;
405 width -= 4;
406
407 XDrawLine (xinfo->display, binfo->window, binfo->gc [top],
408 x, y, x + width, y);
409 XDrawLine (xinfo->display, binfo->window, binfo->gc [top],
410 x, y, x, y + height - 1);
411 XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom],
412 x + width, y + 1, x + width, y + height);
413 XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom],
414 x, y + height, x + width, y + height);
415
416 x++; y++; width -= 2; height -= 2;
417 XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
418 x, y, width, height);
419
420 switch (button)
421 {
422 case STOP_BUTTON:
423 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
424 x + width / 2 - 6, y + height / 2 - 4, 11, 11);
425 if (pressed && !binfo->pressed [STOP_BUTTON])
426 {
427 draw_button (xinfo, binfo, PLAY_BUTTON, NO);
428 draw_button (xinfo, binfo, PAUSE_BUTTON, NO);
429 draw_button (xinfo, binfo, RECORD_BUTTON, NO);
430 }
431 break;
432 case PAUSE_BUTTON:
433 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
434 x + width / 2 - 6, y + height / 2 - 4, 5, 11);
435 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
436 x + width / 2 + 1, y + height / 2 - 4, 5, 11);
437 break;
438 case PLAY_BUTTON:
439 {
440 XPoint triangle [3];
441
442 triangle [0].x = x + width / 2 - 5;
443 triangle [0].y = y + height / 2 - 5;
444 triangle [1].x = 10;
445 triangle [1].y = 6;
446 triangle [2].x = -10;
447 triangle [2].y = 6;
448
449 XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
450 triangle, 3, Convex, CoordModePrevious);
451 if (pressed && !binfo->pressed [PLAY_BUTTON]
452 && binfo->pressed [RECORD_BUTTON])
453 draw_button (xinfo, binfo, RECORD_BUTTON, NO);
454 }
455 break;
456 case RECORD_BUTTON:
457 if (!binfo->record_is_rewind)
458 {
459 XFillArc (xinfo->display, binfo->window, binfo->gc [RED],
460 x + width / 2 - 5, y + height / 2 - 5, 11, 11, 0,
461 360 * 64);
462 if (pressed && !binfo->pressed [RECORD_BUTTON])
463 {
464 draw_button (xinfo, binfo, STOP_BUTTON, YES);
465 draw_button (xinfo, binfo, PLAY_BUTTON, NO);
466 draw_button (xinfo, binfo, PAUSE_BUTTON, NO);
467 }
468 }
469 else
470 {
471 XPoint triangle [3];
472
473 triangle [0].x = x + width / 2 + 5;
474 triangle [0].y = y + height / 2 - 5;
475 triangle [1].x = -10;
476 triangle [1].y = 6;
477 triangle [2].x = 10;
478 triangle [2].y = 6;
479
480 XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
481 triangle, 3, Convex, CoordModePrevious);
482 if (pressed && !binfo->pressed [RECORD_BUTTON]
483 && binfo->pressed [PLAY_BUTTON])
484 draw_button (xinfo, binfo, PLAY_BUTTON, NO);
485 }
486 break;
487 case QUIT_BUTTON:
488 {
489 XPoint triangle [3];
490
491 triangle [0].x = x + width / 2 - 6;
492 triangle [0].y = y + height / 2 + 2;
493 triangle [1].x = 6;
494 triangle [1].y = -7;
495 triangle [2].x = 6;
496 triangle [2].y = 7;
497
498 XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
499 triangle, 3, Convex, CoordModePrevious);
500 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
501 x + width / 2 - 5, y + height / 2 + 4, 11, 3);
502 }
503 break;
504 default:
505 break;
506 }
507 binfo->pressed [button] = pressed;
508 }
509
510 #endif /* not X_DISPLAY_MISSING */
511