/* Copyright 1989, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ /* * Author: Davor Matic, MIT X Consortium */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "CutPaste.h" #include "ScaleP.h" #ifdef HAVE_LRINT #define myrint(x) lrint(x) #else #define myrint(x) floor(x + 0.5) #endif #define streq(a,b) (strcmp( (a), (b) ) == 0) #ifndef min #define min(x, y) ((x) > (y) ? (y) : (x)) #endif #ifndef max #define max(x, y) ((x) < (y) ? (y) : (x)) #endif #define DefaultBufferSize 1024 #define DefaultScaleFactor NULL #define Offset(field) XtOffsetOf(ScaleRec, scale.field) static XtResource resources[] = { {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground}, {XtNgravity, XtCGravity, XtRGravity, sizeof(XtGravity), Offset(gravity), XtRImmediate, (XtPointer) "ForgetGravity"}, {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), Offset(internal_width), XtRImmediate, (XtPointer) 2}, {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), Offset(internal_height), XtRImmediate, (XtPointer) 2}, {XtNresize, XtCResize, XtRBoolean, sizeof(Boolean), Offset(resize), XtRImmediate, (XtPointer) True}, {XtNautoscale, XtCAutoscale, XtRBoolean, sizeof(Boolean), Offset(autoscale), XtRImmediate, (XtPointer) True}, {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean), Offset(proportional), XtRImmediate, (XtPointer) True}, {XtNscaleX, XtCScaleFactor, XtRString, sizeof(String), Offset(scale_x_str), XtRImmediate, (XtPointer) DefaultScaleFactor}, {XtNscaleY, XtCScaleFactor, XtRString, sizeof(String), Offset(scale_y_str), XtRImmediate, (XtPointer) DefaultScaleFactor}, {XtNaspectRatio, XtCAspectRatio, XtRString, sizeof(String), Offset(aspect_ratio_str), XtRImmediate, (XtPointer) "1.0"}, {XtNprecision, XtCPrecision, XtRString, sizeof(String), Offset(precision_str), XtRImmediate, (XtPointer) "0.001"}, {XtNimage, XtCImage, XtRImage, sizeof(XImage*), Offset(image), XtRImmediate, (XtPointer) NULL}, {XtNpasteBuffer, XtCPasteBuffer, XtRBoolean, sizeof(Boolean), Offset(paste_buffer), XtRImmediate, (XtPointer) False}, {XtNbufferSize, XtCBufferSize, XtRCardinal, sizeof(Cardinal), Offset(buffer_size), XtRImmediate, (XtPointer) DefaultBufferSize}, {XtNuserData, XtCuserData, XtRuserData, sizeof(XtPointer), Offset(userData), XtRImmediate, (XtPointer) NULL}, { XtNvisual, XtCvisual, XtRVisual, sizeof(Visual*), Offset(visual), XtRImmediate, CopyFromParent} }; #undef Offset static void ClassInitialize ( void ); static void GetGC ( ScaleWidget sw ); static void GetInitialScaleValues ( ScaleWidget sw ); static void GetRectangleBuffer ( ScaleWidget sw, Cardinal buffer_size ); static void Initialize ( Widget request, Widget new, ArgList args, Cardinal *num_args ); static void BuildTable ( ScaleWidget sw ); static void FlushRectangles ( ScaleWidget sw, Drawable drawable, GC gc ); static void FillRectangle ( ScaleWidget sw, Drawable drawable, GC gc, Position x, Position y, Dimension width, Dimension height ); static void ScaleImage ( ScaleWidget sw, Drawable drawable, Position img_x, Position img_y, Position dst_x, Position dst_y, Dimension img_width, Dimension img_height ); static int FindPixel ( ScaleWidget sw, Position x, Position y, Position *img_x, Position *img_y, Pixel *img_pixel ); static void Redisplay ( Widget w, XEvent *event, Region region ); static void TryResize ( ScaleWidget sw ); static void Precision ( ScaleWidget sw ); static void Proportional ( ScaleWidget sw ); static void GetScaledSize ( ScaleWidget sw ); static void GetScaleValues ( ScaleWidget sw ); static void Unscale ( ScaleWidget sw ); static void Autoscale ( ScaleWidget sw ); static void PositionImage ( ScaleWidget sw ); static void Resize ( Widget w ); static void Realize ( Widget wid, Mask *vmask, XSetWindowAttributes *attr ); static void Destroy ( Widget w ); static Boolean SetValues ( Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args ); static XtActionsRec actions[] = { {"unscale", SWUnscale}, {"autoscale", SWAutoscale}, {"initial-size", SWInitialSize}, {"paste", RequestSelection}, {"cut", GrabSelection} }; static char translations[] = "\ u: unscale()\n\ a: autoscale()\n\ i: initial-size()\n\ "; ScaleClassRec scaleClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &simpleClassRec, /* class_name */ "Scale", /* widget_size */ sizeof(ScaleRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ NULL, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMaximal| XtExposeGraphicsExposeMerged, /* compress_enterleave */ TRUE, /* visible_interest */ TRUE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ translations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, { /* change_sensitive */ XtInheritChangeSensitive, } }; WidgetClass scaleWidgetClass = (WidgetClass) &scaleClassRec; /* * Private Procedures */ static void ClassInitialize(void) { } static void GetGC(ScaleWidget sw) { XGCValues values; values.foreground = sw->scale.foreground_pixel; values.background = sw->core.background_pixel; values.function = GXcopy; sw->scale.gc = XtGetGC((Widget) sw, GCForeground | GCBackground | GCFunction, &values); } static void GetInitialScaleValues(ScaleWidget sw) { if (sw->scale.proportional) { sw->scale.scale_x = sw->scale.scale_y = ((sw->scale.aspect_ratio > 1.0) ? sw->scale.aspect_ratio : 1.0 / sw->scale.aspect_ratio) * (sw->scale.precision > 1.0 ? sw->scale.precision : 1.0); Proportional(sw); /* need to cut them down to proper values */ } else sw->scale.scale_x = sw->scale.scale_y = 1.0; } static void GetRectangleBuffer(ScaleWidget sw, Cardinal buffer_size) /* * This procedure will realloc a new rectangles buffer. * If the new buffer size is less than nrectangles, some * information will be lost. */ { if (buffer_size == 0) { buffer_size = DefaultBufferSize; XtWarning("buffer size has to be a positive number greater than zero"); } sw->scale.rectangles = (XRectangle *) XtRealloc((char *) sw->scale.rectangles, buffer_size * sizeof(XRectangle)); sw->scale.buffer_size = buffer_size; } /* ARGSUSED */ static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) { ScaleWidget new_sw = (ScaleWidget) new; new_sw->scale.table.x = (Position *) NULL; new_sw->scale.table.y = (Position *) NULL; new_sw->scale.table.width = (Dimension *) NULL; new_sw->scale.table.height = (Dimension *) NULL; new_sw->scale.nrectangles = 0; new_sw->scale.rectangles = (XRectangle *) NULL; GetRectangleBuffer(new_sw, new_sw->scale.buffer_size); GetGC(new_sw); if (new_sw->scale.image != NULL) { if (new_sw->core.width == 0) new_sw->core.width = new_sw->scale.image->width + 2 * new_sw->scale.internal_width; if (new_sw->core.height == 0) new_sw->core.height = new_sw->scale.image->height + 2 *new_sw->scale.internal_height; } else { if (new_sw->core.width == 0) new_sw->core.width = 1 + 2 * new_sw->scale.internal_width; if (new_sw->core.height == 0) new_sw->core.height = 1 + 2 * new_sw->scale.internal_height; new_sw->scale.image = XCreateImage(XtDisplay(new), DefaultVisual(XtDisplay(new), DefaultScreen(XtDisplay(new))), 1, XYBitmap, 0, XtCalloc(1, sizeof(char)), 1, 1, 8, 0); } if ((new_sw->scale.aspect_ratio = atof(new_sw->scale.aspect_ratio_str)) < 0.0) { new_sw->scale.aspect_ratio = 1.0; XtWarning("AspectRatio has to be a positive number. (forced to 1.0)"); } if ((new_sw->scale.precision = atof(new_sw->scale.precision_str)) < 0.0) { new_sw->scale.precision = 0.001; XtWarning("Precision has to be a positive number. (forced to 0.001)"); } if (new_sw->scale.scale_x_str == DefaultScaleFactor || new_sw->scale.scale_y_str == DefaultScaleFactor) GetInitialScaleValues(new_sw); else { if ((new_sw->scale.scale_x = atof(new_sw->scale.scale_x_str)) < 0.0) { new_sw->scale.scale_x = 1.0; XtWarning("ScaleValue has to be a positive number. (forced to 1.0)"); } if ((new_sw->scale.scale_y = atof(new_sw->scale.scale_y_str)) < 0.0) { new_sw->scale.scale_y = 1.0; XtWarning("ScaleValue has to be a positive number. (forced to 1.0)"); } } } static void BuildTable(ScaleWidget sw) /* * This procedure builds scaling table for image in the scale struct * Requires image, scale_x and scale_y to be set properly */ { Position x, y; XtFree((char *) sw->scale.table.x); XtFree((char *) sw->scale.table.y); XtFree((char *) sw->scale.table.width); XtFree((char *) sw->scale.table.height); sw->scale.table.x = (Position *) XtMalloc(sizeof(Position) * sw->scale.image->width); sw->scale.table.y = (Position *) XtMalloc(sizeof(Position) * sw->scale.image->height); sw->scale.table.width = (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->width); sw->scale.table.height = (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->height); /* Build the scaling table */ for (x = 0; x < sw->scale.image->width; x++) { sw->scale.table.x[(int) x] = (Position) myrint(sw->scale.scale_x * x); sw->scale.table.width[(int) x] = (Dimension) myrint(sw->scale.scale_x *(x + 1)) - myrint(sw->scale.scale_x * x); } for (y = 0; y < sw->scale.image->height; y++) { sw->scale.table.y[(int) y] = (Position) myrint(sw->scale.scale_y * y); sw->scale.table.height[(int) y] = (Dimension) myrint(sw->scale.scale_y *(y + 1)) - myrint(sw->scale.scale_y * y); } } static void FlushRectangles(ScaleWidget sw, Drawable drawable, GC gc) { XFillRectangles(XtDisplay(sw), drawable, gc, sw->scale.rectangles, sw->scale.nrectangles); sw->scale.nrectangles = 0; } static void FillRectangle(ScaleWidget sw, Drawable drawable, GC gc, Position x, Position y, Dimension width, Dimension height) { if (sw->scale.nrectangles == sw->scale.buffer_size) FlushRectangles(sw, drawable, gc); sw->scale.rectangles[(int) sw->scale.nrectangles].x = x; sw->scale.rectangles[(int) sw->scale.nrectangles].y = y; sw->scale.rectangles[(int) sw->scale.nrectangles].width = width; sw->scale.rectangles[(int) sw->scale.nrectangles].height = height; ++sw->scale.nrectangles; } static void ScaleImage(ScaleWidget sw, Drawable drawable, Position img_x, Position img_y, Position dst_x, Position dst_y, Dimension img_width, Dimension img_height) /* * This procedure scales image into the specified drawable * It assumes scaling table was already built */ { GC gc; XGCValues gcv; Position x, y; Pixel pixel; /* Clip the img coordinates */ img_x = min(max(img_x, 0), (Position) sw->scale.image->width - 1); img_y = min(max(img_y, 0), (Position) sw->scale.image->height - 1); img_width = min(img_width, (Dimension)(sw->scale.image->width - (Dimension)img_x)); img_height = min(img_height, (Dimension)(sw->scale.image->height - (Dimension)img_y)); if (sw->scale.scale_x == 1.0 && sw->scale.scale_y == 1.0) XPutImage(XtDisplay(sw), drawable, sw->scale.gc, sw->scale.image, img_x, img_y, dst_x, dst_y, img_width, img_height); else { dst_x = dst_x - sw->scale.table.x[(int) img_x]; dst_y = dst_y - sw->scale.table.y[(int) img_y]; gc = XCreateGC(XtDisplay(sw), drawable, 0, NULL); gcv.function = GXcopy; XChangeGC(XtDisplay(sw), gc, GCFunction, &gcv); /* make sure gc knows the right background */ gcv.background = sw->core.background_pixel; XChangeGC(XtDisplay(sw), gc, GCBackground, &gcv); /* Set the background of drawable. If the most frequent color is the background color it can speed up scaling process. */ gcv.foreground = gcv.background; XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv); XFillRectangle(XtDisplay(sw), drawable, gc, sw->scale.table.x[(int) img_x] + dst_x, sw->scale.table.y[(int) img_y] + dst_y, sw->scale.table.x[(int) img_x + img_width - 1] - sw->scale.table.x[(int) img_x], sw->scale.table.y[(int) img_y + img_height - 1] - sw->scale.table.y[(int) img_y]); if (sw->scale.image->format == XYBitmap) { for (x = img_x; x < img_x + (Position)img_width; x++) for (y = img_y; y < img_y + (Position)img_height; y++) { pixel = XGetPixel(sw->scale.image, x, y); if (pixel) /* Do not draw background */ FillRectangle(sw, drawable, sw->scale.gc, sw->scale.table.x[(int) x] + dst_x, sw->scale.table.y[(int) y] + dst_y, sw->scale.table.width[(int) x], sw->scale.table.height[(int) y]); } FlushRectangles(sw, drawable, sw->scale.gc); } else { for (x = img_x; x < img_x + (Position)img_width; x++) for (y = img_y; y < img_y + (Position)img_height; y++) { pixel = XGetPixel(sw->scale.image, x, y); if (pixel != gcv.background) { /* Do not draw background */ if (gcv.foreground != pixel) { /* Change fg to pixel */ gcv.foreground = pixel; XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv); } XFillRectangle(XtDisplay(sw), drawable, gc, sw->scale.table.x[(int) x] + dst_x, sw->scale.table.y[(int) y] + dst_y, sw->scale.table.width[(int) x], sw->scale.table.height[(int) y]); } } } XFreeGC(XtDisplay(sw), gc); } } static int FindPixel(ScaleWidget sw, Position x, Position y, Position *img_x, Position *img_y, Pixel *img_pixel) /* (x,y) == (0,0) where image starts in sw window*/ { if (*img_x < 0 || *img_x >= sw->scale.image->width || *img_y < 0 || *img_y >= sw->scale.image->height) return (-1); if (sw->scale.table.x[(int) *img_x] >= x) { --*img_x; return FindPixel(sw, x, y, img_x, img_y, img_pixel); } if (sw->scale.table.x[(int) *img_x] + (Position)sw->scale.table.width[(int) *img_x] < x) { ++*img_x; return FindPixel(sw, x, y, img_x, img_y, img_pixel); } if (sw->scale.table.y[(int) *img_y] >= y) { --*img_y; return FindPixel(sw, x, y, img_x, img_y, img_pixel); } if (sw->scale.table.y[(int) *img_y] + (Position)sw->scale.table.height[(int) *img_y] < y) { ++*img_y; return FindPixel(sw, x, y, img_x, img_y, img_pixel); } *img_pixel = XGetPixel(sw->scale.image, *img_x, *img_y); return (0); } int SWGetImagePixel(Widget w, Position x, Position y, Position *img_x, Position *img_y, Pixel *img_pixel) { ScaleWidget sw = (ScaleWidget) w; x -= sw->scale.x; y -= sw->scale.y; *img_x = (Position) floor(x / sw->scale.scale_x); *img_y = (Position) floor(y / sw->scale.scale_y); return FindPixel(sw, x, y, img_x, img_y, img_pixel); } /* ARGSUSED */ static void Redisplay(Widget w, XEvent *event, Region region) { ScaleWidget sw = (ScaleWidget) w; Position x, y, img_x, img_y; Dimension width, height; if (event->type == Expose) { if (event->xexpose.x < sw->scale.x) { x = 0; width = event->xexpose.width - (sw->scale.x - event->xexpose.x); } else { x = event->xexpose.x - sw->scale.x; width = event->xexpose.width; } if (event->xexpose.y < sw->scale.y) { y = 0; height = event->xexpose.height - (sw->scale.y - event->xexpose.y); } else { y = event->xexpose.y - sw->scale.y; height = event->xexpose.height; } img_x = min(max((Position) floor((float) x / (float) sw->scale.scale_x), 0), (Position) sw->scale.image->width - 1); img_y = min(max((Position) floor((float) y / (float) sw->scale.scale_y), 0), (Position) sw->scale.image->height - 1); if (sw->core.visible) { ScaleImage(sw, XtWindow(w), img_x, img_y, sw->scale.x + sw->scale.table.x[(int) img_x], sw->scale.y + sw->scale.table.y[(int) img_y], (Dimension) ceil((float) width / sw->scale.scale_x) + 1, (Dimension) ceil((float) height / sw->scale.scale_y) + 1); } } } static void TryResize(ScaleWidget sw) { Dimension width, height; XtGeometryResult result; width = (Dimension) floor(sw->scale.image->width * sw->scale.scale_x) + 2 * sw->scale.internal_width; height = (Dimension) floor(sw->scale.image->height * sw->scale.scale_y) + 2 * sw->scale.internal_height; while ((result = /* SUPPRESS 530 */XtMakeResizeRequest((Widget)sw,width,height,&width,&height)) == XtGeometryAlmost); if (result != XtGeometryNo) { sw->core.width = width; sw->core.height = height; } } static void Precision(ScaleWidget sw) { if (sw->scale.scale_x != 1.0) sw->scale.scale_x = floor(sw->scale.scale_x / sw->scale.precision) * sw->scale.precision; if (sw->scale.scale_y != 1.0) sw->scale.scale_y = floor(sw->scale.scale_y / sw->scale.precision) * sw->scale.precision; } static void Proportional(ScaleWidget sw) { float scale_x, scale_y; scale_x = sw->scale.scale_y / sw->scale.aspect_ratio; scale_y = sw->scale.scale_x * sw->scale.aspect_ratio; if (scale_x <= sw->scale.scale_x && scale_y <= sw->scale.scale_y) { if (scale_x > scale_y) sw->scale.scale_x = scale_x; else sw->scale.scale_y = scale_y; } else if (scale_x <= sw->scale.scale_x) sw->scale.scale_x = scale_x; else if (scale_y <= sw->scale.scale_y) sw->scale.scale_y = scale_y; else { float x_ratio, y_ratio; x_ratio = scale_x / sw->scale.scale_x; y_ratio = scale_y / sw->scale.scale_y; if (x_ratio < y_ratio) sw->scale.scale_y /= x_ratio; else sw->scale.scale_x /= y_ratio; } if (fabs(sw->scale.scale_x / sw->scale.scale_y * sw->scale.aspect_ratio - 1.0) > sw->scale.precision) XtWarning("can not preserve aspect ratio"); } static void GetScaledSize(ScaleWidget sw) { sw->scale.width = (Dimension) max(myrint(sw->scale.scale_x * sw->scale.image->width), 1); sw->scale.height = (Dimension) max(myrint(sw->scale.scale_y * sw->scale.image->height), 1); } static void GetScaleValues(ScaleWidget sw) { /* * Make sure to subtract internal width and height. */ sw->scale.scale_x = (float) max((int)(sw->core.width - 2 * sw->scale.internal_width), 1) / (float) sw->scale.image->width; sw->scale.scale_y = (float) max((int)(sw->core.height - 2 * sw->scale.internal_height), 1) / (float) sw->scale.image->height; } static void Unscale(ScaleWidget sw) { sw->scale.scale_x = sw->scale.scale_y = 1.0; GetScaledSize(sw); BuildTable(sw); } static void Autoscale(ScaleWidget sw) { GetScaleValues(sw); if (sw->scale.proportional) Proportional(sw); Precision(sw); GetScaledSize(sw); BuildTable(sw); } static void PositionImage(ScaleWidget sw) { /* * Set as if for ForgegGravity (that is center the image) */ sw->scale.x = (Position) (sw->core.width - sw->scale.width) / 2; sw->scale.y = (Position) (sw->core.height - sw->scale.height) / 2; /***** if (sw->scale.gravity & WestGravity) { } if (sw->scale.gravity & EastGravity) { } if (sw->scale.gravity & NorthGravity) { } if (sw->scale.gravity & SouthGravity) { } *****/ } static void Resize(Widget w) { ScaleWidget sw = (ScaleWidget) w; if (sw->scale.autoscale) Autoscale(sw); PositionImage(sw); } static void Realize(Widget wid, Mask *vmask, XSetWindowAttributes *attr) { ScaleWidget sw = (ScaleWidget) wid; XtCreateWindow(wid, (unsigned int) InputOutput, (Visual *) sw->scale.visual, *vmask, attr); } static void Destroy(Widget w) { ScaleWidget sw = (ScaleWidget) w; XtFree((char *) sw->scale.table.x); XtFree((char *) sw->scale.table.y); XtFree((char *) sw->scale.table.width); XtFree((char *) sw->scale.table.height); XtFree((char *) sw->scale.rectangles); XtReleaseGC(w, sw->scale.gc); XDestroyImage(sw->scale.image); } /* ARGSUSED */ static Boolean SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args) { ScaleWidget cur_sw = (ScaleWidget) current; /* ScaleWidget req_sw = (ScaleWidget) request; */ ScaleWidget new_sw = (ScaleWidget) new; Boolean redisplay = False; Cardinal i; for (i = 0; i < *num_args; i++) { if (streq(XtNbackground, args[i].name)) { XSetBackground(XtDisplay(new), new_sw->scale.gc, new_sw->core.background_pixel); } if (streq(XtNforeground, args[i].name)) { XSetForeground(XtDisplay(new), new_sw->scale.gc, new_sw->scale.foreground_pixel); } if (streq(XtNimage, args[i].name)) { XDestroyImage(cur_sw->scale.image); if (new_sw->scale.image == NULL) new_sw->scale.image = XCreateImage(XtDisplay(new), DefaultVisual(XtDisplay(new), DefaultScreen(XtDisplay(new))), 1, XYBitmap, 0, XtCalloc(1, sizeof(char)), 1, 1, 8, 0); else new_sw->scale.image = XSubImage(new_sw->scale.image, 0, 0, new_sw->scale.image->width, new_sw->scale.image->height); if (new_sw->scale.resize) TryResize(new_sw); if (new_sw->scale.autoscale) Autoscale(new_sw); else { GetScaledSize(new_sw); BuildTable(new_sw); } PositionImage(new_sw); redisplay = True; } if (streq(XtNuserData, args[i].name)) new_sw->scale.userData = (XtPointer)args[i].value; if (streq(XtNbufferSize, args[i].name)) { if (new_sw->scale.buffer_size != cur_sw->scale.buffer_size) { GetRectangleBuffer(new_sw, new_sw->scale.buffer_size); } } if (streq(XtNaspectRatio, args[i].name)) { if ((new_sw->scale.aspect_ratio = atof(new_sw->scale.aspect_ratio_str)) < 0.0) { new_sw->scale.aspect_ratio = cur_sw->scale.aspect_ratio; XtWarning("AspectRatio has to be a positive number."); } else if (new_sw->scale.aspect_ratio != cur_sw->scale.aspect_ratio){ if (new_sw->scale.proportional) { Proportional(new_sw); Precision(new_sw); GetScaledSize(new_sw); BuildTable(new_sw); PositionImage(new_sw); redisplay = True; } } } if (streq(XtNproportional, args[i].name)) { if (new_sw->scale.proportional != cur_sw->scale.proportional) { if (new_sw->scale.proportional) Proportional(new_sw); Precision(new_sw); GetScaledSize(new_sw); BuildTable(new_sw); PositionImage(new_sw); redisplay = True; } } if (streq(XtNscaleX, args[i].name) || streq(XtNscaleY, args[i].name)) { if (new_sw->scale.scale_x_str == DefaultScaleFactor || new_sw->scale.scale_y_str == DefaultScaleFactor) GetInitialScaleValues(new_sw); else { if ((new_sw->scale.scale_x = atof(new_sw->scale.scale_x_str)) < 0.0) { new_sw->scale.scale_x = cur_sw->scale.scale_x; XtWarning("ScaleValue has to be a positive number."); } if ((new_sw->scale.scale_y = atof(new_sw->scale.scale_y_str)) < 0.0) { new_sw->scale.scale_y = cur_sw->scale.scale_y; XtWarning("ScaleValue has to be a positive number."); } } if (new_sw->scale.scale_x != cur_sw->scale.scale_x || new_sw->scale.scale_y != cur_sw->scale.scale_y) { /*?*?*?*?*?*?*?*?*?*?*?*?*?*?**?*?*?*?*?*?*?*?*?***?*/ fprintf(stderr, "================>>%f %f\n", new_sw->scale.scale_x, new_sw->scale.scale_y); if (new_sw->scale.proportional) Proportional(new_sw); Precision(new_sw); if (new_sw->scale.resize) TryResize(new_sw); GetScaledSize(new_sw); BuildTable(new_sw); PositionImage(new_sw); redisplay = True; } } if (streq(XtNprecision, args[i].name)) { if ((new_sw->scale.precision = atof(new_sw->scale.precision_str)) < 0.0) { new_sw->scale.precision = cur_sw->scale.precision; XtWarning("Precision has to be a positive number."); } if (new_sw->scale.precision != cur_sw->scale.precision) { if (new_sw->scale.proportional) Proportional(new_sw); Precision(new_sw); GetScaledSize(new_sw); BuildTable(new_sw); PositionImage(new_sw); redisplay = True; } } } return(redisplay); } void SWUnscale(Widget w, XEvent *event, String *params, Cardinal *num_params) { ScaleWidget sw = (ScaleWidget) w; Unscale(sw); PositionImage(sw); XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); } void SWAutoscale(Widget w, XEvent *event, String *params, Cardinal *num_params) { ScaleWidget sw = (ScaleWidget) w; Autoscale(sw); PositionImage(sw); XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); } void SWInitialSize(Widget w, XEvent *event, String *params, Cardinal *num_params) { ScaleWidget sw = (ScaleWidget) w; GetInitialScaleValues(sw); if (sw->scale.proportional) Proportional(sw); Precision(sw); if (sw->scale.resize) TryResize(sw); GetScaledSize(sw); BuildTable(sw); PositionImage(sw); XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); } void SWSetImage(Widget w, XImage *image) { int n; Arg wargs[2]; n = 0; XtSetArg(wargs[n], XtNimage, (XtArgVal) image); n++; XtSetValues(w, wargs, n); } void RequestSelection(Widget w, XEvent *event, String *params, Cardinal *num_params) { SWRequestSelection(w, event->xbutton.time); } void GrabSelection(Widget w, XEvent *event, String *params, Cardinal *num_params) { SWGrabSelection(w, event->xbutton.time); } Pixmap SWGetPixmap(Widget w) { ScaleWidget sw = (ScaleWidget) w; Pixmap pixmap; pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), sw->scale.width, sw->scale.height, sw->scale.image->depth); ScaleImage(sw, pixmap, 0, 0, 0, 0, (Dimension) sw->scale.image->width, (Dimension) sw->scale.image->height); return(pixmap); }