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
/
Hueleaf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-28
|
25KB
|
809 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
* Hueleaf.c -- the HueleafWidget a drawing area for HvcleafWidget
*
* DESCRIPTION
*
*
* HISTORY
*
* HISTORY END
*
*/
#ifndef LINT
static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
#ifdef RCS_ID
static char *rcsid= "$Header: Hueleaf.c,v 1.3 91/08/28 10:09:55 adamsc Exp $";
#endif /* RCS_ID */
#endif /* LINT */
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "HueleafP.h"
#include "VShell.h"
#include <X11/Xcms.h>
static XtResource resources[] = {
#define offset(field) XtOffset(HueleafWidget, hueleaf.field)
/* {name, class, type, size, offset, default_type, default_addr}, */
{ XtNhvc, XtCHvc, XtRHvc, sizeof(XcmsColor *),
offset(pHvc), XtRImmediate, (XtPointer)NULL },
{ XtNbase, XtCBase, XtRPixel, sizeof(Pixel),
offset(base), XtRImmediate, (XtPointer)-1 },
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(fgpixel), XtRImmediate, (XtPointer)XtDefaultForeground },
{ XtNactivateCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
offset(activate), XtRImmediate, (XtPointer)NULL },
#undef offset
};
/* translation table and action list */
static void Arm();
static void Disarm();
static void Drag();
static char defaultTranslations[] =
"<Btn1Down>: Arm() \n\
<Btn1Up>: Disarm() \n\
Button1<PtrMoved>: Drag()";
static XtActionsRec actionsList[] =
{
{ "Arm", (XtActionProc) Arm},
{ "Disarm", (XtActionProc) Disarm},
{ "Drag", (XtActionProc) Drag}
};
/* forward declarations for the class struct */
static void Initialize();
static void Destroy();
static void Exposed();
static void Resized();
static Boolean SetValues();
static XtGeometryResult QueryGeometry();
HueleafClassRec hueleafClassRec = {
{ /* Core fields */
/* superclass */ (WidgetClass) &simpleClassRec,
/* class_name */ "Hueleaf",
/* widget_size */ sizeof(HueleafRec),
/* class_initialize */ NULL,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resized,
/* expose */ Exposed,
/* 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 */ defaultTranslations,
/* query_geometry */ QueryGeometry,
/* display_accelerator */ NULL,
/* extension */ NULL
},
{ /* simple fields */
/* change_sensitive */ XtInheritChangeSensitive,
},
{ /* hueleaf fields */
/* extension */ NULL
}
};
WidgetClass hueleafWidgetClass = (WidgetClass)&hueleafClassRec;
/* forward declarations for utility functions */
static void DoCallback();
static void Draw();
static void GetGC();
static XcmsFloat InterpolateVC();
/*
* Controls what happens on draw.
* Ordering is important, going from least work to most.
*/
#define DrawMark 0
#define DrawLeaf 1
#define DrawAll 2
/* this is the slop in the calculations. */
#define EPS 0.001
/* Some minimum size for this leaf */
#define MIN_WIDTH 200
static void Arm(leaf, e)
HueleafWidget leaf;
XEvent *e;
{
DoCallback(leaf, (XButtonEvent *)e, CR_ARM);
}
static void Disarm(leaf, e)
HueleafWidget leaf;
XEvent *e;
{
DoCallback(leaf, (XButtonEvent *)e, CR_DISARM);
}
static void Drag(leaf, e)
HueleafWidget leaf;
XEvent *e;
{
DoCallback(leaf, (XButtonEvent *)e, CR_DRAG);
}
static char *warning1 = "hue must be non-negative and less than 360.0";
static char *warning2 = "value must be between 0.0 and 100.0, inclusive";
static char *warning3 = "chroma must be non-negative";
static char *warning4 = "gamut of display device in this hue is too large";
static char *warning5 = "XcmsTekHVCClipC failure from SampleMaxChroma";
static char *warning6 = "XcmsConvertColors failure from SampleMaxChroma";
static void Warning (widget, message)
Widget widget;
char *message;
{
/* R4 says use XtAppWarningMsg but no information on how to set
* the parameters.
*/
if (!widget)
XtWarning(message);
else
XtAppWarning(XtWidgetToApplicationContext(widget), message);
}
/*
* Sample the maximum chroma at different values for this hue.
* Values are evenly spaced between max (100.0) and the value which
* yields the max chroma of this hue.
*/
static void SampleMaxChroma(leaf)
HueleafWidget leaf;
{
int i, j;
XcmsColor max[ChromaSamples];
XcmsFloat inc, Hue;
Hue = leaf->hueleaf.curhvc.spec.TekHVC.H;
/*
* Max value samples does not give enough discrimination around the point
* of max chromaticity for blue hues; so weight some extra samples here.
*/
for (i = 0; i < ChromaSamples-2; i++) {
max[i].spec.TekHVC.H = Hue;
max[i].format = XcmsTekHVCFormat;
}
XcmsTekHVCQueryMaxVSamples(leaf->hueleaf.pXcmsCCC, Hue,
max, (unsigned short)(ChromaSamples-2));
for (i = 0, j = ChromaSamples - 3; i < ChromaSamples-2; i++, j--) {
leaf->hueleaf.cValue[i] = max[j].spec.TekHVC.V;
leaf->hueleaf.maxChroma[i] = max[j].spec.TekHVC.C;
}
leaf->hueleaf.cValue[ChromaSamples-1] = max[0].spec.TekHVC.V;
leaf->hueleaf.maxChroma[ChromaSamples-1] = max[0].spec.TekHVC.C;
inc = (max[0].spec.TekHVC.V - max[1].spec.TekHVC.V) / 3.0;
max[0].spec.TekHVC.H = Hue;
max[0].spec.TekHVC.V -= inc;
for (i = 0, j = ChromaSamples-2; i < 2; i++, j--) {
if (XcmsTekHVCClipC(leaf->hueleaf.pXcmsCCC, max, 1, 0, NULL) == XcmsFailure) {
Warning(leaf, warning5);
return;
}
if ((XcmsConvertColors(leaf->hueleaf.pXcmsCCC, max, 1,
XcmsTekHVCFormat, NULL) == XcmsFailure) &&
max[0].format != XcmsTekHVCFormat) {
Warning(leaf, warning6);
return;
}
leaf->hueleaf.cValue[j] = max[0].spec.TekHVC.V;
leaf->hueleaf.maxChroma[j] = max[0].spec.TekHVC.C;
max[0].spec.TekHVC.V -= inc;
max[0].spec.TekHVC.H = Hue;
}
}
static void Destroy(leaf)
HueleafWidget leaf;
{
if (leaf->hueleaf.leafGC)
XFreeGC(XtDisplay(leaf), leaf->hueleaf.leafGC);
}
/*ARGSUSED*/
static void Exposed(leaf, e, region)
HueleafWidget leaf;
XEvent *e;
Region region;
{
Draw(leaf, DrawAll);
}
static void Initialize(req, new)
HueleafWidget req, new;
{
/* For now use the Default Color Conversion Context */
new->hueleaf.pXcmsCCC = XcmsDefaultCCC(XtDisplay(new),
DefaultScreen (XtDisplay(new)));
if (req->core.width == 0)
new->core.width = MIN_WIDTH;
if (req->core.height == 0)
new->core.height = MIN_WIDTH;
/* Building the GC is deferred until we know we have a window, */
/* ie, when the widget is first expose */
new->hueleaf.leafGC = 0;
if (new->hueleaf.pHvc) {
XcmsColor *phvc = new->hueleaf.pHvc;
bcopy ((char *)phvc, (char *)&new->hueleaf.curhvc, sizeof(XcmsColor));
/*
* validate hvc values:
* hue must be in range [0-360)
* value must be [0-100]
* chroma is open ended, but must be non-negative
*/
if ( (phvc->spec.TekHVC.H < 0.0) || (phvc->spec.TekHVC.H >= 360.0) ) {
Warning(new, warning1);
while (phvc->spec.TekHVC.H < 0.0) {
phvc->spec.TekHVC.H += 360.0;
}
while (phvc->spec.TekHVC.H >= 360.0) {
phvc->spec.TekHVC.H -= 360.0;
}
new->hueleaf.curhvc.spec.TekHVC.H = phvc->spec.TekHVC.H;
}
if ( (phvc->spec.TekHVC.V < 0.0) || (phvc->spec.TekHVC.V > 100.0) ) {
Warning(new, warning2);
if (phvc->spec.TekHVC.V < 0.0) {
new->hueleaf.curhvc.spec.TekHVC.V = EPS;
}
if (phvc->spec.TekHVC.V > 100.0) {
new->hueleaf.curhvc.spec.TekHVC.V = 100.0 - EPS;
}
}
if (phvc->spec.TekHVC.C < 0.0) {
Warning(new, warning3);
new->hueleaf.curhvc.spec.TekHVC.C = 0.0;
} else if (phvc->spec.TekHVC.C > LeafMaxChroma) {
/* Not an error, so no warning, but restrict anyway */
new->hueleaf.curhvc.spec.TekHVC.C = LeafMaxChroma;
}
} else {
new->hueleaf.curhvc.spec.TekHVC.H = 0.0;
new->hueleaf.curhvc.spec.TekHVC.V = 0.0;
new->hueleaf.curhvc.spec.TekHVC.C = 0.0;
new->hueleaf.curhvc.format = XcmsTekHVCFormat;
new->hueleaf.curhvc.pixel = -1;
}
SampleMaxChroma(new);
new->hueleaf.dragging = False;
new->hueleaf.lastx = new->hueleaf.lasty = -1;
}
/* Only allow the leaf widget to be a square. */
/* The HVC leaf is assumed to have an aspect ratio of x / y = 1.0 */
/* This is not used because geometry is determined in Manageleaf.c */
static XtGeometryResult QueryGeometry (leaf, proposed, result)
HueleafWidget leaf;
XtWidgetGeometry *proposed, *result;
{
XtGeometryMask requestMode = proposed->request_mode & (CWWidth | CWHeight);
if (!((requestMode & CWHeight) || (requestMode & CWWidth))) {
result->request_mode = NULL;
return (XtGeometryYes);
}
if (leaf->core.width == proposed->width &&
leaf->core.height == proposed->height &&
proposed->width == proposed->height &&
proposed->width > MIN_WIDTH) {
return (XtGeometryNo);
}
result->request_mode = (CWWidth | CWHeight);
if (proposed->height != proposed->width) {
if (proposed->height > proposed->width) {
result->height = proposed->width;
result->width = proposed->width;
} else {
result->width = proposed->height;
result->height = proposed->height;
}
} else {
result->height = proposed->height;
result->width = proposed->width;
if (result->height < MIN_WIDTH) {
result->height = result->width = MIN_WIDTH;
return (XtGeometryAlmost);
} else {
return (XtGeometryYes);
}
}
if (result->height < 100) {
result->height = result->width = MIN_WIDTH;
}
return (XtGeometryAlmost);
}
/* Could cache leaf outline points for current size */
static void Resized(leaf)
HueleafWidget leaf;
{
XRectangle rect;
/* adjust the clipping rectangle to fit new geometry */
/* if there is not a context yet, simply return */
if (!leaf->hueleaf.leafGC)
return;
rect.x = 0;
rect.y = 0;
rect.width = leaf->core.width;
rect.height = leaf->core.height;
/* only one rectanlge, so it must be banded */
XSetClipRectangles(XtDisplay(leaf), leaf->hueleaf.leafGC, 0, 0,
&rect, 1, YXBanded);
}
/*
* 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)
HueleafWidget cur, req, new;
{
int flag = -1;
if (!new->hueleaf.pHvc)
return(False);
if ( (new->hueleaf.pHvc->spec.TekHVC.H < 0.0) || (new->hueleaf.pHvc->spec.TekHVC.H >= 360.0) ) {
Warning(new, warning1);
new->hueleaf.curhvc.spec.TekHVC.H = cur->hueleaf.curhvc.spec.TekHVC.H;
} else
new->hueleaf.curhvc.spec.TekHVC.H = new->hueleaf.pHvc->spec.TekHVC.H;
if ( (new->hueleaf.pHvc->spec.TekHVC.V < 0.0) || (new->hueleaf.pHvc->spec.TekHVC.V > 100.0) ) {
Warning(new, warning2);
new->hueleaf.curhvc.spec.TekHVC.V = cur->hueleaf.curhvc.spec.TekHVC.V;
} else
new->hueleaf.curhvc.spec.TekHVC.V = new->hueleaf.pHvc->spec.TekHVC.V;
if (new->hueleaf.pHvc->spec.TekHVC.C < 0.0) {
Warning(new, warning3);
new->hueleaf.curhvc.spec.TekHVC.C = cur->hueleaf.curhvc.spec.TekHVC.C;
} else
new->hueleaf.curhvc.spec.TekHVC.C = new->hueleaf.pHvc->spec.TekHVC.C;
if (new->hueleaf.pHvc->spec.TekHVC.C > LeafMaxChroma) {
/* Not an error, so no warning, but restrict anyway */
new->hueleaf.pHvc->spec.TekHVC.C = LeafMaxChroma;
}
if (new->hueleaf.curhvc.spec.TekHVC.H != cur->hueleaf.curhvc.spec.TekHVC.H) {
SampleMaxChroma(new);
if (flag < DrawLeaf)
flag = DrawLeaf;
}
if ( (new->hueleaf.curhvc.spec.TekHVC.V != cur->hueleaf.curhvc.spec.TekHVC.V)
|| (new->hueleaf.curhvc.spec.TekHVC.C != cur->hueleaf.curhvc.spec.TekHVC.C) ) {
if (flag < DrawMark)
flag = DrawMark;
}
if (new->hueleaf.base != cur->hueleaf.base) {
if (flag < DrawLeaf)
flag = DrawLeaf;
}
if (flag >= 0 && XtIsRealized((Widget)new))
Draw(new, flag);
return(False);
}
#define XtoC(ex) (LeafMaxChroma * \
(XcmsFloat)((ex) / (XcmsFloat)(width - 1)))
#define YtoV(ey) (100.0 - \
(((XcmsFloat)(ey) / (XcmsFloat)(height - 1)) * 100.0))
/*
* This event type is a bit of a hack.
* This assumes that only button and mouse motion events will be passed
* this routine, and that the fields of interest in the structures (x,y)
* are identical. As it turns out, the structures are exactly identical -
* at least when this was written.
*/
static void DoCallback(leaf, e, reason)
HueleafWidget leaf;
XButtonEvent *e;
int reason;
{
int width = leaf->core.width;
int height = leaf->core.height;
XcmsFloat v, c;
XcmsFloat diffv, diffc;
XcmsColor tmp;
HvcCallbackStruct data;
v = YtoV(e->y);
c = XtoC(e->x);
/* apply our known constraints */
if (v < 0.0)
v = 0.0;
else if (v > 100.0)
v = 100.0;
if (c < 0.0)
c = 0.0;
else if (c > LeafMaxChroma)
c = LeafMaxChroma;
/* Don't exercise callback on drags if there is no change */
diffv = v - leaf->hueleaf.curhvc.spec.TekHVC.V;
if (diffv < 0.0)
diffv *= -1.0; /* avoid call to abs */
diffc = c - leaf->hueleaf.curhvc.spec.TekHVC.C;
if (diffc < 0.0)
diffc *= -1.0; /* avoid call to abs */
/* 0.1 is probably better than the device can handle, anyway */
if ( (diffv < 0.1) && (diffc < 0.1) && (reason == CR_DRAG) )
return;
data.reason = reason;
data.event = (XEvent *)e;
data.hvc = &tmp;
tmp.spec.TekHVC.H = leaf->hueleaf.curhvc.spec.TekHVC.H; /* hue never changes */
tmp.spec.TekHVC.V = v;
tmp.spec.TekHVC.C = c;
XtCallCallbacks((Widget)leaf, XtNactivateCallback, &data);
/* could check to see if application trashed return */
leaf->hueleaf.curhvc.spec.TekHVC.V = tmp.spec.TekHVC.V;
leaf->hueleaf.curhvc.spec.TekHVC.C = tmp.spec.TekHVC.C;
/* Could check to see if there still is a change, but it's not worth it */
Draw(leaf, DrawMark);
}
/* There is a point for each sample plus value 100 and value 0 */
#define PointCt (ChromaSamples+2)
/* this (MarkSize) could be a widget attribute */
#define MarkSize 5
#define CtoX(c) ((int)((XcmsFloat)(c) * (XcmsFloat)(width-1) / \
LeafMaxChroma + 0.5))
#define VtoY(v) (height - \
((int)((XcmsFloat)(v) * (XcmsFloat)(height-1) / 100.0 + 0.5) \
+ 1))
#define MarkLevels 12
static XcmsFloat markValues[MarkLevels+1] = {0.0, 10.0, 20.0, 30.0, 40.0, 50.0,
60.0, 70.0, 80.0, 87.5, 92.5, 97.5, 100.0};
/* back off leaf fill this much from the edge of the leaf. Could be attribute*/
#define FillPad 2
/* It should not take any more than this colors to fill the leaf */
#define MaxLeafColors 56
#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
#define fillPtsCopy(a,b) \
a[0] = b[0]; \
a[1] = b[1]; \
a[2] = b[2]; \
a[3] = b[3];
static void Draw(leaf, howmuch)
HueleafWidget leaf;
int howmuch;
{
XPoint leafPts[PointCt];
Display *dpy = XtDisplay(leaf);
Window win = XtWindow(leaf);
int i;
int visualclass;
int x = 0;
int y = 0;
int width = leaf->core.width;
int height = leaf->core.height;
int mx, my;
if (!XtIsRealized((Widget)leaf))
return;
if (!leaf->hueleaf.leafGC)
GetGC(leaf);
if (howmuch == DrawAll)
XClearWindow(dpy, win);
else if (howmuch == DrawLeaf)
XClearArea(dpy, win, x, y, width, height, False);
else
/* clear all around the mark, just in case */
XClearArea(dpy, win,
leaf->hueleaf.lastx - 2 * MarkSize,
leaf->hueleaf.lasty - 2 * MarkSize,
4 * MarkSize, 4 * MarkSize, False);
/* if erasing the mark damaged the frame, redraw everything */
if ( (leaf->hueleaf.lastx <= 2 * MarkSize)
|| (leaf->hueleaf.lasty <= 2 * MarkSize)
|| (leaf->hueleaf.lastx >= width - 2 * MarkSize)
|| (leaf->hueleaf.lasty >= height - 2 * MarkSize) )
howmuch = DrawAll;
/* always draw the outline of the leaf */
leafPts[0].x = x;
leafPts[0].y = y;
for (i = 1; i < PointCt - 1; i++) {
leafPts[i].x = CtoX(leaf->hueleaf.maxChroma[i-1]);
leafPts[i].y = VtoY(leaf->hueleaf.cValue[i-1]);
}
leafPts[PointCt-1].x = x;
leafPts[PointCt-1].y = y + height - 1;
XDrawLines(dpy, win, leaf->hueleaf.leafGC,
leafPts, PointCt, CoordModeOrigin);
/* if there is a base color, always fill the leaf */
if ((int)leaf->hueleaf.base >= 0) {
XPoint maxPoint, fillPts[4], fillPtsSave[2*MaxLeafColors][4];
int markX[MarkLevels+1];
int j, k, n;
XcmsFloat tx, ty;
XcmsColor cell[MaxLeafColors+1];
Pixel index = leaf->hueleaf.base;
/* unsigned char clamped[MaxLeafColors+1]; */
maxPoint = leafPts[PointCt-2];
/* find points of max chroma at value .9, .8, ..., .1 */
j = 0;
for (i = MarkLevels - 1; i > 0; i--) {
ty = markValues[i];
while ( (j < ChromaSamples) && (leaf->hueleaf.cValue[j] > ty) ) {
j++;
}
if (j == 0)
tx = InterpolateVC(ty, 100.0, leaf->hueleaf.cValue[0],
0.0, leaf->hueleaf.maxChroma[0]);
else if (j == ChromaSamples)
tx = InterpolateVC(ty, leaf->hueleaf.cValue[j-1], 0.0,
leaf->hueleaf.maxChroma[j-1], 0.0);
else
tx = InterpolateVC(ty,
leaf->hueleaf.cValue[j-1], leaf->hueleaf.cValue[j],
leaf->hueleaf.maxChroma[j-1], leaf->hueleaf.maxChroma[j]);
markX[i] = CtoX(tx);
}
markX[0] = CtoX(0.0);
markX[MarkLevels] = markX[0];
k = n = 0;
fillPts[2].y = VtoY(100.0);
for (i = MarkLevels; i > 0; i--) {
/* set value corresponding to middle of square */
fillPts[0].y = fillPts[2].y; /* copy from previous edge */
fillPts[1].y = fillPts[0].y;
fillPts[2].y = VtoY(markValues[i-1]);
fillPts[3].y = fillPts[2].y;
fillPts[1].x = CtoX(0.0) - FillPad;
for (j = 0; j < 10; j++) {
fillPts[0].x = fillPts[1].x; /* copy from previous edge */
fillPts[3].x = fillPts[0].x;
/* but set the chroma to right edge value */
cell[k].pixel = index;
cell[k].format = XcmsTekHVCFormat;
cell[k].spec.TekHVC.H = leaf->hueleaf.curhvc.spec.TekHVC.H;
cell[k].spec.TekHVC.V =
(markValues[i] + markValues[i-1]) / 2.0;
cell[k].spec.TekHVC.C = (XcmsFloat)(j + 1) * 10.0;
fillPts[1].x = CtoX((XcmsFloat)(j+1) * 10.0) - FillPad;
fillPts[2].x = fillPts[1].x;
if ( (fillPts[1].x > markX[i])
|| (fillPts[2].x > markX[i-1]) ) {
fillPts[1].x = markX[i] - FillPad;
fillPts[2].x = markX[i-1] - FillPad;
j = 11; /* force a break */
}
fillPtsCopy(fillPtsSave[n],fillPts);
n++;
/* Don't allow the cell range to overflow */
index++;
if (++k >= MaxLeafColors) {
--k; --index;
Warning(leaf, warning4);
}
}
}
/* fill the tip triangle with most vivid color */
fillPts[1] = maxPoint;
fillPts[1].x -= FillPad;
fillPts[2].x = CtoX(0.0) - FillPad;
fillPts[2].y = VtoY(100.0);
for (i = MarkLevels-1; i > 0; i--) {
fillPts[0] = fillPts[2];
fillPts[2].x = markX[i] - FillPad;
fillPts[2].y = VtoY(markValues[i]);
if (fillPts[2].y > maxPoint.y)
break;
}
fillPts[3] = fillPts[0]; /* assign 4th point for consistency */
fillPtsCopy(fillPtsSave[n],fillPts);
n++;
cell[k].pixel = index;
cell[k].format = XcmsTekHVCFormat;
cell[k].spec.TekHVC.H = leaf->hueleaf.curhvc.spec.TekHVC.H;
cell[k].spec.TekHVC.V = leaf->hueleaf.cValue[ChromaSamples-1];
cell[k].spec.TekHVC.C = leaf->hueleaf.maxChroma[ChromaSamples-1];
k++;
/*
* Store colors cached in array while filling the leaf.
* Colors on edge of fill will have chromas decreased.
*/
visualclass = GetVisualClass ((Widget)leaf);
if (visualclass == PseudoColor || visualclass == DirectColor ||
visualclass == GrayScale)
{
if (XcmsStoreColors(XtDisplay(leaf), leaf->core.colormap,
cell, k, NULL) == XcmsFailure) {
#ifdef XDEBUG
printf ("Warning: XcmsStoreColors failed in Hueleaf.c\n");
#endif
}
} else {
for (i = 0; i < k; i++) {
if (XcmsAllocColor(XtDisplay(leaf), leaf->core.colormap,
&cell[i], NULL) == XcmsFailure) {
#ifdef XDEBUG
printf ("Warning: XcmsAllocColors failed in Hueleaf.c\n");
#endif
}
}
}
/*
* Fill all the saved polygons at once.
* There is a remote chance that we may have more polygons than
* the max color indeces that we could use. This is handled by
* reusing the last index on the overflow polygons.
*/
for(i = 0; i < n; i++) {
XSetForeground(dpy,leaf->hueleaf.leafGC,cell[MIN(i,k-1)].pixel);
XFillPolygon(dpy,win,leaf->hueleaf.leafGC,fillPtsSave[i],4,Convex,CoordModeOrigin);
}
/* restore foreground to default */
XSetForeground(dpy, leaf->hueleaf.leafGC, leaf->hueleaf.fgpixel);
}
/* always draw the marker */
mx = CtoX(leaf->hueleaf.curhvc.spec.TekHVC.C) - MarkSize / 2;
my = VtoY(leaf->hueleaf.curhvc.spec.TekHVC.V) - MarkSize / 2;
XFillRectangle(dpy, win, leaf->hueleaf.leafGC,
mx, my, MarkSize, MarkSize);
/* remember position so it can be erased next time */
leaf->hueleaf.lastx = mx;
leaf->hueleaf.lasty = my;
}
static void GetGC(leaf)
HueleafWidget leaf;
{
XtGCMask mask = GCForeground | GCBackground | GCFillStyle;
XGCValues gcv;
XRectangle rect;
gcv.foreground = leaf->hueleaf.fgpixel;
gcv.background = leaf->core.background_pixel;
gcv.fill_style = FillSolid;
leaf->hueleaf.leafGC=XCreateGC(XtDisplay(leaf), XtWindow(leaf), mask,&gcv);
mask |= GCLineStyle;
gcv.line_style = LineDoubleDash;
rect.x = 0;
rect.y = 0;
rect.width = leaf->core.width;
rect.height = leaf->core.height;
/* only one rectanlge, so it must be banded */
XSetClipRectangles(XtDisplay(leaf), leaf->hueleaf.leafGC, 0, 0,
&rect, 1, YXBanded);
}
/*
* Simple linear interpolation between points.
*/
static XcmsFloat InterpolateVC(midy, hiy, loy, hix, lox)
XcmsFloat midy, hiy, loy, hix, lox;
{
return(lox + (hix - lox) * (midy - loy) / (hiy - loy));
}
/*
* Externally visible convenience function to update value, chroma
*/
void HueleafSetBase(leaf, base)
HueleafWidget leaf;
Pixel base;
{
if ( base == leaf->hueleaf.base )
return;
leaf->hueleaf.base = base;
Draw(leaf, DrawLeaf);
}
void HueleafSetVC(leaf, v, c)
HueleafWidget leaf;
XcmsFloat v, c;
{
if ((v == leaf->hueleaf.curhvc.spec.TekHVC.V) &&
(c == leaf->hueleaf.curhvc.spec.TekHVC.C) )
return;
leaf->hueleaf.curhvc.spec.TekHVC.V = v;
leaf->hueleaf.curhvc.spec.TekHVC.C = c;
Draw(leaf, DrawMark);
}