home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
x
/
xtici.zip
/
xtici
/
widgets
/
Hvcleaf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-28
|
22KB
|
693 lines
/*
* Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
* All Rights Reserved
*
* This file is a component of an X Window System client which uses the Xcms
* Color Management System. TekColor is a trademark of Tektronix, Inc. The
* TekColor Editor is the subject of U.S. and foreign patents pending. The
* term "TekHVC" designates a particular color space that is the subject of
* U.S. Patent No. 4,985,853 (equivalent foreign patents pending).
* Permission is hereby granted to use, copy, modify, sell, and otherwise
* distribute this software and its documentation for the X Window System
* environment, for any purpose and without fee, provided that:
*
* 1. The code and documentation are only used to implement a
* TekColor Editor in an X Window System environment; and
* 2. This copyright and permission notice is reproduced in all copies
* of the code and in supporting documentation.
*
* Permission is granted to modify this code as required to allow it to
* be compiled on any host computer, provided that the functionality of
* the TekColor Editor is not modified in any way. A description of any
* modifications must be sent to Tektronix, Inc. Contact
* Tektronix Inc., P.O. Box 1000, Mail Station 60-850,
* Network Displays Division Engineering, Wilsonville, OR 97070.
*
* Tektronix makes no representation about the suitability of this software
* for any purpose. It is provided "as is" and with all faults.
*
* TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
* INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
*
*
* NAME
* Hvcleaf.c -- The HvcleafWidget to hold the HuelafWidget
*
* DESCRIPTION
*
*
* HISTORY
*
* HISTORY END
*
*/
#ifndef LINT
static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
#ifdef RCS_ID
static char *rcsid= "$Header: Hvcleaf.c,v 1.2 91/08/22 11:36:59 adamsc Exp $";
#endif /* RCS_ID */
#endif /* LINT */
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xmu/Misc.h>
#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include "HvcleafP.h"
#include "Hueleaf.h"
#include "RepeatB.h"
#ifndef EPS
#define EPS 0.001
#endif
static XtResource resources[] = {
#define offset(field) XtOffset(HvcleafWidget, hvcleaf.field)
/* {name, class, type, size, offset, default_type, default_addr}, */
{ XtNhvc, XtCHvc, XtRHvc, sizeof(XcmsColor *),
offset(pHvc), XtRImmediate, (XtPointer)NULL },
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(fgpixel), XtRImmediate, (XtPointer)XtDefaultForeground },
{ XtNbase, XtCBase, XtRPixel, sizeof(Pixel),
offset(base), XtRImmediate, (XtPointer)-1 },
{ XtNactivateCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
offset(activate), XtRImmediate, (XtPointer)NULL }
#undef offset
};
/* forward declarations for the class struct */
static void ChangeManaged();
static void Initialize();
static void Resize();
static Boolean SetValues();
static XtGeometryResult GeometryManager();
static XtGeometryResult QueryGeometry();
HvcleafClassRec hvcleafClassRec = {
{ /* Core fields */
/* superclass */ (WidgetClass) &compositeClassRec,
/* class_name */ "Leaf",
/* widget_size */ sizeof(HvcleafRec),
/* class_initialize */ XawInitializeWidgetSet,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ Resize,
/* expose */ NULL,
/* 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 */ NULL,
/* query_geometry */ QueryGeometry,
/* display_accelerator */ NULL,
/* extension */ NULL
},
{ /* Composite fields */
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
},
{ /* hvcleaf fields */
/* extension */ NULL
}
};
WidgetClass hvcleafWidgetClass = (WidgetClass)&hvcleafClassRec;
/****************************************************************
*
* Private Routines
*
****************************************************************/
/*
* Sometime in the future this geometry management could be simplified
* for now just use the box routines.
*
* Do a layout, either actually assigning positions, or just calculating size.
* Returns minimum width and height that will preserve the same layout.
*
*/
static DoLayout(hlw, width, height, reply_width, reply_height, position)
HvcleafWidget hlw;
Dimension width, height;
Dimension *reply_width, *reply_height; /* bounding box */
Boolean position; /* actually reposition the windows? */
{
Cardinal i;
Dimension w, h; /* Width and height needed for widget */
Dimension lw, lh; /* Width and height needed for current line */
Dimension bw, bh; /* Width and height needed for current widget */
register Widget widget; /* Current widget */
int num_mapped_children = 0;
/* Hvcleaf width and height */
w = 0;
h = 0;
/* Line width and height */
lh = 0;
lw = 0;
for (i = 0; i < hlw->composite.num_children; i++) {
widget = hlw->composite.children[i];
if (widget->core.managed) {
if (widget->core.mapped_when_managed)
num_mapped_children++;
/* Compute widget width */
bw = widget->core.width + 2*widget->core.border_width;
if (lw + bw > width) {
if (lw != 0) {
/* At least one widget on this line, and
* can't fit any more. Start new line.
*/
AssignMax(w, lw);
h += lh;
lh = 0;
lw = 0;
} else if (!position) {
/* too narrow for this widget; we'll assume we can grow */
DoLayout(hlw, lw + bw, height, reply_width,
reply_height, position);
return;
}
}
if (position && (lw != widget->core.x || h != widget->core.y)) {
/* It would be nice to use window gravity, but there isn't
* sufficient fine-grain control to nicely handle all
* situations (e.g. when only the height changes --
* a common case). Explicit unmapping is a cheap hack
* to speed things up & avoid the visual jitter as
* things slide around.
*
* %%% perhaps there should be a client resource to
* control this. If so, we'll have to optimize to
* perform the moves from the correct end so we don't
* force extra exposures as children occlude each other.
*/
if (XtIsRealized(widget) && widget->core.mapped_when_managed)
XUnmapWindow( XtDisplay(widget), XtWindow(widget) );
XtMoveWidget(widget, (int)lw, (int)h);
}
lw += bw;
bh = widget->core.height + 2*widget->core.border_width;
AssignMax(lh, bh);
} /* if managed */
} /* for */
if (position && XtIsRealized((Widget)hlw)) {
if (hlw->composite.num_children == num_mapped_children)
XMapSubwindows( XtDisplay((Widget)hlw), XtWindow((Widget)hlw) );
else {
int i = hlw->composite.num_children;
register Widget *childP = hlw->composite.children;
for (; i > 0; childP++, i--)
if (XtIsRealized(*childP) && XtIsManaged(*childP) &&
(*childP)->core.mapped_when_managed)
XtMapWidget(*childP);
}
}
/* Finish off last line */
if (lw != 0) {
AssignMax(w, lw);
h += lh;
}
*reply_width = Max(w, 1);
*reply_height = Max(h, 1);
}
/*
*
* Calculate preferred size, given constraining box, caching it in the widget.
*
*/
static XtGeometryResult QueryGeometry(widget, constraint, preferred)
Widget widget;
XtWidgetGeometry *constraint, *preferred;
{
HvcleafWidget w = (HvcleafWidget)widget;
Dimension width /*, height */;
Dimension preferred_width = w->hvcleaf.preferred_width;
Dimension preferred_height = w->hvcleaf.preferred_height;
constraint->request_mode &= CWWidth | CWHeight;
if (constraint->request_mode == 0)
/* parent isn't going to change w or h, so nothing to re-compute */
return XtGeometryYes;
if (constraint->request_mode == w->hvcleaf.last_query_mode &&
(!(constraint->request_mode & CWWidth) ||
constraint->width == w->hvcleaf.last_query_width) &&
(!(constraint->request_mode & CWHeight) ||
constraint->height == w->hvcleaf.last_query_height)) {
/* same query; current preferences are still valid */
preferred->request_mode = CWWidth | CWHeight;
preferred->width = preferred_width;
preferred->height = preferred_height;
if (constraint->request_mode == (CWWidth | CWHeight) &&
constraint->width == preferred_width &&
constraint->height == preferred_height)
return XtGeometryYes;
else
return XtGeometryAlmost;
}
/* else gotta do it the long way...
I have a preference for tall and narrow, so if my width is
constrained, I'll accept it; otherwise, I'll compute the minimum
width that will fit me within the height constraint */
w->hvcleaf.last_query_mode = constraint->request_mode;
w->hvcleaf.last_query_width = constraint->width;
w->hvcleaf.last_query_height= constraint->height;
if (constraint->request_mode & CWWidth)
width = constraint->width;
else { /* if (constraint->request_mode & CWHeight) */
/* let's see if I can become any narrower */
width = 0;
constraint->width = 65535;
}
/* height is currently ignored by DoLayout.
height = (constraint->request_mode & CWHeight) ? constraint->height
: *preferred_height;
*/
DoLayout(w, width, (Dimension)0, &preferred_width, &preferred_height,
FALSE);
if (constraint->request_mode & CWHeight &&
preferred_height > constraint->height) {
/* find minimum width for this height */
if (preferred_width > constraint->width) {
/* punt; over-constrained */
} else {
width = preferred_width;
do { /* find some width big enough to stay within this height */
width *= 2;
if (width > constraint->width)
width = constraint->width;
DoLayout(w, width, 0, &preferred_width, &preferred_height, FALSE);
} while (preferred_height > constraint->height &&
width < constraint->width);
if (width != constraint->width) {
do { /* find minimum width */
width = preferred_width;
DoLayout(w, preferred_width-1, 0,
&preferred_width, &preferred_height, FALSE);
} while (preferred_height < constraint->height);
/* one last time */
DoLayout(w, width, 0, &preferred_width, &preferred_height, FALSE);
}
}
}
preferred->request_mode = CWWidth | CWHeight;
preferred->width = w->hvcleaf.preferred_width = preferred_width;
preferred->height = w->hvcleaf.preferred_height = preferred_height;
if (constraint->request_mode == (CWWidth|CWHeight)
&& constraint->width == preferred_width
&& constraint->height == preferred_height)
return XtGeometryYes;
else
return XtGeometryAlmost;
}
/*
*
* Actually layout the widget
*
*/
static void Resize(w)
Widget w;
{
Dimension junk;
Widget form = ((HvcleafWidget)w)->hvcleaf.form;
DoLayout((HvcleafWidget)w, w->core.width, w->core.height, &junk, &junk,
TRUE);
XtResizeWidget(form, w->core.width, w->core.height,
form->core.border_width);
} /* Resize */
/*
*
* Try to do a new layout within the current width and height;
* if that fails try to resize and do it within the size returned
* by QueryGeometry.
*
* TryNewLayout just says if it's possible, and doesn't actually move the kids
*/
static Boolean TryNewLayout(hlw)
HvcleafWidget hlw;
{
Dimension preferred_width, preferred_height;
Dimension proposed_width, proposed_height;
int iterations;
DoLayout( hlw, hlw->core.width, hlw->core.height,
&preferred_width, &preferred_height, FALSE );
/* at this point, preferred_width is guaranteed to not be greater
than hlw->core.width unless some child is larger, so there's no
point in re-computing another layout */
if ((hlw->core.width == preferred_width) &&
(hlw->core.height == preferred_height)) {
/* Same size */
return (TRUE);
}
/* let's see if our parent will go for a new size. */
iterations = 0;
proposed_width = preferred_width;
proposed_height = preferred_height;
do {
switch (XtMakeResizeRequest((Widget)hlw,proposed_width,proposed_height,
&proposed_width, &proposed_height))
{
case XtGeometryYes:
return (TRUE);
case XtGeometryNo:
if (iterations > 0)
/* protect from malicious parents who change their minds */
DoLayout( hlw, hlw->core.width, hlw->core.height,
&preferred_width, &preferred_height, FALSE );
if ((preferred_width <= hlw->core.width) &&
(preferred_height <= hlw->core.height))
return (TRUE);
else
return (FALSE);
case XtGeometryAlmost:
if (proposed_height >= preferred_height &&
proposed_width >= preferred_width) {
/*
* Take it, and assume the parent knows what it is doing.
*
* The parent must accept this since it was returned in
* almost.
*
*/
(void) XtMakeResizeRequest( (Widget)hlw,
proposed_width, proposed_height,
&proposed_width, &proposed_height);
return(TRUE);
}
else if (proposed_width != preferred_width) {
/* recalc bounding box; height might change */
DoLayout(hlw, proposed_width, 0,
&preferred_width, &preferred_height, FALSE);
proposed_height = preferred_height;
}
else { /* proposed_height != preferred_height */
XtWidgetGeometry constraints, reply;
constraints.request_mode = CWHeight;
constraints.height = proposed_height;
(void)QueryGeometry((Widget)hlw, &constraints, &reply);
proposed_width = preferred_width;
}
}
iterations++;
} while (iterations < 10);
return (FALSE);
}
/*
*
* Geometry Manager
*
* 'reply' is unused; we say only yeay or nay, never almost.
*
*/
/*ARGSUSED*/
static XtGeometryResult GeometryManager(w, request, reply)
Widget w;
XtWidgetGeometry *request;
XtWidgetGeometry *reply; /* RETURN */
{
Dimension width, height, borderWidth;
HvcleafWidget hlw;
/* Position request always denied */
if ((request->request_mode & CWX && request->x != w->core.x) ||
(request->request_mode & CWY && request->y != w->core.y))
return (XtGeometryNo);
/* Size changes must see if the new size can be accomodated */
if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
/* Make all three fields in the request valid */
if ((request->request_mode & CWWidth) == 0)
request->width = w->core.width;
if ((request->request_mode & CWHeight) == 0)
request->height = w->core.height;
if ((request->request_mode & CWBorderWidth) == 0)
request->border_width = w->core.border_width;
/* Save current size and set to new size */
width = w->core.width;
height = w->core.height;
borderWidth = w->core.border_width;
w->core.width = request->width;
w->core.height = request->height;
w->core.border_width = request->border_width;
/* Decide if new layout works: (1) new widget is smaller,
(2) new widget fits in existing Hvcleaf, (3) Hvcleaf can be
expanded to allow new widget to fit */
hlw = (HvcleafWidget) w->core.parent;
if (TryNewLayout(hlw)) {
/* Fits in existing or new space, relayout */
(*XtClass((Widget)hlw)->core_class.resize)((Widget)hlw);
return (XtGeometryYes);
} else {
/* Cannot satisfy request, change back to original geometry */
w->core.width = width;
w->core.height = height;
w->core.border_width = borderWidth;
return (XtGeometryNo);
}
} /* if any size changes requested */
/* Any stacking changes don't make a difference, so allow if that's all */
return (XtGeometryYes);
}
static void ChangeManaged(w)
Widget w;
{
/* Reconfigure the widget */
(void) TryNewLayout((HvcleafWidget)w);
Resize(w);
}
/* ARGSUSED */
static void HvcActivate(widget, which, call)
Widget widget;
XtPointer which;
XtPointer call;
{
Widget hw = widget;
while (hw) {
if (IsHvcleaf(hw))
break;
hw = XtParent(hw);
}
if (!hw)
return;
XtCallCallbacks (hw, XtNactivateCallback, call);
}
static void CreateChildren(new)
HvcleafWidget new;
{
Arg args[10];
WidgetList wlist = new->hvcleaf.wlist;
Widget form;
int cnt;
cnt = 0;
XtSetArg(args[cnt], XtNborderWidth, 0); cnt++;
XtSetArg(args[cnt], XtNwidth, new->core.width); cnt++;
XtSetArg(args[cnt], XtNheight, new->core.height); cnt++;
form = XtCreateManagedWidget ("hvcform", formWidgetClass, (Widget)new,
args, cnt);
new->hvcleaf.form = form;
cnt = 0;
XtSetArg(args[cnt], XtNlabel, "VALUE"); cnt++;
XtSetArg (args[cnt], XtNvertDistance, 125); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[ValueLabel] = XtCreateWidget("value", labelWidgetClass, form,
args, cnt);
/* this is the up repeater button for the value up arrow */
cnt = 0;
XtSetArg (args[cnt], XtNvertDistance, 116); cnt++;
XtSetArg (args[cnt], XtNfromHoriz, wlist[ValueLabel]); cnt++;
XtSetArg (args[cnt], XtNarrowDirection, XtorientationUp); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[UpArrow] = XtCreateWidget("uparrow", repeaterButtonClass, form,
args, cnt);
/* this is the down repeater button for the value down arrow */
cnt = 0;
XtSetArg (args[cnt], XtNfromVert, wlist[UpArrow]); cnt++;
XtSetArg (args[cnt], XtNfromHoriz, wlist[ValueLabel]); cnt++;
XtSetArg (args[cnt], XtNarrowDirection, XtorientationDown); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[DownArrow] = XtCreateWidget("downarrow", repeaterButtonClass, form,
args, cnt);
cnt = 0;
XtSetArg (args[cnt], XtNwidth, 255); cnt++;
XtSetArg (args[cnt], XtNheight, 255); cnt++;
XtSetArg (args[cnt], XtNfromHoriz, wlist[UpArrow]); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
if (new->hvcleaf.pHvc) {
XtSetArg (args[cnt], XtNhvc, new->hvcleaf.pHvc); cnt++;
}
wlist[HueLeaf] = XtCreateWidget("hueleaf", hueleafWidgetClass, form,
args, cnt);
XtAddCallback (wlist[HueLeaf], XtNactivateCallback, HvcActivate, NULL);
/* this is the left repeater button for the chroma left arrow */
cnt = 0;
XtSetArg (args[cnt], XtNhorizDistance, 115); cnt++;
XtSetArg (args[cnt], XtNfromHoriz, wlist[UpArrow]); cnt++;
XtSetArg (args[cnt], XtNfromVert, wlist[HueLeaf]); cnt++;
XtSetArg (args[cnt], XtNarrowDirection, XtorientationLeft); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[LeftArrow] = XtCreateWidget("leftarrow", repeaterButtonClass, form,
args, cnt);
/* this is the right repeater button for the chroma right arrow */
cnt = 0;
XtSetArg (args[cnt], XtNfromHoriz, wlist[LeftArrow]); cnt++;
XtSetArg (args[cnt], XtNfromVert, wlist[HueLeaf]); cnt++;
XtSetArg (args[cnt], XtNarrowDirection, XtorientationRight); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[RightArrow] = XtCreateWidget("rightarrow", repeaterButtonClass, form,
args, cnt);
cnt = 0;
XtSetArg(args[cnt], XtNlabel, "CHROMA"); cnt++;
XtSetArg (args[cnt], XtNhorizDistance, 90); cnt++;
XtSetArg (args[cnt], XtNfromHoriz, wlist[UpArrow]); cnt++;
XtSetArg (args[cnt], XtNfromVert, wlist[LeftArrow]); cnt++;
XtSetArg (args[cnt], XtNresizable, True); cnt++;
wlist[ChromaLabel] = XtCreateWidget("chroma", labelWidgetClass, form,
args, cnt);
XtManageChildren (wlist, HvcLeafChildCt);
new->hvcleaf.numchildren = HvcLeafChildCt;
}
static void Initialize(req, new)
HvcleafWidget req, new;
{
HvcleafWidget leaf;
XcmsFloat tmp;
if (req->core.width == 0)
new->core.width = 100;
if (req->core.height == 0)
new->core.height = 100;
new->hvcleaf.aspect = 1.0;
CreateChildren(new);
leaf = (HvcleafWidget)new->hvcleaf.wlist[HueLeaf];
if (req->core.width == 0)
new->core.width = leaf->core.width;
if (req->core.height == 0)
new->core.height = leaf->core.height;
if (new->core.width < leaf->core.width)
new->core.width = leaf->core.width;
if (new->core.height < leaf->core.height)
new->core.height = leaf->core.height;
tmp = (XcmsFloat)new->core.width / (XcmsFloat)new->core.height;
if (tmp < 1.0 - EPS || tmp > 1.0 + EPS) {
if (new->core.width > new->core.height) {
new->core.width = new->core.height;
} else {
new->core.height = new->core.width;
}
}
new->hvcleaf.preferred_width = 0;
new->hvcleaf.preferred_height = 0;
new->hvcleaf.last_query_mode = 0;
}
/*
* Always draw ourselves if needed, so we can avoid redrawing shadows.
* This means we always return false, of course.
*/
/* ARGSUSED */
static Boolean SetValues(cur, req, new)
HvcleafWidget cur, req, new;
{
Arg args[10];
Widget leaf;
int cnt = 0;
if (new->hvcleaf.pHvc && new->hvcleaf.pHvc != cur->hvcleaf.pHvc) {
XtSetArg (args[cnt], XtNhvc, new->hvcleaf.pHvc); cnt++;
}
if (new->hvcleaf.base != cur->hvcleaf.base) {
XtSetArg (args[cnt], XtNbase, new->hvcleaf.base); cnt++;
}
if (cnt) {
leaf = new->hvcleaf.wlist[HueLeaf];
XtSetValues (leaf, args, cnt);
}
return (False);
}