This is Chart.c in view mode; [Download] [Up]
#if ( !defined(lint) && !defined(SABER))
static char PCN_rcsid[] = "$Header: /ufs/comp/mei/PROJ_PCN/onprofile/IFModel/Xsw/RCS/Chart.c,v 1.1 1992/04/17 18:21:53 mei Exp $";
#endif
/******************************************************************************
* *
* Copyright (C) The Aerospace Corporation 1991 *
* *
* This software was developed by The Aerospace Corporation as a *
* research endeavor for the United States Air Force *
* Space Systems Division. The current version of the Gauge *
* computer program is available for release to you for *
* educational and research purposes only. It is not *
* to be used for commercial purposes. *
* *
* In addition, the following conditions shall apply. *
* *
* 1) The computer software and documentation were designed to *
* satisfy internal Aerospace requirements only. *
* The software is provided ``as is,'' and The Aerospace Corporation *
* makes no warranty, expressed or implied, as to it accuracy, *
* functioning, or fitness for a particular purpose. *
* *
* 2) The Aerospace Corporation and its personnel are not *
* responsible for providing technical support or general assistance *
* with respect to the software. *
* *
* 3) Neither The Aerospace Corporation nor its personnel shall be *
* liable for claims, losses, or damages arising out of or connected *
* with the use of this software. *
* Your sole and exclusive remedy shall be to request a replacement *
* copy of the program. *
* *
******************************************************************************/
/*
* Chart.c - chart widget.
*/
#include <X11/IntrinsicP.h>
#include "Xsw.h"
#include <string.h>
#include "ChartP.h"
#include "Patterns.h"
#define DEFAULT_CHART_WIDTH 32 /* in cells */
#define DEFAULT_CHART_HEIGHT 32 /* in cells */
#define DEFAULT_CELL_SIZE 16 /* in pixels */
static XtResource resources[] = {
#define offset(field) XtOffset(ChartWidget, chart.field)
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(foreground), XtRString, XtDefaultForeground },
{ XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
offset(highlight), XtRString, XtDefaultForeground },
{ XtNcellWidth, XtCCellSize, XtRInt, sizeof(int),
offset(cell_width), XtRImmediate, (XtPointer)DEFAULT_CELL_SIZE },
{ XtNcellHeight, XtCCellSize, XtRInt, sizeof(int),
offset(cell_height), XtRImmediate, (XtPointer)DEFAULT_CELL_SIZE },
{ XtNcellSeparation, XtCCellSeparation, XtRInt, sizeof(int),
offset(border), XtRImmediate, (XtPointer) 1 },
{ XtNboxThickness, XtCBoxThickness, XtRInt, sizeof(int),
offset(frame), XtRImmediate, (XtPointer) 3 },
{ XtNbox, XtCBox, XtRBoolean, sizeof(Boolean),
offset(box), XtRString, "True" },
{ XtNrigidZoom, XtCRigidZoom, XtRBoolean, sizeof(Boolean),
offset(rigid_zoom), XtRString, "True" },
{ XtNcolors, XtCColors, XtRPixelList, sizeof(PixelList),
offset(colors), XtRString, "black" },
{ XtNpatterns, XtCPatterns, XtRPatternList, sizeof(PatternList),
offset(patterns), XtRString, "solid" },
{ XtNpalette, XtCPalette, XtRString, sizeof(String),
offset(palette), XtRString, "Palette" },
{ XtNwidthInCells, XtCNumberCells, XtRDimension, sizeof(Dimension),
offset(width), XtRImmediate, (XtPointer)DEFAULT_CHART_WIDTH },
{ XtNheightInCells, XtCNumberCells, XtRDimension, sizeof(Dimension),
offset(height), XtRImmediate, (XtPointer)DEFAULT_CHART_HEIGHT },
{ XtNcurX, XtCCurX, XtRInt, sizeof(int),
offset(cur_x), XtRImmediate, (XtPointer) 0 },
{ XtNcurY, XtCCurY, XtRInt, sizeof(int),
offset(cur_y), XtRImmediate, (XtPointer) 0 },
{ XtNcellArray, XtCCellArray, XtRPointer, sizeof(double *),
offset(cell), XtRImmediate, (XtPointer)NULL },
{ XtNstateArray, XtCStateArray, XtRPointer, sizeof(Boolean *),
offset(state), XtRImmediate, (XtPointer)NULL },
{ XtNtwoD, XtCTwoD, XtRBoolean, sizeof(Boolean),
offset(twoD), XtRString, "True" },
{ XtNzoom, XtCZoom, XtRBoolean, sizeof(Boolean),
offset(zoom), XtRString, "True" },
{ XtNcallback, XtCCallback, XtRCallback, sizeof(XPointer),
offset(callback), XtRCallback, NULL },
{ XtNchartResize, XtCCallback, XtRCallback, sizeof(XPointer),
offset(chart_resize), XtRCallback, NULL },
};
static void Initialize();
static void ClassPartInitialize();
static void Redisplay();
static void Destroy();
static void Resize();
static Boolean SetValues();
/* the following are private functions unique to Chart */
static void DoCell(), DrawIntoBigPixmap();
/* the following are actions of Chart */
static void SelectCell(), ManyCells();
static char defaultTranslations[] =
"<Btn1Down>: SelectCell() \n\
<Btn1Motion>: ManyCells()";
static XtActionsRec actions[] = {
{"SelectCell", SelectCell},
{"ManyCells", ManyCells},
};
ChartClassRec chartClassRec = {
{
/* core_class fields */
/* superclass */ (WidgetClass) &coreClassRec,
/* class_name */ "Chart",
/* widget_size */ sizeof(ChartRec),
/* class_initialize */ NULL,
/* class_part_initialize */ ClassPartInitialize,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ actions,
/* num_actions */ XtNumber(actions),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* 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 */ defaultTranslations,
/* query_geometry */ NULL,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{
/* dummy_field */ 0,
},
};
WidgetClass chartWidgetClass = (WidgetClass) & chartClassRec;
/*
CoreClassPart SuperClass;
#define Superclass (&(chartClassRec.core_class.superclass))
*/
/* ARGSUSED */
Boolean CvtStringToPattern(display, args, nargs,
fromVal, toVal, converter_data)
Display* display;
XrmValuePtr args, fromVal, toVal;
int *nargs;
XtPointer* converter_data;
{
static int result;
if (XswStrCmp((char *)fromVal->addr, "solid"))
result = 0;
else if (XswStrCmp((char *)fromVal->addr, "checkered"))
result = 1;
else if (XswStrCmp((char *)fromVal->addr, "slantleft"))
result = 2;
else if (XswStrCmp((char *)fromVal->addr, "slantright"))
result = 3;
else if (XswStrCmp((char *)fromVal->addr, "vertical"))
result = 4;
else if (XswStrCmp((char *)fromVal->addr, "horizontal"))
result = 5;
else
XtStringConversionWarning((char *) fromVal->addr, "Pattern");
DONE(Pattern, result);
}
CVT_STRING_TO_LIST(CvtStringToPatternList, Pattern, XtRPattern,
(Pattern)END_OF_LIST)
static void
GetAllGC(cw)
ChartWidget cw;
{
XGCValues values;
XtGCMask mask = GCForeground | GCBackground | GCFillStyle | GCLineWidth;
int i, n_clrs, n_pats;
unsigned int colors[300];
Boolean bw = False;
String file_name;
/* This GC used to erase areas */
values.background = cw->core.background_pixel;
values.fill_style = FillSolid;
values.foreground = cw->core.background_pixel;
values.line_width = cw->chart.frame;
cw->chart.cleargc = XtGetGC((Widget)cw, mask, &values);
/* This GC used for drawing the box to indicate selections */
values.foreground = cw->chart.highlight;
cw->chart.boxgc = XtGetGC((Widget)cw, mask, &values);
/* Get GCs for multiple bars in 2D chart */
mask = mask | GCStipple;
values.fill_style = FillOpaqueStippled;
n_pats = 0;
while (cw->chart.patterns[n_pats] != END_OF_LIST) n_pats++;
n_clrs = 0;
while(cw->chart.colors[n_clrs] != END_OF_LIST) n_clrs++;
cw->chart.styles = MIN(n_pats, n_clrs);
cw->chart.style_gc = (GC *)XtMalloc((cw->chart.styles+1) *
sizeof(GC));
for(i=0; i < cw->chart.styles; i++) {
if (i < n_pats) {
values.stipple =
XCreateBitmapFromData(XtDisplay(cw),
ROOTWINDOW(cw),
&patterns[cw->chart.patterns[i]*
PAT_WIDTH*PAT_HEIGHT/8],
PAT_WIDTH, PAT_HEIGHT);
} else {
values.stipple =
XCreateBitmapFromData(XtDisplay(cw),
ROOTWINDOW(cw),
hundred,
PAT_WIDTH, PAT_HEIGHT);
}
if (i < n_clrs) {
values.foreground = cw->chart.colors[i];
} else {
values.foreground = cw->chart.foreground;
}
cw->chart.style_gc[i] = XtGetGC((Widget)cw, mask, &values);
}
/* Now get GCs to use to indicate values in 3D chart */
/* load in selected palette */
file_name = XswGetLibName(cw->chart.palette);
if (file_name != NULL) {
cw->chart.values =
load_color_palette(XtDisplay(cw),DefaultScreen(XtDisplay(cw)),
file_name, colors);
} else {
cw->chart.values = -1;
}
if (cw->chart.values < 0) /* if no palette then use greyscale */
cw->chart.values =
load_color_palette(XtDisplay(cw),DefaultScreen(XtDisplay(cw)),
"Greyscale64", colors);
if (cw->chart.values <= 0) { /* if one-bit pixel display */
cw->chart.values = NUM_PERCENTS;
bw = True;
}
cw->chart.value_gc = (GC *)XtMalloc((cw->chart.values+1) *
sizeof(GC));
values.stipple =
XCreateBitmapFromData(XtDisplay(cw),
ROOTWINDOW(cw),
hundred,
PAT_WIDTH, PAT_HEIGHT);
for (i = 0; i < cw->chart.values; i++) {
if (bw) {
values.stipple =
XCreateBitmapFromData(XtDisplay(cw),
ROOTWINDOW(cw),
&percents[i*PAT_WIDTH*PAT_HEIGHT/8],
PAT_WIDTH, PAT_HEIGHT);
values.foreground = cw->chart.foreground;
}
else {
values.foreground = colors[i];
}
cw->chart.value_gc[i] = XtGetGC((Widget)cw, mask, &values);
}
/* get highlight GC to use is box is turned off*/
values.foreground = cw->chart.highlight;
values.stipple =
XCreateBitmapFromData(XtDisplay(cw),
ROOTWINDOW(cw),
hundred,
PAT_WIDTH, PAT_HEIGHT);
cw->chart.value_gc[cw->chart.values] =
XtGetGC((Widget)cw, mask, &values);
cw->chart.style_gc[cw->chart.styles] =
XtGetGC((Widget)cw, mask, &values);
}
/* ARGSUSED */
static void
ClassPartInitialize(class)
WidgetClass class;
{
XtSetTypeConverter(XtRString, XtRPattern,
CvtStringToPattern, NULL, 0,
XtCacheAll, NULL);
XtSetTypeConverter(XtRString, XtRPatternList,
CvtStringToPatternList, NULL, 0,
XtCacheAll, NULL);
}
/* ARGSUSED */
static void
Initialize(request, new)
ChartWidget request, new;
{
/*
* Check instance values set by resources that may be invalid.
*/
if (new->chart.twoD) new->chart.width = 1;
if ((new->chart.width < 1) ||
(new->chart.height < 1)) {
XtWarning("Chart: pixmapWidth and/or pixmapHeight is too small (using 10 x 10).");
new->chart.width = 10;
new->chart.height = 10;
}
if (new->chart.cell_width < (2*new->chart.border + 1)) {
XtWarning("Chart: cellWidth is too small.");
new->chart.cell_width = (2*new->chart.border + 1);
}
if (new->chart.cell_height < (2*new->chart.border + 1)) {
XtWarning("Chart: cellHeight is too small.");
new->chart.cell_height = (2*new->chart.border + 1);
}
new->chart.save_width = new->chart.cell_width;
new->chart.save_height = new->chart.cell_height;
if ((new->chart.cur_x < 0) || (new->chart.cur_y < 0)) {
XtWarning("Chart: cur_x and cur_y must be non-negative (using 0, 0).");
new->chart.cur_x = 0;
new->chart.cur_y = 0;
}
new->chart.save_y = new->chart.cur_y;
new->chart.save_x = new->chart.cur_x;
new->chart.save_border = new->chart.border;
new->chart.save_frame = new->chart.frame;
if (new->chart.cell == NULL)
new->chart.cell = (double *)XtCalloc(new->chart.width * new->chart.height, sizeof(double));
if (new->chart.state == NULL)
new->chart.state = (Boolean *)XtCalloc(new->chart.width * new->chart.height, sizeof(Boolean));
if (new->core.width == 0) {
if (new->chart.twoD) {
new->core.width = 200;
}
else new->core.width = new->chart.width * new->chart.cell_width +
new->chart.border;
}
if (new->core.height == 0) {
new->core.height = new->chart.height * new->chart.cell_height +
new->chart.border;
}
new->core.height = MIN(new->core.height, 1000);
new->core.width = MIN(new->core.width, 1000);
GetAllGC(new);
if (new->chart.zoom) {
Resize(new);
}
}
/* ARGSUSED */
static void
Redisplay(cw, event)
ChartWidget cw;
XExposeEvent *event;
{
register int x, y;
int maxX, maxY;
if (!XtIsRealized((Widget) cw))
return;
if (event) { /* called from btn-event or expose */
if (cw->chart.zoom && !cw->chart.rigid_zoom) {
x = event->x /
(double)((double)cw->core.width/(double)cw->chart.width);
y = event->y /
(double)((double)cw->core.height/(double)cw->chart.height);
maxX = (event->x + event->width) /
(double)((double)cw->core.width/(double)cw->chart.width);
maxY = (event->y + event->height) /
(double)((double)cw->core.height/(double)cw->chart.height);
} else {
x = cw->chart.cur_x + event->x / cw->chart.cell_width;
y = cw->chart.cur_y + event->y / cw->chart.cell_height;
maxX = cw->chart.cur_x +
(event->width+event->x)/cw->chart.cell_width + 1;
maxY = cw->chart.cur_y +
(event->height+event->y)/cw->chart.cell_height + 1;
}
if (cw->chart.twoD) x = 0;
maxX = MIN(maxX, cw->chart.width);
maxY = MIN(maxY, cw->chart.height);
x = MIN(x, cw->chart.width);
y = MIN(y, cw->chart.height);
/* draw current chart */
DoCell(cw, x, y, maxX, maxY);
}
else { /* called because complete redraw */
DrawIntoBigPixmap(cw);
}
}
static void ScrollChart(cw, x0, y0, x1, y1)
ChartWidget cw;
int x0, y0, x1, y1;
{
int y, x;
unsigned int height, width, excess;
XExposeEvent fake_event;
unsigned int event_x, event_y, event_width, event_height;
y = (y1 - y0) * cw->chart.cell_height;
x = (x1 - x0) * cw->chart.cell_width;
if (y != 0) {
if (cw->chart.zoom && !cw->chart.rigid_zoom) {
excess = 0;
} else {
excess = cw->core.height % cw->chart.cell_height;
}
if (y > 0) {
y0 = y;
y1 = 0;
height = cw->core.height - y -
excess;
fake_event.y = height;
fake_event.height = y0;
event_y = y0;
event_height = cw->core.height - y0;
}
else {
y0 = 0;
y1 = -y;
height = cw->core.height + y -
excess;
fake_event.y = 0;
fake_event.height = y1;
event_y = 0;
event_height = cw->core.height - y1;
}
}
else {
y0 = 0;
y1 = 0;
if (cw->chart.zoom && !cw->chart.rigid_zoom) {
height = cw->core.height;
} else {
if (cw->core.height < cw->chart.height*cw->chart.cell_height)
height = cw->core.height;
else height = cw->chart.height*cw->chart.cell_height;
}
event_y = 0;
event_height = cw->core.height;
}
if (x != 0) {
if (cw->chart.zoom && !cw->chart.rigid_zoom) {
excess = 0;
} else {
excess = cw->core.width % cw->chart.cell_width;
}
if (x > 0) {
x0 = x;
x1 = 0;
width = cw->core.width - x -
excess;
event_x = width;
event_width = x0;
}
else {
x0 = 0;
x1 = -x;
width = cw->core.width + x -
excess;
event_x = 0;
event_width = x1;
}
}
else {
x0 = 0;
x1 = 0;
if (cw->chart.zoom && !cw->chart.rigid_zoom) {
width = cw->core.width;
} else {
if (cw->core.width < cw->chart.width*cw->chart.cell_width)
width = cw->core.width;
else {
if (cw->chart.twoD) width = cw->core.width;
else width = cw->chart.width*cw->chart.cell_width;
}
}
}
XCopyArea(XtDisplay(cw), XtWindow(cw), XtWindow(cw),
cw->chart.boxgc, x0, y0, width,
height, x1, y1);
if (y != 0) {
fake_event.x = 0;
fake_event.width = width;
Redisplay(cw, &fake_event);
}
if (x != 0) {
fake_event.y = event_y;
fake_event.height = event_height;
fake_event.x = event_x;
fake_event.width = event_width;
Redisplay(cw, &fake_event);
}
}
static void
CalibrateXY(cw)
ChartWidget cw;
{
while ((cw->chart.cur_y > 0) &&
(cw->chart.cell_height*
(cw->chart.height-(cw->chart.cur_y-1)) <
cw->core.height))
cw->chart.cur_y--;
if (!cw->chart.twoD)
while ((cw->chart.cur_x > 0) &&
(cw->chart.cell_width*
(cw->chart.width-(cw->chart.cur_x-1)) <
cw->core.width))
cw->chart.cur_x--;
}
static void
CalibrateSpace(cw)
ChartWidget cw;
{
int i;
int original_frame = cw->chart.frame;
unsigned int smallest;
if ((cw->chart.zoom) && (!cw->chart.rigid_zoom)) {
smallest = MIN(cw->core.height/cw->chart.height,
cw->core.width/cw->chart.width);
} else {
smallest = MIN(cw->chart.cell_height, cw->chart.cell_width);
}
cw->chart.border = cw->chart.save_border;
cw->chart.frame = cw->chart.save_frame;
if (smallest > 1) {
while (smallest <= cw->chart.border+2*cw->chart.frame + 1) {
cw->chart.border > cw->chart.frame ?
cw->chart.border-- : cw->chart.frame--;
}
} else {
cw->chart.border = 0;
cw->chart.frame = 0;
}
if (cw->chart.frame != original_frame) {
if (cw->chart.boxgc)
XtReleaseGC((Widget) cw, cw->chart.boxgc);
if (cw->chart.cleargc)
XtReleaseGC((Widget) cw, cw->chart.cleargc);
for(i = 0; i <= cw->chart.values; i++)
if (cw->chart.value_gc[i])
XtReleaseGC((Widget) cw, cw->chart.value_gc[i]);
for(i = 0; i <= cw->chart.styles; i++)
if (cw->chart.style_gc[i])
XtReleaseGC((Widget) cw, cw->chart.style_gc[i]);
GetAllGC((Widget) cw);
}
}
/* ARGSUSED */
static Boolean
SetValues(current, request, new)
Widget current, request, new;
{
ChartWidget curcw = (ChartWidget) current;
ChartWidget newcw = (ChartWidget) new;
Boolean do_redisplay = False;
int i;
if ((curcw->chart.foreground != newcw->chart.foreground) ||
(curcw->chart.colors != newcw->chart.colors) ||
(curcw->chart.patterns != newcw->chart.patterns)) {
if (newcw->chart.boxgc)
XtReleaseGC((Widget) newcw, newcw->chart.boxgc);
if (newcw->chart.cleargc)
XtReleaseGC((Widget) newcw, newcw->chart.cleargc);
for(i = 0; i <= newcw->chart.values; i++)
if (newcw->chart.value_gc[i])
XtReleaseGC((Widget) newcw, newcw->chart.value_gc[i]);
for(i = 0; i <= newcw->chart.styles; i++)
if (newcw->chart.style_gc[i])
XtReleaseGC((Widget) newcw, newcw->chart.style_gc[i]);
GetAllGC((Widget) newcw);
do_redisplay = True;
}
if ((curcw->chart.cur_x != newcw->chart.cur_x) ||
(curcw->chart.cur_y != newcw->chart.cur_y)) {
CalibrateXY(newcw);
if (newcw->chart.cur_x < 0)
newcw->chart.cur_x = 0;
if (newcw->chart.cur_y < 0)
newcw->chart.cur_y = 0;
ScrollChart(newcw, curcw->chart.cur_x, curcw->chart.cur_y,
newcw->chart.cur_x, newcw->chart.cur_y);
}
if (curcw->chart.log != newcw->chart.log)
do_redisplay = True;
if ((curcw->chart.width != newcw->chart.width) ||
(curcw->core.width != newcw->core.width) ||
(curcw->chart.height != newcw->chart.height) ||
(curcw->core.height != newcw->core.height)) {
if(newcw->core.height <= 0) {
newcw->core.height = newcw->chart.height *
newcw->chart.cell_height + newcw->chart.border;
XtWarning("Correct the Chart height (0)");
}
/* 4/1992 found redundant hui when debugging from R4->R5
Resize(newcw);
*/
do_redisplay = True;
}
if (curcw->chart.twoD != newcw->chart.twoD) {
if (newcw->chart.twoD) {
if (!curcw->chart.zoom)
newcw->chart.save_x = newcw->chart.cur_x;
newcw->chart.cur_x = 0;
} else {
if (!curcw->chart.zoom)
newcw->chart.cur_x = newcw->chart.save_x;
}
}
if (curcw->chart.zoom != newcw->chart.zoom) {
if (newcw->chart.zoom) {
newcw->chart.save_y = newcw->chart.cur_y;
newcw->chart.cur_y = 0;
if (!newcw->chart.twoD) {
newcw->chart.save_x = newcw->chart.cur_x;
newcw->chart.cur_x = 0;
}
} else {
newcw->chart.cur_y = newcw->chart.save_y;
if (!newcw->chart.twoD)
newcw->chart.cur_x = newcw->chart.save_x;
}
}
if ((curcw->chart.zoom != newcw->chart.zoom) ||
(curcw->chart.twoD != newcw->chart.twoD)){
newcw->chart.cell_height = newcw->chart.save_height;
newcw->chart.cell_width = newcw->chart.save_width;
Resize(newcw);
if (!newcw->chart.zoom)
CalibrateSpace(newcw);
do_redisplay = True;
}
return do_redisplay;
}
static void
Destroy(cw)
ChartWidget cw;
{
int i;
if (cw->chart.boxgc)
XtReleaseGC((Widget) cw, cw->chart.boxgc);
if (cw->chart.cleargc)
XtReleaseGC((Widget) cw, cw->chart.cleargc);
for(i = 0; i <= cw->chart.values; i++)
if (cw->chart.value_gc[i])
XtReleaseGC((Widget) cw, cw->chart.value_gc[i]);
XtFree((char *)cw->chart.value_gc);
for(i = 0; i <= cw->chart.styles; i++)
if (cw->chart.style_gc[i])
XtReleaseGC((Widget) cw, cw->chart.style_gc[i]);
XtFree((char *)cw->chart.style_gc);
}
static Boolean
GetCoord(w, event, xPtr, yPtr)
ChartWidget w;
XButtonEvent *event;
int * xPtr, * yPtr;
{
if (w->chart.zoom && !w->chart.rigid_zoom) {
*xPtr = event->x /
(double)((double)w->core.width/(double)w->chart.width);
*yPtr = event->y /
(double)((double)w->core.height/(double)w->chart.height);
if (w->chart.twoD) *xPtr = 0;
if (*xPtr >= w->chart.width)
*xPtr = w->chart.width-1;
if (*yPtr >= w->chart.height)
*yPtr = w->chart.height-1;
} else {
*xPtr = w->chart.cur_x + event->x / w->chart.cell_width;
*yPtr = w->chart.cur_y + event->y / w->chart.cell_height;
if (w->chart.twoD) *xPtr = 0;
if ((*xPtr >= (w->core.width/w->chart.cell_width)+w->chart.cur_x) ||
(*yPtr >= (w->core.height/w->chart.cell_height)+w->chart.cur_y) ||
(*xPtr < w->chart.cur_x) || (*yPtr < w->chart.cur_y) ||
(*xPtr >= w->chart.width) || (*yPtr >= w->chart.height))
return False;
}
return True;
}
static void
SelectCell(w, event)
ChartWidget w;
XButtonEvent *event;
{
int newx;
int newy;
if (!GetCoord(w, event, &newx, &newy)) return;
w->chart.state[newx + newy * w->chart.width] =
!w->chart.state[newx + newy * w->chart.width];
w->chart.tog_state =
w->chart.state[newx + newy * w->chart.width];
w->chart.info.state = w->chart.tog_state;
w->chart.info.x = newx;
w->chart.info.y = newy;
XtCallCallbacks((Widget) w, XtNcallback, (XtPointer)&(w->chart.info));
DoCell(w, newx, newy,
(int)(w->chart.twoD ? w->chart.width : newx+1), newy+1);
}
static void
ManyCells(w, event)
ChartWidget w;
XButtonEvent *event;
{
int newx;
int newy;
if (!GetCoord(w, event, &newx, &newy)) return;
if (w->chart.state[newx + newy * w->chart.width] !=
w->chart.tog_state) {
w->chart.state[newx + newy * w->chart.width] =
w->chart.tog_state;
w->chart.info.state = w->chart.tog_state;
w->chart.info.x = newx;
w->chart.info.y = newy;
XtCallCallbacks((Widget) w, XtNcallback, (XtPointer)&(w->chart.info));
DoCell(w, newx, newy,
(int)(w->chart.twoD ? w->chart.width : newx+1), newy+1);
}
}
static void
DrawIntoBigPixmap(cw)
ChartWidget cw;
{
int maxX, maxY;
if (cw->chart.zoom) {
DoCell(cw, 0, 0, (int)cw->chart.width, (int)cw->chart.height);
} else {
maxX = cw->chart.cur_x + cw->core.width/cw->chart.cell_width;
maxY = cw->chart.cur_y + cw->core.height/cw->chart.cell_height;
if (maxX > cw->chart.width)
maxX = cw->chart.width;
if (maxY > cw->chart.height)
maxY = cw->chart.height;
DoCell(cw, cw->chart.cur_x, cw->chart.cur_y, maxX, maxY);
}
}
/* A Public function, not static */
double *
ChartGetArrayString(w)
ChartWidget w;
{
return (w->chart.cell);
}
static void
Resize(cw)
ChartWidget cw;
{
if (cw->chart.zoom) {
/*
* Calculate the maximum cell size that will allow the
* entire chart to be displayed.
*/
cw->chart.cell_width =
MAX(cw->core.width / cw->chart.width, 1);
cw->chart.cell_height =
MAX(cw->core.height / cw->chart.height, 1);
CalibrateSpace(cw);
}
else {
CalibrateXY(cw);
}
XtCallCallbacks((Widget) cw, XtNchartResize, (XtPointer)NULL);
}
static void
GetRectangle(w, x, y, pIndex, pRectangle)
ChartWidget w;
int x, y;
int * pIndex;
XRectangle * pRectangle;
{
double percent;
if (w->chart.zoom && !w->chart.rigid_zoom) {
pRectangle->y =
(int)((double)y*(double)w->core.height/(double)w->chart.height) +
w->chart.border;
pRectangle->height =
(int)((double)(y+1)*(double)w->core.height/(double)w->chart.height)
+ w->chart.border - pRectangle->y;
} else {
pRectangle->y = w->chart.cell_height * (y - w->chart.cur_y)
+ w->chart.border;
pRectangle->height = (unsigned int)w->chart.cell_height;
}
percent = w->chart.cell[x + y*w->chart.width];
if (w->chart.twoD) {
*pIndex = w->chart.values-1;
pRectangle->x = w->chart.border;
pRectangle->width = percent*w->core.width;
}
else {
*pIndex = percent*(double)w->chart.values;
if (*pIndex >= w->chart.values) *pIndex = w->chart.values-1;
if (w->chart.zoom && !w->chart.rigid_zoom) {
pRectangle->x =
(int)((double)x*(double)w->core.width/(double)w->chart.width) +
w->chart.border;
pRectangle->width =
(int)((double)(x+1)*(double)w->core.width/(double)w->chart.width)
+ w->chart.border - pRectangle->x;
} else {
pRectangle->x = w->chart.cell_width * (x - w->chart.cur_x)
+ w->chart.border;
pRectangle->width = (unsigned int)w->chart.cell_width;
}
}
/* if (pRectangle->width < w->chart.border+2*w->chart.frame)
pRectangle->width = w->chart.border+2*w->chart.frame; */
if (pRectangle->height < w->chart.border+2*w->chart.frame)
pRectangle->height = w->chart.border+2*w->chart.frame;
}
static void
DoCell(w, x0, y0, x1, y1)
ChartWidget w;
int x0, y0, x1, y1;
{
int x, y;
int fill_types;
int next_x;
int frame, index;
XRectangle rectangle;
XRectangle * drawRect;
int drawRects = 0;
XRectangle ** fillRect;
int * fillRects;
XRectangle * clearRect;
int clearRects = 0;
int i, nRects;
Display * disp;
Window win;
nRects = (x1-x0)*(y1-y0);
drawRect = (XRectangle *)XtMalloc(nRects * sizeof(XRectangle));
clearRect = (XRectangle *)XtMalloc(nRects * sizeof(XRectangle));
fill_types = (w->chart.twoD ? w->chart.styles : w->chart.values)+1;
fillRect = (XRectangle **)XtMalloc(fill_types * sizeof(XRectangle *));
fillRects = (int *)XtMalloc(fill_types * sizeof(int));
for(i = 0; i < fill_types; i++) {
fillRect[i] = (XRectangle *)XtMalloc(nRects * sizeof(XRectangle));
fillRects[i] = 0;
}
for (y = y0; y < y1; y++) {
for(x = x0; x < x1; x++) {
GetRectangle(w, x, y, &index, &rectangle);
if ((rectangle.y+rectangle.height-1 <= w->core.height) &&
(rectangle.x+rectangle.width-1 <= w->core.width)) {
if (w->chart.twoD) {
if (w->chart.state[x0 + y * w->chart.width])
frame = w->chart.frame;
else frame = 0;
index = x - x0;
if (x > x0) rectangle.x = next_x;
else rectangle.width -= w->chart.border+frame;
next_x = rectangle.x+rectangle.width;
}
if (!w->chart.twoD || (x == x1-1)) {
if (w->chart.box && (w->chart.frame > 0)) {
if (w->chart.state[(w->chart.twoD ? x0 : x) +
y * w->chart.width]) {
frame = w->chart.frame;
if (w->chart.twoD) {
drawRect[drawRects].x = w->chart.border+frame/2;
drawRect[drawRects].width = next_x-w->chart.border;
} else {
drawRect[drawRects].x = rectangle.x+frame/2;
drawRect[drawRects].width =
rectangle.width-w->chart.border-frame;
}
drawRect[drawRects].y = rectangle.y+frame/2;
drawRect[drawRects].height =
rectangle.height-w->chart.border-frame;
drawRects++;
} else {
frame = 0;
}
} else {
frame = 0;
if (w->chart.state[(w->chart.twoD ? x0 : x) +
y * w->chart.width])
index = w->chart.twoD ? w->chart.styles : w->chart.values;
}
}
if (w->chart.twoD)
if (x != x1-1) {
fillRect[index][fillRects[index]].width =
rectangle.width;
} else {
fillRect[index][fillRects[index]].width =
rectangle.width - frame;
}
else
fillRect[index][fillRects[index]].width =
rectangle.width-w->chart.border-2*frame;
fillRect[index][fillRects[index]].x = rectangle.x+frame;
fillRect[index][fillRects[index]].y = rectangle.y+frame;
fillRect[index][fillRects[index]].height =
rectangle.height-w->chart.border-2*frame;
fillRects[index]++;
if (w->chart.twoD && (x == x1-1)) {
clearRect[clearRects].x = next_x+frame;
clearRect[clearRects].y = rectangle.y;
clearRect[clearRects].width =
w->core.width-next_x-frame;
clearRect[clearRects].height =
rectangle.height;
clearRects++;
}
}
}
}
if (drawRects > 0) {
disp = XtDisplay(w);
win = XtWindow(w);
XDrawRectangles(disp, win,
w->chart.boxgc,
drawRect, drawRects);
}
XtFree((char *)drawRect);
for (i=0; i < fill_types; i++) {
if (fillRects[i] >0)
XFillRectangles(XtDisplay(w), XtWindow(w),
w->chart.twoD ?
w->chart.style_gc[i] : w->chart.value_gc[i],
fillRect[i], fillRects[i]);
XtFree((char *)fillRect[i]);
}
XtFree((char *)fillRect);
if (clearRects > 0)
XFillRectangles(XtDisplay(w), XtWindow(w),
w->chart.cleargc,
clearRect, clearRects);
XtFree((char *)clearRect);
}
int
XswChartNumValues(w)
ChartWidget w;
{
return w->chart.values;
}
void
XswChartSetRow(w, row, state)
ChartWidget w;
int row;
Boolean state;
{
int j;
for(j = 0; j < w->chart.width; j++) {
if (w->chart.state[j + row * w->chart.width] != state) {
w->chart.state[j + row * w->chart.width] = state;
w->chart.info.state = state;
w->chart.info.x = j;
w->chart.info.y = row;
XtCallCallbacks((Widget) w, XtNcallback, &(w->chart.info));
}
}
if (w->chart.zoom) {
DoCell(w, 0, row, (int)w->chart.width, row + 1);
} else {
DoCell(w, w->chart.cur_x, row,
(int)MIN(w->core.width/w->chart.cell_width + w->chart.cur_x,
(int)w->chart.width),
row + 1);
}
}
void
XswChartSetCol(w, col, state)
ChartWidget w;
int col;
Boolean state;
{
int j;
for(j = 0; j < w->chart.height; j++) {
if (w->chart.state[col + j * w->chart.width] != state) {
w->chart.state[col + j * w->chart.width] = state;
w->chart.info.state = state;
w->chart.info.x = col;
w->chart.info.y = j;
XtCallCallbacks((Widget) w, XtNcallback, &(w->chart.info));
}
}
if (w->chart.zoom) {
DoCell(w, col, 0, col + 1, (int)w->chart.height);
} else {
DoCell(w, col, w->chart.cur_y, col + 1,
(int)MIN(w->core.height/w->chart.cell_height + w->chart.cur_y,
w->chart.height));
}
}
void XswChartRedisplay(w)
ChartWidget w;
{
if (!XtIsRealized((Widget) w))
return;
else
DrawIntoBigPixmap(w);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.