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 / Zoom.c < prev    next >
C/C++ Source or Header  |  1991-08-28  |  18KB  |  578 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.  *    NAME
  38.  *        Zoom.c -- the Zoom widget
  39.  *
  40.  *    DESCRIPTION
  41.  *        This widget is used within the ColorScale Widget to
  42.  *        display the Zoom lines between the two color bars.
  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: Zoom.c,v 1.2 91/08/22 11:36:47 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 "ZoomP.h"
  63.  
  64. static XtResource resources[] = {
  65. #define offset(field) XtOffset(ZoomWidget, zoom.field)
  66.     /* {name, class, type, size, offset, default_type, default_addr}, */
  67.     { XtNleftMin, XtCMinimum, XtRInt, sizeof(int),
  68.       offset(leftMin), XtRImmediate, (XtPointer)0 },
  69.     { XtNleftMax, XtCMaximum, XtRInt, sizeof(int),
  70.       offset(leftMax), XtRImmediate, (XtPointer)100 },
  71.     { XtNrightMin, XtCMinimum, XtRInt, sizeof(int),
  72.       offset(rightMin), XtRImmediate, (XtPointer)0 },
  73.     { XtNrightMax, XtCMaximum, XtRInt, sizeof(int),
  74.       offset(rightMax), XtRImmediate, (XtPointer)100 },
  75.     { XtNleftLow, XtCValue, XtRInt, sizeof(int),
  76.       offset(leftLow), XtRImmediate, (XtPointer)-1 },
  77.     { XtNleftHigh, XtCValue, XtRInt, sizeof(int),
  78.       offset(leftHigh), XtRImmediate, (XtPointer)-1 },
  79.     { XtNleftValue, XtCValue, XtRInt, sizeof(int),
  80.       offset(leftValue), XtRImmediate, (XtPointer)0 },
  81.     { XtNrightLow, XtCValue, XtRInt, sizeof(int),
  82.       offset(rightLow), XtRImmediate, (XtPointer)-1 },
  83.     { XtNrightHigh, XtCValue, XtRInt, sizeof(int),
  84.       offset(rightHigh), XtRImmediate, (XtPointer)-1 },
  85.     { XtNrightValue, XtCValue, XtRInt, sizeof(int),
  86.       offset(rightValue), XtRImmediate, (XtPointer)0 },
  87.     { XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
  88.       offset(orientation), XtRImmediate, (XtPointer)XtorientVertical },
  89.     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  90.       offset(foreground_pixel), XtRString, "XtDefaultForeground" }
  91. #undef offset
  92. };
  93.  
  94. #define MIN_WIDTH   15
  95. #define MIN_HEIGHT  15
  96. #define MAX_WIDTH   30
  97.  
  98. /* forward declarations for the class struct */
  99. static void Initialize();
  100. static void Destroy();
  101. static void Exposed();
  102. static Boolean SetValues();
  103. #ifdef LATER
  104. static XtGeometryResult PreferredGeometry();
  105. #endif
  106.  
  107. ZoomWidgetClassRec zoomWidgetClassRec = {
  108.   { /* core fields */
  109.     /* superclass        */    (WidgetClass) &simpleClassRec,
  110.     /* class_name        */    "Zoom",
  111.     /* widget_size        */    sizeof(ZoomWidgetRec),
  112.     /* class_initialize        */    NULL,
  113.     /* class_part_initialize    */    NULL,
  114.     /* class_inited        */    FALSE,
  115.     /* initialize        */    Initialize,
  116.     /* initialize_hook        */    NULL,
  117.     /* realize            */    XtInheritRealize,
  118.     /* actions            */    NULL,
  119.     /* num_actions        */    0,
  120.     /* resources        */    resources,
  121.     /* num_resources        */    XtNumber(resources),
  122.     /* xrm_class        */    NULLQUARK,
  123.     /* compress_motion        */    TRUE,
  124.     /* compress_exposure    */    TRUE,
  125.     /* compress_enterleave    */    TRUE,
  126.     /* visible_interest        */    FALSE,
  127.     /* destroy            */    Destroy,
  128.     /* resize            */    NULL,
  129.     /* expose            */    Exposed,
  130.     /* set_values        */    SetValues,
  131.     /* set_values_hook        */    NULL,
  132.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  133.     /* get_values_hook        */    NULL,
  134.     /* accept_focus        */    NULL,
  135.     /* version            */    XtVersion,
  136.     /* callback_private        */    NULL,
  137.     /* tm_table            */    NULL,
  138.     /* query_geometry        */    NULL,
  139.     /* display_accelerator    */    NULL,
  140.     /* extension        */    NULL
  141.   },
  142.   { /* simple fields */
  143.     /* change_sensitive        */    XtInheritChangeSensitive,
  144.   },
  145.   { /* zoom fields */
  146.     /* extension        */    NULL
  147.   }
  148. };
  149.  
  150. WidgetClass zoomWidgetClass = (WidgetClass)&zoomWidgetClassRec;
  151.  
  152. /* forward declarations for utility functions */
  153. static void Draw();
  154. static void GetZoomGC();
  155.  
  156.  
  157. static char *warning1 = "orientation is not vertical or horizontal";
  158. static char *warning2 = "maximum must be greater than minimum";
  159. static char *warning3 = "values must be within the range [min, max]";
  160. static char *warning4 = "improper widget initialization";
  161.  
  162. static void Destroy(self)
  163. ZoomWidget self;
  164. {
  165.     if (self->zoom.gc)
  166.     XFreeGC(XtDisplay(self), self->zoom.gc);
  167. }
  168.  
  169. /*ARGSUSED*/
  170. static void Exposed(self, e, region)
  171. ZoomWidget self;
  172. XEvent *e;
  173. Region region;
  174. {
  175.     Draw(self);
  176. }
  177.  
  178. static void Warning (widget, message)
  179. Widget widget;
  180. char *message;
  181. {
  182.     /*  R4 says use XtAppWarningMsg but no information on how to set
  183.      *  the parameters.
  184.      */
  185.     if (!widget)
  186.     XtWarning(message);
  187.     else
  188.     XtAppWarning(XtWidgetToApplicationContext(widget), message);
  189. }
  190. static void Initialize(req, new)
  191. ZoomWidget req, new;
  192. {
  193.     if ( (new->zoom.orientation != XtorientVertical)
  194.         && (new->zoom.orientation != XtorientHorizontal) ) {
  195.     Warning(new, warning1);
  196.     new->zoom.orientation = XtorientVertical;
  197.     }
  198.  
  199.     if (new->zoom.leftMin > new->zoom.leftMax) {
  200.     Warning(new, warning2);
  201.     new->zoom.leftMax = new->zoom.leftMin + 1;
  202.     }
  203.     if (new->zoom.rightMin > new->zoom.rightMax) {
  204.     Warning(new, warning2);
  205.     new->zoom.rightMax = new->zoom.rightMin + 1;
  206.     }
  207.  
  208.     if (new->zoom.leftLow < 0)
  209.     new->zoom.llEffective = new->zoom.leftMin;
  210.     else
  211.     new->zoom.llEffective = new->zoom.leftLow;
  212.     if (new->zoom.leftHigh < 0)
  213.     new->zoom.lhEffective = new->zoom.leftMax;
  214.     else
  215.     new->zoom.lhEffective = new->zoom.leftHigh;
  216.     if (new->zoom.rightLow < 0)
  217.     new->zoom.rlEffective = new->zoom.rightMin;
  218.     else
  219.     new->zoom.rlEffective = new->zoom.rightLow;
  220.     if (new->zoom.rightHigh < 0)
  221.     new->zoom.rhEffective = new->zoom.rightMax;
  222.     else
  223.     new->zoom.rhEffective = new->zoom.rightHigh;
  224.  
  225.     if ( (new->zoom.llEffective < new->zoom.leftMin) 
  226.         || (new->zoom.llEffective > new->zoom.leftMax) ) {
  227.     Warning(new, warning3);
  228.     new->zoom.llEffective = new->zoom.leftMin;
  229.     }
  230.     if ( (new->zoom.lhEffective < new->zoom.leftMin) 
  231.         || (new->zoom.lhEffective > new->zoom.leftMax) ) {
  232.     Warning(new, warning3);
  233.     new->zoom.lhEffective = new->zoom.leftMax;
  234.     }
  235.     if ( (new->zoom.leftValue < new->zoom.leftMin)
  236.         || (new->zoom.leftValue > new->zoom.leftMax) ) {
  237.     Warning(new, warning3);
  238.     new->zoom.leftValue = new->zoom.leftMin;
  239.     }
  240.     if ( (new->zoom.rlEffective < new->zoom.rightMin) 
  241.         || (new->zoom.rlEffective > new->zoom.rightMax) ) {
  242.     Warning(new, warning3);
  243.     new->zoom.rlEffective = new->zoom.rightMin;
  244.     }
  245.     if ( (new->zoom.rhEffective < new->zoom.rightMin) 
  246.         || (new->zoom.rhEffective > new->zoom.rightMax) ) {
  247.     Warning(new, warning3);
  248.     new->zoom.rhEffective = new->zoom.rightMax;
  249.     }
  250.     if ( (new->zoom.rightValue < new->zoom.rightMin)
  251.         || (new->zoom.rightValue > new->zoom.rightMax) ) {
  252.     Warning(new, warning3);
  253.     new->zoom.rightValue = new->zoom.rightMin;
  254.     }
  255.  
  256.     if (req->core.width == 0)
  257.     new->core.width = MIN_WIDTH;
  258.     if (req->core.height == 0)
  259.     new->core.height = MIN_HEIGHT;
  260.     if (req->core.width > MAX_WIDTH)
  261.     new->core.width = MAX_WIDTH;
  262.  
  263.     /* graphics context creation is deferred until first draw */
  264.     new->zoom.gc = 0;
  265. }
  266.  
  267. /*ARGSUSED*/
  268. static Boolean SetValues(cur, req, new)
  269. ZoomWidget cur, req, new;
  270. {
  271.     Boolean flag;
  272.  
  273.     if ( (new->zoom.orientation != XtorientVertical)
  274.         && (new->zoom.orientation != XtorientHorizontal) ) {
  275.     Warning(new, warning1);
  276.     new->zoom.orientation = XtorientVertical;
  277.     }
  278.  
  279.     if (new->zoom.leftMin > new->zoom.leftMax) {
  280.     Warning(new, warning2);
  281.     new->zoom.leftMax = new->zoom.leftMin + 1;
  282.     }
  283.     if (new->zoom.rightMin > new->zoom.rightMax) {
  284.     Warning(new, warning2);
  285.     new->zoom.rightMax = new->zoom.rightMin + 1;
  286.     }
  287.  
  288.     if (new->zoom.leftLow < 0)
  289.     new->zoom.llEffective = new->zoom.leftMin;
  290.     else
  291.     new->zoom.llEffective = new->zoom.leftLow;
  292.     if (new->zoom.leftHigh < 0)
  293.     new->zoom.lhEffective = new->zoom.leftMax;
  294.     else
  295.     new->zoom.lhEffective = new->zoom.leftHigh;
  296.     if (new->zoom.rightLow < 0)
  297.     new->zoom.rlEffective = new->zoom.rightMin;
  298.     else
  299.     new->zoom.rlEffective = new->zoom.rightLow;
  300.     if (new->zoom.rightHigh < 0)
  301.     new->zoom.rhEffective = new->zoom.rightMax;
  302.     else
  303.     new->zoom.rhEffective = new->zoom.rightHigh;
  304.  
  305.     if ( (new->zoom.llEffective < new->zoom.leftMin) 
  306.         || (new->zoom.llEffective > new->zoom.leftMax) ) {
  307.     Warning(new, warning3);
  308.     new->zoom.llEffective = new->zoom.leftMin;
  309.     }
  310.     if ( (new->zoom.lhEffective < new->zoom.leftMin) 
  311.         || (new->zoom.lhEffective > new->zoom.leftMax) ) {
  312.     Warning(new, warning3);
  313.     new->zoom.lhEffective = new->zoom.leftMax;
  314.     }
  315.     if ( (new->zoom.leftValue < new->zoom.leftMin)
  316.         || (new->zoom.leftValue > new->zoom.leftMax) ) {
  317.     Warning(new, warning3);
  318.     new->zoom.leftValue = new->zoom.leftMin;
  319.     }
  320.     if ( (new->zoom.rlEffective < new->zoom.rightMin) 
  321.         || (new->zoom.rlEffective > new->zoom.rightMax) ) {
  322.     Warning(new, warning3);
  323.     new->zoom.rlEffective = new->zoom.rightMin;
  324.     }
  325.     if ( (new->zoom.rhEffective < new->zoom.rightMin) 
  326.         || (new->zoom.rhEffective > new->zoom.rightMax) ) {
  327.     Warning(new, warning3);
  328.     new->zoom.rhEffective = new->zoom.rightMax;
  329.     }
  330.     if ( (new->zoom.rightValue < new->zoom.rightMin)
  331.         || (new->zoom.rightValue > new->zoom.rightMax) ) {
  332.     Warning(new, warning3);
  333.     new->zoom.rightValue = new->zoom.rightMin;
  334.     }
  335.  
  336.     flag = (new->zoom.orientation != cur->zoom.orientation)
  337.         || (new->zoom.leftMin != cur->zoom.leftMin)
  338.         || (new->zoom.leftMax != cur->zoom.leftMax)
  339.         || (new->zoom.llEffective != cur->zoom.llEffective)
  340.         || (new->zoom.lhEffective != cur->zoom.lhEffective)
  341.         || (new->zoom.leftValue != cur->zoom.leftValue)
  342.         || (new->zoom.rightMin != cur->zoom.rightMin)
  343.         || (new->zoom.rightMax != cur->zoom.rightMax)
  344.         || (new->zoom.rlEffective != cur->zoom.rlEffective)
  345.         || (new->zoom.rhEffective != cur->zoom.rhEffective)
  346.         || (new->zoom.rightValue != cur->zoom.rightValue);
  347.  
  348.     return(flag);
  349. }
  350.  
  351. #ifdef LATER
  352. static XtGeometryResult PreferredGeometry(widget, request, prefer)
  353. Widget widget;
  354. XtWidgetGeometry *request;
  355. XtWidgetGeometry *prefer;
  356. {
  357.     if (!IsZoom(widget))
  358.     return (XtGeometryNo);
  359.  
  360.     prefer->width = request->width;
  361.     prefer->height = request->height;
  362.     prefer->request_mode = CWWidth | CWHeight;
  363.     if ((!(request->request_mode & (CWWidth | CWHeight))) ||
  364.         (request->width == widget->core.width && 
  365.      request->height == widget->core.height))
  366.     return (XtGeometryYes);
  367.  
  368.     if (request->request_mode & CWWidth) {
  369.     if (request->width < MIN_WIDTH) {
  370.         request->width = MIN_WIDTH;
  371.     }
  372.     }
  373.     return (XtGeometryAlmost);
  374. }
  375. #endif /* LATER */
  376.  
  377. #define LineSize    5
  378. #define Left        0
  379. #define Right        (LineSize-1)
  380. #define Top        Left
  381. #define Bot        Right
  382.  
  383. static void Draw(self)
  384. ZoomWidget self;
  385. {
  386.     Display *dpy = XtDisplay(self);
  387.     Window win = XtWindow(self);
  388.     GC gc;
  389.     int width, height;
  390.     int x, y;
  391.     XPoint ltValue, lbValue, rtValue, rbValue;
  392.     XPoint hi[LineSize], lo[LineSize];
  393.     int slots;
  394.     int i;
  395.     int tdx, bdx, tdy, bdy;
  396.     int xdiv, ydiv;
  397.  
  398.     /* back out gracefully if not realized */
  399.     if (!XtIsRealized((Widget)self))
  400.     return;
  401.  
  402.     if (!self->zoom.gc)
  403.     GetZoomGC(self);
  404.     gc = self->zoom.gc;
  405.  
  406.     /*
  407.      * Even though this widget does not draw a box around itself,
  408.      * the widgets adjacent to it do, and the effect is to draw lines
  409.      * with reference to the surrounding widgets.
  410.      */
  411.     /* highlight thickness ??? */
  412.     width = self->core.width - 2 * self->core.border_width;
  413.     height = self->core.height - 2 * self->core.border_width;
  414.     x = self->core.border_width;
  415.     y = self->core.border_width;
  416.  
  417.     /* Check if the widget is so small that zoom should not be drawn */
  418.     if ( (width <= 0) || (height <= 0) )
  419.     return;
  420.  
  421.     if (self->zoom.orientation == XtorientVertical) {
  422.     /* this assumes max on top - should be attribute */
  423.     slots  = self->zoom.leftMax - self->zoom.leftMin + 1;
  424.     hi[Left].x = x;
  425.     hi[Left].y = y + (self->zoom.leftMax - self->zoom.lhEffective) 
  426.             * height / slots;
  427.     ltValue.x = x;
  428.     ltValue.y = y + (self->zoom.leftMax - self->zoom.leftValue)
  429.             * height / slots;
  430.     lbValue.x = x;
  431.     lbValue.y = y - 1 + (self->zoom.leftMax - self->zoom.leftValue + 1)
  432.             * height / slots;
  433.     lo[Left].x = x;
  434.     lo[Left].y = y - 1 
  435.             + (self->zoom.leftMax - self->zoom.llEffective + 1) 
  436.             * height / slots;
  437.  
  438.     slots  = self->zoom.rightMax - self->zoom.rightMin + 1;
  439.     hi[Right].x = x + width;
  440.     hi[Right].y = y + (self->zoom.rightMax - self->zoom.rhEffective) 
  441.             * height / slots;
  442.     rtValue.x = x + width;
  443.     rtValue.y = y + (self->zoom.rightMax - self->zoom.rightValue)
  444.             * height / slots;
  445.     rbValue.x = x + width;
  446.     rbValue.y = y-1 + (self->zoom.rightMax - self->zoom.rightValue + 1)
  447.             * height / slots;
  448.     lo[Right].x = x + width;
  449.     lo[Right].y = y - 1 
  450.             + (self->zoom.rightMax - self->zoom.rlEffective + 1) 
  451.             * height / slots;
  452.  
  453.     /* draw value delimiters with straight lines */
  454.     XDrawLine(dpy, win, gc, ltValue.x, ltValue.y, rtValue.x, rtValue.y);
  455.     XDrawLine(dpy, win, gc, lbValue.x, lbValue.y, rbValue.x, rbValue.y);
  456.  
  457.     /* draw the hi and lo zoom lines with a simple quadratic */
  458.     tdx = width;
  459.         /* zooming left to right */
  460.     if ((lo[Left].y-hi[Left].y) < (lo[Right].y-hi[Right].y)) {
  461.         tdy = hi[Right].y - hi[Left].y;
  462.         bdy = lo[Right].y - lo[Left].y;
  463.         xdiv = 2;
  464.         ydiv = 4;
  465.         for (i = Right - 1; i > Left; i--) {
  466.         hi[i].x = x + (tdx + xdiv/2) / xdiv;
  467.         hi[i].y = hi[Left].y + (tdy + ydiv/2) / ydiv;
  468.         lo[i].x = hi[i].x;
  469.         lo[i].y = lo[Left].y + (bdy + ydiv/2) / ydiv;
  470.         xdiv *= 2;
  471.         ydiv = xdiv * xdiv;
  472.         }
  473.  
  474.         /* zooming right to left */
  475.     } else {
  476.         tdy = hi[Left].y - hi[Right].y;
  477.         bdy = lo[Left].y - lo[Right].y;
  478.         xdiv = 2;
  479.         ydiv = 4;
  480.         for (i = Left + 1; i < Right; i++) {
  481.         hi[i].x = x + (tdx + xdiv/2) / xdiv;
  482.         hi[i].y = hi[Right].y + (tdy + ydiv/2) / ydiv;
  483.         lo[i].x = hi[i].x;
  484.         lo[i].y = lo[Right].y + (bdy + ydiv/2) / ydiv;
  485.         xdiv *= 2;
  486.         ydiv = xdiv * xdiv;
  487.         }
  488.     }
  489.     XDrawLines(dpy, win, gc, hi, LineSize, CoordModeOrigin);
  490.     XDrawLines(dpy, win, gc, lo, LineSize, CoordModeOrigin);
  491.  
  492.     /* WARNING!!!: orientation code horizontal poorly tested */
  493.     } else {
  494.     /* this assumes max on right - should be attribute */
  495.     slots  = self->zoom.leftMax - self->zoom.leftMin + 1;
  496.     hi[Top].y = y;
  497.     hi[Top].x = x + (self->zoom.lhEffective * width / slots);
  498.     ltValue.y = y;
  499.     ltValue.x = x + (self->zoom.leftValue * width / slots);
  500.     lbValue.y = y;
  501.     lbValue.x = x - 1 + (self->zoom.leftValue + 1) * width / slots;
  502.     lo[Top].y = y;
  503.     lo[Top].x = x - 1 + (self->zoom.llEffective + 1) * width / slots;
  504.  
  505.     slots  = self->zoom.rightMax - self->zoom.rightMin + 1;
  506.     hi[Bot].y = y;
  507.     hi[Bot].x = x + (self->zoom.rhEffective * width / slots);
  508.     ltValue.y = y;
  509.     ltValue.x = x + (self->zoom.rightValue * width / slots);
  510.     lbValue.y = y;
  511.     lbValue.x = x - 1 + (self->zoom.rightValue + 1) * width / slots;
  512.     lo[Bot].y = y;
  513.     lo[Bot].x = x - 1 + (self->zoom.rlEffective + 1) * width / slots;
  514.  
  515.     /* draw value delimiters with straight lines */
  516.     XDrawLine(dpy, win, gc, ltValue.x, ltValue.y, rtValue.x, rtValue.y);
  517.     XDrawLine(dpy, win, gc, lbValue.x, lbValue.y, rbValue.x, rbValue.y);
  518.  
  519.     /* draw the hi and lo zoom lines with a simple quadratic */
  520.     tdy = height;
  521.         /* zooming top to bottom */
  522.     if ((lo[Top].x-hi[Top].x) < (lo[Bot].x-hi[Bot].x)) {
  523.         tdx = hi[Bot].x - hi[Top].x;
  524.         bdx = lo[Bot].x - lo[Top].x;
  525.         ydiv = 2;
  526.         xdiv = 4;
  527.         for (i = Bot - 1; i > Top; i--) {
  528.         hi[i].y = y + (tdy + ydiv/2) / ydiv;
  529.         hi[i].x = hi[Top].x + (tdx + xdiv/2) / xdiv;
  530.         lo[i].y = hi[i].y;
  531.         lo[i].x = lo[Top].x + (bdx + xdiv/2) / xdiv;
  532.         ydiv *= 2;
  533.         xdiv = ydiv * ydiv;
  534.         }
  535.  
  536.         /* zooming bottom to top */
  537.     } else {
  538.         tdx = hi[Top].x - hi[Bot].x;
  539.         bdx = lo[Top].x - lo[Bot].x;
  540.         ydiv = 2;
  541.         xdiv = 4;
  542.         for (i = Top + 1; i < Bot; i++) {
  543.         hi[i].y = y + (tdy + ydiv/2) / ydiv;
  544.         hi[i].x = hi[Bot].x + (tdx + xdiv/2) / xdiv;
  545.         lo[i].y = hi[i].y;
  546.         lo[i].x = lo[Bot].x + (bdx + xdiv/2) / xdiv;
  547.         ydiv *= 2;
  548.         xdiv = ydiv * ydiv;
  549.         }
  550.     }
  551.     XDrawLines(dpy, win, gc, hi, LineSize, CoordModeOrigin);
  552.     XDrawLines(dpy, win, gc, lo, LineSize, CoordModeOrigin);
  553.     }
  554. }
  555.  
  556. static void GetZoomGC(self)
  557. ZoomWidget self;
  558. {
  559.     Display    *dpy;
  560.     Window    win;
  561.     XGCValues    gcv;
  562.     XtGCMask    mask;
  563.  
  564.     if (!self ||
  565.     !(dpy = XtDisplayOfObject((Widget)self)) ||
  566.     !(win = XtWindowOfObject((Widget)self))) {
  567.         Warning(self, warning4);
  568.         return;
  569.     }
  570.  
  571.     gcv.fill_style = FillSolid;
  572.     gcv.background = self->core.background_pixel;
  573.     gcv.foreground = self->zoom.foreground_pixel;
  574.  
  575.     mask = GCFillStyle | GCBackground | GCForeground;
  576.     self->zoom.gc = XCreateGC(dpy, win, mask, &gcv);
  577. }
  578.