xenocara/app/xmag/Scale.c

1031 lines
27 KiB
C
Raw Normal View History

2006-11-25 13:07:29 -07:00
/*
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
*/
2013-01-14 15:17:01 -07:00
#include "config.h"
2006-11-25 13:07:29 -07:00
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xos.h>
#include <X11/Xaw/XawInit.h>
#include "CutPaste.h"
#include "ScaleP.h"
2013-01-14 15:17:01 -07:00
#ifdef HAVE_LRINT
#define myrint(x) lrint(x)
#else
2006-11-25 13:07:29 -07:00
#define myrint(x) floor(x + 0.5)
2013-01-14 15:17:01 -07:00
#endif
2006-11-25 13:07:29 -07:00
#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 );
2015-05-10 04:20:17 -06:00
static void Initialize ( Widget request, Widget new, ArgList args,
2006-11-25 13:07:29 -07:00
Cardinal *num_args );
static void BuildTable ( ScaleWidget sw );
static void FlushRectangles ( ScaleWidget sw, Drawable drawable, GC gc );
2015-05-10 04:20:17 -06:00
static void FillRectangle ( ScaleWidget sw, Drawable drawable, GC gc,
Position x, Position y,
2006-11-25 13:07:29 -07:00
Dimension width, Dimension height );
2015-05-10 04:20:17 -06:00
static void ScaleImage ( ScaleWidget sw, Drawable drawable,
Position img_x, Position img_y,
Position dst_x, Position dst_y,
2006-11-25 13:07:29 -07:00
Dimension img_width, Dimension img_height );
2015-05-10 04:20:17 -06:00
static int FindPixel ( ScaleWidget sw, Position x, Position y,
2006-11-25 13:07:29 -07:00
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 );
2015-05-10 04:20:17 -06:00
static Boolean SetValues ( Widget current, Widget request, Widget new,
2006-11-25 13:07:29 -07:00
ArgList args, Cardinal *num_args );
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
static XtActionsRec actions[] =
{
{"unscale", SWUnscale},
{"autoscale", SWAutoscale},
{"initial-size", SWInitialSize},
{"paste", RequestSelection},
{"cut", GrabSelection}
};
static char translations[] =
"\
<Key>u: unscale()\n\
<Key>a: autoscale()\n\
<Key>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
},
2015-05-10 04:20:17 -06:00
{
2006-11-25 13:07:29 -07:00
/* change_sensitive */ XtInheritChangeSensitive,
}
};
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
WidgetClass scaleWidgetClass = (WidgetClass) &scaleClassRec;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
/*
* Private Procedures
*/
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
ClassInitialize(void)
{
2015-05-10 04:20:17 -06:00
}
2006-11-25 13:07:29 -07:00
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
GetGC(ScaleWidget sw)
{
XGCValues values;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
values.foreground = sw->scale.foreground_pixel;
values.background = sw->core.background_pixel;
values.function = GXcopy;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
sw->scale.gc = XtGetGC((Widget) sw,
2015-05-10 04:20:17 -06:00
GCForeground |
GCBackground |
2006-11-25 13:07:29 -07:00
GCFunction,
&values);
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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 *)
2015-05-10 04:20:17 -06:00
XtRealloc((char *) sw->scale.rectangles,
2006-11-25 13:07:29 -07:00
buffer_size * sizeof(XRectangle));
sw->scale.buffer_size = buffer_size;
}
/* ARGSUSED */
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
{
ScaleWidget new_sw = (ScaleWidget) new;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
new_sw->scale.nrectangles = 0;
new_sw->scale.rectangles = (XRectangle *) NULL;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
GetGC(new_sw);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (new_sw->scale.image != NULL) {
if (new_sw->core.width == 0)
2015-05-10 04:20:17 -06:00
new_sw->core.width =
2006-11-25 13:07:29 -07:00
new_sw->scale.image->width + 2 * new_sw->scale.internal_width;
if (new_sw->core.height == 0)
2015-05-10 04:20:17 -06:00
new_sw->core.height =
2006-11-25 13:07:29 -07:00
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),
2015-05-10 04:20:17 -06:00
DefaultVisual(XtDisplay(new),
2006-11-25 13:07:29 -07:00
DefaultScreen(XtDisplay(new))),
2015-05-10 04:20:17 -06:00
1, XYBitmap, 0,
2006-11-25 13:07:29 -07:00
XtCalloc(1, sizeof(char)),
1, 1, 8, 0);
}
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.aspect_ratio =
2006-11-25 13:07:29 -07:00
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)");
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (new_sw->scale.scale_x_str == DefaultScaleFactor
2015-05-10 04:20:17 -06:00
||
2006-11-25 13:07:29 -07:00
new_sw->scale.scale_y_str == DefaultScaleFactor)
GetInitialScaleValues(new_sw);
else {
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.scale_x =
2006-11-25 13:07:29 -07:00
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)");
}
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.scale_y =
2006-11-25 13:07:29 -07:00
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)");
}
}
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
BuildTable(ScaleWidget sw)
2015-05-10 04:20:17 -06:00
/*
2006-11-25 13:07:29 -07:00
* 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;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
XtFree((char *) sw->scale.table.x);
XtFree((char *) sw->scale.table.y);
XtFree((char *) sw->scale.table.width);
XtFree((char *) sw->scale.table.height);
2015-05-10 04:20:17 -06:00
sw->scale.table.x =
2006-11-25 13:07:29 -07:00
(Position *) XtMalloc(sizeof(Position) * sw->scale.image->width);
2015-05-10 04:20:17 -06:00
sw->scale.table.y =
2006-11-25 13:07:29 -07:00
(Position *) XtMalloc(sizeof(Position) * sw->scale.image->height);
2015-05-10 04:20:17 -06:00
sw->scale.table.width =
2006-11-25 13:07:29 -07:00
(Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->width);
2015-05-10 04:20:17 -06:00
sw->scale.table.height =
2006-11-25 13:07:29 -07:00
(Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->height);
2015-05-10 04:20:17 -06:00
/* Build the scaling table */
2006-11-25 13:07:29 -07:00
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);
}
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
FlushRectangles(ScaleWidget sw, Drawable drawable, GC gc)
{
2015-05-10 04:20:17 -06:00
XFillRectangles(XtDisplay(sw), drawable, gc,
2006-11-25 13:07:29 -07:00
sw->scale.rectangles, sw->scale.nrectangles);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
sw->scale.nrectangles = 0;
}
2015-05-10 04:20:17 -06:00
static void
FillRectangle(ScaleWidget sw, Drawable drawable, GC gc,
2006-11-25 13:07:29 -07:00
Position x, Position y, Dimension width, Dimension height)
{
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
static void
ScaleImage(ScaleWidget sw, Drawable drawable, Position img_x, Position img_y,
Position dst_x, Position dst_y,
2006-11-25 13:07:29 -07:00
Dimension img_width, Dimension img_height)
2015-05-10 04:20:17 -06:00
/*
2006-11-25 13:07:29 -07:00
* This procedure scales image into the specified drawable
* It assumes scaling table was already built
*/
{
GC gc;
XGCValues gcv;
Position x, y;
Pixel pixel;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
/* 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);
2015-05-10 04:20:17 -06:00
img_width =
2006-11-25 13:07:29 -07:00
min(img_width, (Dimension)(sw->scale.image->width - (Dimension)img_x));
2015-05-10 04:20:17 -06:00
img_height =
2006-11-25 13:07:29 -07:00
min(img_height, (Dimension)(sw->scale.image->height - (Dimension)img_y));
2015-05-10 04:20:17 -06:00
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,
2006-11-25 13:07:29 -07:00
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;
2015-05-10 04:20:17 -06:00
XChangeGC(XtDisplay(sw), gc, GCBackground, &gcv);
2006-11-25 13:07:29 -07:00
/* 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);
2015-05-10 04:20:17 -06:00
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] -
2006-11-25 13:07:29 -07:00
sw->scale.table.y[(int) img_y]);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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 */
2015-05-10 04:20:17 -06:00
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],
2006-11-25 13:07:29 -07:00
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,
2015-05-10 04:20:17 -06:00
sw->scale.table.x[(int) x] + dst_x,
sw->scale.table.y[(int) y] + dst_y,
sw->scale.table.width[(int) x],
2006-11-25 13:07:29 -07:00
sw->scale.table.height[(int) y]);
}
}
}
XFreeGC(XtDisplay(sw), gc);
}
}
2015-05-10 04:20:17 -06:00
static int
FindPixel(ScaleWidget sw, Position x, Position y,
2006-11-25 13:07:29 -07:00
Position *img_x, Position *img_y, Pixel *img_pixel)
/* (x,y) == (0,0) where image starts in sw window*/
{
2015-05-10 04:20:17 -06:00
if (*img_x < 0 || *img_x >= sw->scale.image->width
2006-11-25 13:07:29 -07:00
||
*img_y < 0 || *img_y >= sw->scale.image->height)
return (-1);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (sw->scale.table.x[(int) *img_x] >= x) {
--*img_x;
return FindPixel(sw, x, y, img_x, img_y, img_pixel);
}
2015-05-10 04:20:17 -06:00
if (sw->scale.table.x[(int) *img_x] +
2006-11-25 13:07:29 -07:00
(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);
}
2015-05-10 04:20:17 -06:00
if (sw->scale.table.y[(int) *img_y] +
2006-11-25 13:07:29 -07:00
(Position)sw->scale.table.height[(int) *img_y] < y) {
++*img_y;
return FindPixel(sw, x, y, img_x, img_y, img_pixel);
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
*img_pixel = XGetPixel(sw->scale.image, *img_x, *img_y);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
return (0);
}
2015-05-10 04:20:17 -06:00
int
SWGetImagePixel(Widget w, Position x, Position y,
2006-11-25 13:07:29 -07:00
Position *img_x, Position *img_y, Pixel *img_pixel)
{
ScaleWidget sw = (ScaleWidget) w;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
x -= sw->scale.x;
y -= sw->scale.y;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
*img_x = (Position) floor(x / sw->scale.scale_x);
*img_y = (Position) floor(y / sw->scale.scale_y);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
return FindPixel(sw, x, y, img_x, img_y, img_pixel);
}
/* ARGSUSED */
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
img_x = min(max((Position) floor((float) x
2006-11-25 13:07:29 -07:00
/ (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);
2015-05-10 04:20:17 -06:00
if (sw->core.visible) {
2006-11-25 13:07:29 -07:00
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
2015-05-10 04:20:17 -06:00
/ sw->scale.scale_x) + 1,
2006-11-25 13:07:29 -07:00
(Dimension) ceil((float) height
/ sw->scale.scale_y) + 1);
}
}
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
TryResize(ScaleWidget sw)
{
Dimension width, height;
XtGeometryResult result;
2015-05-10 04:20:17 -06:00
width = (Dimension)
2006-11-25 13:07:29 -07:00
floor(sw->scale.image->width * sw->scale.scale_x)
+ 2 * sw->scale.internal_width;
2015-05-10 04:20:17 -06:00
height = (Dimension)
2006-11-25 13:07:29 -07:00
floor(sw->scale.image->height * sw->scale.scale_y)
+ 2 * sw->scale.internal_height;
2015-05-10 04:20:17 -06:00
while ((result =
2006-11-25 13:07:29 -07:00
/* SUPPRESS 530 */XtMakeResizeRequest((Widget)sw,width,height,&width,&height))
2015-05-10 04:20:17 -06:00
== XtGeometryAlmost);
2006-11-25 13:07:29 -07:00
if (result != XtGeometryNo) {
sw->core.width = width;
sw->core.height = height;
}
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
x_ratio = scale_x / sw->scale.scale_x;
y_ratio = scale_y / sw->scale.scale_y;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (x_ratio < y_ratio)
sw->scale.scale_y /= x_ratio;
else
sw->scale.scale_x /= y_ratio;
}
2015-05-10 04:20:17 -06:00
if (fabs(sw->scale.scale_x / sw->scale.scale_y * sw->scale.aspect_ratio
2006-11-25 13:07:29 -07:00
- 1.0) > sw->scale.precision)
XtWarning("can not preserve aspect ratio");
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
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);
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
GetScaleValues(ScaleWidget sw)
{
/*
* Make sure to subtract internal width and height.
*/
2015-05-10 04:20:17 -06:00
sw->scale.scale_x =
2006-11-25 13:07:29 -07:00
(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;
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Unscale(ScaleWidget sw)
{
sw->scale.scale_x = sw->scale.scale_y = 1.0;
2015-05-10 04:20:17 -06:00
GetScaledSize(sw);
2006-11-25 13:07:29 -07:00
BuildTable(sw);
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Autoscale(ScaleWidget sw)
{
GetScaleValues(sw);
if (sw->scale.proportional) Proportional(sw);
Precision(sw);
GetScaledSize(sw);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
BuildTable(sw);
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
PositionImage(ScaleWidget sw)
{
/*
* Set as if for ForgegGravity (that is center the image)
*/
2015-05-10 04:20:17 -06:00
sw->scale.x = (Position)
2006-11-25 13:07:29 -07:00
(sw->core.width - sw->scale.width) / 2;
sw->scale.y = (Position)
(sw->core.height - sw->scale.height) / 2;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
/*****
2015-05-10 04:20:17 -06:00
if (sw->scale.gravity & WestGravity) {
2006-11-25 13:07:29 -07:00
}
2015-05-10 04:20:17 -06:00
if (sw->scale.gravity & EastGravity) {
2006-11-25 13:07:29 -07:00
}
if (sw->scale.gravity & NorthGravity) {
}
if (sw->scale.gravity & SouthGravity) {
}
*****/
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Resize(Widget w)
{
ScaleWidget sw = (ScaleWidget) w;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (sw->scale.autoscale) Autoscale(sw);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
PositionImage(sw);
}
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Realize(Widget wid, Mask *vmask, XSetWindowAttributes *attr)
{
ScaleWidget sw = (ScaleWidget) wid;
XtCreateWindow(wid, (unsigned int) InputOutput,
(Visual *) sw->scale.visual, *vmask, attr);
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
2015-05-10 04:20:17 -06:00
static void
2006-11-25 13:07:29 -07:00
Destroy(Widget w)
{
2015-05-10 04:20:17 -06:00
ScaleWidget sw = (ScaleWidget) w;
2006-11-25 13:07:29 -07:00
XtFree((char *) sw->scale.table.x);
XtFree((char *) sw->scale.table.y);
XtFree((char *) sw->scale.table.width);
XtFree((char *) sw->scale.table.height);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
XtFree((char *) sw->scale.rectangles);
XtReleaseGC(w, sw->scale.gc);
XDestroyImage(sw->scale.image);
}
/* ARGSUSED */
2015-05-10 04:20:17 -06:00
static Boolean
SetValues(Widget current, Widget request, Widget new,
2006-11-25 13:07:29 -07:00
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;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
for (i = 0; i < *num_args; i++) {
if (streq(XtNbackground, args[i].name)) {
2015-05-10 04:20:17 -06:00
XSetBackground(XtDisplay(new), new_sw->scale.gc,
2006-11-25 13:07:29 -07:00
new_sw->core.background_pixel);
}
if (streq(XtNforeground, args[i].name)) {
2015-05-10 04:20:17 -06:00
XSetForeground(XtDisplay(new), new_sw->scale.gc,
2006-11-25 13:07:29 -07:00
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),
2015-05-10 04:20:17 -06:00
DefaultVisual(XtDisplay(new),
2006-11-25 13:07:29 -07:00
DefaultScreen(XtDisplay(new))),
2015-05-10 04:20:17 -06:00
1, XYBitmap, 0,
2006-11-25 13:07:29 -07:00
XtCalloc(1, sizeof(char)),
1, 1, 8, 0);
else
2015-05-10 04:20:17 -06:00
new_sw->scale.image =
XSubImage(new_sw->scale.image,
0, 0,
new_sw->scale.image->width,
2006-11-25 13:07:29 -07:00
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;
}
2015-05-10 04:20:17 -06:00
if (streq(XtNuserData, args[i].name))
2006-11-25 13:07:29 -07:00
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)) {
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.aspect_ratio =
2006-11-25 13:07:29 -07:00
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;
}
}
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
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;
}
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (streq(XtNscaleX, args[i].name)
2015-05-10 04:20:17 -06:00
||
2006-11-25 13:07:29 -07:00
streq(XtNscaleY, args[i].name)) {
if (new_sw->scale.scale_x_str == DefaultScaleFactor
2015-05-10 04:20:17 -06:00
||
2006-11-25 13:07:29 -07:00
new_sw->scale.scale_y_str == DefaultScaleFactor)
GetInitialScaleValues(new_sw);
else {
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.scale_x =
2006-11-25 13:07:29 -07:00
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.");
}
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.scale_y =
2006-11-25 13:07:29 -07:00
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) {
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
/*?*?*?*?*?*?*?*?*?*?*?*?*?*?**?*?*?*?*?*?*?*?*?***?*/
fprintf(stderr, "================>>%f %f\n",
new_sw->scale.scale_x, new_sw->scale.scale_y);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (new_sw->scale.proportional) Proportional(new_sw);
Precision(new_sw);
if (new_sw->scale.resize)
TryResize(new_sw);
2015-05-10 04:20:17 -06:00
GetScaledSize(new_sw);
2006-11-25 13:07:29 -07:00
BuildTable(new_sw);
PositionImage(new_sw);
redisplay = True;
}
}
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
if (streq(XtNprecision, args[i].name)) {
2015-05-10 04:20:17 -06:00
if ((new_sw->scale.precision =
2006-11-25 13:07:29 -07:00
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);
2015-05-10 04:20:17 -06:00
GetScaledSize(new_sw);
2006-11-25 13:07:29 -07:00
BuildTable(new_sw);
PositionImage(new_sw);
redisplay = True;
}
}
2015-05-10 04:20:17 -06:00
}
2006-11-25 13:07:29 -07:00
return(redisplay);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
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);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
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);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
SWInitialSize(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
ScaleWidget sw = (ScaleWidget) w;
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
GetInitialScaleValues(sw);
if (sw->scale.proportional) Proportional(sw);
Precision(sw);
if (sw->scale.resize)
TryResize(sw);
2015-05-10 04:20:17 -06:00
GetScaledSize(sw);
2006-11-25 13:07:29 -07:00
BuildTable(sw);
PositionImage(sw);
XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
SWSetImage(Widget w, XImage *image)
{
int n;
Arg wargs[2];
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
n = 0;
XtSetArg(wargs[n], XtNimage, (XtArgVal) image); n++;
XtSetValues(w, wargs, n);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
RequestSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
SWRequestSelection(w, event->xbutton.time);
}
2015-05-10 04:20:17 -06:00
void
2006-11-25 13:07:29 -07:00
GrabSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
SWGrabSelection(w, event->xbutton.time);
}
2015-05-10 04:20:17 -06:00
Pixmap
2006-11-25 13:07:29 -07:00
SWGetPixmap(Widget w)
{
ScaleWidget sw = (ScaleWidget) w;
Pixmap pixmap;
2015-05-10 04:20:17 -06:00
pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w),
sw->scale.width,
sw->scale.height,
2006-11-25 13:07:29 -07:00
sw->scale.image->depth);
2015-05-10 04:20:17 -06:00
ScaleImage(sw, pixmap,
0, 0, 0, 0,
(Dimension) sw->scale.image->width,
2006-11-25 13:07:29 -07:00
(Dimension) sw->scale.image->height);
2015-05-10 04:20:17 -06:00
2006-11-25 13:07:29 -07:00
return(pixmap);
}