1077 lines
29 KiB
C
1077 lines
29 KiB
C
/*
|
|
*
|
|
Copyright 1989, 1994, 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: Jim Fulton, MIT X Consortium
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <X11/IntrinsicP.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <X11/Xos.h>
|
|
#include <X11/Xmu/CharSet.h>
|
|
#include <X11/Xmu/Drawing.h>
|
|
#include <X11/Xmu/Misc.h>
|
|
#include <X11/Xaw/PannerP.h>
|
|
#include <X11/Xaw/XawInit.h>
|
|
#include "Private.h"
|
|
#include <stdlib.h> /* for atof() */
|
|
|
|
/*
|
|
* Class Methods
|
|
*/
|
|
static void XawPannerDestroy(Widget);
|
|
static void XawPannerInitialize(Widget, Widget, ArgList, Cardinal*);
|
|
static XtGeometryResult XawPannerQueryGeometry(Widget, XtWidgetGeometry*,
|
|
XtWidgetGeometry*);
|
|
static void XawPannerRealize(Widget, XtValueMask*, XSetWindowAttributes*);
|
|
static void XawPannerRedisplay(Widget, XEvent*, Region);
|
|
static void XawPannerResize(Widget);
|
|
static Boolean XawPannerSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
|
|
static void XawPannerSetValuesAlmost(Widget, Widget, XtWidgetGeometry*,
|
|
XtWidgetGeometry*);
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
static void check_knob(PannerWidget, Bool);
|
|
static void get_default_size(PannerWidget, Dimension*, Dimension*);
|
|
static Bool get_event_xy(PannerWidget, XEvent*, int*, int*);
|
|
static void move_shadow(PannerWidget);
|
|
static int parse_page_string(String, int, int, Bool*);
|
|
static void rescale(PannerWidget);
|
|
static void reset_shadow_gc(PannerWidget);
|
|
static void reset_slider_gc(PannerWidget);
|
|
static void reset_xor_gc(PannerWidget);
|
|
static void scale_knob(PannerWidget, Bool, Bool);
|
|
|
|
/*
|
|
* Actions
|
|
*/
|
|
static void ActionAbort(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionMove(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionNotify(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionPage(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionSet(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionStart(Widget, XEvent*, String*, Cardinal*);
|
|
static void ActionStop(Widget, XEvent*, String*, Cardinal*);
|
|
|
|
/*
|
|
* From Xmu/Distinct.c
|
|
*/
|
|
Bool XmuDistinguishablePixels(Display*, Colormap, unsigned long*, int);
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
static char defaultTranslations[] =
|
|
"<Btn1Down>:" "start()\n"
|
|
"<Btn1Motion>:" "move()\n"
|
|
"<Btn1Up>:" "notify() stop()\n"
|
|
"<Btn2Down>:" "abort()\n"
|
|
":<Key>KP_Enter:" "set(rubberband,toggle)\n"
|
|
"<Key>space:" "page(+1p,+1p)\n"
|
|
"<Key>Delete:" "page(-1p,-1p)\n"
|
|
":<Key>KP_Delete:" "page(-1p,-1p)\n"
|
|
"<Key>BackSpace:" "page(-1p,-1p)\n"
|
|
"<Key>Left:" "page(-.5p,+0)\n"
|
|
":<Key>KP_Left:" "page(-.5p,+0)\n"
|
|
"<Key>Right:" "page(+.5p,+0)\n"
|
|
":<Key>KP_Right:" "page(+.5p,+0)\n"
|
|
"<Key>Up:" "page(+0,-.5p)\n"
|
|
":<Key>KP_Up:" "page(+0,-.5p)\n"
|
|
"<Key>Down:" "page(+0,+.5p)\n"
|
|
":<Key>KP_Down:" "page(+0,+.5p)\n"
|
|
"<Key>Home:" "page(0,0)\n"
|
|
":<Key>KP_Home:" "page(0,0)\n"
|
|
;
|
|
|
|
static XtActionsRec actions[] = {
|
|
{"start", ActionStart}, /* start tmp graphics */
|
|
{"stop", ActionStop}, /* stop tmp graphics */
|
|
{"abort", ActionAbort}, /* punt */
|
|
{"move", ActionMove}, /* move tmp graphics on Motion event */
|
|
{"page", ActionPage}, /* page around usually from keyboard */
|
|
{"notify", ActionNotify}, /* callback new position */
|
|
{"set", ActionSet}, /* set various parameters */
|
|
};
|
|
|
|
#define offset(field) XtOffsetOf(PannerRec, panner.field)
|
|
static XtResource resources[] = {
|
|
{
|
|
XtNallowOff,
|
|
XtCAllowOff,
|
|
XtRBoolean,
|
|
sizeof(Boolean),
|
|
offset(allow_off),
|
|
XtRImmediate,
|
|
(XtPointer)False
|
|
},
|
|
{
|
|
XtNresize,
|
|
XtCResize,
|
|
XtRBoolean,
|
|
sizeof(Boolean),
|
|
offset(resize_to_pref),
|
|
XtRImmediate,
|
|
(XtPointer)True
|
|
},
|
|
{
|
|
XtNreportCallback,
|
|
XtCReportCallback,
|
|
XtRCallback,
|
|
sizeof(XtPointer),
|
|
offset(report_callbacks),
|
|
XtRCallback,
|
|
NULL
|
|
},
|
|
{
|
|
XtNdefaultScale,
|
|
XtCDefaultScale,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(default_scale),
|
|
XtRImmediate,
|
|
(XtPointer)PANNER_DEFAULT_SCALE
|
|
},
|
|
{
|
|
XtNrubberBand,
|
|
XtCRubberBand,
|
|
XtRBoolean,
|
|
sizeof(Boolean),
|
|
offset(rubber_band),
|
|
XtRImmediate,
|
|
(XtPointer)False
|
|
},
|
|
{
|
|
XtNforeground,
|
|
XtCForeground,
|
|
XtRPixel,
|
|
sizeof(Pixel),
|
|
offset(foreground),
|
|
XtRString,
|
|
(XtPointer)XtDefaultBackground
|
|
},
|
|
{
|
|
XtNinternalSpace,
|
|
XtCInternalSpace,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(internal_border),
|
|
XtRImmediate,
|
|
(XtPointer)4
|
|
},
|
|
{
|
|
XtNlineWidth,
|
|
XtCLineWidth,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(line_width),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNcanvasWidth,
|
|
XtCCanvasWidth,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(canvas_width),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNcanvasHeight,
|
|
XtCCanvasHeight,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(canvas_height),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNsliderX,
|
|
XtCSliderX,
|
|
XtRPosition,
|
|
sizeof(Position),
|
|
offset(slider_x),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNsliderY,
|
|
XtCSliderY,
|
|
XtRPosition,
|
|
sizeof(Position),
|
|
offset(slider_y),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNsliderWidth,
|
|
XtCSliderWidth,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(slider_width),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNsliderHeight,
|
|
XtCSliderHeight,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(slider_height),
|
|
XtRImmediate,
|
|
(XtPointer)0
|
|
},
|
|
{
|
|
XtNshadowColor,
|
|
XtCShadowColor,
|
|
XtRPixel,
|
|
sizeof(Pixel),
|
|
offset(shadow_color),
|
|
XtRString,
|
|
(XtPointer)XtDefaultForeground
|
|
},
|
|
{
|
|
XtNshadowThickness,
|
|
XtCShadowThickness,
|
|
XtRDimension,
|
|
sizeof(Dimension),
|
|
offset(shadow_thickness),
|
|
XtRImmediate,
|
|
(XtPointer)2
|
|
},
|
|
{
|
|
XtNbackgroundStipple,
|
|
XtCBackgroundStipple,
|
|
XtRString,
|
|
sizeof(String),
|
|
offset(stipple_name),
|
|
XtRImmediate,
|
|
NULL
|
|
},
|
|
};
|
|
#undef offset
|
|
|
|
#define Superclass (&simpleClassRec)
|
|
PannerClassRec pannerClassRec = {
|
|
/* core */
|
|
{
|
|
(WidgetClass)Superclass, /* superclass */
|
|
"Panner", /* class_name */
|
|
sizeof(PannerRec), /* widget_size */
|
|
XawInitializeWidgetSet, /* class_initialize */
|
|
NULL, /* class_part_initialize */
|
|
False, /* class_inited */
|
|
XawPannerInitialize, /* initialize */
|
|
NULL, /* initialize_hook */
|
|
XawPannerRealize, /* realize */
|
|
actions, /* actions */
|
|
XtNumber(actions), /* num_actions */
|
|
resources, /* resources */
|
|
XtNumber(resources), /* num_resources */
|
|
NULLQUARK, /* xrm_class */
|
|
True, /* compress_motion */
|
|
True, /* compress_exposure */
|
|
True, /* compress_enterleave */
|
|
False, /* visible_interest */
|
|
XawPannerDestroy, /* destroy */
|
|
XawPannerResize, /* resize */
|
|
XawPannerRedisplay, /* expose */
|
|
XawPannerSetValues, /* set_values */
|
|
NULL, /* set_values_hook */
|
|
XawPannerSetValuesAlmost, /* set_values_almost */
|
|
NULL, /* get_values_hook */
|
|
NULL, /* accept_focus */
|
|
XtVersion, /* version */
|
|
NULL, /* callback_private */
|
|
defaultTranslations, /* tm_table */
|
|
XawPannerQueryGeometry, /* query_geometry */
|
|
XtInheritDisplayAccelerator, /* display_accelerator */
|
|
NULL, /* extension */
|
|
},
|
|
/* simple */
|
|
{
|
|
XtInheritChangeSensitive, /* change_sensitive */
|
|
#ifndef OLDXAW
|
|
NULL,
|
|
#endif
|
|
},
|
|
/* panner */
|
|
{
|
|
NULL, /* extension */
|
|
}
|
|
};
|
|
|
|
WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
|
|
|
|
|
|
/*
|
|
* Implementation
|
|
*/
|
|
static void
|
|
reset_shadow_gc(PannerWidget pw)
|
|
{
|
|
XtGCMask valuemask;
|
|
XGCValues values;
|
|
unsigned long pixels[3];
|
|
|
|
if (pw->panner.shadow_gc)
|
|
XtReleaseGC((Widget)pw, pw->panner.shadow_gc);
|
|
|
|
pixels[0] = pw->panner.foreground;
|
|
pixels[1] = pw->core.background_pixel;
|
|
pixels[2] = pw->panner.shadow_color;
|
|
|
|
if (!pw->panner.stipple_name &&
|
|
!XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
|
|
pixels, 3) &&
|
|
XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
|
|
pixels, 2)) {
|
|
valuemask = GCTile | GCFillStyle;
|
|
values.fill_style = FillTiled;
|
|
values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
|
|
pw->panner.foreground,
|
|
pw->core.background_pixel,
|
|
pw->core.depth);
|
|
}
|
|
else {
|
|
if (!pw->panner.line_width &&
|
|
!XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
|
|
pixels, 2))
|
|
pw->panner.line_width = 1;
|
|
valuemask = GCForeground;
|
|
values.foreground = pw->panner.shadow_color;
|
|
}
|
|
if (pw->panner.line_width > 0) {
|
|
values.line_width = pw->panner.line_width;
|
|
valuemask |= GCLineWidth;
|
|
}
|
|
|
|
pw->panner.shadow_gc = XtGetGC((Widget)pw, valuemask, &values);
|
|
}
|
|
|
|
static void
|
|
reset_slider_gc(PannerWidget pw)
|
|
{
|
|
XtGCMask valuemask = GCForeground;
|
|
XGCValues values;
|
|
|
|
if (pw->panner.slider_gc)
|
|
XtReleaseGC((Widget)pw, pw->panner.slider_gc);
|
|
|
|
values.foreground = pw->panner.foreground;
|
|
|
|
pw->panner.slider_gc = XtGetGC((Widget)pw, valuemask, &values);
|
|
}
|
|
|
|
static void
|
|
reset_xor_gc(PannerWidget pw)
|
|
{
|
|
if (pw->panner.xor_gc)
|
|
XtReleaseGC((Widget)pw, pw->panner.xor_gc);
|
|
|
|
if (pw->panner.rubber_band) {
|
|
XtGCMask valuemask = (GCForeground | GCFunction);
|
|
XGCValues values;
|
|
Pixel tmp;
|
|
|
|
tmp = (pw->panner.foreground == pw->core.background_pixel ?
|
|
pw->panner.shadow_color : pw->panner.foreground);
|
|
values.foreground = tmp ^ pw->core.background_pixel;
|
|
values.function = GXxor;
|
|
if (pw->panner.line_width > 0) {
|
|
valuemask |= GCLineWidth;
|
|
values.line_width = pw->panner.line_width;
|
|
}
|
|
pw->panner.xor_gc = XtGetGC((Widget)pw, valuemask, &values);
|
|
}
|
|
else
|
|
pw->panner.xor_gc = NULL;
|
|
}
|
|
|
|
static void
|
|
check_knob(PannerWidget pw, Bool knob)
|
|
{
|
|
Position pad = (Position)(pw->panner.internal_border << 1);
|
|
Position maxx = (Position)(XtWidth(pw) - pad - pw->panner.knob_width);
|
|
Position maxy = (Position)(XtHeight(pw) - pad - pw->panner.knob_height);
|
|
Position *x = knob ? &pw->panner.knob_x : &pw->panner.tmp.x;
|
|
Position *y = knob ? &pw->panner.knob_y : &pw->panner.tmp.y;
|
|
|
|
/*
|
|
* note that positions are already normalized (i.e. internal_border
|
|
* has been subtracted out)
|
|
*/
|
|
if (*x < 0)
|
|
*x = 0;
|
|
if (*x > maxx)
|
|
*x = maxx;
|
|
|
|
if (*y < 0)
|
|
*y = 0;
|
|
if (*y > maxy)
|
|
*y = maxy;
|
|
|
|
if (knob) {
|
|
pw->panner.slider_x = (Position)((double)pw->panner.knob_x
|
|
/ pw->panner.haspect + 0.5);
|
|
pw->panner.slider_y = (Position)((double)pw->panner.knob_y
|
|
/ pw->panner.vaspect + 0.5);
|
|
pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
move_shadow(PannerWidget pw)
|
|
{
|
|
if (pw->panner.shadow_thickness > 0) {
|
|
int lw = pw->panner.shadow_thickness + (pw->panner.line_width << 1);
|
|
int pad = pw->panner.internal_border;
|
|
|
|
if (pw->panner.knob_height > lw && pw->panner.knob_width > lw) {
|
|
XRectangle *r = pw->panner.shadow_rects;
|
|
|
|
r->x = (short)(pw->panner.knob_x + pad + pw->panner.knob_width);
|
|
r->y = (short)(pw->panner.knob_y + pad + lw);
|
|
r->width = (unsigned short)(pw->panner.shadow_thickness);
|
|
r->height = (unsigned short)(pw->panner.knob_height - lw);
|
|
r++;
|
|
r->x = (short)(pw->panner.knob_x + pad + lw);
|
|
r->y = (short)(pw->panner.knob_y + pad + pw->panner.knob_height);
|
|
r->width = (unsigned short)(pw->panner.knob_width - lw + pw->panner.shadow_thickness);
|
|
r->height = (unsigned short)(pw->panner.shadow_thickness);
|
|
pw->panner.shadow_valid = True;
|
|
return;
|
|
}
|
|
}
|
|
pw->panner.shadow_valid = False;
|
|
}
|
|
|
|
static void
|
|
scale_knob(PannerWidget pw, Bool location, Bool size)
|
|
{
|
|
if (location) {
|
|
pw->panner.knob_x = (Position)PANNER_HSCALE(pw, pw->panner.slider_x);
|
|
pw->panner.knob_y = (Position)PANNER_VSCALE(pw, pw->panner.slider_y);
|
|
}
|
|
if (size) {
|
|
Dimension width, height;
|
|
|
|
if (pw->panner.slider_width < 1)
|
|
pw->panner.slider_width = pw->panner.canvas_width;
|
|
if (pw->panner.slider_height < 1)
|
|
pw->panner.slider_height = pw->panner.canvas_height;
|
|
width = Min(pw->panner.slider_width, pw->panner.canvas_width);
|
|
height = Min(pw->panner.slider_height, pw->panner.canvas_height);
|
|
|
|
pw->panner.knob_width = (Dimension)PANNER_HSCALE(pw, width);
|
|
pw->panner.knob_height = (Dimension)PANNER_VSCALE(pw, height);
|
|
}
|
|
if (!pw->panner.allow_off)
|
|
check_knob(pw, True);
|
|
move_shadow(pw);
|
|
}
|
|
|
|
static void
|
|
rescale(PannerWidget pw)
|
|
{
|
|
int hpad = pw->panner.internal_border << 1;
|
|
int vpad = hpad;
|
|
|
|
if (pw->panner.canvas_width < 1)
|
|
pw->panner.canvas_width = XtWidth(pw);
|
|
if (pw->panner.canvas_height < 1)
|
|
pw->panner.canvas_height = XtHeight(pw);
|
|
|
|
if (XtWidth(pw) <= hpad)
|
|
hpad = 0;
|
|
if (XtHeight(pw) <= vpad)
|
|
vpad = 0;
|
|
|
|
pw->panner.haspect = ((double)XtWidth(pw) - hpad + .5)
|
|
/ (double)pw->panner.canvas_width;
|
|
pw->panner.vaspect = ((double)XtHeight(pw) - vpad + .5)
|
|
/ (double)pw->panner.canvas_height;
|
|
scale_knob(pw, True, True);
|
|
}
|
|
|
|
static void
|
|
get_default_size(PannerWidget pw, Dimension *wp, Dimension *hp)
|
|
{
|
|
Dimension pad = (Dimension)(pw->panner.internal_border << 1);
|
|
|
|
*wp = (Dimension)(PANNER_DSCALE(pw, pw->panner.canvas_width) + pad);
|
|
*hp = (Dimension)(PANNER_DSCALE(pw, pw->panner.canvas_height) + pad);
|
|
}
|
|
|
|
static Bool
|
|
get_event_xy(PannerWidget pw, XEvent *event, int *x, int *y)
|
|
{
|
|
int pad = pw->panner.internal_border;
|
|
|
|
switch (event->type) {
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
*x = event->xbutton.x - pad;
|
|
*y = event->xbutton.y - pad;
|
|
return (True);
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
*x = event->xkey.x - pad;
|
|
*y = event->xkey.y - pad;
|
|
return (True);
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
*x = event->xcrossing.x - pad;
|
|
*y = event->xcrossing.y - pad;
|
|
return (True);
|
|
case MotionNotify:
|
|
*x = event->xmotion.x - pad;
|
|
*y = event->xmotion.y - pad;
|
|
return (True);
|
|
}
|
|
|
|
return (False);
|
|
}
|
|
|
|
static int
|
|
parse_page_string(String s, int pagesize, int canvassize, Bool *relative)
|
|
{
|
|
String cp;
|
|
double val = 1.0;
|
|
Bool rel = False;
|
|
|
|
/*
|
|
* syntax: spaces [+-] number spaces [pc\0] spaces
|
|
*/
|
|
for (; isascii((unsigned char)*s) && isspace((unsigned char)*s); s++) /* skip white space */
|
|
;
|
|
|
|
if (*s == '+' || *s == '-') { /* deal with signs */
|
|
rel = True;
|
|
if (*s == '-')
|
|
val = -1.0;
|
|
s++;
|
|
}
|
|
if (!*s) { /* if null then return nothing */
|
|
*relative = True;
|
|
return (0);
|
|
}
|
|
|
|
/* skip over numbers */
|
|
for (cp = s; isascii((unsigned char)*s) && (isdigit((unsigned char)*s) || *s == '.'); s++)
|
|
;
|
|
val *= atof(cp);
|
|
|
|
/* skip blanks */
|
|
for (; isascii((unsigned char)*s) && isspace((unsigned char)*s); s++)
|
|
;
|
|
|
|
if (*s) { /* if units */
|
|
switch (s[0]) {
|
|
case 'p':
|
|
case 'P':
|
|
val *= (double)pagesize;
|
|
break;
|
|
case 'c':
|
|
case 'C':
|
|
val *= (double)canvassize;
|
|
break;
|
|
}
|
|
}
|
|
*relative = rel;
|
|
|
|
return ((int)val);
|
|
}
|
|
|
|
#define DRAW_TMP(pw) \
|
|
{ \
|
|
XDrawRectangle(XtDisplay(pw), XtWindow(pw), \
|
|
pw->panner.xor_gc, \
|
|
(pw->panner.tmp.x + pw->panner.internal_border), \
|
|
(pw->panner.tmp.y + pw->panner.internal_border), \
|
|
(unsigned)(pw->panner.knob_width - 1), \
|
|
(unsigned)(pw->panner.knob_height - 1)); \
|
|
pw->panner.tmp.showing = !pw->panner.tmp.showing; \
|
|
}
|
|
|
|
#define UNDRAW_TMP(pw) \
|
|
{ \
|
|
if (pw->panner.tmp.showing) \
|
|
DRAW_TMP(pw); \
|
|
}
|
|
|
|
#define BACKGROUND_STIPPLE(pw) \
|
|
XmuLocatePixmapFile(pw->core.screen, pw->panner.stipple_name, \
|
|
pw->panner.shadow_color, pw->core.background_pixel, \
|
|
pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
|
|
|
|
#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
XawPannerInitialize(Widget greq, Widget gnew, ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
|
|
{
|
|
PannerWidget req = (PannerWidget)greq, cnew = (PannerWidget)gnew;
|
|
Dimension defwidth, defheight;
|
|
|
|
if (req->panner.canvas_width < 1)
|
|
cnew->panner.canvas_width = 1;
|
|
if (req->panner.canvas_height < 1)
|
|
cnew->panner.canvas_height = 1;
|
|
if (req->panner.default_scale < 1)
|
|
cnew->panner.default_scale = PANNER_DEFAULT_SCALE;
|
|
|
|
get_default_size(req, &defwidth, &defheight);
|
|
if (XtWidth(req) < 1)
|
|
XtWidth(cnew) = defwidth;
|
|
if (XtHeight(req) < 1)
|
|
XtHeight(cnew) = defheight;
|
|
|
|
cnew->panner.shadow_gc = NULL;
|
|
reset_shadow_gc(cnew); /* shadowColor */
|
|
cnew->panner.slider_gc = NULL;
|
|
reset_slider_gc(cnew); /* foreground */
|
|
cnew->panner.xor_gc = NULL;
|
|
reset_xor_gc(cnew); /* foreground ^ background */
|
|
|
|
rescale(cnew); /* does a position check */
|
|
cnew->panner.shadow_valid = False;
|
|
cnew->panner.tmp.doing = False;
|
|
cnew->panner.tmp.showing = False;
|
|
}
|
|
|
|
static void
|
|
XawPannerRealize(Widget gw, XtValueMask *valuemaskp,
|
|
XSetWindowAttributes *attr)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
Pixmap pm = XtUnspecifiedPixmap;
|
|
Bool gotpm = False;
|
|
|
|
if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
|
|
if (pw->panner.stipple_name)
|
|
pm = BACKGROUND_STIPPLE(pw);
|
|
|
|
if (PIXMAP_OKAY(pm)) {
|
|
attr->background_pixmap = pm;
|
|
*valuemaskp |= CWBackPixmap;
|
|
*valuemaskp &= (XtValueMask)(~CWBackPixel);
|
|
gotpm = True;
|
|
}
|
|
}
|
|
(*pannerWidgetClass->core_class.superclass->core_class.realize)
|
|
(gw, valuemaskp, attr);
|
|
|
|
if (gotpm)
|
|
XFreePixmap(XtDisplay(gw), pm);
|
|
}
|
|
|
|
static void
|
|
XawPannerDestroy(Widget gw)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
|
|
XtReleaseGC(gw, pw->panner.shadow_gc);
|
|
XtReleaseGC(gw, pw->panner.slider_gc);
|
|
XtReleaseGC(gw, pw->panner.xor_gc);
|
|
}
|
|
|
|
static void
|
|
XawPannerResize(Widget gw)
|
|
{
|
|
rescale((PannerWidget)gw);
|
|
}
|
|
|
|
static void
|
|
XawPannerRedisplay(Widget gw, XEvent *event, Region region)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
Display *dpy = XtDisplay(gw);
|
|
Window w = XtWindow(gw);
|
|
int pad = pw->panner.internal_border;
|
|
Dimension lw = pw->panner.line_width;
|
|
Dimension extra = (Dimension)(pw->panner.shadow_thickness + (lw << 1));
|
|
int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
|
|
|
|
if (Superclass->core_class.expose)
|
|
(Superclass->core_class.expose)(gw, event, region);
|
|
|
|
pw->panner.tmp.showing = False;
|
|
XClearArea(XtDisplay(pw), XtWindow(pw),
|
|
(int)pw->panner.last_x - ((int)lw) + pad,
|
|
(int)pw->panner.last_y - ((int)lw) + pad,
|
|
(unsigned)(pw->panner.knob_width + extra),
|
|
(unsigned)(pw->panner.knob_height + extra),
|
|
False);
|
|
pw->panner.last_x = pw->panner.knob_x;
|
|
pw->panner.last_y = pw->panner.knob_y;
|
|
|
|
XFillRectangle(dpy, w, pw->panner.slider_gc, kx, ky,
|
|
(unsigned)(pw->panner.knob_width - 1),
|
|
(unsigned)(pw->panner.knob_height - 1));
|
|
|
|
if (lw)
|
|
XDrawRectangle(dpy, w, pw->panner.shadow_gc, kx, ky,
|
|
(unsigned)(pw->panner.knob_width - 1),
|
|
(unsigned)(pw->panner.knob_height - 1));
|
|
|
|
if (pw->panner.shadow_valid)
|
|
XFillRectangles(dpy, w, pw->panner.shadow_gc, pw->panner.shadow_rects, 2);
|
|
|
|
if (pw->panner.tmp.doing && pw->panner.rubber_band)
|
|
DRAW_TMP(pw);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static Boolean
|
|
XawPannerSetValues(Widget gcur, Widget greq _X_UNUSED, Widget gnew,
|
|
ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
|
|
{
|
|
PannerWidget cur = (PannerWidget)gcur;
|
|
PannerWidget cnew = (PannerWidget)gnew;
|
|
Bool redisplay = False;
|
|
|
|
if (cur->panner.foreground != cnew->panner.foreground) {
|
|
reset_slider_gc(cnew);
|
|
if (cur->panner.foreground != cur->core.background_pixel)
|
|
reset_xor_gc(cnew);
|
|
redisplay = True;
|
|
}
|
|
else if (cur->panner.line_width != cnew->panner.line_width ||
|
|
cur->core.background_pixel != cnew->core.background_pixel) {
|
|
reset_xor_gc(cnew);
|
|
redisplay = True;
|
|
}
|
|
if (cur->panner.shadow_color != cnew->panner.shadow_color) {
|
|
reset_shadow_gc(cnew);
|
|
if (cur->panner.foreground == cur->core.background_pixel)
|
|
reset_xor_gc(cnew);
|
|
redisplay = True;
|
|
}
|
|
if (cur->panner.shadow_thickness != cnew->panner.shadow_thickness) {
|
|
move_shadow(cnew);
|
|
redisplay = True;
|
|
}
|
|
if (cur->panner.rubber_band != cnew->panner.rubber_band) {
|
|
reset_xor_gc(cnew);
|
|
if (cnew->panner.tmp.doing)
|
|
redisplay = True;
|
|
}
|
|
|
|
if ((cur->panner.stipple_name != cnew->panner.stipple_name
|
|
|| cur->panner.shadow_color != cnew->panner.shadow_color
|
|
|| cur->core.background_pixel != cnew->core.background_pixel)
|
|
&& XtIsRealized(gnew)) {
|
|
Pixmap pm = cnew->panner.stipple_name ?
|
|
BACKGROUND_STIPPLE(cnew) : XtUnspecifiedPixmap;
|
|
|
|
if (PIXMAP_OKAY(pm)) {
|
|
XSetWindowBackgroundPixmap(XtDisplay(cnew), XtWindow(cnew), pm);
|
|
XFreePixmap(XtDisplay(cnew), pm);
|
|
}
|
|
else
|
|
XSetWindowBackground(XtDisplay(cnew), XtWindow(cnew),
|
|
cnew->core.background_pixel);
|
|
|
|
redisplay = True;
|
|
}
|
|
|
|
if (cnew->panner.resize_to_pref &&
|
|
(cur->panner.canvas_width != cnew->panner.canvas_width
|
|
|| cur->panner.canvas_height != cnew->panner.canvas_height
|
|
|| cur->panner.resize_to_pref != cnew->panner.resize_to_pref)) {
|
|
get_default_size(cnew, &cnew->core.width, &cnew->core.height);
|
|
redisplay = True;
|
|
}
|
|
else if (cur->panner.canvas_width != cnew->panner.canvas_width
|
|
|| cur->panner.canvas_height != cnew->panner.canvas_height
|
|
|| cur->panner.internal_border != cnew->panner.internal_border) {
|
|
rescale(cnew); /* does a scale_knob as well */
|
|
redisplay = True;
|
|
}
|
|
else {
|
|
Bool loc = cur->panner.slider_x != cnew->panner.slider_x ||
|
|
cur->panner.slider_y != cnew->panner.slider_y;
|
|
Bool siz = cur->panner.slider_width != cnew->panner.slider_width ||
|
|
cur->panner.slider_height != cnew->panner.slider_height;
|
|
if (loc || siz || (cur->panner.allow_off != cnew->panner.allow_off
|
|
&& cnew->panner.allow_off)) {
|
|
scale_knob(cnew, loc, siz);
|
|
redisplay = True;
|
|
}
|
|
}
|
|
|
|
return (Boolean)(redisplay);
|
|
}
|
|
|
|
static void
|
|
XawPannerSetValuesAlmost(Widget gold, Widget gnew, XtWidgetGeometry *req,
|
|
XtWidgetGeometry *reply)
|
|
{
|
|
if (reply->request_mode == 0) /* got turned down, so cope */
|
|
XawPannerResize(gnew);
|
|
|
|
(*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
|
|
(gold, gnew, req, reply);
|
|
}
|
|
|
|
static XtGeometryResult
|
|
XawPannerQueryGeometry(Widget gw, XtWidgetGeometry *intended,
|
|
XtWidgetGeometry *pref)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
|
|
pref->request_mode = (CWWidth | CWHeight);
|
|
get_default_size(pw, &pref->width, &pref->height);
|
|
|
|
if (((intended->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
|
|
&& intended->width == pref->width && intended->height == pref->height)
|
|
return (XtGeometryYes);
|
|
else if (pref->width == XtWidth(pw) && pref->height == XtHeight(pw))
|
|
return (XtGeometryNo);
|
|
|
|
return (XtGeometryAlmost);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
ActionStart(Widget gw, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
int x, y;
|
|
|
|
if (!get_event_xy(pw, event, &x, &y)) {
|
|
XBell(XtDisplay(gw), 0);
|
|
return;
|
|
}
|
|
|
|
pw->panner.tmp.doing = True;
|
|
pw->panner.tmp.startx = pw->panner.knob_x;
|
|
pw->panner.tmp.starty = pw->panner.knob_y;
|
|
pw->panner.tmp.dx = (Position)(x - pw->panner.knob_x);
|
|
pw->panner.tmp.dy = (Position)(y - pw->panner.knob_y);
|
|
pw->panner.tmp.x = pw->panner.knob_x;
|
|
pw->panner.tmp.y = pw->panner.knob_y;
|
|
if (pw->panner.rubber_band)
|
|
DRAW_TMP(pw);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
ActionStop(Widget gw, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
int x, y;
|
|
|
|
if (get_event_xy(pw, event, &x, &y)) {
|
|
pw->panner.tmp.x = (Position)(x - pw->panner.tmp.dx);
|
|
pw->panner.tmp.y = (Position)(y - pw->panner.tmp.dy);
|
|
if (!pw->panner.allow_off)
|
|
check_knob(pw, False);
|
|
}
|
|
if (pw->panner.rubber_band)
|
|
DRAW_TMP(pw);
|
|
pw->panner.tmp.doing = False;
|
|
}
|
|
|
|
static void
|
|
ActionAbort(Widget gw, XEvent *event, String *params, Cardinal *num_params)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
|
|
if (!pw->panner.tmp.doing)
|
|
return;
|
|
|
|
if (pw->panner.rubber_band)
|
|
UNDRAW_TMP(pw);
|
|
|
|
if (!pw->panner.rubber_band) { /* restore old position */
|
|
pw->panner.tmp.x = pw->panner.tmp.startx;
|
|
pw->panner.tmp.y = pw->panner.tmp.starty;
|
|
ActionNotify(gw, event, params, num_params);
|
|
}
|
|
pw->panner.tmp.doing = False;
|
|
}
|
|
|
|
static void
|
|
ActionMove(Widget gw, XEvent *event, String *params, Cardinal *num_params)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
int x, y;
|
|
|
|
if (!pw->panner.tmp.doing)
|
|
return;
|
|
|
|
if (!get_event_xy(pw, event, &x, &y)) {
|
|
XBell(XtDisplay(gw), 0); /* should do error message */
|
|
return;
|
|
}
|
|
|
|
if (pw->panner.rubber_band)
|
|
UNDRAW_TMP(pw);
|
|
pw->panner.tmp.x = (Position)(x - pw->panner.tmp.dx);
|
|
pw->panner.tmp.y = (Position)(y - pw->panner.tmp.dy);
|
|
|
|
if (!pw->panner.rubber_band)
|
|
ActionNotify(gw, event, params, num_params);
|
|
else {
|
|
if (!pw->panner.allow_off)
|
|
check_knob(pw, False);
|
|
DRAW_TMP(pw);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
ActionPage(Widget gw, XEvent *event, String *params, Cardinal *num_params)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
Cardinal zero = 0;
|
|
Bool isin = pw->panner.tmp.doing;
|
|
int x, y;
|
|
Bool relx, rely;
|
|
int pad = pw->panner.internal_border << 1;
|
|
|
|
if (*num_params != 2) {
|
|
XBell(XtDisplay(gw), 0);
|
|
return;
|
|
}
|
|
|
|
x = parse_page_string(params[0], pw->panner.knob_width,
|
|
(int)XtWidth(pw) - pad, &relx);
|
|
y = parse_page_string(params[1], pw->panner.knob_height,
|
|
(int)XtHeight(pw) - pad, &rely);
|
|
|
|
if (relx)
|
|
x += pw->panner.knob_x;
|
|
if (rely)
|
|
y += pw->panner.knob_y;
|
|
|
|
if (isin) { /* if in, then use move */
|
|
XEvent ev = {
|
|
.xbutton.type = ButtonPress,
|
|
.xbutton.x = x,
|
|
.xbutton.y = y
|
|
};
|
|
ActionMove(gw, &ev, NULL, &zero);
|
|
}
|
|
else {
|
|
pw->panner.tmp.doing = True;
|
|
pw->panner.tmp.x = (Position)x;
|
|
pw->panner.tmp.y = (Position)y;
|
|
ActionNotify(gw, event, NULL, &zero);
|
|
pw->panner.tmp.doing = False;
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
ActionNotify(Widget gw, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
|
|
if (!pw->panner.tmp.doing)
|
|
return;
|
|
|
|
if (!pw->panner.allow_off)
|
|
check_knob(pw, False);
|
|
pw->panner.knob_x = pw->panner.tmp.x;
|
|
pw->panner.knob_y = pw->panner.tmp.y;
|
|
move_shadow(pw);
|
|
|
|
pw->panner.slider_x = (Position)((double)pw->panner.knob_x
|
|
/ pw->panner.haspect + 0.5);
|
|
pw->panner.slider_y = (Position)((double) pw->panner.knob_y
|
|
/ pw->panner.vaspect + 0.5);
|
|
if (!pw->panner.allow_off) {
|
|
Position tmp;
|
|
|
|
if (pw->panner.slider_x
|
|
> (tmp = (Position)(pw->panner.canvas_width -
|
|
pw->panner.slider_width)))
|
|
pw->panner.slider_x = tmp;
|
|
if (pw->panner.slider_x < 0)
|
|
pw->panner.slider_x = 0;
|
|
if (pw->panner.slider_y
|
|
> (tmp = (Position)(pw->panner.canvas_height -
|
|
pw->panner.slider_height)))
|
|
pw->panner.slider_y = tmp;
|
|
if (pw->panner.slider_y < 0)
|
|
pw->panner.slider_y = 0;
|
|
}
|
|
|
|
if (pw->panner.last_x != pw->panner.knob_x ||
|
|
pw->panner.last_y != pw->panner.knob_y) {
|
|
XawPannerReport rep;
|
|
|
|
XawPannerRedisplay(gw, NULL, NULL);
|
|
rep.changed = XawPRSliderX | XawPRSliderY;
|
|
rep.slider_x = pw->panner.slider_x;
|
|
rep.slider_y = pw->panner.slider_y;
|
|
rep.slider_width = pw->panner.slider_width;
|
|
rep.slider_height = pw->panner.slider_height;
|
|
rep.canvas_width = pw->panner.canvas_width;
|
|
rep.canvas_height = pw->panner.canvas_height;
|
|
XtCallCallbackList(gw, pw->panner.report_callbacks, (XtPointer)&rep);
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
ActionSet(Widget gw, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
|
|
{
|
|
PannerWidget pw = (PannerWidget)gw;
|
|
Bool rb;
|
|
|
|
if (*num_params < 2 ||
|
|
XmuCompareISOLatin1(params[0], "rubberband") != 0) {
|
|
XBell(XtDisplay(gw), 0);
|
|
return;
|
|
}
|
|
|
|
if (XmuCompareISOLatin1(params[1], "on") == 0)
|
|
rb = True;
|
|
else if (XmuCompareISOLatin1(params[1], "off") == 0)
|
|
rb = False;
|
|
else if (XmuCompareISOLatin1(params[1], "toggle") == 0)
|
|
rb = !pw->panner.rubber_band;
|
|
else {
|
|
XBell(XtDisplay(gw), 0);
|
|
return;
|
|
}
|
|
|
|
if (rb != pw->panner.rubber_band) {
|
|
Arg args[1];
|
|
|
|
XtSetArg(args[0], XtNrubberBand, rb);
|
|
XtSetValues(gw, args, 1);
|
|
}
|
|
}
|