1 /* widget.c -- Xlib widget support for xspringies
2 * Copyright (C) 1991,1992 Douglas M. DeCarlo
3 *
4 * This file is part of XSpringies, a mass and spring simulation system for X
5 *
6 * XSpringies is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
9 * any later version.
10 *
11 * XSpringies is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XSpringies; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include "defs.h"
25
26 #define NAME_LEN 32
27 #define MAX_OBJS 16
28 #define NUM_DIGS 12
29
30 /* Bitmaps used */
31 static unsigned char check_bits[] = {
32 0x00, 0x00, 0xfe, 0x7f, 0x06, 0x60, 0x0a, 0x50, 0x12, 0x48, 0x22, 0x44,
33 0x42, 0x42, 0x82, 0x41, 0x82, 0x41, 0x42, 0x42, 0x22, 0x44, 0x12, 0x48,
34 0x0a, 0x50, 0x06, 0x60, 0xfe, 0x7f, 0x00, 0x00};
35 static unsigned char checked_bits[] = {
36 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x7f, 0x0e, 0x70, 0x16, 0x68, 0x26, 0x64,
37 0x46, 0x62, 0x86, 0x61, 0x86, 0x61, 0x46, 0x62, 0x26, 0x64, 0x16, 0x68,
38 0x0e, 0x70, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x00};
39 static unsigned char unchecked_bits[] = {
40 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60,
41 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60,
42 0x06, 0x60, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x00};
43 static unsigned char box_bits[] = {
44 0x00, 0x00, 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
45 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
46 0x02, 0x40, 0x02, 0x40, 0xfe, 0x7f, 0x00, 0x00};
47 static unsigned char rarr_bits[] = {
48 0xfc, 0x1f, 0xfe, 0x3f, 0x07, 0x70, 0x13, 0x60, 0x73, 0x60, 0xf3, 0x61,
49 0xf3, 0x67, 0xf3, 0x6f, 0xf3, 0x67, 0xf3, 0x61, 0x73, 0x60, 0x13, 0x60,
50 0x07, 0x70, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00};
51 static unsigned char riarr_bits[] = {
52 0xfc, 0x1f, 0x06, 0x30, 0xfb, 0x6f, 0xed, 0x5f, 0x8d, 0x5f, 0x0d, 0x5e,
53 0x0d, 0x58, 0x0d, 0x50, 0x0d, 0x58, 0x0d, 0x5e, 0x8d, 0x5f, 0xed, 0x5f,
54 0xfb, 0x6f, 0x06, 0x30, 0xfc, 0x1f, 0x00, 0x00};
55 static unsigned char larr_bits[] = {
56 0xfc, 0x1f, 0xfe, 0x3f, 0x07, 0x70, 0x03, 0x64, 0x03, 0x67, 0xc3, 0x67,
57 0xf3, 0x67, 0xfb, 0x67, 0xf3, 0x67, 0xc3, 0x67, 0x03, 0x67, 0x03, 0x64,
58 0x07, 0x70, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00};
59 static unsigned char liarr_bits[] = {
60 0xfc, 0x1f, 0x06, 0x30, 0xfb, 0x6f, 0xfd, 0x5b, 0xfd, 0x58, 0x3d, 0x58,
61 0x0d, 0x58, 0x05, 0x58, 0x0d, 0x58, 0x3d, 0x58, 0xfd, 0x58, 0xfd, 0x5b,
62 0xfb, 0x6f, 0x06, 0x30, 0xfc, 0x1f, 0x00, 0x00};
63
64 /* Types of objects */
65 typedef struct {
66 Window win;
67 int ulx, uly, lrx, lry;
68 int idno;
69 char name[NAME_LEN];
70 boolean state;
71 } button;
72
73 /* Types of objects */
74 typedef struct {
75 Window win;
76 int ulx, uly, lrx, lry;
77 int idno;
78 char name[NAME_LEN];
79 int *activeid;
80 Pixmap pm;
81 int pmwid, pmht;
82 boolean state;
83 boolean disable;
84 } modebutton;
85
86 typedef struct {
87 Window win;
88 int ulx, uly, lrx, lry;
89 int idno;
90 char name[NAME_LEN];
91 boolean nowstate;
92 boolean *state;
93 } checkbox;
94
95 typedef struct {
96 Window win;
97 int ulx, uly, lrx, lry;
98 int idno;
99 char name[NAME_LEN];
100 char format[NAME_LEN];
101 int state, active;
102 double nowvalue;
103 double *value;
104 double vmin, vmax, vincr;
105 } slider;
106
107 /* Object globals */
108 static button buttons[MAX_OBJS];
109 static modebutton mbuttons[MAX_OBJS];
110 static checkbox cboxes[MAX_OBJS];
111 static slider sliders[MAX_OBJS];
112 static char keybuff[NUM_DIGS + 1];
113 static int numb, numm, nums, numc, cur_type, cur_num, cur_but, key_active;
114 static boolean key_dirty;
115 static Pixmap cb_pm, cbc_pm, cbcb_pm, cbub_pm, la_pm, lap_pm, ra_pm, rap_pm;
116
117 /* Flag if the arrow buttons on sliders are in scan mode */
118 boolean scan_flag;
119
120 /* X variables from elsewhere */
121 extern Display *dpy;
122 extern Window main_win;
123 extern GC drawgc, erasegc, fggc, bggc, revgc, hlgc;
124 extern Pixmap acts_pm;
125 void (*notify_func)();
126
127 Pixmap get_pixmap(char *bits, int width, int height, boolean inv);
128
129 void init_widgets(notify)
130 void (*notify)();
131 {
132 numb = nums = numc = numm = cur_type = cur_num = 0;
133 key_active = cur_but = -1;
134 scan_flag = FALSE;
135
136 notify_func = notify;
137
138 cb_pm = get_pixmap(box_bits, 16, 16, FALSE);
139 cbc_pm = get_pixmap(check_bits, 16, 16, FALSE);
140 cbcb_pm = get_pixmap(checked_bits, 16, 16, FALSE);
141 cbub_pm = get_pixmap(unchecked_bits, 16, 16, FALSE);
142 la_pm = get_pixmap(larr_bits, 16, 16, FALSE);
143 lap_pm = get_pixmap(liarr_bits, 16, 16, FALSE);
144 ra_pm = get_pixmap(rarr_bits, 16, 16, FALSE);
145 rap_pm = get_pixmap(riarr_bits, 16, 16, FALSE);
146 }
147
add_button(d,win,ulx,uly,lrx,lry,name,idno)148 void add_button(d, win, ulx, uly, lrx, lry, name, idno)
149 Drawable d;
150 Window win;
151 int ulx, uly, lrx, lry;
152 char *name;
153 int idno;
154 {
155 int len;
156
157 if (numb < MAX_OBJS - 1) {
158 buttons[numb].win = win;
159 buttons[numb].ulx = ulx;
160 buttons[numb].uly = uly;
161 buttons[numb].lrx = lrx;
162 buttons[numb].lry = lry;
163 strncpy(buttons[numb].name, name, NAME_LEN-1);
164 buttons[numb].name[NAME_LEN-1] = '\0';
165 len = strlen(buttons[numb].name);
166 buttons[numb].idno = idno;
167 buttons[numb].state = FALSE;
168
169 XDrawRectangle(dpy, d, drawgc, ulx, uly, lrx - ulx + 1, lry - uly + 1);
170 XDrawRectangle(dpy, d, drawgc, ulx+1, uly+1, lrx - ulx - 1, lry - uly - 1);
171
172 XDrawString(dpy, d, drawgc, (ulx + lrx - len * F_WID) / 2, (uly + lry + F_HT) / 2,
173 buttons[numb].name, len);
174
175 numb++;
176 }
177 }
178
draw_modebutton(d,which)179 void draw_modebutton(d, which)
180 Drawable d;
181 int which;
182 {
183 int ulx, uly, lrx, lry, pmwid, pmht;
184 int len;
185 Pixmap pm;
186
187 ulx = mbuttons[which].ulx;
188 uly = mbuttons[which].uly;
189 lrx = mbuttons[which].lrx;
190 lry = mbuttons[which].lry;
191 pmwid = mbuttons[which].pmwid;
192 pmht = mbuttons[which].pmht;
193 pm = mbuttons[which].pm;
194
195 len = strlen(mbuttons[which].name);
196
197 if (len) {
198 XCopyArea(dpy, pm, d, drawgc, 0, 0, pmwid, pmht, ulx + (lrx - ulx - pmwid) / 2, uly + (lry - uly - 4 * F_HT / 3 - 1 - pmht) / 2);
199 XDrawString(dpy, d, drawgc, ulx + (lrx - ulx - len * F_WID) / 2, lry - F_HT / 3 - 1, mbuttons[which].name, len);
200 } else {
201 XCopyArea(dpy, pm, d, drawgc, 0, 0, pmwid, pmht, ulx + (lrx - ulx - pmwid) / 2, uly + (lry - uly - pmht) / 2);
202 }
203 }
204
add_modebutton(d,win,ulx,uly,lrx,lry,name,pm_bits,pmwid,pmht,idno,activeid,disable)205 void add_modebutton(d, win, ulx, uly, lrx, lry, name, pm_bits, pmwid, pmht, idno, activeid, disable)
206 Drawable d;
207 Window win;
208 int ulx, uly, lrx, lry;
209 char *name;
210 char *pm_bits;
211 int pmwid, pmht;
212 int idno;
213 int *activeid;
214 boolean disable;
215 {
216 if (numm < MAX_OBJS - 1) {
217 mbuttons[numm].win = win;
218 mbuttons[numm].ulx = ulx;
219 mbuttons[numm].uly = uly;
220 mbuttons[numm].lrx = lrx;
221 mbuttons[numm].lry = lry;
222 strncpy(mbuttons[numm].name, name, NAME_LEN-1);
223 mbuttons[numm].name[NAME_LEN-1] = '\0';
224 mbuttons[numm].idno = idno;
225 mbuttons[numm].activeid = activeid;
226 mbuttons[numm].state = (mbuttons[numm].idno == *activeid);
227
228 mbuttons[numm].disable = disable;
229
230 XDrawRectangle(dpy, d, drawgc, ulx, uly, lrx - ulx + 1, lry - uly + 1);
231 XDrawRectangle(dpy, d, drawgc, ulx+1, uly+1, lrx - ulx - 1, lry - uly - 1);
232
233 mbuttons[numm].pm = get_pixmap(pm_bits, pmwid, pmht, FALSE);
234 mbuttons[numm].pmwid = pmwid;
235 mbuttons[numm].pmht = pmht;
236
237 draw_modebutton(d, numm);
238
239 numm++;
240 }
241 }
242
add_checkbox(d,win,ulx,uly,lrx,lry,name,idno,state)243 void add_checkbox(d, win, ulx, uly, lrx, lry, name, idno, state)
244 Drawable d;
245 Window win;
246 int ulx, uly, lrx, lry;
247 char *name;
248 int idno;
249 boolean *state;
250 {
251 int len;
252
253 if (numc < MAX_OBJS - 1) {
254 cboxes[numc].win = win;
255 cboxes[numc].ulx = ulx;
256 cboxes[numc].uly = uly;
257 cboxes[numc].lrx = lrx;
258 cboxes[numc].lry = lry;
259 strncpy(cboxes[numc].name, name, NAME_LEN-1);
260 cboxes[numc].name[NAME_LEN-1] = '\0';
261 len = strlen(cboxes[numc].name);
262 cboxes[numc].idno = idno;
263 cboxes[numc].state = state;
264 cboxes[numc].nowstate = *(cboxes[numc].state);
265
266 XCopyArea(dpy, cb_pm, d, drawgc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2);
267
268 XDrawString(dpy, d, drawgc, ulx + 20, (uly + lry + F_HT) / 2 - 1, cboxes[numc].name, len);
269
270 numc++;
271 }
272 }
273
add_slider(d,win,ulx,uly,lrx,lry,name,format,idno,value,vmax,vmin,vincr)274 void add_slider(d, win, ulx, uly, lrx, lry, name, format, idno, value, vmax, vmin, vincr)
275 Drawable d;
276 Window win;
277 int ulx, uly, lrx, lry;
278 char *name, *format;
279 int idno;
280 double *value;
281 double vmin, vmax, vincr;
282 {
283 int len;
284
285 if (numc < MAX_OBJS - 1) {
286 sliders[nums].win = win;
287 sliders[nums].ulx = ulx;
288 sliders[nums].uly = uly;
289 sliders[nums].lrx = lrx;
290 sliders[nums].lry = lry;
291 strncpy(sliders[nums].name, name, NAME_LEN-1);
292 sliders[nums].name[NAME_LEN-1] = '\0';
293 len = strlen(sliders[nums].name);
294 strncpy(sliders[nums].format, format, NAME_LEN-1);
295 sliders[nums].format[NAME_LEN-1] = '\0';
296 sliders[nums].idno = idno;
297 sliders[nums].value = value;
298 sliders[nums].nowvalue = *(sliders[nums].value);
299 sliders[nums].vmax = vmax;
300 sliders[nums].vmin = vmin;
301 sliders[nums].vincr = vincr;
302 sliders[nums].state = O_NOTHING;
303 sliders[nums].active = FALSE;
304
305 XCopyArea(dpy, la_pm, d, drawgc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2);
306 XCopyArea(dpy, ra_pm, d, drawgc, 0, 0, 16, 16, ulx + 16 + F_WID * NUM_DIGS + 12, (uly + lry - 16) / 2);
307
308 XDrawRectangle(dpy, d, drawgc, ulx + 16 + 2, (uly + lry - 16) / 2, F_WID * NUM_DIGS + 6, F_HT + 4);
309 XDrawRectangle(dpy, d, drawgc, ulx + 16 + 3, (uly + lry - 16) / 2 + 1, F_WID * NUM_DIGS + 4, F_HT + 2);
310
311 XDrawString(dpy, d, drawgc, ulx + 16 + F_WID * NUM_DIGS + 32, (uly + lry + F_HT) / 2 - 2, sliders[nums].name, len);
312
313 nums++;
314 }
315 }
316
activate_mbutton(activeptr,state)317 void activate_mbutton(activeptr, state)
318 int *activeptr;
319 boolean state;
320 {
321 int i;
322
323 for (i = 0; i < numm; i++) {
324 if (mbuttons[i].activeid == activeptr) {
325 *(mbuttons[i].activeid) = state ? mbuttons[i].idno : -1;
326 break;
327 }
328 }
329 }
330
update_mbutton(old_id,new_id)331 static void update_mbutton(old_id, new_id)
332 int old_id, new_id;
333 {
334 int i, ulx, uly, lrx, lry;
335
336 /* Invert old mode button */
337 for (i = 0; i < numm; i++) {
338 if (mbuttons[i].idno == old_id)
339 break;
340 }
341 if (mbuttons[i].idno == old_id) {
342 ulx = mbuttons[i].ulx;
343 uly = mbuttons[i].uly;
344 lrx = mbuttons[i].lrx;
345 lry = mbuttons[i].lry;
346
347 XCopyPlane(dpy, acts_pm, mbuttons[i].win, fggc, ulx+3, uly+3, lrx - ulx - 4, lry - uly - 4, ulx+3, uly+3, 0x1);
348 }
349
350 /* Invert new mode button */
351 for (i = 0; i < numm; i++) {
352 if (mbuttons[i].idno == new_id)
353 break;
354 }
355 if (mbuttons[i].idno == new_id) {
356 ulx = mbuttons[i].ulx;
357 uly = mbuttons[i].uly;
358 lrx = mbuttons[i].lrx;
359 lry = mbuttons[i].lry;
360
361 XCopyPlane(dpy, acts_pm, mbuttons[i].win, revgc, ulx+3, uly+3, lrx - ulx - 4, lry - uly - 4, ulx+3, uly+3, 0x1);
362 }
363 }
364
update_slider_box(cur,ulx,uly,lrx,lry,inverted)365 void update_slider_box(cur, ulx, uly, lrx, lry, inverted)
366 int cur;
367 boolean inverted;
368 {
369 int len;
370 char valuebuf[256];
371
372 if (cur == key_active && key_dirty) {
373 strcpy(valuebuf, keybuff);
374 len = strlen(valuebuf);
375 } else {
376 sprintf(valuebuf, sliders[cur].format, *(sliders[cur].value));
377 if ((len = strlen(valuebuf)) > NUM_DIGS)
378 len = NUM_DIGS;
379 }
380
381 XFillRectangle(dpy, sliders[cur].win, bggc, ulx + 16 + 4, (uly + lry - 16) / 2 + 2, F_WID * NUM_DIGS + 3, F_HT + 1);
382
383 if (inverted) {
384 XFillRectangle(dpy, sliders[cur].win, hlgc, ulx + 16 + 5, (uly + lry - 16) / 2 + 3, F_WID * NUM_DIGS + 1, F_HT - 1);
385 }
386 XDrawString(dpy, sliders[cur].win, inverted ? bggc : fggc, ulx + 16 + 4, (uly + lry + F_HT) / 2 - 2, valuebuf, len);
387 }
388
update_slider(cur)389 void update_slider(cur)
390 int cur;
391 {
392 int ulx, uly, lrx, lry;
393
394 ulx = sliders[cur].ulx;
395 uly = sliders[cur].uly;
396 lrx = sliders[cur].lrx;
397 lry = sliders[cur].lry;
398
399 /* Set to proper range */
400 if (*(sliders[cur].value) < sliders[cur].vmin) {
401 *(sliders[cur].value) = sliders[cur].vmin;
402 } else if (*(sliders[cur].value) > sliders[cur].vmax) {
403 *(sliders[cur].value) = sliders[cur].vmax;
404 }
405
406 update_slider_box(cur, ulx, uly, lrx, lry, cur == key_active);
407 }
408
change_slider_parms(cur,valp,max,min)409 void change_slider_parms(cur, valp, max, min)
410 int cur;
411 double *valp, max, min;
412 {
413 sliders[cur].value = valp;
414 sliders[cur].vmax = max;
415 sliders[cur].vmin = min;
416 }
417
slider_valno(idno)418 int slider_valno(idno)
419 int idno;
420 {
421 int i;
422
423 /* Draw sliders */
424 for (i = 0; i < nums; i++) {
425 if (sliders[i].idno == idno)
426 return i;
427 }
428 return -1;
429 }
430
update_checkbox(cur,active)431 static void update_checkbox(cur, active)
432 int cur;
433 boolean active;
434 {
435 int ulx, uly, lry;
436 Pixmap which_pm;
437
438 ulx = cboxes[cur].ulx;
439 uly = cboxes[cur].uly;
440 lry = cboxes[cur].lry;
441
442 if (active) {
443 which_pm = cboxes[cur].nowstate ? cbub_pm : cbcb_pm;
444 } else {
445 which_pm = *(cboxes[cur].state) ? cbc_pm : cb_pm;
446 }
447
448 XCopyPlane(dpy, which_pm, cboxes[cur].win, fggc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2, 0x1);
449 }
450
redraw_widgets(mode)451 void redraw_widgets(mode)
452 boolean mode;
453 {
454 int i;
455
456 if (mode){
457 /* Draw mode buttons */
458 for (i = 0; i < numm; i++) {
459 if (*(mbuttons[i].activeid) == mbuttons[i].idno)
460 update_mbutton(-1, mbuttons[i].idno);
461 }
462 }
463
464 /* Draw checkboxes */
465 for (i = 0; i < numc; i++) {
466 update_checkbox(i, FALSE);
467 }
468
469 /* Draw sliders */
470 for (i = 0; i < nums; i++) {
471 update_slider(i);
472 }
473
474
475 /* Redraw active object */
476 }
477
key_widgets(key,win)478 boolean key_widgets(key, win)
479 int key;
480 Window win;
481 {
482 int len, ka = key_active;
483
484 if (key_active < 0 || sliders[key_active].win != win)
485 return FALSE;
486
487 len = strlen(keybuff);
488
489 switch (key) {
490 case K_DELETE:
491 if (len > 0) {
492 keybuff[len - 1] = '\0';
493 }
494 break;
495 case K_RETURN:
496 if (keybuff[0]) {
497 sscanf(keybuff, "%lf", sliders[key_active].value);
498 }
499 case K_ESCAPE:
500 key_active = -1;
501 break;
502 default:
503 if (len < NUM_DIGS - 1) {
504 keybuff[len] = (char)key;
505 keybuff[len+1] = '\0';
506 }
507 break;
508 }
509
510 key_dirty = TRUE;
511 update_slider(ka);
512 if (key == K_RETURN) {
513 notify_func(O_SLIDER, ka);
514 }
515 return TRUE;
516 }
517
check_widgets(win,mx,my,butn,mstat)518 boolean check_widgets(win, mx, my, butn, mstat)
519 Window win;
520 int mx, my;
521 int butn, mstat;
522 {
523 int i;
524 int ulx, uly, lrx, lry;
525
526 switch (mstat) {
527 case M_UP:
528 /* If button up, then just deactivate current widget */
529 if (cur_but == butn) {
530 switch (cur_type) {
531 case O_BUTTON:
532 ulx = buttons[cur_num].ulx;
533 uly = buttons[cur_num].uly;
534 lrx = buttons[cur_num].lrx;
535 lry = buttons[cur_num].lry;
536
537 if (buttons[cur_num].state) {
538 XCopyPlane(dpy, acts_pm, win, fggc, ulx+3, uly+3, lrx - ulx - 4, lry - uly - 4, ulx+3, uly+3, 0x1);
539 buttons[cur_num].state = FALSE;
540 notify_func(O_BUTTON, buttons[cur_num].idno);
541 }
542 break;
543
544 case O_MBUTTON:
545 if (mbuttons[cur_num].state) {
546 *(mbuttons[cur_num].activeid) = (*(mbuttons[cur_num].activeid) != mbuttons[cur_num].idno) ? mbuttons[cur_num].idno : -1;
547 mbuttons[cur_num].state = FALSE;
548 notify_func(O_MBUTTON, mbuttons[cur_num].idno);
549 }
550 break;
551
552 case O_SLIDER:
553 ulx = sliders[cur_num].ulx;
554 uly = sliders[cur_num].uly;
555 lrx = sliders[cur_num].lrx;
556 lry = sliders[cur_num].lry;
557
558 if (sliders[cur_num].state == O_LSLIDER) {
559 XCopyPlane(dpy, la_pm, win, fggc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2, 0x1);
560 sliders[cur_num].active = FALSE;
561 notify_func(O_SLIDER, sliders[cur_num].idno);
562 } else if (sliders[cur_num].state == O_RSLIDER) {
563 XCopyPlane(dpy, ra_pm, win, fggc, 0, 0, 16, 16, ulx + 16 + F_WID * NUM_DIGS + 12, (uly + lry - 16) / 2, 0x1);
564 sliders[cur_num].active = FALSE;
565 notify_func(O_SLIDER, sliders[cur_num].idno);
566 } else if (sliders[cur_num].state == O_TSLIDER) {
567 if (sliders[cur_num].active) {
568 key_active = cur_num;
569 key_dirty = FALSE;
570 keybuff[0] = '\0';
571 }
572 }
573
574 scan_flag = FALSE;
575 break;
576
577 case O_CHECKBOX:
578 ulx = cboxes[cur_num].ulx;
579 uly = cboxes[cur_num].uly;
580 lrx = cboxes[cur_num].lrx;
581 lry = cboxes[cur_num].lry;
582
583 if (*(cboxes[cur_num].state) != cboxes[cur_num].nowstate) {
584 *(cboxes[cur_num].state) = cboxes[cur_num].nowstate;
585 update_checkbox(cur_num, FALSE);
586
587 notify_func(O_CHECKBOX, cboxes[cur_num].idno);
588 }
589 break;
590 }
591 cur_type = cur_num = 0;
592 cur_but = -1;
593 return TRUE;
594 }
595 break;
596
597 case M_DOWN:
598 if (cur_but < 0) {
599 /* Check buttons */
600 for (i = 0; i < numb; i++) {
601 ulx = buttons[i].ulx;
602
603 uly = buttons[i].uly;
604 lrx = buttons[i].lrx;
605 lry = buttons[i].lry;
606
607 if (buttons[i].win == win && ulx < mx && mx < lrx && uly < my && my < lry) {
608 if (!buttons[i].state) {
609 XCopyPlane(dpy, acts_pm, win, revgc, ulx+3, uly+3, lrx - ulx - 4, lry - uly - 4, ulx+3, uly+3, 0x1);
610 buttons[i].state = TRUE;
611 }
612 cur_type = O_BUTTON;
613 cur_num = i;
614 cur_but = butn;
615 return TRUE;
616 }
617 }
618
619 /* Check checkboxes */
620 for (i = 0; i < numc; i++) {
621 ulx = cboxes[i].ulx;
622 uly = cboxes[i].uly;
623 lrx = cboxes[i].lrx;
624 lry = cboxes[i].lry;
625
626 if (cboxes[i].win == win && ulx < mx && mx < lrx && uly < my && my < lry) {
627 if (*(cboxes[i].state)) {
628 cboxes[i].nowstate = FALSE;
629 } else {
630 cboxes[i].nowstate = TRUE;
631 }
632 update_checkbox(i, TRUE);
633
634 cur_type = O_CHECKBOX;
635 cur_num = i;
636 cur_but = butn;
637 return TRUE;
638 }
639 }
640
641 /* Check mode buttons */
642 for (i = 0; i < numm; i++) {
643 ulx = mbuttons[i].ulx;
644 uly = mbuttons[i].uly;
645 lrx = mbuttons[i].lrx;
646 lry = mbuttons[i].lry;
647
648 if (mbuttons[i].win == win && ulx < mx && mx < lrx && uly < my && my < lry) {
649 if ((*(mbuttons[i].activeid) == mbuttons[i].idno) && !mbuttons[i].disable)
650 return FALSE;
651
652 update_mbutton(*(mbuttons[i].activeid), (*(mbuttons[i].activeid) != mbuttons[i].idno) ? mbuttons[i].idno : -1);
653 mbuttons[i].state = TRUE;
654
655 cur_type = O_MBUTTON;
656 cur_num = i;
657 cur_but = butn;
658 return TRUE;
659 }
660 }
661
662 /* Check sliders */
663 for (i = 0; i < nums; i++) {
664 ulx = sliders[i].ulx;
665 uly = sliders[i].uly;
666 lrx = sliders[i].lrx;
667 lry = sliders[i].lry;
668
669 if (sliders[i].win == win && ulx < mx && (uly + lry - 16) / 2 < my && my < (uly + lry - 16) / 2 + 16) {
670 if (mx < ulx + 16) {
671 /* Do left arrow */
672 if (i == key_active) {
673 key_widgets(K_RETURN, sliders[key_active].win);
674 }
675 sliders[i].state = O_LSLIDER;
676 XCopyPlane(dpy, lap_pm, win, fggc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2, 0x1);
677 if (butn == 1)
678 *(sliders[i].value) -= sliders[i].vincr;
679 update_slider(i);
680 sliders[i].active = TRUE;
681 if (butn != 1)
682 scan_flag = TRUE;
683 } else if (ulx + 16 + F_WID * NUM_DIGS + 12 < mx && mx < ulx + 16 + F_WID * NUM_DIGS + 12 + 16) {
684 /* Do right arrow */
685 if (i == key_active) {
686 key_widgets(K_RETURN, sliders[key_active].win);
687 }
688 sliders[i].state = O_RSLIDER;
689 XCopyPlane(dpy, rap_pm, win, fggc, 0, 0, 16, 16, ulx + 16 + F_WID * NUM_DIGS + 12, (uly + lry - 16) / 2, 0x1);
690 if (butn == 1)
691 *(sliders[i].value) += sliders[i].vincr;
692 update_slider(i);
693 sliders[i].active = TRUE;
694 if (butn != 1)
695 scan_flag = TRUE;
696 } else if (ulx + 18 < mx && mx < ulx + 18 + F_WID * NUM_DIGS + 6) {
697 /* Do text box */
698 key_widgets(K_RETURN, sliders[key_active].win);
699 sliders[i].state = O_TSLIDER;
700 sliders[i].active = TRUE;
701 update_slider_box(i, ulx, uly, lrx, lry, TRUE);
702 }
703
704 cur_type = O_SLIDER;
705 cur_num = i;
706 cur_but = butn;
707 return TRUE;
708 }
709 }
710
711 }
712 break;
713
714 case M_DRAG:
715 if (cur_but >= 0) {
716 boolean inside;
717
718 switch (cur_type) {
719 case O_BUTTON:
720 ulx = buttons[cur_num].ulx;
721 uly = buttons[cur_num].uly;
722 lrx = buttons[cur_num].lrx;
723 lry = buttons[cur_num].lry;
724
725 inside = (buttons[cur_num].win == win) && ulx < mx && mx < lrx && uly < my && my < lry;
726
727 if ((inside && !buttons[cur_num].state) || (!inside && buttons[cur_num].state)) {
728 /* Flip button value */
729 XCopyPlane(dpy, acts_pm, win, buttons[cur_num].state ? fggc : revgc, ulx+3, uly+3, lrx - ulx - 4, lry - uly - 4, ulx+3, uly+3, 0x1);
730 buttons[cur_num].state = !buttons[cur_num].state;
731 }
732 break;
733
734 case O_MBUTTON:
735 ulx = mbuttons[cur_num].ulx;
736 uly = mbuttons[cur_num].uly;
737 lrx = mbuttons[cur_num].lrx;
738 lry = mbuttons[cur_num].lry;
739
740 inside = (mbuttons[cur_num].win == win) && ulx < mx && mx < lrx && uly < my && my < lry;
741
742 if ((inside && !mbuttons[cur_num].state) || (!inside && mbuttons[cur_num].state)) {
743 /* Flip button value */
744 if (mbuttons[cur_num].state)
745 update_mbutton((*(mbuttons[cur_num].activeid) != mbuttons[cur_num].idno) ? mbuttons[cur_num].idno : -1, *(mbuttons[cur_num].activeid));
746 else
747 update_mbutton(*(mbuttons[cur_num].activeid), (*(mbuttons[cur_num].activeid) != mbuttons[cur_num].idno) ? mbuttons[cur_num].idno : -1);
748
749 mbuttons[cur_num].state = !mbuttons[cur_num].state;
750 }
751 break;
752
753 case O_SLIDER:
754 ulx = sliders[cur_num].ulx;
755 uly = sliders[cur_num].uly;
756 lrx = sliders[cur_num].lrx;
757 lry = sliders[cur_num].lry;
758
759 inside = ((uly + lry - 16) / 2 < my && my < (uly + lry - 16) / 2 + 16);
760
761 if (sliders[cur_num].state == O_LSLIDER) {
762 inside = inside && (ulx < mx) && (mx < ulx + 16);
763
764 if (sliders[cur_num].active && !inside) {
765 XCopyPlane(dpy, la_pm, win, fggc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2, 0x1);
766 sliders[cur_num].active = FALSE;
767 } else if (!sliders[cur_num].active && inside) {
768 XCopyPlane(dpy, lap_pm, win, fggc, 0, 0, 16, 16, ulx, (uly + lry - 16) / 2, 0x1);
769 sliders[cur_num].active = TRUE;
770 }
771 scan_flag = (cur_but != 1 && sliders[cur_num].active);
772 } else if (sliders[cur_num].state == O_RSLIDER) {
773 inside = inside && (ulx + 16 + F_WID * NUM_DIGS + 12 < mx) && (mx < ulx + 16 + F_WID * NUM_DIGS + 12 + 16);
774
775 if (sliders[cur_num].active && !inside) {
776 XCopyPlane(dpy, ra_pm, win, fggc, 0, 0, 16, 16, ulx + 16 + F_WID * NUM_DIGS + 12, (uly + lry - 16) / 2, 0x1);
777 sliders[cur_num].active = FALSE;
778 } else if (!sliders[cur_num].active && inside) {
779 XCopyPlane(dpy, rap_pm, win, fggc, 0, 0, 16, 16, ulx + 16 + F_WID * NUM_DIGS + 12, (uly + lry - 16) / 2, 0x1);
780 sliders[cur_num].active = TRUE;
781 }
782 scan_flag = (cur_but != 1 && sliders[cur_num].active);
783 } else if (sliders[cur_num].state == O_TSLIDER) {
784 inside = (uly + lry - 16) / 2 < my && my <= (uly + lry - 16) / 2 + F_HT + 3 && ulx + 18 < mx && mx < ulx + 18 + F_WID * NUM_DIGS + 6;
785
786 if ((sliders[cur_num].active && !inside) || (!sliders[cur_num].active && inside)) {
787 update_slider_box(cur_num, ulx, uly, lrx, lry, inside);
788 sliders[cur_num].active = !sliders[cur_num].active;
789 }
790 }
791 break;
792
793 case O_CHECKBOX:
794 ulx = cboxes[cur_num].ulx;
795 uly = cboxes[cur_num].uly;
796 lrx = cboxes[cur_num].lrx;
797 lry = cboxes[cur_num].lry;
798
799 inside = (cboxes[cur_num].win == win) && ulx < mx && mx < lrx && uly < my && my < lry;
800
801 if (inside && *(cboxes[cur_num].state) == cboxes[cur_num].nowstate) {
802 cboxes[cur_num].nowstate = !*(cboxes[cur_num].state);
803 } else if (!inside && *(cboxes[cur_num].state) != cboxes[cur_num].nowstate) {
804 cboxes[cur_num].nowstate = *(cboxes[cur_num].state);
805 } else {
806 break;
807 }
808
809 /* Change checkbox value */
810 update_checkbox(cur_num, inside);
811 break;
812 }
813 }
814 break;
815
816 case M_HOLD:
817 if (cur_but >= 1 && cur_type == O_SLIDER) {
818 double mag = 1.0;
819
820 if (cur_but == 3)
821 mag = 10.0;
822
823 if (sliders[cur_num].state == O_LSLIDER) {
824 *(sliders[cur_num].value) -= sliders[cur_num].vincr * mag;
825 update_slider(cur_num);
826 } else if (sliders[cur_num].state == O_RSLIDER) {
827 *(sliders[cur_num].value) += sliders[cur_num].vincr * mag;
828 update_slider(cur_num);
829 }
830 }
831 break;
832 }
833
834 return FALSE;
835 }
836