home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xtici.zip / xtici / widgets / RepeatB.c < prev    next >
C/C++ Source or Header  |  1991-08-28  |  17KB  |  580 lines

  1. /*
  2.  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
  3.  *     All Rights Reserved
  4.  * 
  5.  * This file is a component of an X Window System client which uses the Xcms 
  6.  * Color Management System.  TekColor is a trademark of Tektronix, Inc.  The
  7.  * TekColor Editor is the subject of U.S. and foreign patents pending.  The
  8.  * term "TekHVC" designates a particular color space that is the subject of
  9.  * U.S. Patent No. 4,985,853 (equivalent foreign patents pending).
  10.  * Permission is hereby granted to use, copy, modify, sell, and otherwise
  11.  * distribute this software and its documentation for the X Window System
  12.  * environment, for any purpose and without fee, provided that:
  13.  * 
  14.  * 1.    The code and documentation are only used to implement a 
  15.  *      TekColor Editor in an X Window System environment; and
  16.  * 2.    This copyright and permission notice is reproduced in all copies
  17.  *     of the code and in supporting documentation.
  18.  * 
  19.  * Permission is granted to modify this code as required to allow it to
  20.  * be compiled on any host computer, provided that the functionality of
  21.  * the TekColor Editor is not modified in any way.  A description of any 
  22.  * modifications must be sent to Tektronix, Inc.  Contact 
  23.  * Tektronix Inc., P.O. Box 1000, Mail Station 60-850, 
  24.  * Network Displays Division Engineering, Wilsonville, OR 97070.
  25.  *
  26.  * Tektronix makes no representation about the suitability of this software
  27.  * for any purpose.  It is provided "as is" and with all faults.
  28.  * 
  29.  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
  30.  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  31.  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
  32.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  33.  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
  34.  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  35.  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
  36.  *  
  37.  *  
  38.  *    NAME
  39.  *        RepeatB.c -- The RepeaterButton Widget
  40.  *
  41.  *    DESCRIPTION
  42.  *        This is an arrow button with a repeat value.
  43.  *
  44.  *    HISTORY
  45.  *
  46.  *    HISTORY END
  47.  *
  48.  */
  49.  
  50. #ifndef LINT
  51. static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
  52. #ifdef RCS_ID
  53. static char *rcsid= "$Header: RepeatB.c,v 1.2 91/08/22 11:36:33 adamsc Exp $";
  54. #endif /* RCS_ID */
  55. #endif /* LINT */
  56.  
  57. #include <stdio.h>
  58. #include <X11/IntrinsicP.h>
  59. #include <X11/StringDefs.h>
  60. #include <X11/Xaw/XawInit.h>
  61. #include <X11/Xaw/SimpleP.h>
  62. #include "RepeatBP.h"
  63.  
  64. /*
  65.  * Translations to give user interface of press-notify...-release_or_leave
  66.  */
  67. static char defaultTranslations[] =
  68.     "<Btn1Down>:      arm() armActivate() \n\
  69.          <Btn1Up>:        disarm()";
  70.  
  71. static XtResource resources[] = {
  72. #define offset(field) XtOffset(RepeaterButtonWidget, repeater.field)
  73.     /* {name, class, type, size, offset, default_type, default_addr}, */
  74.     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  75.        offset(fg_pixel), XtRImmediate, (XtPointer) XtDefaultForeground },
  76.     { XtNinitialDelay, XtCDelay, XtRInt, sizeof(int),
  77.        offset(initial), XtRImmediate, (XtPointer) (REP_DEF_INITIAL_DELAY * 4)},
  78.     { XtNminimumDelay, XtCMinimumDelay, XtRInt, sizeof (int),
  79.        offset(minimum), XtRImmediate, (XtPointer) REP_DEF_MINIMUM_DELAY },
  80.     { XtNrepeatDelay, XtCDelay, XtRInt, sizeof(int),
  81.        offset(repeat), XtRImmediate, (XtPointer)REP_DEF_REPEAT_DELAY },
  82.     { XtNarrowDirection, XtCArrowDirection, XtRInt, sizeof(int),
  83.        offset(direction), XtRImmediate, (XtPointer)XtorientationUp },
  84.     { XtNarmCallback, XtCArmCallback, XtRCallback, sizeof(XtPointer),
  85.        offset(arm_callbacks), XtRImmediate, (XtPointer) NULL },
  86.     { XtNactivateCallback, XtCActivateCallback, XtRCallback, sizeof(XtPointer),
  87.        offset(activate_callbacks), XtRImmediate, (XtPointer) NULL },
  88.     { XtNdisarmCallback, XtCDisarmCallback, XtRCallback, sizeof(XtPointer),
  89.        offset(disarm_callbacks), XtRImmediate, (XtPointer) NULL },
  90. #undef offset
  91. };
  92.  
  93. #define MIN_WIDTH 15
  94.  
  95. /* forward declarations for the class struct */
  96. static void Initialize();
  97. static void Destroy();
  98. static void Exposed();
  99. static void Resize();
  100. static Boolean SetValues();
  101. static XtGeometryResult QueryGeometry();
  102.  
  103. /*
  104.  * Actions added by this widget
  105.  */
  106. static void Arm(), ArmActivate(), Disarm();
  107.  
  108. static XtActionsRec actionsList[] = {
  109.     { "arm", Arm },            /* add the timer */
  110.     { "armActivate", ArmActivate },    /* trigger the timer */
  111.     { "disarm", Disarm },        /* clear the timer */
  112. };
  113.  
  114. RepeaterButtonClassRec repeaterButtonClassRec = {
  115.   { /* core fields */
  116.     /* superclass        */  (WidgetClass) &simpleClassRec,
  117.     /* class_name        */    "RepeaterButton",
  118.     /* widget_size        */    sizeof(RepeaterButtonRec),
  119.     /* class_initialize        */    XawInitializeWidgetSet,
  120.     /* class_part_initialize    */    NULL,
  121.     /* class_inited        */    FALSE,
  122.     /* initialize        */    Initialize,
  123.     /* initialize_hook        */    NULL,
  124.     /* realize            */    XtInheritRealize,
  125.     /* actions            */    actionsList,
  126.     /* num_actions        */    XtNumber(actionsList),
  127.     /* resources        */    resources,
  128.     /* num_resources        */    XtNumber(resources),
  129.     /* xrm_class        */    NULLQUARK,
  130.     /* compress_motion        */    TRUE,
  131.     /* compress_exposure    */    TRUE,
  132.     /* compress_enterleave    */    TRUE,
  133.     /* visible_interest        */    FALSE,
  134.     /* destroy            */    Destroy,
  135.     /* resize            */    Resize,
  136.     /* expose            */    Exposed,
  137.     /* set_values        */    SetValues,
  138.     /* set_values_hook        */    NULL,
  139.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  140.     /* get_values_hook        */    NULL,
  141.     /* accept_focus        */    NULL,
  142.     /* version            */    XtVersion,
  143.     /* callback_private        */    NULL,
  144.     /* tm_table            */    defaultTranslations,
  145.     /* query_geometry        */    QueryGeometry,
  146.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  147.     /* extension        */    NULL
  148.   },
  149.   { /* simple fields */
  150.     /* change_sensitive        */    XtInheritChangeSensitive,
  151.   },
  152.   { /* repeater fields */
  153.     /* extension        */    NULL
  154.   }
  155. };
  156.  
  157. WidgetClass repeaterButtonClass = (WidgetClass)&repeaterButtonClassRec;
  158.  
  159. /* forward declarations for utility functions */
  160. static void TimeoutContinue();
  161. static void TimeoutStop();
  162. static void Draw();
  163.  
  164. static char *warning1 = "Delay must be positive";
  165. static char *warning2 = "Foreground color must be different than background";
  166. static char *warning3 = "Arrow direction must be up, down, left or right";
  167.  
  168. static void ArmActivate(rpt)
  169. RepeaterButtonWidget rpt;
  170. {
  171.     /* if already armed (a timeout set), just activate */
  172.     if (rpt->repeater.timer) {
  173.     ScaleCallbackStruct data;
  174.  
  175.     data.reason = CR_ACTIVATE;
  176.     data.event = NULL;
  177.     XtCallCallbacks((Widget)rpt, XtNactivateCallback, &data);
  178.     return;
  179.     }
  180.  
  181.     /* replace the timeout with ours that will activate AND disarm */
  182.     if (rpt->repeater.timer)        /* should always be true */
  183.     XtRemoveTimeOut(rpt->repeater.timer);
  184.  
  185.     rpt->repeater.timer =  XtAppAddTimeOut(
  186.                     XtWidgetToApplicationContext((Widget)rpt),
  187.                     rpt->repeater.repeat, TimeoutStop, rpt);
  188. }
  189.  
  190. static void Warning (widget, message)
  191. Widget widget;
  192. char *message;
  193. {
  194.     /*  R4 says use XtAppWarningMsg but no information on how to set
  195.      *  the parameters.
  196.      */
  197.     if (!widget)
  198.     XtWarning(message);
  199.     else
  200.     XtAppWarning(XtWidgetToApplicationContext(widget), message);
  201. }
  202.  
  203. static void Initialize(req, new)
  204. RepeaterButtonWidget req, new;
  205. {
  206.     if (new->repeater.minimum < 0) {
  207.     Warning(new, warning1);
  208.     new->repeater.minimum = 0;
  209.     }
  210.     if (new->repeater.initial < new->repeater.minimum) {
  211.     Warning(new, warning1);
  212.     new->repeater.initial = new->repeater.minimum;
  213.     }
  214.  
  215.     if (new->repeater.repeat < new->repeater.minimum) {
  216.     Warning(new, warning1);
  217.     new->repeater.repeat = new->repeater.minimum;
  218.     }
  219.  
  220.     new->repeater.timer = (XtIntervalId) 0;
  221.  
  222.     if (req->core.width == 0)
  223.     new->core.width = MIN_WIDTH;
  224.     if (req->core.height == 0)
  225.     new->core.height = MIN_WIDTH;
  226.  
  227.     if (new->core.width > new->core.height) {
  228.         new->repeater.prefer_width = new->core.height;
  229.         new->repeater.prefer_height = new->core.height;
  230.     } else {
  231.         new->repeater.prefer_width = new->core.width;
  232.         new->repeater.prefer_height = new->core.width;
  233.     }
  234.     if (new->repeater.prefer_width < MIN_WIDTH) {
  235.         new->repeater.prefer_width = MIN_WIDTH;
  236.     new->repeater.prefer_height = MIN_WIDTH;
  237.     }
  238.     
  239.     /* Building the GC is deferred until we know we have a window, */
  240.     /* ie, when the widget is first expose */
  241.     new->repeater.localGC = 0;
  242.  
  243.     if (new->core.background_pixel == new->repeater.fg_pixel) {
  244.     Warning(new, warning2);
  245.     if (new->core.background_pixel > 0)
  246.         new->repeater.fg_pixel = new->core.background_pixel - 1;
  247.     else
  248.         new->repeater.fg_pixel = new->core.background_pixel + 1;
  249.     }
  250.  
  251.     switch (new->repeater.direction) {
  252.     case XtorientationUp:
  253.     case XtorientationLeft:
  254.     case XtorientationDown:
  255.     case XtorientationRight:
  256.         break;
  257.     default:
  258.         Warning(new, warning3);
  259.         new->repeater.direction = XtorientationUp;
  260.         break;
  261.     }    
  262. }
  263.  
  264. static void Destroy (w)
  265. RepeaterButtonWidget w;
  266. {
  267.     Disarm (w);
  268.  
  269.     if (w->repeater.localGC)
  270.     XFreeGC(XtDisplay(w), w->repeater.localGC);
  271. }
  272.  
  273. /*ARGSUSED*/
  274. static void Exposed (rpt, evnt, region)
  275. RepeaterButtonWidget rpt;
  276. XEvent *evnt;
  277. Region region;
  278. {
  279.     Draw (rpt);
  280. }
  281.  
  282. static void Resize (rpt)
  283. RepeaterButtonWidget rpt;
  284. {
  285.     /* defer the drawing until we have a window to work in */
  286.     if (!rpt->repeater.localGC)
  287.     return;
  288.  
  289.     Draw (rpt);
  290.  
  291.     if (rpt->core.width > rpt->core.height) {
  292.         rpt->repeater.prefer_width = rpt->core.height;
  293.         rpt->repeater.prefer_height = rpt->core.height;
  294.     } else {
  295.         rpt->repeater.prefer_width = rpt->core.width;
  296.         rpt->repeater.prefer_height = rpt->core.width;
  297.     }
  298.     if (rpt->repeater.prefer_width < MIN_WIDTH) {
  299.         rpt->repeater.prefer_width = MIN_WIDTH;
  300.     rpt->repeater.prefer_height = MIN_WIDTH;
  301.     }
  302. }
  303.  
  304. static XtGeometryResult QueryGeometry(rpt, request, result)
  305. RepeaterButtonWidget rpt;
  306. XtWidgetGeometry *request, *result;
  307. {
  308.     result->request_mode = CWWidth | CWHeight;
  309.  
  310.     result->width = rpt->repeater.prefer_width;
  311.     result->height = rpt->repeater.prefer_height;
  312.  
  313.     if (((request->request_mode & (CWWidth | CWHeight)) == 
  314.       (CWWidth | CWHeight)) &&
  315.      request->width == result->width &&
  316.      request->height == result->height)
  317.         return (XtGeometryYes);
  318.     else if (result->width == rpt->core.width &&
  319.          result->height == rpt->core.height)
  320.         return (XtGeometryNo);
  321.     return (XtGeometryAlmost);
  322. }
  323.  
  324. /*ARGSUSED*/
  325. static Boolean SetValues(cur, req, new)
  326. RepeaterButtonWidget cur, req, new;
  327. {
  328.     if (cur->repeater.minimum < 0) {
  329.     new->repeater.minimum = 0;
  330.     }
  331.  
  332.     if (new->repeater.initial < new->repeater.minimum) {
  333.     Warning(new, warning1);
  334.     new->repeater.initial = new->repeater.minimum;
  335.     }
  336.  
  337.     if (new->repeater.repeat < 0) {
  338.     Warning(new, warning1);
  339.     new->repeater.repeat = cur->repeater.repeat;
  340.     }
  341.  
  342.     if (cur->repeater.minimum != new->repeater.minimum) {
  343.     if (new->repeater.next_delay < new->repeater.minimum)
  344.         new->repeater.next_delay = new->repeater.minimum;
  345.     }
  346.  
  347.     if (cur->repeater.fg_pixel != new->repeater.fg_pixel) {
  348.     if (cur->core.background_pixel == new->repeater.fg_pixel) {
  349.         Warning(new, warning2);
  350.         new->repeater.fg_pixel = cur->core.background_pixel;
  351.     }    
  352.     }
  353.  
  354.     if (cur->core.background_pixel != new->core.background_pixel) {
  355.     if (new->core.background_pixel == new->repeater.fg_pixel) {
  356.         Warning(new, warning2);
  357.         if (new->core.background_pixel > 0)
  358.         new->repeater.fg_pixel = new->core.background_pixel - 1;
  359.         else
  360.         new->repeater.fg_pixel = new->core.background_pixel + 1;
  361.     }
  362.     }
  363.     return(False);
  364. }
  365.  
  366. static void Arm(rpt)
  367. RepeaterButtonWidget rpt;
  368. {
  369.     /* If a timer is there, it was set by arrow button.  override */
  370.     if (rpt->repeater.timer)
  371.     XtRemoveTimeOut(rpt->repeater.timer);
  372.  
  373.     rpt->repeater.timer = XtAppAddTimeOut(
  374.                 XtWidgetToApplicationContext((Widget)rpt),
  375.                 rpt->repeater.initial, TimeoutContinue, rpt);
  376.  
  377.     Draw (rpt);
  378. }
  379.  
  380. static void Disarm(rpt)
  381. RepeaterButtonWidget rpt;
  382. {
  383.     if (rpt->repeater.timer)
  384.     XtRemoveTimeOut(rpt->repeater.timer);
  385.  
  386.     rpt->repeater.timer = 0;
  387.  
  388.     Draw(rpt);
  389. }
  390.  
  391. /*ARGSUSED*/
  392. static void TimeoutContinue(prpt, id)
  393. XtPointer prpt;
  394. XtIntervalId *id;
  395. {
  396.     RepeaterButtonWidget rpt = (RepeaterButtonWidget)prpt;
  397.     ScaleCallbackStruct data;
  398.  
  399.     if (rpt->repeater.timer <= 0) {
  400.     rpt->repeater.timer = 0;
  401.     return;
  402.     }
  403.     rpt->repeater.timer = 0;
  404.  
  405.     data.reason = CR_ACTIVATE;
  406.     data.event = NULL;
  407.     XtCallCallbacks((Widget)rpt, XtNactivateCallback, &data);
  408.  
  409.     rpt->repeater.timer = XtAppAddTimeOut(
  410.                     XtWidgetToApplicationContext((Widget)rpt),
  411.                 rpt->repeater.repeat, TimeoutContinue, rpt);
  412. }
  413.  
  414. /*ARGSUSED*/
  415. static void TimeoutStop(rpt, id)
  416. RepeaterButtonWidget rpt;
  417. XtIntervalId *id;
  418. {
  419.     ScaleCallbackStruct data;
  420.  
  421.     rpt->repeater.timer = 0;
  422.  
  423.     data.reason = CR_ACTIVATE;
  424.     data.event = NULL;
  425.     XtCallCallbacks((Widget)rpt, XtNactivateCallback, &data);
  426.  
  427.     data.reason = CR_DISARM;
  428.     data.event = NULL;
  429.     XtCallCallbacks((Widget)rpt, XtNdisarmCallback, &data);
  430.  
  431.     /* redraw using inherited routine */
  432. }
  433.  
  434. static GC GetGC(rpt)
  435. RepeaterButtonWidget rpt;
  436. {
  437.     XtGCMask mask = GCForeground | GCBackground | GCFillStyle;
  438.     XGCValues gcv;
  439.  
  440.     gcv.foreground = rpt->repeater.fg_pixel;
  441.     gcv.background = rpt->core.background_pixel;
  442.     gcv.fill_style = FillSolid;
  443.  
  444.     return (XCreateGC(XtDisplay(rpt), XtWindow(rpt), mask, &gcv));
  445. }
  446.  
  447. static void Draw(rpt)
  448. RepeaterButtonWidget rpt;
  449. {
  450.     Display *pDpy;
  451.     Window win;
  452.     Position nx, ny;
  453.     Dimension width;
  454.     XPoint points[4];
  455.  
  456.     if (!XtIsRealized((Widget)rpt))
  457.     return;
  458.  
  459.     if (!rpt->repeater.localGC)
  460.     rpt->repeater.localGC = GetGC(rpt);
  461.     if (!rpt->repeater.localGC)
  462.     return;
  463.     
  464.     pDpy = XtDisplay (rpt);
  465.     win = XtWindow(rpt);
  466.  
  467.     XClearWindow (pDpy, win);
  468.  
  469.     switch (rpt->repeater.direction) {
  470.     case XtorientationUp:
  471.         /* when pointing up put the arrow head in lower right */
  472.         if (rpt->core.width > rpt->core.height) {
  473.         nx = rpt->core.width - rpt->core.height;
  474.         ny = 0;
  475.         width = rpt->core.height;
  476.         } else {
  477.         nx = 0;
  478.         ny = rpt->core.height - rpt->core.width;
  479.         width = rpt->core.width;
  480.         }
  481.         points[0].x = nx + (width / 2);
  482.         if (width > 20) {
  483.         points[0].y = ny + 4;
  484.         points[1].x = rpt->core.width - 4;
  485.         points[1].y = rpt->core.height - 4;
  486.         points[2].x = nx + 4;
  487.         } else {
  488.         points[0].y = ny + 1;
  489.         points[1].x = rpt->core.width - 1;
  490.         points[1].y = rpt->core.height - 1;
  491.         points[2].x = nx + 1;
  492.         }
  493.         points[2].y = points[1].y;
  494.         break;
  495.     case XtorientationLeft:
  496.         /* when pointing left put the arrow head in upper right */
  497.         ny = 0;
  498.         if (rpt->core.width > rpt->core.height) {
  499.         nx = rpt->core.width - rpt->core.height;
  500.         width = rpt->core.height;
  501.         } else {
  502.         nx = 0;
  503.         width = rpt->core.width;
  504.         }
  505.         points[0].y = width / 2;
  506.         if (width > 20) {
  507.         points[0].x = nx + 4;
  508.         points[1].x = rpt->core.width - 4;
  509.         points[1].y = 4;
  510.         points[2].y = width - 4;
  511.         } else {
  512.         points[0].x = nx + 1;
  513.         points[1].x = rpt->core.width - 1;
  514.         points[1].y = 1;
  515.         points[2].y = width - 1;
  516.         }
  517.         points[2].x = points[1].x;
  518.         break;
  519.     case XtorientationDown:
  520.         /* when pointing down put the arrow head in upper right */
  521.         ny = 0;
  522.         if (rpt->core.width > rpt->core.height) {
  523.         nx = rpt->core.width - rpt->core.height;
  524.         width = rpt->core.height;
  525.         } else {
  526.         nx = 0;
  527.         width = rpt->core.width;
  528.         }
  529.         points[0].x = nx + (width / 2);
  530.         if (width > 20) {
  531.         points[0].y = width - 4;
  532.         points[1].x = nx + 4;
  533.         points[1].y = 4;
  534.         points[2].x = rpt->core.width - 4;
  535.         } else {
  536.         points[0].y = width - 1;
  537.         points[1].x = nx + 1;
  538.         points[1].y = 1;
  539.         points[2].x = rpt->core.width - 1;
  540.         }
  541.         points[2].y = points[1].y;
  542.         break;
  543.     case XtorientationRight:
  544.         /* when pointing right put the arrow head in upper right */
  545.         nx = 0;
  546.         ny = 0;
  547.         if (rpt->core.width > rpt->core.height) {
  548.         width = rpt->core.height;
  549.         } else {
  550.         width = rpt->core.width;
  551.         }
  552.         points[0].y = width / 2;
  553.         if (width > 20) {
  554.         points[0].x = width - 4;
  555.         points[1].x = 4;
  556.         points[1].y = width - 4;
  557.         points[2].y = 4;
  558.         } else {
  559.         points[0].x = rpt->core.width - 1;
  560.         points[1].x = 1;
  561.         points[1].y = width - 1;
  562.         points[2].y = 1;
  563.         }
  564.         points[2].x = points[1].x;
  565.         break;
  566.     }
  567.  
  568.     if (rpt->repeater.timer) {
  569.     /* With the timer on draw the button in the down position */
  570.     XFillPolygon(pDpy, win, rpt->repeater.localGC, points, 3,
  571.              Convex, CoordModeOrigin);
  572.     } else {
  573.     /* With the timer off draw the button in the up position */
  574.     points[3].x = points[0].x;
  575.     points[3].y = points[0].y;
  576.     XDrawLines(pDpy, win, rpt->repeater.localGC, points, 4,
  577.             CoordModeOrigin);
  578.     }
  579. }
  580.