source: trunk/athena/lib/Xj/Button.c @ 12350

Revision 12350, 14.2 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: Button.c,v 1.2 1999-01-22 23:16:48 ghudson Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char *rcsid =
13"$Id: Button.c,v 1.2 1999-01-22 23:16:48 ghudson Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include "Jets.h"
19#include "Button.h"
20
21extern int DEBUG;
22
23#define offset(field) XjOffset(ButtonJet,field)
24
25static XjResource resources[] = {
26  { XjNactivateProc, XjCActivateProc, XjRCallback, sizeof(XjCallback *),
27      offset(button.activateProc), XjRString, NULL },
28  { XjNdeactivateProc, XjCDeactivateProc, XjRCallback, sizeof(XjCallback *),
29      offset(button.deactivateProc), XjRString, NULL },
30  { XjNx, XjCX, XjRInt, sizeof(int),
31      offset(core.x), XjRString, XjInheritValue },
32  { XjNy, XjCY, XjRInt, sizeof(int),
33      offset(core.y), XjRString, XjInheritValue },
34  { XjNwidth, XjCWidth, XjRInt, sizeof(int),
35      offset(core.width), XjRString, XjInheritValue },
36  { XjNheight, XjCHeight, XjRInt, sizeof(int),
37      offset(core.height), XjRString, XjInheritValue },
38  { XjNborderWidth, XjCBorderWidth, XjRInt, sizeof(int),
39      offset(button.borderWidth), XjRString, "1" },
40  { XjNborderThickness, XjCBorderThickness, XjRInt, sizeof(int),
41      offset(button.borderThickness), XjRString, "2" },
42  { XjNpadding, XjCPadding, XjRInt, sizeof(int),
43      offset(button.padding), XjRString, "5" },
44  { XjNforeground, XjCForeground, XjRColor, sizeof(int),
45      offset(button.foreground), XjRString, XjDefaultForeground },
46  { XjNbackground, XjCBackground, XjRColor, sizeof(int),
47      offset(button.background), XjRString, XjDefaultBackground },
48  { XjNreverseVideo, XjCReverseVideo, XjRBoolean, sizeof(Boolean),
49      offset(button.reverseVideo), XjRBoolean, (caddr_t) False },
50  { XjNtoggle, XjCToggle, XjRBoolean, sizeof(Boolean),
51      offset(button.toggle), XjRBoolean, (caddr_t) False },
52  { XjNstate, XjCState, XjRBoolean, sizeof(Boolean),
53      offset(button.state), XjRBoolean, (caddr_t) False },
54  { XjNrepeatDelay, XjCInterval, XjRInt, sizeof(int),
55      offset(button.repeatDelay), XjRString, "0" },
56  { XjNinitialDelay, XjCInterval, XjRInt, sizeof(int),
57      offset(button.initialDelay), XjRString, "0" },
58  { XjNhighlightOnEnter, XjCHighlightOnEnter, XjRBoolean, sizeof(Boolean),
59      offset(button.highlightOnEnter), XjRBoolean, (caddr_t) True },
60};
61
62#undef offset
63
64static Boolean event_handler();
65static void realize(), resize(), querySize(),
66  move(), destroy(), wakeup();
67
68ButtonClassRec buttonClassRec = {
69  {
70    /* class name */            "Button",
71    /* jet size   */            sizeof(ButtonRec),
72    /* classInitialize */       NULL,
73    /* classInitialized? */     1,
74    /* initialize */            NULL,
75    /* prerealize */            NULL,
76    /* realize */               realize,
77    /* event */                 event_handler,
78    /* expose */                NULL,
79    /* querySize */             querySize,
80    /* move */                  move,
81    /* resize */                resize,
82    /* destroy */               destroy,
83    /* resources */             resources,
84    /* number of 'em */         XjNumber(resources)
85  }
86};
87
88JetClass buttonJetClass = (JetClass)&buttonClassRec;
89
90
91/*
92 * Things are currently broken screenwise.
93 * It will be fun to fix later. :)
94 */
95static void realize(me)
96     ButtonJet me;
97{
98  unsigned long valuemask;
99  XGCValues values;
100
101  if (me->button.reverseVideo)
102    {
103      int temp;
104
105      temp = me->button.foreground;
106      me->button.foreground = me->button.background;
107      me->button.background = temp;
108    }
109
110  values.function = GXcopy;
111  values.foreground = me->button.foreground;
112  values.background = me->button.background;
113  values.line_width = me->button.borderThickness;
114  values.graphics_exposures = False;
115  values.cap_style = CapProjecting;
116  valuemask = ( GCForeground | GCBackground | GCLineWidth
117               | GCFunction | GCGraphicsExposures | GCCapStyle );
118
119  me->button.foreground_gc = XjCreateGC(me->core.display,
120                                        me->core.window,
121                                        valuemask,
122                                        &values);
123
124  values.foreground = me->button.background;
125
126  me->button.background_gc = XjCreateGC(me->core.display,
127                                        me->core.window,
128                                        valuemask,
129                                        &values);
130
131  values.foreground = me->button.foreground;
132  values.line_width = me->button.borderWidth;
133
134  me->button.gc = XjCreateGC(me->core.display,
135                             me->core.window,
136                             valuemask,
137                             &values);
138
139  values.function = GXxor;
140  values.foreground = (me->button.foreground ^
141                       me->button.background);
142
143  me->button.invert_gc = XjCreateGC(me->core.display,
144                                    me->core.window,
145                                    valuemask,
146                                    &values);
147
148  /*
149   * Usurp events for this window
150   */
151  XjRegisterWindow(me->core.window, (Jet) me);
152  XjSelectInput(me->core.display, me->core.window,
153                ExposureMask | EnterWindowMask | LeaveWindowMask |
154                StructureNotifyMask | ButtonPressMask | ButtonReleaseMask);
155
156  me->button.inside = 0;
157  me->button.selected = 0;
158  me->button.pressed = 0;
159
160
161  if (me->core.child)
162    {
163      XjVaGetValues(me->core.child,
164                    XjNhighlightProc, &me->button.hilite,
165                    XjNunHighlightProc, &me->button.unhilite,
166                    NULL, NULL);
167    }
168}
169
170
171static void destroy(me)
172     ButtonJet me;
173{
174  XjFreeGC(me->core.display, me->button.gc);
175  XjFreeGC(me->core.display, me->button.invert_gc);
176  XjFreeGC(me->core.display, me->button.foreground_gc);
177  XjFreeGC(me->core.display, me->button.background_gc);
178
179  XjUnregisterWindow(me->core.window, (Jet) me);
180}
181
182
183static void querySize(me, size)
184     ButtonJet me;
185     XjSize *size;
186{
187  if (DEBUG)
188    printf ("QS(button) '%s'\n", me->core.name);
189
190  if (me->core.child != NULL)
191    XjQuerySize(me->core.child, size);
192
193  if (me->core.child == NULL || size->width == -1)
194    size->width = size->height = 0;
195
196  size->width += (me->button.borderWidth +
197                  me->button.borderThickness + me->button.padding) * 2;
198  size->height += (me->button.borderWidth +
199                   me->button.borderThickness + me->button.padding) * 2;
200}
201
202
203static void move(me, x, y)
204     ButtonJet me;
205     int x, y;
206{
207  if (DEBUG)
208    printf ("MV(button) '%s' x=%d,y=%d\n", me->core.name, x, y);
209
210  me->core.x = x;
211  me->core.y = y;
212
213  if (me->core.child != NULL)
214    XjMove(me->core.child,
215           me->core.x + me->button.borderWidth +
216           me->button.borderThickness + me->button.padding,
217           me->core.y + me->button.borderWidth +
218           me->button.borderThickness + me->button.padding);
219}
220
221
222static void resize(me, size)
223     ButtonJet me;
224     XjSize *size;
225{
226  XjSize childSize;
227
228  if (DEBUG)
229    printf ("RS(button) '%s' w=%d,h=%d\n", me->core.name,
230            size->width, size->height);
231
232  me->core.width = size->width;
233  me->core.height = size->height;
234
235  if (me->core.child != NULL)
236    {
237      childSize.width = size->width -
238        (me->button.borderWidth +
239         me->button.borderThickness + me->button.padding) * 2;
240      childSize.height = size->height -
241        (me->button.borderWidth +
242         me->button.borderThickness + me->button.padding) * 2;
243      XjResize((Jet) me->core.child, &childSize);
244    }
245}
246
247
248static void outline(me, foreground)
249     ButtonJet me;
250     Boolean foreground;
251{
252  if (me->button.highlightOnEnter)
253    XDrawRectangle(me->core.display, me->core.window,
254                   ((foreground) ?
255                    me->button.foreground_gc : me->button.background_gc),
256                   me->button.borderWidth + me->button.borderThickness / 2,
257                   me->button.borderWidth + me->button.borderThickness / 2,
258                   me->core.width - (2 * me->button.borderWidth) -
259                   1 - me->button.borderThickness / 2,
260                   me->core.height - (2 * me->button.borderWidth) -
261                   1 - me->button.borderThickness / 2);
262}
263
264
265static void frame(me)
266     ButtonJet me;
267{
268  if (me->button.borderWidth != 0)
269    XDrawRectangle(me->core.display, me->core.window, me->button.gc,
270                   me->button.borderWidth/2,
271                   me->button.borderWidth/2,
272                   me->core.width -
273                   1 - me->button.borderWidth / 2,
274                   me->core.height -
275                   1 - me->button.borderWidth / 2);
276}
277
278
279/* make sure we don't mess with select() */
280static void btn_select(me, flag)
281     ButtonJet me;
282     Boolean flag;
283{
284  if (flag != me->button.selected)
285    {
286      if (me->button.hilite)
287        if (flag)
288          XjCallCallbacks((caddr_t) me->core.child, me->button.hilite, NULL);
289      if (me->button.unhilite)
290        if (!flag)
291          XjCallCallbacks((caddr_t) me->core.child, me->button.unhilite, NULL);
292
293      if (!me->button.hilite)
294        XFillRectangle(me->core.display, me->core.window,
295                       me->button.invert_gc,
296                       me->button.borderWidth + me->button.borderThickness,
297                       me->button.borderWidth + me->button.borderThickness,
298                       me->core.width - 2 * (me->button.borderWidth +
299                                             me->button.borderThickness),
300                       me->core.height - 2 * (me->button.borderWidth +
301                                              me->button.borderThickness));
302      me->button.selected = flag;
303    }
304}
305
306
307static void btn_invert(me, flag)
308     ButtonJet me;
309     Boolean flag;
310{
311  if (flag)
312    {
313      if (me->button.hilite)
314        XjCallCallbacks((caddr_t) me->core.child, me->button.hilite, NULL);
315      else
316        XFillRectangle(me->core.display, me->core.window,
317                       me->button.invert_gc,
318                       me->button.borderWidth + me->button.borderThickness,
319                       me->button.borderWidth + me->button.borderThickness,
320                       me->core.width - 2 * (me->button.borderWidth +
321                                             me->button.borderThickness),
322                       me->core.height - 2 * (me->button.borderWidth +
323                                              me->button.borderThickness));
324    }
325
326  else
327    if (me->button.unhilite)
328      XjCallCallbacks((caddr_t) me->core.child, me->button.unhilite, NULL);
329}
330
331
332static void wakeup(me, id)
333     ButtonJet me;
334     int id;
335{
336  Window junkwin;
337  int junk;
338  unsigned int mask;
339
340  XQueryPointer(XjDisplay(me), XjWindow(me),
341                &junkwin, &junkwin, &junk, &junk, &junk, &junk, &mask);
342
343  if (me->button.inside == True  &&
344      (mask & Button1Mask ||
345       mask & Button2Mask ||
346       mask & Button3Mask ||
347       mask & Button4Mask ||
348       mask & Button5Mask))
349    {
350      XjCallCallbacks((caddr_t) me, me->button.activateProc, NULL);
351      me->button.timerid = XjAddWakeup(wakeup, me, me->button.repeatDelay);
352    }
353}
354
355
356static Boolean event_handler(me, event)
357     ButtonJet me;
358     XEvent *event;
359{
360  switch(event->type)
361    {
362    case GraphicsExpose:
363    case Expose:
364      if (event->xexpose.count != 0)
365        break;
366
367      XClearWindow(me->core.display, me->core.window);
368
369      /* we can deal properly with a single child... */
370      if (me->core.child != NULL)
371        XjExpose(me->core.child, event);
372#ifdef notdefined
373        if (me->core.child->core.classRec->core_class.expose != NULL)
374          me->core.child->core.classRec->core_class.expose(me->core.child,
375                                                           event);
376#endif
377
378      frame(me);
379      if (me->button.toggle)
380        {
381          if (me->button.inside)
382            {
383              outline(me, !me->button.state);
384              if (me->button.pressed)
385                btn_invert(me, me->button.state);
386              else
387                btn_invert(me, !me->button.state);
388            }
389          else
390            {
391              outline(me, me->button.state);
392              if (me->button.pressed)
393                btn_invert(me, !me->button.state);
394              else
395                btn_invert(me, me->button.state);
396            }
397        }
398      else if (me->button.inside)
399        {
400          outline(me, True);
401          btn_invert(me, me->button.pressed);
402        }
403      break;
404
405    case EnterNotify:
406      if (me->button.inside == 1)
407        break;
408      me->button.inside = 1;
409      if (me->button.toggle)
410        {
411          outline(me, !me->button.state);
412          if (me->button.pressed)
413            btn_select(me, !me->button.state);
414        }
415      else
416        {
417          outline(me, True);
418          btn_select(me, me->button.pressed);
419          if (me->button.pressed == True  &&
420              me->button.repeatDelay > 0)
421            {
422              XjCallCallbacks((caddr_t) me, me->button.activateProc, NULL);
423              me->button.timerid = XjAddWakeup(wakeup, me,
424                                               me->button.repeatDelay);
425            }
426        }
427      break;
428
429    case LeaveNotify:
430      if (me->button.inside == 0)
431        break;
432      me->button.inside = 0;
433      if (me->button.toggle)
434        {
435          outline(me, me->button.state);
436          btn_select(me, me->button.state);
437        }
438      else
439        {
440          outline(me, False);
441          btn_select(me, False);
442        }
443      if (me->button.timerid)
444        (void)XjRemoveWakeup(me->button.timerid);
445      break;
446 
447    case ConfigureNotify:
448      if (event->xconfigure.width != me->core.width ||
449          event->xconfigure.height != me->core.height)
450        {
451          XjSize size;
452
453          size.width = event->xconfigure.width;
454          size.height = event->xconfigure.height;
455          XjResize((Jet) me, &size);
456
457          /*
458          me->core.width = event->xconfigure.width;
459          me->core.height = event->xconfigure.height;
460
461          if (me->core.child != NULL)
462            {
463              me->core.child->core.width = me->core.width;
464              me->core.child->core.height = me->core.height;
465            }
466            */
467        }
468      break;
469
470    case ButtonPress:
471    case ButtonRelease:
472      if (me->button.toggle)
473        {
474          if (event->type == ButtonPress)
475            btn_select(me, !me->button.state);
476          else
477            outline(me, me->button.state);
478        }
479      else
480        btn_select(me, event->type == ButtonPress);
481
482      if (event->type == ButtonPress  &&
483          me->button.inside == True  &&
484          me->button.repeatDelay > 0)
485        {
486          XjCallCallbacks((caddr_t) me,
487                          me->button.activateProc,
488                          (caddr_t) event);
489          me->button.timerid = XjAddWakeup(wakeup, me,
490                                           ((me->button.initialDelay > 0)
491                                            ? me->button.initialDelay
492                                            : me->button.repeatDelay));
493        }
494
495      if (event->type == ButtonRelease  &&
496          me->button.pressed == True   &&
497          me->button.inside == True)
498        {
499          if (me->button.toggle)
500            {
501              me->button.state = !(me->button.state);
502              if (me->button.state)
503                XjCallCallbacks((caddr_t) me,
504                                me->button.activateProc,
505                                (caddr_t) event);
506              else
507                XjCallCallbacks((caddr_t) me,
508                                me->button.deactivateProc,
509                                (caddr_t) event);
510            }
511          else
512            if (me->button.repeatDelay <= 0)
513              XjCallCallbacks((caddr_t) me,
514                              me->button.activateProc,
515                              (caddr_t) event);
516        }
517
518      if (event->type == ButtonRelease  &&
519          me->button.timerid)
520        (void)XjRemoveWakeup(me->button.timerid);
521
522      me->button.pressed = (event->type == ButtonPress);
523      break;
524
525    default:
526      return False;
527    }
528  return True;
529}
530
531
532void SetToggleState(me, bool, callcallback)
533     ButtonJet me;
534     Boolean bool, callcallback;
535{
536  if (me->button.inside)
537    outline(me, !bool);
538  else
539    outline(me, bool);
540
541  if (me->button.state != bool)
542    btn_select(me, bool);
543
544  me->button.state = bool;
545
546  if (callcallback)
547    if (bool)
548      XjCallCallbacks((caddr_t) me, me->button.activateProc, NULL);
549    else
550      XjCallCallbacks((caddr_t) me, me->button.deactivateProc, NULL);
551}
552
553Boolean GetToggleState(me)
554     ButtonJet me;
555{
556  return (me->button.state);
557}
Note: See TracBrowser for help on using the repository browser.