home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xmag / Scale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-26  |  26.7 KB  |  1,022 lines

  1. /*
  2.  * $XConsortium: Scale.c,v 1.15 91/08/26 11:00:15 gildea Exp $
  3.  *
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Davor Matic, MIT X Consortium
  24.  */
  25.  
  26.  
  27. #include <stdio.h>
  28. #include <ctype.h>
  29. #include <string.h> 
  30. #include <math.h>
  31. #include <X11/IntrinsicP.h>
  32. #include <X11/StringDefs.h>
  33. #include <X11/Xaw/XawInit.h>
  34. #include "ScaleP.h"
  35. #include <X11/Xosdefs.h>
  36.  
  37. #define myrint(x) floor(x + 0.5)
  38.  
  39. #ifndef X_NOT_STDC_ENV
  40. #include <stdlib.h>
  41. #endif
  42.  
  43. #if defined(ISC) && defined(SYSV) && defined(SYSV386) && __STDC__
  44. extern double atof(char *);
  45. #endif
  46.  
  47. #define streq(a,b) (strcmp( (a), (b) ) == 0)
  48. #define min(x, y) (x > y ? y : x)
  49. #define max(x, y) (x < y ? y : x)
  50.  
  51. #define DefaultBufferSize 1024
  52. #define DefaultScaleFactor NULL
  53.  
  54. #define Offset(field) XtOffsetOf(ScaleRec, scale.field)
  55.  
  56. static XtResource resources[] = {
  57. {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  58.      Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground},
  59. {XtNgravity, XtCGravity, XtRGravity, sizeof(XtGravity),
  60.      Offset(gravity), XtRImmediate, (XtPointer) "ForgetGravity"},
  61. {XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
  62.      Offset(internal_width), XtRImmediate, (XtPointer) 2},
  63. {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
  64.      Offset(internal_height), XtRImmediate, (XtPointer) 2},
  65. {XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
  66.      Offset(resize), XtRImmediate, (XtPointer) True},
  67. {XtNautoscale, XtCAutoscale, XtRBoolean, sizeof(Boolean),
  68.      Offset(autoscale), XtRImmediate, (XtPointer) True},
  69. {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean),
  70.      Offset(proportional), XtRImmediate, (XtPointer) True},
  71. {XtNscaleX, XtCScaleFactor, XtRString, sizeof(String),
  72.      Offset(scale_x_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  73. {XtNscaleY, XtCScaleFactor, XtRString, sizeof(String),
  74.      Offset(scale_y_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  75. {XtNaspectRatio, XtCAspectRatio, XtRString, sizeof(String),
  76.      Offset(aspect_ratio_str), XtRImmediate, (XtPointer) "1.0"},
  77. {XtNprecision, XtCPrecision, XtRString, sizeof(String),
  78.      Offset(precision_str), XtRImmediate, (XtPointer) "0.001"},
  79. {XtNimage, XtCImage, XtRImage, sizeof(XImage*),
  80.      Offset(image), XtRImmediate, (XtPointer) NULL},
  81. {XtNpasteBuffer, XtCPasteBuffer, XtRBoolean, sizeof(Boolean),
  82.      Offset(paste_buffer), XtRImmediate, (XtPointer) False},
  83. {XtNbufferSize, XtCBufferSize, XtRCardinal, sizeof(Cardinal),
  84.      Offset(buffer_size), XtRImmediate, (XtPointer) DefaultBufferSize},
  85. {XtNuserData, XtCuserData, XtRuserData, sizeof(XtPointer),
  86.      Offset(userData), XtRImmediate, (XtPointer) NULL},
  87. { XtNvisual, XtCvisual, XtRVisual, sizeof(Visual*),
  88.      Offset(visual), XtRImmediate, CopyFromParent}
  89. };
  90.  
  91. #undef Offset
  92.  
  93. static void ClassInitialize();
  94. static void Initialize();
  95. static void Realize();
  96. static void Redisplay();
  97. static void Resize();
  98. static void Destroy();
  99. static Boolean SetValues();
  100.  
  101. void SWUnscale();
  102. void SWAutoscale();
  103. void SWInitialSize();
  104. void RequestSelection();
  105. void GrabSelection();
  106.  
  107. static XtActionsRec actions[] =
  108. {
  109. {"unscale", SWUnscale},
  110. {"autoscale", SWAutoscale},
  111. {"initial-size", SWInitialSize},
  112. {"paste", RequestSelection},
  113. {"cut", GrabSelection}
  114. };
  115.  
  116. static char translations[] =
  117. "\
  118.  <Key>u:           unscale()\n\
  119.  <Key>a:           autoscale()\n\
  120.  <Key>i:           initial-size()\n\
  121. ";
  122.  
  123. ScaleClassRec scaleClassRec = {
  124. {   /* core fields */
  125.     /* superclass        */    (WidgetClass) &simpleClassRec,
  126.     /* class_name        */    "Scale",
  127.     /* widget_size        */    sizeof(ScaleRec),
  128.     /* class_initialize        */    ClassInitialize,
  129.     /* class_part_initialize    */    NULL,
  130.     /* class_inited        */    FALSE,
  131.     /* initialize        */    Initialize,
  132.     /* initialize_hook        */    NULL,
  133.     /* realize            */    Realize,
  134.     /* actions            */    actions,
  135.     /* num_actions        */    XtNumber(actions),
  136.     /* resources        */    resources,
  137.     /* num_resources        */    XtNumber(resources),
  138.     /* xrm_class        */    NULLQUARK,
  139.     /* compress_motion        */    TRUE,
  140.     /* compress_exposure    */      XtExposeCompressMaximal|
  141.                                         XtExposeGraphicsExposeMerged,
  142.     /* compress_enterleave    */    TRUE,
  143.     /* visible_interest        */    TRUE,
  144.     /* destroy            */    Destroy,
  145.     /* resize            */    Resize,
  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_private        */    NULL,
  154.     /* tm_table            */      translations,
  155.     /* query_geometry        */    XtInheritQueryGeometry,
  156.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  157.     /* extension        */    NULL
  158.   },
  159.   { 
  160.     /* change_sensitive        */    XtInheritChangeSensitive,
  161.   }
  162. };
  163.  
  164. WidgetClass scaleWidgetClass = (WidgetClass) &scaleClassRec;
  165.     
  166.  
  167.  
  168. /*
  169.  * Private Procedures
  170.  */
  171.  
  172.  
  173. static void ClassInitialize()
  174. {
  175.  
  176.  
  177.  
  178. void GetGC(sw)
  179.     ScaleWidget sw;
  180. {
  181.     XGCValues values;
  182.     
  183.     values.foreground = sw->scale.foreground_pixel;
  184.     values.background = sw->core.background_pixel;
  185.     values.function = GXcopy;
  186.     
  187.     sw->scale.gc = XtGetGC((Widget) sw,
  188.                GCForeground | 
  189.                GCBackground | 
  190.                GCFunction,
  191.                &values);
  192. }
  193.  
  194.  
  195.  
  196. void Proportional();
  197.  
  198. void GetInitialScaleValues(sw)
  199.     ScaleWidget sw;
  200. {
  201.     if (sw->scale.proportional) {
  202.     sw->scale.scale_x = sw->scale.scale_y =
  203.         ((sw->scale.aspect_ratio > 1.0) ?
  204.          sw->scale.aspect_ratio : 1.0 / sw->scale.aspect_ratio) *
  205.          (sw->scale.precision > 1.0 ?
  206.           sw->scale.precision : 1.0);
  207.     Proportional(sw); /* need to cut them down to proper values */
  208.     }
  209.     else
  210.     sw->scale.scale_x = sw->scale.scale_y = 1.0;
  211. }
  212.  
  213.  
  214.  
  215. void GetRectangleBuffer(sw, buffer_size)
  216.     ScaleWidget sw;
  217.     Cardinal buffer_size;
  218.     /*
  219.      * This procedure will realloc a new rectangles buffer.
  220.      * If the new buffer size is less than nrectangles, some
  221.      * information will be lost.
  222.      */
  223. {
  224.     if (buffer_size == 0) {
  225.     buffer_size = DefaultBufferSize;
  226.     XtWarning("buffer size has to be a positive number greater than zero");
  227.     }
  228.     sw->scale.rectangles = (XRectangle *)
  229.     XtRealloc((char *) sw->scale.rectangles, 
  230.           buffer_size * sizeof(XRectangle));
  231.     sw->scale.buffer_size = buffer_size;
  232. }
  233.  
  234.  
  235.  
  236. /* ARGSUSED */
  237. static void Initialize(request, new)
  238.     Widget request, new;
  239. {
  240.     ScaleWidget new_sw = (ScaleWidget) new;
  241.     
  242.     new_sw->scale.table.x = (Position *) NULL;
  243.     new_sw->scale.table.y = (Position *) NULL;
  244.     new_sw->scale.table.width = (Dimension *) NULL;
  245.     new_sw->scale.table.height = (Dimension *) NULL;
  246.     
  247.     new_sw->scale.nrectangles = 0;
  248.     new_sw->scale.rectangles = (XRectangle *) NULL;
  249.     
  250.     GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  251.     
  252.     GetGC(new_sw);
  253.     
  254.     if (new_sw->scale.image != NULL) {
  255.     if (new_sw->core.width == 0)
  256.         new_sw->core.width = 
  257.         new_sw->scale.image->width + 2 * new_sw->scale.internal_width;
  258.     if (new_sw->core.height == 0)
  259.         new_sw->core.height = 
  260.         new_sw->scale.image->height + 2 *new_sw->scale.internal_height;
  261.     }
  262.     else {
  263.     if (new_sw->core.width == 0)
  264.         new_sw->core.width = 1 + 2 * new_sw->scale.internal_width;
  265.     if (new_sw->core.height == 0)
  266.         new_sw->core.height = 1 + 2 * new_sw->scale.internal_height;
  267.     new_sw->scale.image = XCreateImage(XtDisplay(new),
  268.                        DefaultVisual(XtDisplay(new), 
  269.                             DefaultScreen(XtDisplay(new))),
  270.                        1, XYBitmap, 0, 
  271.                        XtCalloc(1, sizeof(char)),
  272.                        1, 1, 8, 0);
  273.     }
  274.  
  275.     if ((new_sw->scale.aspect_ratio = 
  276.      atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  277.     new_sw->scale.aspect_ratio = 1.0;
  278.     XtWarning("AspectRatio has to be a positive number. (forced to 1.0)");
  279.     }
  280.  
  281.     if ((new_sw->scale.precision =
  282.          atof(new_sw->scale.precision_str)) < 0.0) {
  283.     new_sw->scale.precision = 0.001;
  284.     XtWarning("Precision has to be a positive number. (forced to 0.001)");
  285.     }
  286.     
  287.     if (new_sw->scale.scale_x_str == DefaultScaleFactor
  288.     || 
  289.     new_sw->scale.scale_y_str == DefaultScaleFactor)
  290.     GetInitialScaleValues(new_sw);
  291.     else {
  292.     if ((new_sw->scale.scale_x = 
  293.          atof(new_sw->scale.scale_x_str)) < 0.0) {
  294.         new_sw->scale.scale_x = 1.0;
  295.         XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  296.     }
  297.     if ((new_sw->scale.scale_y = 
  298.          atof(new_sw->scale.scale_y_str)) < 0.0) {
  299.         new_sw->scale.scale_y = 1.0;
  300.         XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  301.     }
  302.     }
  303. }
  304.  
  305.  
  306.  
  307. void BuildTable(sw)
  308.     ScaleWidget sw;
  309.     /* 
  310.      * This procedure builds scaling table for image in the scale struct
  311.      * Requires image, scale_x and scale_y to be set properly
  312.      */
  313. {
  314.     Position x, y;
  315.     
  316.     XtFree((char *) sw->scale.table.x);
  317.     XtFree((char *) sw->scale.table.y);
  318.     XtFree((char *) sw->scale.table.width);
  319.     XtFree((char *) sw->scale.table.height);
  320.     sw->scale.table.x = 
  321.     (Position *) XtMalloc(sizeof(Position) * sw->scale.image->width);
  322.     sw->scale.table.y = 
  323.     (Position *) XtMalloc(sizeof(Position) * sw->scale.image->height);
  324.     sw->scale.table.width = 
  325.     (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->width);
  326.     sw->scale.table.height = 
  327.     (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->height);
  328.     
  329.     /* Build the scaling table */    
  330.     for (x = 0; x < sw->scale.image->width; x++) {
  331.     sw->scale.table.x[(int) x] = (Position) myrint(sw->scale.scale_x * x);
  332.     sw->scale.table.width[(int) x] = (Dimension)
  333.         myrint(sw->scale.scale_x *(x + 1)) - myrint(sw->scale.scale_x * x);
  334.     }
  335.     for (y = 0; y < sw->scale.image->height; y++) {
  336.     sw->scale.table.y[(int) y] = (Position) myrint(sw->scale.scale_y * y);
  337.     sw->scale.table.height[(int) y] = (Dimension)
  338.         myrint(sw->scale.scale_y *(y + 1)) - myrint(sw->scale.scale_y * y);
  339.     }
  340. }
  341.  
  342.  
  343.  
  344. void FlushRectangles(sw, drawable, gc)
  345.     ScaleWidget sw;
  346.     Drawable drawable;
  347.     GC gc;
  348. {
  349.     XFillRectangles(XtDisplay(sw), drawable, gc, 
  350.             sw->scale.rectangles, sw->scale.nrectangles);
  351.     
  352.     sw->scale.nrectangles = 0;
  353. }
  354.  
  355.  
  356.  
  357. void FillRectangle(sw, drawable, gc, x, y, width, height)
  358.     ScaleWidget sw;
  359.     Drawable drawable;
  360.     GC gc;
  361.     Position x, y;
  362.     Dimension width, height;
  363. {
  364.     
  365.     if (sw->scale.nrectangles == sw->scale.buffer_size)
  366.     FlushRectangles(sw, drawable, gc);
  367.  
  368.     sw->scale.rectangles[(int) sw->scale.nrectangles].x = x;
  369.     sw->scale.rectangles[(int) sw->scale.nrectangles].y = y;
  370.     sw->scale.rectangles[(int) sw->scale.nrectangles].width = width;
  371.     sw->scale.rectangles[(int) sw->scale.nrectangles].height = height;
  372.  
  373.     ++sw->scale.nrectangles;
  374. }
  375.  
  376.  
  377.  
  378. void ScaleImage(sw, drawable, img_x, img_y, dst_x, dst_y, img_width,img_height)
  379.     ScaleWidget sw;
  380.     Drawable drawable;
  381.     Position img_x, img_y;
  382.     Position dst_x, dst_y;
  383.     Dimension img_width, img_height;
  384.     /* 
  385.      * This procedure scales image into the specified drawable
  386.      * It assumes scaling table was already built
  387.      */
  388. {
  389.     GC gc;
  390.     XGCValues gcv;
  391.     Position x, y;
  392.     Pixel pixel;
  393.     
  394.     /* Clip the img coordinates */
  395.     img_x = min(max(img_x, 0), (Position) sw->scale.image->width - 1);
  396.     img_y = min(max(img_y, 0), (Position) sw->scale.image->height - 1);
  397.     img_width = 
  398.       min(img_width, (Dimension)(sw->scale.image->width - (Dimension)img_x));
  399.     img_height = 
  400.       min(img_height, (Dimension)(sw->scale.image->height - (Dimension)img_y));
  401.  
  402.     if (sw->scale.scale_x == 1.0 && sw->scale.scale_y == 1.0) 
  403.     XPutImage(XtDisplay(sw), drawable, sw->scale.gc, sw->scale.image, 
  404.           img_x, img_y, dst_x, dst_y, 
  405.           img_width, img_height);
  406.     else {
  407.     dst_x = dst_x - sw->scale.table.x[(int) img_x];
  408.     dst_y = dst_y - sw->scale.table.y[(int) img_y];
  409.  
  410.     gc = XCreateGC(XtDisplay(sw), drawable, 0, NULL);
  411.  
  412.     gcv.function = GXcopy;
  413.     XChangeGC(XtDisplay(sw), gc, GCFunction, &gcv);
  414.  
  415.     /* make sure gc knows the right background */
  416.     gcv.background = sw->core.background_pixel;
  417.     XChangeGC(XtDisplay(sw), gc, GCBackground, &gcv);    
  418.  
  419.     /* Set the background of drawable.  If the most frequent color
  420.        is the background color it can speed up scaling process. */
  421.     gcv.foreground = gcv.background;
  422.     XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  423.     XFillRectangle(XtDisplay(sw), drawable, gc, 
  424.                sw->scale.table.x[(int) img_x] + dst_x, 
  425.                sw->scale.table.y[(int) img_y] + dst_y, 
  426.                sw->scale.table.x[(int) img_x + img_width - 1] - 
  427.                sw->scale.table.x[(int) img_x], 
  428.                sw->scale.table.y[(int) img_y + img_height - 1] - 
  429.                sw->scale.table.y[(int) img_y]);
  430.     
  431.     if (sw->scale.image->format == XYBitmap) {
  432.         for (x = img_x; x < img_x + (Position)img_width; x++)
  433.         for (y = img_y; y < img_y + (Position)img_height; y++) {
  434.             pixel = XGetPixel(sw->scale.image, x, y);
  435.             if (pixel) /* Do not draw background */
  436.             FillRectangle(sw, drawable, sw->scale.gc, 
  437.                       sw->scale.table.x[(int) x] + dst_x, 
  438.                       sw->scale.table.y[(int) y] + dst_y, 
  439.                       sw->scale.table.width[(int) x], 
  440.                       sw->scale.table.height[(int) y]);
  441.         }
  442.         FlushRectangles(sw, drawable, sw->scale.gc);
  443.     }
  444.     else {
  445.         for (x = img_x; x < img_x + (Position)img_width; x++)
  446.         for (y = img_y; y < img_y + (Position)img_height; y++) {
  447.             pixel = XGetPixel(sw->scale.image, x, y);
  448.             if (pixel != gcv.background) { /* Do not draw background */
  449.             if (gcv.foreground != pixel) { /* Change fg to pixel */
  450.                 gcv.foreground = pixel;
  451.                 XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  452.             }
  453.             XFillRectangle(XtDisplay(sw), drawable, gc,
  454.                        sw->scale.table.x[(int) x] + dst_x, 
  455.                        sw->scale.table.y[(int) y] + dst_y, 
  456.                        sw->scale.table.width[(int) x], 
  457.                        sw->scale.table.height[(int) y]);
  458.             }
  459.         }
  460.     }
  461.     XFreeGC(XtDisplay(sw), gc);
  462.     }
  463. }
  464.  
  465.  
  466.  
  467. int FindPixel(sw, x, y, img_x, img_y, img_pixel)
  468.     ScaleWidget sw;
  469.     Position x, y; /* (x,y) == (0,0) where image starts in sw window*/
  470.     Position *img_x, *img_y;
  471.     Pixel    *img_pixel;
  472. {
  473.     if (*img_x < 0 || *img_x >= sw->scale.image->width 
  474.     ||
  475.     *img_y < 0 || *img_y >= sw->scale.image->height)
  476.     return (-1);
  477.     
  478.     if (sw->scale.table.x[(int) *img_x] >= x) {
  479.     --*img_x;
  480.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  481.     }
  482.     if (sw->scale.table.x[(int) *img_x] + 
  483.     (Position)sw->scale.table.width[(int) *img_x] < x) {
  484.     ++*img_x;
  485.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  486.     }
  487.     if (sw->scale.table.y[(int) *img_y] >= y) {
  488.     --*img_y;
  489.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  490.     }
  491.     if (sw->scale.table.y[(int) *img_y] + 
  492.     (Position)sw->scale.table.height[(int) *img_y] < y) {
  493.     ++*img_y;
  494.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  495.     }
  496.     
  497.     *img_pixel = XGetPixel(sw->scale.image, *img_x, *img_y);
  498.     
  499.     return (0);
  500. }
  501.  
  502.  
  503.  
  504. int SWGetImagePixel(w, x, y, img_x, img_y, img_pixel)
  505.     Widget w;
  506.     Position x, y;
  507.     Position *img_x, *img_y;
  508.     Pixel    *img_pixel;
  509. {
  510.     ScaleWidget sw = (ScaleWidget) w;
  511.     
  512.     x -= sw->scale.x;
  513.     y -= sw->scale.y;
  514.     
  515.     *img_x = (Position) floor(x / sw->scale.scale_x);
  516.     *img_y = (Position) floor(y / sw->scale.scale_y);
  517.     
  518.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  519. }
  520.  
  521.  
  522.  
  523. /* ARGSUSED */
  524. static void Redisplay(w, event, region)
  525.     Widget w;
  526.     XEvent *event;
  527.     Region region;
  528. {
  529.     ScaleWidget sw = (ScaleWidget) w;
  530.     Position  x, y, img_x, img_y;
  531.     Dimension width, height;
  532.  
  533.     if (event->type == Expose) {
  534.  
  535.     if (event->xexpose.x < sw->scale.x) {
  536.         x = 0;
  537.         width = event->xexpose.width -
  538.         (sw->scale.x - event->xexpose.x);
  539.     }
  540.     else {
  541.         x = event->xexpose.x - sw->scale.x;
  542.         width = event->xexpose.width;
  543.     }
  544.     
  545.     if (event->xexpose.y < sw->scale.y) {
  546.         y = 0;
  547.         height = event->xexpose.height -
  548.         (sw->scale.y - event->xexpose.y);
  549.     }
  550.     else {
  551.         y = event->xexpose.y - sw->scale.y;
  552.         height = event->xexpose.height;
  553.     }
  554.     
  555.     img_x = min(max((Position) floor((float) x 
  556.                      / (float) sw->scale.scale_x), 0),
  557.             (Position) sw->scale.image->width - 1);
  558.  
  559.     img_y = min(max((Position) floor((float) y
  560.                      / (float) sw->scale.scale_y), 0),
  561.             (Position) sw->scale.image->height - 1);
  562.     
  563.     if (sw->core.visible) {  
  564.         ScaleImage(sw, XtWindow(w),
  565.                img_x, img_y,
  566.                sw->scale.x + sw->scale.table.x[(int) img_x],
  567.                sw->scale.y + sw->scale.table.y[(int) img_y],
  568.                (Dimension) ceil((float) width
  569.                     / sw->scale.scale_x) + 1, 
  570.                (Dimension) ceil((float) height
  571.                     / sw->scale.scale_y) + 1);
  572.     }
  573.     }
  574. }
  575.  
  576.  
  577.  
  578. void TryResize(sw)
  579.     ScaleWidget sw;
  580. {
  581.     Dimension width, height;
  582.     XtGeometryResult result;
  583.  
  584.     width = (Dimension) 
  585.     floor(sw->scale.image->width * sw->scale.scale_x)
  586.         + 2 * sw->scale.internal_width;
  587.     height = (Dimension) 
  588.     floor(sw->scale.image->height * sw->scale.scale_y)
  589.         + 2 * sw->scale.internal_height;
  590.     
  591.     while ((result =   
  592. /* SUPPRESS 530 */XtMakeResizeRequest((Widget)sw,width,height,&width,&height))
  593.        == XtGeometryAlmost);  
  594.     
  595.     if (result != XtGeometryNo) {
  596.     sw->core.width = width;
  597.     sw->core.height = height;
  598.     }
  599. }
  600.  
  601.  
  602.  
  603. void Precision(sw)
  604.     ScaleWidget sw;
  605. {
  606.     if (sw->scale.scale_x != 1.0)
  607.     sw->scale.scale_x = floor(sw->scale.scale_x / sw->scale.precision)
  608.                     * sw->scale.precision;
  609.  
  610.     if (sw->scale.scale_y != 1.0)
  611.     sw->scale.scale_y = floor(sw->scale.scale_y / sw->scale.precision)
  612.                 * sw->scale.precision;
  613. }
  614.  
  615.  
  616.  
  617. void Proportional(sw)
  618.     ScaleWidget sw;
  619. {
  620.     float scale_x, scale_y;
  621.  
  622.     scale_x = sw->scale.scale_y / sw->scale.aspect_ratio;
  623.     scale_y = sw->scale.scale_x * sw->scale.aspect_ratio;
  624.     
  625.     if (scale_x <= sw->scale.scale_x && scale_y <= sw->scale.scale_y) {
  626.     if (scale_x > scale_y)
  627.         sw->scale.scale_x = scale_x;
  628.     else
  629.         sw->scale.scale_y = scale_y;
  630.     }
  631.     else if (scale_x <= sw->scale.scale_x)
  632.     sw->scale.scale_x = scale_x;
  633.     else if (scale_y <= sw->scale.scale_y)
  634.     sw->scale.scale_y = scale_y;
  635.     else {
  636.     float x_ratio, y_ratio;
  637.     
  638.     x_ratio = scale_x / sw->scale.scale_x;
  639.     y_ratio = scale_y / sw->scale.scale_y;
  640.     
  641.     if (x_ratio < y_ratio)
  642.         sw->scale.scale_y /= x_ratio;
  643.     else
  644.         sw->scale.scale_x /= y_ratio;
  645.     }
  646.  
  647.     if (fabs(sw->scale.scale_x / sw->scale.scale_y * sw->scale.aspect_ratio 
  648.         - 1.0) > sw->scale.precision)
  649.     XtWarning("can not preserve aspect ratio");
  650. }
  651.  
  652.  
  653.  
  654. void GetScaledSize(sw)
  655.     ScaleWidget sw;
  656. {
  657.     sw->scale.width = (Dimension)
  658.     max(myrint(sw->scale.scale_x * sw->scale.image->width), 1);
  659.     sw->scale.height = (Dimension)
  660.     max(myrint(sw->scale.scale_y * sw->scale.image->height), 1);
  661. }
  662.  
  663.  
  664.  
  665. void GetScaleValues(sw)
  666.     ScaleWidget sw;
  667. {
  668.     /*
  669.      * Make sure to subtract internal width and height.
  670.      */
  671.     
  672.     sw->scale.scale_x = 
  673.     (float) max((int)(sw->core.width - 2 * sw->scale.internal_width), 1)
  674.         / (float) sw->scale.image->width;
  675.  
  676.     sw->scale.scale_y =
  677.     (float) max((int)(sw->core.height - 2 * sw->scale.internal_height), 1)
  678.         / (float) sw->scale.image->height;
  679. }
  680.  
  681.  
  682.  
  683. void Unscale(sw)
  684.     ScaleWidget sw;
  685. {
  686.     sw->scale.scale_x = sw->scale.scale_y = 1.0;
  687.  
  688.     GetScaledSize(sw);        
  689.     
  690.     BuildTable(sw);
  691. }
  692.  
  693.  
  694.  
  695. void Autoscale(sw)
  696.     ScaleWidget sw;
  697. {
  698.     GetScaleValues(sw);
  699.  
  700.     if (sw->scale.proportional) Proportional(sw);
  701.  
  702.     Precision(sw);
  703.  
  704.     GetScaledSize(sw);
  705.     
  706.     BuildTable(sw);
  707. }
  708.  
  709.  
  710.  
  711. void PositionImage(sw)
  712.     ScaleWidget sw;
  713. {
  714.     /*
  715.      * Set as if for ForgegGravity (that is center the image)
  716.      */
  717.     sw->scale.x = (Position) 
  718.     (sw->core.width - sw->scale.width) / 2;
  719.     sw->scale.y = (Position)
  720.     (sw->core.height - sw->scale.height) / 2;
  721.     
  722. /*****
  723.     if (sw->scale.gravity & WestGravity) { 
  724.     }
  725.     if (sw->scale.gravity & EastGravity) { 
  726.     }
  727.     if (sw->scale.gravity & NorthGravity) {
  728.     }
  729.     if (sw->scale.gravity & SouthGravity) {
  730.     }
  731. *****/
  732. }
  733.  
  734.  
  735.  
  736. static void Resize(w)
  737.     Widget w;
  738. {
  739.     ScaleWidget sw = (ScaleWidget) w;
  740.     
  741.     if (sw->scale.autoscale) Autoscale(sw);
  742.     
  743.     PositionImage(sw);
  744. }
  745.  
  746.  
  747.  
  748. static void Realize(wid, vmask, attr)
  749.         Widget wid;
  750.         Mask *vmask;
  751.         XSetWindowAttributes *attr;
  752. {
  753.   ScaleWidget sw = (ScaleWidget) wid;
  754.   XtCreateWindow(wid, (unsigned int) InputOutput,
  755.          (Visual *) sw->scale.visual, *vmask, attr);
  756. }
  757.  
  758.  
  759.  
  760. static void Destroy(w)
  761.     Widget w;
  762. {
  763.     ScaleWidget sw = (ScaleWidget) w; 
  764.  
  765.     XtFree((char *) sw->scale.table.x);
  766.     XtFree((char *) sw->scale.table.y);
  767.     XtFree((char *) sw->scale.table.width);
  768.     XtFree((char *) sw->scale.table.height);
  769.     
  770.     XtFree((char *) sw->scale.rectangles);
  771.  
  772.     XtReleaseGC(w, sw->scale.gc);
  773.  
  774.     XDestroyImage(sw->scale.image);
  775. }
  776.  
  777.  
  778.  
  779. /* ARGSUSED */
  780. static Boolean SetValues(current, request, new, args, num_args)
  781.     Widget current, request, new;
  782.     ArgList args;
  783.     Cardinal *num_args;
  784. {
  785.     ScaleWidget cur_sw = (ScaleWidget) current;
  786.     /* ScaleWidget req_sw = (ScaleWidget) request; */
  787.     ScaleWidget new_sw = (ScaleWidget) new;
  788.     Boolean redisplay = False;
  789.     int i;
  790.     
  791.     for (i = 0; i < *num_args; i++) {
  792.     if (streq(XtNbackground, args[i].name)) {
  793.         XSetBackground(XtDisplay(new), new_sw->scale.gc, 
  794.                new_sw->core.background_pixel);
  795.     }
  796.     if (streq(XtNforeground, args[i].name)) {
  797.         XSetForeground(XtDisplay(new), new_sw->scale.gc, 
  798.                new_sw->scale.foreground_pixel);
  799.     }
  800.     if (streq(XtNimage, args[i].name)) {
  801.         XDestroyImage(cur_sw->scale.image);
  802.         if (new_sw->scale.image == NULL)
  803.         new_sw->scale.image = XCreateImage(XtDisplay(new),
  804.                         DefaultVisual(XtDisplay(new), 
  805.                         DefaultScreen(XtDisplay(new))),
  806.                            1, XYBitmap, 0, 
  807.                            XtCalloc(1, sizeof(char)),
  808.                            1, 1, 8, 0);
  809.         else
  810.         new_sw->scale.image = 
  811.             XSubImage(new_sw->scale.image, 
  812.                   0, 0, 
  813.                   new_sw->scale.image->width, 
  814.                   new_sw->scale.image->height);
  815.  
  816.         if (new_sw->scale.resize)
  817.         TryResize(new_sw);
  818.         if (new_sw->scale.autoscale)
  819.         Autoscale(new_sw);
  820.         else {
  821.         GetScaledSize(new_sw);
  822.         BuildTable(new_sw);
  823.         }
  824.         PositionImage(new_sw);
  825.         redisplay = True;
  826.     }
  827.  
  828.     if (streq(XtNuserData, args[i].name)) 
  829.       new_sw->scale.userData = (XtPointer)args[i].value;
  830.  
  831.     if (streq(XtNbufferSize, args[i].name)) {
  832.         if (new_sw->scale.buffer_size != cur_sw->scale.buffer_size) {
  833.         GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  834.         }
  835.     }
  836.  
  837.     if (streq(XtNaspectRatio, args[i].name)) {
  838.         if ((new_sw->scale.aspect_ratio = 
  839.          atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  840.         new_sw->scale.aspect_ratio = cur_sw->scale.aspect_ratio;
  841.         XtWarning("AspectRatio has to be a positive number.");
  842.         }
  843.         else if (new_sw->scale.aspect_ratio != cur_sw->scale.aspect_ratio){
  844.         if (new_sw->scale.proportional) {
  845.             Proportional(new_sw);
  846.             Precision(new_sw);
  847.             GetScaledSize(new_sw);
  848.             BuildTable(new_sw);
  849.             PositionImage(new_sw);
  850.             redisplay = True;
  851.         }
  852.         }
  853.     }
  854.     
  855.     if (streq(XtNproportional, args[i].name)) {
  856.         if (new_sw->scale.proportional != cur_sw->scale.proportional) {
  857.         if (new_sw->scale.proportional) Proportional(new_sw);
  858.         Precision(new_sw);
  859.         GetScaledSize(new_sw);
  860.         BuildTable(new_sw);
  861.         PositionImage(new_sw);
  862.         redisplay = True;
  863.         }
  864.     }
  865.     
  866.     if (streq(XtNscaleX, args[i].name)
  867.         || 
  868.         streq(XtNscaleY, args[i].name)) {
  869.         if (new_sw->scale.scale_x_str == DefaultScaleFactor
  870.         || 
  871.         new_sw->scale.scale_y_str == DefaultScaleFactor)
  872.         GetInitialScaleValues(new_sw);
  873.         else {
  874.         if ((new_sw->scale.scale_x = 
  875.              atof(new_sw->scale.scale_x_str)) < 0.0) {
  876.             new_sw->scale.scale_x = cur_sw->scale.scale_x;
  877.             XtWarning("ScaleValue has to be a positive number.");
  878.         }
  879.         if ((new_sw->scale.scale_y = 
  880.              atof(new_sw->scale.scale_y_str)) < 0.0) {
  881.             new_sw->scale.scale_y = cur_sw->scale.scale_y;
  882.             XtWarning("ScaleValue has to be a positive number.");
  883.         }
  884.         }
  885.         if (new_sw->scale.scale_x != cur_sw->scale.scale_x
  886.         ||
  887.         new_sw->scale.scale_y != cur_sw->scale.scale_y) {
  888.         
  889.         /*?*?*?*?*?*?*?*?*?*?*?*?*?*?**?*?*?*?*?*?*?*?*?***?*/
  890.         fprintf(stderr, "================>>%f %f\n",
  891.             new_sw->scale.scale_x, new_sw->scale.scale_y);
  892.         
  893.         if (new_sw->scale.proportional) Proportional(new_sw);
  894.         Precision(new_sw);
  895.         if (new_sw->scale.resize)
  896.             TryResize(new_sw);
  897.         GetScaledSize(new_sw);        
  898.         BuildTable(new_sw);
  899.         PositionImage(new_sw);
  900.         redisplay = True;
  901.         }
  902.     }
  903.     
  904.     if (streq(XtNprecision, args[i].name)) {
  905.         if ((new_sw->scale.precision = 
  906.          atof(new_sw->scale.precision_str)) < 0.0) {
  907.         new_sw->scale.precision = cur_sw->scale.precision;
  908.         XtWarning("Precision has to be a positive number.");
  909.         }
  910.         if (new_sw->scale.precision != cur_sw->scale.precision) {
  911.         if (new_sw->scale.proportional) Proportional(new_sw);
  912.         Precision(new_sw);
  913.         GetScaledSize(new_sw);        
  914.         BuildTable(new_sw);
  915.         PositionImage(new_sw);
  916.         redisplay = True;
  917.         }
  918.     }
  919.     }            
  920.     return(redisplay);
  921. }
  922.  
  923.  
  924.  
  925. void SWUnscale(w)
  926.     Widget w;
  927. {
  928.     ScaleWidget sw = (ScaleWidget) w;
  929.  
  930.     Unscale(sw);
  931.     PositionImage(sw);
  932.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  933. }
  934.  
  935.  
  936.  
  937. void SWAutoscale(w)
  938.     Widget w;
  939. {
  940.     ScaleWidget sw = (ScaleWidget) w;
  941.  
  942.     Autoscale(sw);
  943.     PositionImage(sw);
  944.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  945. }
  946.  
  947.  
  948.  
  949. void SWInitialSize(w)
  950.     Widget w;
  951. {
  952.     ScaleWidget sw = (ScaleWidget) w;
  953.     
  954.     GetInitialScaleValues(sw);
  955.  
  956.     if (sw->scale.proportional) Proportional(sw);
  957.     Precision(sw);
  958.     if (sw->scale.resize)
  959.     TryResize(sw);
  960.     GetScaledSize(sw);        
  961.     BuildTable(sw);
  962.     PositionImage(sw);
  963.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  964. }
  965.  
  966.  
  967.  
  968. void SWSetImage(w, image)
  969.     Widget w;
  970.     XImage *image;
  971. {
  972.     int n;
  973.     Arg wargs[2];
  974.     
  975.     n = 0;
  976.     XtSetArg(wargs[n], XtNimage, (XtArgVal) image); n++;
  977.     XtSetValues(w, wargs, n);
  978. }
  979.  
  980.  
  981.  
  982. extern void SWRequestSelection();
  983.  
  984. void RequestSelection(w, event)
  985.     Widget w;
  986.     XEvent *event;
  987. {
  988.     SWRequestSelection(w, event->xbutton.time);
  989. }
  990.  
  991.  
  992.  
  993. extern void SWGrabSelection();
  994.  
  995. void GrabSelection(w, event)
  996.     Widget w;
  997.     XEvent *event;
  998. {
  999.     SWGrabSelection(w, event->xbutton.time);
  1000. }
  1001.  
  1002.  
  1003.  
  1004. Pixmap SWGetPixmap(w)
  1005.     Widget w;
  1006. {
  1007.     ScaleWidget sw = (ScaleWidget) w;
  1008.     Pixmap pixmap;
  1009.  
  1010.     pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), 
  1011.                sw->scale.width, 
  1012.                sw->scale.height, 
  1013.                sw->scale.image->depth);
  1014.     ScaleImage(sw, pixmap, 
  1015.            0, 0, 0, 0, 
  1016.            (Dimension) sw->scale.image->width, 
  1017.            (Dimension) sw->scale.image->height);
  1018.     
  1019.     return(pixmap);
  1020. }
  1021.