home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / x / volume10 / xt-examples / part05 / Pushbutton.c < prev   
C/C++ Source or Header  |  1990-11-04  |  13KB  |  445 lines

  1. /***********************************************************
  2. Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
  3.  
  4.                         All Rights Reserved
  5.  
  6. Permission to use, copy, modify, and distribute these examples for any
  7. purpose and without fee is hereby granted, provided that the above
  8. copyright notice appear in all copies and that both that copyright
  9. notice and this permission notice appear in supporting documentation,
  10. and that the name of Digital not be used in advertising or publicity
  11. pertaining to distribution of the software without specific, written
  12. prior permission.
  13.  
  14. DIGITAL AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  15. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  16. FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
  17. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  18. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19. OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  20. OR PERFORMANCE OF THIS SOFTWARE.
  21.  
  22. ******************************************************************/
  23.  
  24. #include <string.h>        /* Needed for string manipulation */
  25. #include <X11/IntrinsicP.h>    /* Intrinsics header file */
  26. #include <X11/StringDefs.h>    /* Resource string definitions */
  27. #include "PushbuttoP.h"        /* Pushbutton private header file */
  28.  
  29. static void InsPixel(), InsPixmap();
  30.  
  31. #define Offset(field) XtOffsetOf(PushbuttonRec, pushbutton.field)
  32.  
  33. static XtResource resources[] = { 
  34.     {XtNcallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
  35.     Offset(callback), XtRCallback, (XtPointer) NULL},
  36.     {"pri.vate", "Pri.vate", XtRBoolean, sizeof(Boolean),
  37.     Offset(use_insens_pixel), XtRImmediate, (XtPointer) TRUE},
  38.     {XtNinsensitiveForeground, XtCForeground, XtRPixel, sizeof(Pixel),
  39.     Offset(insensitive_foreground),
  40.     XtRCallProc, (XtPointer) InsPixel},
  41.     {XtNinsensitivePixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
  42.     Offset(insensitive_pixmap),
  43.     XtRCallProc, (XtPointer) InsPixmap},
  44.     {XtNhighlightBorder, XtCBorderWidth,
  45.     XtRDimension, sizeof(Dimension),
  46.     Offset(highlight_border), XtRImmediate, (XtPointer) 1},
  47.     {XtNaccelString, XtCAccelString, XtRString, sizeof(String),
  48.     XtOffsetOf(PushbuttonRec, label.accel_string),
  49.     XtRString, NULL},
  50.     {XtNacceleratorString, XtCAcceleratorString,
  51.     XtRString, sizeof(String),
  52.     Offset(accelerator_string), XtRString, NULL},
  53.     {XtNborderWidth, XtCBorderWidth,
  54.     XtRDimension, sizeof(Dimension),
  55.     XtOffsetOf(PushbuttonRec, core.border_width),
  56.     XtRImmediate, (XtPointer) 1},
  57. };  
  58.  
  59. #undef Offset
  60.  
  61. static void InsPixel(w, offset, value)
  62.     Widget w;
  63.     int offset;        /* Not used */
  64.     XrmValue *value;
  65. {
  66.     PushbuttonWidget p = (PushbuttonWidget) w;
  67.  
  68.     /* Any value will work; it won't be used */
  69.     value->addr = (caddr_t) &p->label.foreground;
  70.     p->pushbutton.use_insens_pixel = FALSE;
  71. }
  72.  
  73. /* Return a 2x2 pixmap with the foreground at 50% */
  74.  
  75. static Pixmap GetPixmap(pw)
  76.     PushbuttonWidget pw;
  77. {
  78.     static char bits[] = {0x01, 0x02};
  79.  
  80.     return XCreatePixmapFromBitmapData(XtDisplay(pw),
  81.         RootWindowOfScreen(XtScreen(pw)), bits, 2, 2,
  82.         pw->label.foreground, pw->core.background_pixel,
  83.         pw->core.depth);
  84. }
  85.  
  86. static void InsPixmap(w, offset, value)
  87.     Widget w;
  88.     int offset;        /* Not used */
  89.     XrmValue *value;
  90. {
  91.     PushbuttonWidget pw = (PushbuttonWidget) w;
  92.     static Pixmap pixmap;
  93.  
  94.     if (pw->pushbutton.use_insens_pixel) pixmap = None;
  95.     else pixmap = GetPixmap(pw);
  96.  
  97.     value->addr = (caddr_t) &pixmap;
  98. }
  99.  
  100. static char defaultTranslations[] =
  101.     "<EnterWindow>    : highlight()        \n\
  102.      <LeaveWindow>    : unhighlight()        \n\
  103.      <Btn1Down>    : invert()        \n\
  104.      <Btn1Up>    : notify() uninvert()";
  105.  
  106. static void Highlight(), Unhighlight(), Invert(), Uninvert(), Notify();
  107.  
  108. static XtActionsRec actions[] = {
  109.   {"highlight",        Highlight},
  110.   {"unhighlight",    Unhighlight},
  111.   {"invert",        Invert},
  112.   {"uninvert",        Uninvert},
  113.   {"notify",        Notify},
  114. };
  115.  
  116. /* Forward declarations */
  117.  
  118. static void Initialize(), DisplayAccelerator(), Destroy(), Redisplay();
  119. static Boolean SetValues();
  120.  
  121. /* Class record declaration */
  122.  
  123. PushbuttonClassRec pushbuttonClassRec = {
  124.     /* Core class part */
  125.   {
  126.     /* superclass         */    (WidgetClass) &labelClassRec,
  127.     /* class_name         */    "Pushbutton",
  128.     /* widget_size         */    sizeof(PushbuttonRec),
  129.     /* class_initialize      */ NULL,
  130.     /* class_part_initialize */    NULL,
  131.     /* class_inited          */    FALSE,
  132.     /* initialize         */    Initialize,
  133.     /* initialize_hook       */    NULL,        
  134.     /* realize             */    XtInheritRealize,
  135.     /* actions             */    actions,
  136.     /* num_actions         */    XtNumber(actions),
  137.     /* resources         */    resources,
  138.     /* num_resources         */    XtNumber(resources),
  139.     /* xrm_class         */    NULLQUARK,
  140.     /* compress_motion         */    TRUE,
  141.     /* compress_exposure     */    XtExposeCompressMultiple,
  142.     /* compress_enterleave   */    TRUE,
  143.     /* visible_interest         */    FALSE,
  144.     /* destroy             */    NULL,
  145.     /* resize             */    XtInheritResize,
  146.     /* expose             */    Redisplay,
  147.     /* set_values         */    SetValues,
  148.     /* set_values_hook       */    NULL,            
  149.     /* set_values_almost     */    XtInheritSetValuesAlmost,  
  150.     /* get_values_hook       */    NULL,            
  151.     /* accept_focus         */    NULL,
  152.     /* version             */    XtVersion,
  153.     /* callback offsets      */ NULL,
  154.     /* tm_table              */ defaultTranslations,
  155.     /* query_geometry         */    XtInheritQueryGeometry,
  156.     /* display_accelerator   */ DisplayAccelerator,
  157.     /* extension             */ NULL
  158.   },
  159.     /* Label class part */
  160.   {
  161.     /* select_text         */ InheritSelectText,
  162.     /* extension             */ NULL
  163.   },
  164.     /* Pushbutton class part */
  165.   {
  166.     /* extension             */ NULL
  167.   }
  168. };
  169.  
  170. /* Class record pointer */
  171.  
  172. WidgetClass pushbuttonWidgetClass = (WidgetClass) &pushbuttonClassRec;
  173.  
  174. static void Highlight(w, event, params, num_params)
  175.     Widget w;
  176.     XEvent *event;
  177.     String *params;
  178.     Cardinal *num_params;
  179. {
  180.     PushbuttonWidget pw = (PushbuttonWidget) w;
  181.  
  182.     if (!pw->pushbutton.highlighted) {
  183.     pw->pushbutton.highlighted = TRUE;
  184.     if (XtIsRealized(w)) {
  185.         XClearWindow(XtDisplay(w), XtWindow(w));
  186.         (*(XtClass(w)->core_class.expose))(w, event, NULL);
  187.     }
  188.     }
  189. }
  190.  
  191. static void Unhighlight(w, event, params, num_params)
  192.     Widget w;
  193.     XEvent *event;
  194.     String *params;
  195.     Cardinal *num_params;
  196. {
  197.     PushbuttonWidget pw = (PushbuttonWidget) w;
  198.  
  199.     if (pw->pushbutton.highlighted) {
  200.     pw->pushbutton.highlighted = FALSE;
  201.     if (XtIsRealized(w)) {
  202.         XClearWindow(XtDisplay(w), XtWindow(w));
  203.         (*(XtClass(w)->core_class.expose))(w, event, NULL);
  204.     }
  205.     }
  206. }
  207.  
  208. static void Invert(w, event, params, num_params)
  209.     Widget w;
  210.     XEvent *event;
  211.     String *params;
  212.     Cardinal *num_params;
  213. {
  214.     PushbuttonWidget pw = (PushbuttonWidget) w;
  215.  
  216.     if (!pw->pushbutton.inverted) {
  217.     pw->pushbutton.inverted = TRUE;
  218.     pw->label.current_gc = pw->pushbutton.inverted_gc;
  219.     if (XtIsRealized(w)) {
  220.         XClearWindow(XtDisplay(w), XtWindow(w));
  221.         (*(XtClass(w)->core_class.expose))(w, event, NULL);
  222.     }
  223.     }
  224. }
  225.  
  226. static void Uninvert(w, event, params, num_params)
  227.     Widget w;
  228.     XEvent *event;
  229.     String *params;
  230.     Cardinal *num_params;
  231. {
  232.     PushbuttonWidget pw = (PushbuttonWidget) w;
  233.  
  234.     if (pw->pushbutton.inverted) {
  235.     pw->pushbutton.inverted = FALSE;
  236.     if (XtIsSensitive(w)) {
  237.         pw->label.current_gc = pw->label.gc;
  238.     } else pw->label.current_gc = pw->pushbutton.insensitive_gc;
  239.  
  240.     if (XtIsRealized(w)) {
  241.         XClearWindow(XtDisplay(w), XtWindow(w));
  242.         (*(XtClass(w)->core_class.expose))(w, event, NULL);
  243.     }
  244.     }
  245. }
  246.  
  247. static void Notify(w, event, params, num_params)
  248.     Widget w;
  249.     XEvent *event;
  250.     String *params;
  251.     Cardinal *num_params;
  252. {
  253.     PushbuttonWidget pw = (PushbuttonWidget) w;
  254.  
  255.     /* If event is a button event, and the event's window is the
  256.        widget's window, we were invoked normally.  Make sure
  257.        the pointer is really in the window */
  258.  
  259.     if (event != NULL && event->type == ButtonRelease &&
  260.         event->xany.window == XtWindow(w)) {
  261.     XButtonEvent *b = &event->xbutton;
  262.     if (b->x < 0 || b->y < 0 ||
  263.         b->x >= w->core.width || b->y >= w->core.height) return;
  264.     }
  265.  
  266.     XtCallCallbackList(pw, pw->pushbutton.callback, NULL);
  267. }
  268.  
  269. static GC GetInvertedGC(pw)
  270.     PushbuttonWidget pw;
  271. {
  272.     XGCValues    values;
  273.  
  274.     values.foreground = pw->core.background_pixel;
  275.     values.font = pw->label.font->fid;
  276.     return XtGetGC((Widget) pw, GCForeground | GCFont, &values);
  277. }
  278.  
  279. static GC GetInsensitiveGC(pw)
  280.     PushbuttonWidget pw;
  281. {
  282.     XGCValues    values;
  283.  
  284.     values.font = pw->label.font->fid;
  285.  
  286.     if (pw->pushbutton.use_insens_pixel) {
  287.     values.foreground = pw->pushbutton.insensitive_foreground;
  288.     return XtGetGC((Widget) pw, GCForeground | GCFont, &values);
  289.     } else {
  290.     values.tile = pw->pushbutton.insensitive_pixmap;
  291.     values.fill_style = FillTiled;
  292.     return XtGetGC((Widget) pw,
  293.         GCTile | GCFont | GCFillStyle, &values);
  294.     }
  295. }
  296.  
  297. static void Initialize(req, new)
  298.     Widget req, new;
  299. {
  300.     PushbuttonWidget pw = (PushbuttonWidget) new;
  301.  
  302.     pw->pushbutton.insensitive_gc = GetInsensitiveGC(pw);
  303.     pw->pushbutton.inverted_gc = GetInvertedGC(pw);
  304.     pw->pushbutton.accelerator_string =
  305.         XtNewString(pw->pushbutton.accelerator_string);
  306.  
  307.     pw->pushbutton.highlighted = pw->pushbutton.inverted = FALSE;
  308.  
  309.     if (!XtIsSensitive(pw)) {
  310.     pw->label.current_gc = pw->pushbutton.insensitive_gc;
  311.     }
  312. }
  313.  
  314. static Boolean SetValues(old, req, new, args, num_args)
  315.     Widget  old, req, new;
  316.     ArgList args;
  317.     Cardinal *num_args;
  318. {
  319.     PushbuttonWidget oldpw = (PushbuttonWidget) old;
  320.     PushbuttonWidget newpw = (PushbuttonWidget) new;
  321.  
  322. #define NE(field) (oldpw->field != newpw->field)
  323.  
  324.     /* If insensitive fields or button's font has changed, 
  325.        update insensitive GC */
  326.  
  327.     if (NE(pushbutton.insensitive_foreground)) {
  328.     newpw->pushbutton.use_insens_pixel = TRUE;
  329.     }
  330.  
  331.     if (NE(pushbutton.insensitive_pixmap)) {
  332.     if (newpw->pushbutton.insensitive_pixmap == None) {
  333.         newpw->pushbutton.insensitive_pixmap = GetPixmap(newpw);
  334.     }
  335.         newpw->pushbutton.use_insens_pixel = FALSE;
  336.     }
  337.  
  338.     if (NE(pushbutton.insensitive_foreground) || 
  339.         NE(pushbutton.insensitive_pixmap) || NE(label.font->fid)) {
  340.     XtReleaseGC(newpw, oldpw->pushbutton.insensitive_gc);
  341.     newpw->pushbutton.insensitive_gc = GetInsensitiveGC(newpw);
  342.  
  343.     if (newpw->label.current_gc ==
  344.         oldpw->pushbutton.insensitive_gc) {
  345.         newpw->label.current_gc = newpw->pushbutton.insensitive_gc;
  346.     }
  347.     }
  348.  
  349.     /* If background or font has changed, update inverted GC */
  350.  
  351.     if (NE(core.background_pixel) || NE(label.font->fid)) {
  352.     XtReleaseGC(newpw, oldpw->pushbutton.inverted_gc);
  353.     newpw->pushbutton.inverted_gc = GetInvertedGC(newpw);
  354.  
  355.     if (newpw->pushbutton.inverted) {
  356.         newpw->label.current_gc = newpw->pushbutton.inverted_gc;
  357.     }
  358.     }
  359.  
  360.     /* If sensitivity changing, adjust appearance */
  361.  
  362.     if (NE(core.sensitive) || NE(core.ancestor_sensitive)) {
  363.     if (XtIsSensitive(newpw)) {    /* Just made sensitive */
  364.         newpw->label.current_gc = newpw->label.gc;
  365.  
  366.     } else {            /* Just made insensitive */
  367.         newpw->label.current_gc = 
  368.             newpw->pushbutton.insensitive_gc;
  369.  
  370.         /* If currently highlighted, will never receive
  371.            leave event to unhighlight, so unhighlight */
  372.         newpw->pushbutton.highlighted = FALSE;
  373.     }
  374.     }
  375.  
  376.     /* If current graphics context has changed, inverted
  377.        and foreground has changed, or highlighted and highlight
  378.        width has changed, redisplay */
  379.  
  380.     return NE(label.current_gc) ||
  381.        (NE(label.foreground) && newpw->pushbutton.inverted) ||
  382.        (NE(pushbutton.highlight_border) &&
  383.            newpw->pushbutton.highlighted);
  384. #undef NE
  385. }
  386.  
  387. static void Destroy(w)
  388.     Widget w;
  389. {
  390.     PushbuttonWidget pw = (PushbuttonWidget) w;
  391.  
  392.     /* Release the GCs */
  393.  
  394.     XtReleaseGC(w, pw->pushbutton.insensitive_gc);
  395.     XtReleaseGC(w, pw->pushbutton.inverted_gc);
  396.  
  397.     XtFree(pw->pushbutton.accelerator_string);
  398.     XtFree(pw->label.accel_string);
  399. }
  400.  
  401. static void Redisplay(w, event, region)
  402.     Widget w;
  403.     XEvent *event;
  404.     Region region;
  405. {
  406.     PushbuttonWidget pw = (PushbuttonWidget) w;
  407.     int offset;
  408.  
  409.     /* If inverted, fill background with the foreground color */
  410.  
  411.     if (pw->pushbutton.inverted) {
  412.     XFillRectangle(XtDisplay(w), XtWindow(w), pw->label.gc,
  413.         0, 0, pw->core.width, pw->core.height);
  414.     }
  415.  
  416.     /* If highlighted, draw highlighting border */
  417.  
  418.     if (pw->pushbutton.highlighted) {
  419.     offset = pw->pushbutton.highlight_border / 2;
  420.     XDrawRectangle(XtDisplay(w), XtWindow(w), pw->label.current_gc,
  421.         offset, offset,
  422.         pw->core.width - pw->pushbutton.highlight_border,
  423.         pw->core.height - pw->pushbutton.highlight_border);
  424.     }
  425.  
  426.     /* Make Label redisplay the string */
  427.  
  428.     (*pushbuttonWidgetClass->core_class.superclass->core_class.expose)
  429.         (w, event, region);
  430. }
  431.  
  432. static void DisplayAccelerator(w, string)
  433.     Widget w;
  434.     String string;
  435. {
  436.     PushbuttonWidget pw = (PushbuttonWidget) w;
  437.     Arg args[1];
  438.  
  439.     if (pw->pushbutton.accelerator_string != NULL) {
  440.     XtSetArg(args[0], XtNaccelString,
  441.         pw->pushbutton.accelerator_string);
  442.     XtSetValues(w, args, 1);
  443.     }
  444. }
  445.