source: trunk/kitgen/8.x/blt/generic/bltGrBar.c@ 196

Last change on this file since 196 was 175, checked in by demin, 12 years ago

initial commit

File size: 69.3 KB
Line 
1
2/*
3 * bltGrBar.c --
4 *
5 * This module implements barchart elements for the BLT graph widget.
6 *
7 * Copyright 1993-1998 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 */
27
28#include "bltGraph.h"
29#include <X11/Xutil.h>
30
31#include "bltGrElem.h"
32
33typedef struct {
34 char *name; /* Pen style identifier. If NULL pen
35 * was statically allocated. */
36 Blt_Uid classUid; /* Type of pen */
37 char *typeId; /* String token identifying the type of pen */
38 unsigned int flags; /* Indicates if the pen element is active or
39 * normal */
40 int refCount; /* Reference count for elements using
41 * this pen. */
42 Blt_HashEntry *hashPtr;
43 Tk_ConfigSpec *specsPtr; /* Configuration specifications */
44
45 PenConfigureProc *configProc;
46 PenDestroyProc *destroyProc;
47
48 XColor *fgColor; /* Foreground color of bar */
49 Tk_3DBorder border; /* 3D border and background color */
50 int borderWidth; /* 3D border width of bar */
51 int relief; /* Relief of the bar */
52 Pixmap stipple; /* Stipple */
53 GC gc; /* Graphics context */
54
55 /* Error bar attributes. */
56 int errorBarShow; /* Describes which error bars to
57 * display: none, x, y, or * both. */
58
59 int errorBarLineWidth; /* Width of the error bar segments. */
60
61 int errorBarCapWidth;
62 XColor *errorBarColor; /* Color of the error bar. */
63
64 GC errorBarGC; /* Error bar graphics context. */
65
66 /* Show value attributes. */
67 int valueShow; /* Indicates whether to display data value.
68 * Values are x, y, or none. */
69
70 char *valueFormat; /* A printf format string. */
71 TextStyle valueStyle; /* Text attributes (color, font,
72 * rotation, etc.) of the value. */
73
74} BarPen;
75
76typedef struct {
77 Weight weight; /* Weight range where this pen is valid. */
78
79 BarPen *penPtr; /* Pen to draw */
80
81 Segment2D *xErrorBars; /* Point to start of this pen's X-error bar
82 * segments in the element's array. */
83
84 Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar
85 * segments in the element's array. */
86 int xErrorBarCnt; /* # of error bars for this pen. */
87
88 int yErrorBarCnt; /* # of error bars for this pen. */
89
90 int errorBarCapWidth; /* Length of the cap ends on each
91 * error bar. */
92
93 int symbolSize; /* Size of the pen's symbol scaled to the
94 * current graph size. */
95
96 /* Bar chart specific data. */
97 XRectangle *rectangles; /* Indicates starting location in bar
98 * array for this pen. */
99 int nRects; /* Number of bar segments for this pen. */
100
101} BarPenStyle;
102
103typedef struct {
104 char *name; /* Identifier to refer the
105 * element. Used in the "insert",
106 * "delete", or "show", commands. */
107
108 Blt_Uid classUid; /* Type of element; either
109 * bltBarElementUid, bltLineElementUid, or
110 * bltStripElementUid. */
111
112 Graph *graphPtr; /* Graph widget of element*/
113 unsigned int flags; /* Indicates if the entire element is
114 * active, or if coordinates need to
115 * be calculated */
116 char **tags;
117 int hidden; /* If non-zero, don't display the element. */
118
119 Blt_HashEntry *hashPtr;
120 char *label; /* Label displayed in legend */
121 int labelRelief; /* Relief of label in legend. */
122
123 Axis2D axes;
124 ElemVector x, y, w; /* Contains array of numeric values */
125
126 ElemVector xError; /* Relative/symmetric X error values. */
127 ElemVector yError; /* Relative/symmetric Y error values. */
128 ElemVector xHigh, xLow; /* Absolute/asymmetric X-coordinate high/low
129 error values. */
130 ElemVector yHigh, yLow; /* Absolute/asymmetric Y-coordinate high/low
131 error values. */
132
133 int *activeIndices; /* Array of indices (malloc-ed) that
134 * indicate the data points have been
135 * selected as active (drawn with
136 * "active" colors). */
137
138 int nActiveIndices; /* Number of active data points. Special
139 * case: if nActiveIndices < 0 and the
140 * active bit is set in "flags", then all
141 * data points are drawn active. */
142
143 ElementProcs *procsPtr; /* Class information for bar elements */
144 Tk_ConfigSpec *specsPtr; /* Configuration specifications */
145
146 Segment2D *xErrorBars; /* Point to start of this pen's X-error bar
147 * segments in the element's array. */
148 Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar
149 * segments in the element's array. */
150 int xErrorBarCnt; /* # of error bars for this pen. */
151 int yErrorBarCnt; /* # of error bars for this pen. */
152
153 int *xErrorToData; /* Maps individual error bar segments back
154 * to the data point associated with it. */
155 int *yErrorToData; /* Maps individual error bar segments back
156 * to the data point associated with it. */
157
158 int errorBarCapWidth; /* Length of cap on error bars */
159
160 BarPen *activePenPtr; /* Standard Pens */
161 BarPen *normalPenPtr;
162
163 Blt_Chain *palette; /* Chain of pen style information. */
164
165 /* Symbol scaling */
166 int scaleSymbols; /* If non-zero, the symbols will scale
167 * in size as the graph is zoomed
168 * in/out. */
169
170 double xRange, yRange; /* Initial X-axis and Y-axis ranges:
171 * used to scale the size of element's
172 * symbol. */
173 int state;
174 /*
175 * Bar specific attributes
176 */
177 BarPen builtinPen;
178
179 int *rectToData;
180 XRectangle *rectangles; /* Array of rectangles comprising the bar
181 * segments of the element. */
182 int nRects; /* # of visible bar segments for element */
183
184 int padX; /* Spacing on either side of bar */
185 double barWidth;
186 int nActive;
187
188 XRectangle *activeRects;
189 int *activeToData;
190} Bar;
191
192extern Tk_CustomOption bltBarPenOption;
193extern Tk_CustomOption bltDataOption;
194extern Tk_CustomOption bltDataPairsOption;
195extern Tk_CustomOption bltDistanceOption;
196extern Tk_CustomOption bltListOption;
197extern Tk_CustomOption bltXAxisOption;
198extern Tk_CustomOption bltYAxisOption;
199extern Tk_CustomOption bltShadowOption;
200extern Tk_CustomOption bltFillOption;
201extern Tk_CustomOption bltColorOption;
202extern Tk_CustomOption bltStateOption;
203
204extern Tk_OptionParseProc Blt_StringToStyles;
205extern Tk_OptionPrintProc Blt_StylesToString;
206static Tk_OptionParseProc StringToBarMode;
207static Tk_OptionPrintProc BarModeToString;
208
209static Tk_CustomOption stylesOption =
210{
211 Blt_StringToStyles, Blt_StylesToString, (ClientData)sizeof(BarPenStyle)
212};
213
214Tk_CustomOption bltBarModeOption =
215{
216 StringToBarMode, BarModeToString, (ClientData)0
217};
218
219#define DEF_BAR_ACTIVE_PEN "activeBar"
220#define DEF_BAR_AXIS_X "x"
221#define DEF_BAR_AXIS_Y "y"
222#define DEF_BAR_BACKGROUND "navyblue"
223#define DEF_BAR_BG_MONO BLACK
224#define DEF_BAR_BORDERWIDTH "2"
225#define DEF_BAR_DATA (char *)NULL
226#define DEF_BAR_ERRORBAR_COLOR "defcolor"
227#define DEF_BAR_ERRORBAR_LINE_WIDTH "1"
228#define DEF_BAR_ERRORBAR_CAP_WIDTH "1"
229#define DEF_BAR_FOREGROUND "blue"
230#define DEF_BAR_FG_MONO WHITE
231#define DEF_BAR_HIDE "no"
232#define DEF_BAR_LABEL (char *)NULL
233#define DEF_BAR_LABEL_RELIEF "flat"
234#define DEF_BAR_NORMAL_STIPPLE ""
235#define DEF_BAR_RELIEF "raised"
236#define DEF_BAR_SHOW_ERRORBARS "both"
237#define DEF_BAR_STATE "normal"
238#define DEF_BAR_STYLES ""
239#define DEF_BAR_TAGS "all"
240#define DEF_BAR_WIDTH "0.0"
241#define DEF_BAR_DATA (char *)NULL
242
243#define DEF_PEN_ACTIVE_BACKGROUND "red"
244#define DEF_PEN_ACTIVE_BG_MONO WHITE
245#define DEF_PEN_ACTIVE_FOREGROUND "pink"
246#define DEF_PEN_ACTIVE_FG_MONO BLACK
247#define DEF_PEN_BORDERWIDTH "2"
248#define DEF_PEN_NORMAL_BACKGROUND "navyblue"
249#define DEF_PEN_NORMAL_BG_MONO BLACK
250#define DEF_PEN_NORMAL_FOREGROUND "blue"
251#define DEF_PEN_NORMAL_FG_MONO WHITE
252#define DEF_PEN_RELIEF "raised"
253#define DEF_PEN_STIPPLE ""
254#define DEF_PEN_TYPE "bar"
255#define DEF_PEN_VALUE_ANCHOR "s"
256#define DEF_PEN_VALUE_COLOR RGB_BLACK
257#define DEF_PEN_VALUE_FONT STD_FONT_SMALL
258#define DEF_PEN_VALUE_FORMAT "%g"
259#define DEF_PEN_VALUE_ROTATE (char *)NULL
260#define DEF_PEN_VALUE_SHADOW (char *)NULL
261#define DEF_PEN_SHOW_VALUES "no"
262
263static Tk_ConfigSpec barPenConfigSpecs[] =
264{
265 {TK_CONFIG_BORDER, "-background", "background", "Background",
266 DEF_PEN_ACTIVE_BACKGROUND, Tk_Offset(BarPen, border),
267 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ACTIVE_PEN},
268 {TK_CONFIG_BORDER, "-background", "background", "Background",
269 DEF_PEN_ACTIVE_BACKGROUND, Tk_Offset(BarPen, border),
270 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ACTIVE_PEN},
271 {TK_CONFIG_BORDER, "-background", "background", "Background",
272 DEF_PEN_NORMAL_BACKGROUND, Tk_Offset(BarPen, border),
273 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | NORMAL_PEN},
274 {TK_CONFIG_BORDER, "-background", "background", "Background",
275 DEF_PEN_NORMAL_BACKGROUND, Tk_Offset(BarPen, border),
276 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | NORMAL_PEN},
277 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL,
278 (char *)NULL, 0, ALL_PENS},
279 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL,
280 (char *)NULL, 0, ALL_PENS},
281 {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth",
282 DEF_PEN_BORDERWIDTH, Tk_Offset(BarPen, borderWidth), ALL_PENS,
283 &bltDistanceOption},
284 {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
285 DEF_BAR_ERRORBAR_COLOR, Tk_Offset(BarPen, errorBarColor),
286 ALL_PENS, &bltColorOption},
287 {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
288 DEF_BAR_ERRORBAR_LINE_WIDTH, Tk_Offset(BarPen, errorBarLineWidth),
289 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
290 {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap",
291 DEF_BAR_ERRORBAR_CAP_WIDTH, Tk_Offset(BarPen, errorBarCapWidth),
292 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
293 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL,
294 (char *)NULL, 0, ALL_PENS},
295 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
296 DEF_PEN_ACTIVE_FOREGROUND, Tk_Offset(BarPen, fgColor),
297 ACTIVE_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY},
298 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
299 DEF_PEN_ACTIVE_FOREGROUND, Tk_Offset(BarPen, fgColor),
300 ACTIVE_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY},
301 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
302 DEF_PEN_NORMAL_FOREGROUND, Tk_Offset(BarPen, fgColor),
303 NORMAL_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY},
304 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
305 DEF_PEN_NORMAL_FOREGROUND, Tk_Offset(BarPen, fgColor),
306 NORMAL_PEN | TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY},
307 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
308 DEF_PEN_RELIEF, Tk_Offset(BarPen, relief), ALL_PENS},
309 {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars",
310 DEF_BAR_SHOW_ERRORBARS, Tk_Offset(BarPen, errorBarShow),
311 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
312 {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues",
313 DEF_PEN_SHOW_VALUES, Tk_Offset(BarPen, valueShow),
314 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
315 {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple",
316 DEF_PEN_STIPPLE, Tk_Offset(BarPen, stipple),
317 ALL_PENS | TK_CONFIG_NULL_OK},
318 {TK_CONFIG_STRING, "-type", (char *)NULL, (char *)NULL,
319 DEF_PEN_TYPE, Tk_Offset(BarPen, typeId), ALL_PENS | TK_CONFIG_NULL_OK},
320 {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
321 DEF_PEN_VALUE_ANCHOR, Tk_Offset(BarPen, valueStyle.anchor), ALL_PENS},
322 {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor",
323 DEF_PEN_VALUE_COLOR, Tk_Offset(BarPen, valueStyle.color), ALL_PENS},
324 {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont",
325 DEF_PEN_VALUE_FONT, Tk_Offset(BarPen, valueStyle.font), ALL_PENS},
326 {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat",
327 DEF_PEN_VALUE_FORMAT, Tk_Offset(BarPen, valueFormat),
328 ALL_PENS | TK_CONFIG_NULL_OK},
329 {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
330 DEF_PEN_VALUE_ROTATE, Tk_Offset(BarPen, valueStyle.theta), ALL_PENS},
331 {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow",
332 DEF_PEN_VALUE_SHADOW, Tk_Offset(BarPen, valueStyle.shadow),
333 ALL_PENS, &bltShadowOption},
334 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
335};
336
337
338static Tk_ConfigSpec barElemConfigSpecs[] =
339{
340 {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen",
341 DEF_BAR_ACTIVE_PEN, Tk_Offset(Bar, activePenPtr),
342 TK_CONFIG_NULL_OK, &bltBarPenOption},
343 {TK_CONFIG_BORDER, "-background", "background", "Background",
344 DEF_BAR_BACKGROUND, Tk_Offset(Bar, builtinPen.border),
345 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY},
346 {TK_CONFIG_BORDER, "-background", "background", "Background",
347 DEF_BAR_BACKGROUND, Tk_Offset(Bar, builtinPen.border),
348 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY},
349 {TK_CONFIG_DOUBLE, "-barwidth", "barWidth", "BarWidth",
350 DEF_BAR_WIDTH, Tk_Offset(Bar, barWidth),
351 TK_CONFIG_DONT_SET_DEFAULT},
352 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL,
353 (char *)NULL, 0, 0},
354 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL,
355 (char *)NULL, 0, 0},
356 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
357 DEF_BAR_TAGS, Tk_Offset(Bar, tags),
358 TK_CONFIG_NULL_OK, &bltListOption},
359 {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth",
360 DEF_BAR_BORDERWIDTH, Tk_Offset(Bar, builtinPen.borderWidth),
361 0, &bltDistanceOption},
362 {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
363 DEF_BAR_ERRORBAR_COLOR, Tk_Offset(Bar, builtinPen.errorBarColor),
364 0, &bltColorOption},
365 {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
366 DEF_BAR_ERRORBAR_LINE_WIDTH,
367 Tk_Offset(Bar, builtinPen.errorBarLineWidth),
368 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
369 {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap",
370 DEF_BAR_ERRORBAR_CAP_WIDTH, Tk_Offset(Bar, builtinPen.errorBarCapWidth),
371 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
372 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0},
373 {TK_CONFIG_CUSTOM, "-data", "data", "Data",
374 (char *)NULL, 0, 0, &bltDataPairsOption},
375 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
376 DEF_BAR_FOREGROUND, Tk_Offset(Bar, builtinPen.fgColor),
377 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY},
378 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
379 DEF_BAR_FOREGROUND, Tk_Offset(Bar, builtinPen.fgColor),
380 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY},
381 {TK_CONFIG_STRING, "-label", "label", "Label",
382 DEF_BAR_LABEL, Tk_Offset(Bar, label), TK_CONFIG_NULL_OK},
383 {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief",
384 DEF_BAR_LABEL_RELIEF, Tk_Offset(Bar, labelRelief),
385 TK_CONFIG_DONT_SET_DEFAULT},
386 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
387 DEF_BAR_HIDE, Tk_Offset(Bar, hidden),
388 TK_CONFIG_DONT_SET_DEFAULT},
389 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
390 DEF_BAR_AXIS_X, Tk_Offset(Bar, axes.x), 0, &bltXAxisOption},
391 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
392 DEF_BAR_AXIS_Y, Tk_Offset(Bar, axes.y), 0, &bltYAxisOption},
393 {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen",
394 (char *)NULL, Tk_Offset(Bar, normalPenPtr),
395 TK_CONFIG_NULL_OK, &bltBarPenOption},
396 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
397 DEF_BAR_RELIEF, Tk_Offset(Bar, builtinPen.relief), 0},
398 {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars",
399 DEF_BAR_SHOW_ERRORBARS, Tk_Offset(Bar, builtinPen.errorBarShow),
400 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
401 {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues",
402 DEF_PEN_SHOW_VALUES, Tk_Offset(Bar, builtinPen.valueShow),
403 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
404 {TK_CONFIG_CUSTOM, "-state", "state", "State",
405 DEF_BAR_STATE, Tk_Offset(Bar, state),
406 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
407 {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple",
408 DEF_BAR_NORMAL_STIPPLE, Tk_Offset(Bar, builtinPen.stipple),
409 TK_CONFIG_NULL_OK},
410 {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles",
411 DEF_BAR_STYLES, Tk_Offset(Bar, palette),
412 TK_CONFIG_NULL_OK, &stylesOption},
413 {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
414 DEF_PEN_VALUE_ANCHOR, Tk_Offset(Bar, builtinPen.valueStyle.anchor), 0},
415 {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor",
416 DEF_PEN_VALUE_COLOR, Tk_Offset(Bar, builtinPen.valueStyle.color), 0},
417 {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont",
418 DEF_PEN_VALUE_FONT, Tk_Offset(Bar, builtinPen.valueStyle.font), 0},
419 {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat",
420 DEF_PEN_VALUE_FORMAT, Tk_Offset(Bar, builtinPen.valueFormat),
421 TK_CONFIG_NULL_OK},
422 {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
423 DEF_PEN_VALUE_ROTATE, Tk_Offset(Bar, builtinPen.valueStyle.theta), 0},
424 {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow",
425 DEF_PEN_VALUE_SHADOW, Tk_Offset(Bar, builtinPen.valueStyle.shadow),
426 0, &bltShadowOption},
427
428 {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights",
429 (char *)NULL, Tk_Offset(Bar, w), 0, &bltDataOption},
430 {TK_CONFIG_CUSTOM, "-x", "xdata", "Xdata",
431 DEF_BAR_DATA, Tk_Offset(Bar, x), 0, &bltDataOption},
432 {TK_CONFIG_CUSTOM, "-y", "ydata", "Ydata",
433 DEF_BAR_DATA, Tk_Offset(Bar, y), 0, &bltDataOption},
434 {TK_CONFIG_CUSTOM, "-xdata", "xdata", "Xdata",
435 DEF_BAR_DATA, Tk_Offset(Bar, x), 0, &bltDataOption},
436 {TK_CONFIG_CUSTOM, "-ydata", "ydata", "Ydata",
437 DEF_BAR_DATA, Tk_Offset(Bar, y), 0, &bltDataOption},
438 {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError",
439 DEF_BAR_DATA, Tk_Offset(Bar, xError), 0, &bltDataOption},
440 {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh",
441 DEF_BAR_DATA, Tk_Offset(Bar, xHigh), 0, &bltDataOption},
442 {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow",
443 DEF_BAR_DATA, Tk_Offset(Bar, xLow), 0, &bltDataOption},
444 {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError",
445 DEF_BAR_DATA, Tk_Offset(Bar, yError), 0, &bltDataOption},
446 {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh",
447 DEF_BAR_DATA, Tk_Offset(Bar, yHigh), 0, &bltDataOption},
448 {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow",
449 DEF_BAR_DATA, Tk_Offset(Bar, yLow), 0, &bltDataOption},
450 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
451};
452
453/* Forward declarations */
454static PenConfigureProc ConfigurePen;
455static PenDestroyProc DestroyPen;
456static ElementClosestProc ClosestBar;
457static ElementConfigProc ConfigureBar;
458static ElementDestroyProc DestroyBar;
459static ElementDrawProc DrawActiveBar;
460static ElementDrawProc DrawNormalBar;
461static ElementDrawSymbolProc DrawSymbol;
462static ElementExtentsProc GetBarExtents;
463static ElementToPostScriptProc ActiveBarToPostScript;
464static ElementToPostScriptProc NormalBarToPostScript;
465static ElementSymbolToPostScriptProc SymbolToPostScript;
466static ElementMapProc MapBar;
467
468INLINE static int
469Round(x)
470 register double x;
471{
472 return (int) (x + ((x < 0.0) ? -0.5 : 0.5));
473}
474
475/*
476 * ----------------------------------------------------------------------
477 * Custom option parse and print procedures
478 * ----------------------------------------------------------------------
479 */
480
481/*
482 * ----------------------------------------------------------------------
483 *
484 * NameOfBarMode --
485 *
486 * Converts the integer representing the mode style into a string.
487 *
488 * ----------------------------------------------------------------------
489 */
490static char *
491NameOfBarMode(mode)
492 BarMode mode;
493{
494 switch (mode) {
495 case MODE_INFRONT:
496 return "infront";
497 case MODE_OVERLAP:
498 return "overlap";
499 case MODE_STACKED:
500 return "stacked";
501 case MODE_ALIGNED:
502 return "aligned";
503 default:
504 return "unknown mode value";
505 }
506}
507
508/*
509 * ----------------------------------------------------------------------
510 *
511 * StringToMode --
512 *
513 * Converts the mode string into its numeric representation.
514 *
515 * Valid mode strings are:
516 *
517 * "infront" Draw a full bar at each point in the element.
518 *
519 * "stacked" Stack bar segments vertically. Each stack is defined
520 * by each ordinate at a particular abscissa. The height
521 * of each segment is represented by the sum the previous
522 * ordinates.
523 *
524 * "aligned" Align bar segments as smaller slices one next to
525 * the other. Like "stacks", aligned segments are
526 * defined by each ordinate at a particular abscissa.
527 *
528 * Results:
529 * A standard Tcl result.
530 *
531 * ----------------------------------------------------------------------
532 */
533/*ARGSUSED*/
534static int
535StringToBarMode(clientData, interp, tkwin, string, widgRec, offset)
536 ClientData clientData; /* Not used. */
537 Tcl_Interp *interp; /* Interpreter to send results back to */
538 Tk_Window tkwin; /* Not used. */
539 char *string; /* Mode style string */
540 char *widgRec; /* Cubicle structure record */
541 int offset; /* Offset of style in record */
542{
543 BarMode *modePtr = (BarMode *)(widgRec + offset);
544 unsigned int length;
545 char c;
546
547 c = string[0];
548 length = strlen(string);
549 if ((c == 'n') && (strncmp(string, "normal", length) == 0)) {
550 *modePtr = MODE_INFRONT;
551 } else if ((c == 'i') && (strncmp(string, "infront", length) == 0)) {
552 *modePtr = MODE_INFRONT;
553 } else if ((c == 's') && (strncmp(string, "stacked", length) == 0)) {
554 *modePtr = MODE_STACKED;
555 } else if ((c == 'a') && (strncmp(string, "aligned", length) == 0)) {
556 *modePtr = MODE_ALIGNED;
557 } else if ((c == 'o') && (strncmp(string, "overlap", length) == 0)) {
558 *modePtr = MODE_OVERLAP;
559 } else {
560 Tcl_AppendResult(interp, "bad mode argument \"", string,
561 "\": should be \"infront\", \"stacked\", \"overlap\", or \"aligned\"",
562 (char *)NULL);
563 return TCL_ERROR;
564 }
565 return TCL_OK;
566}
567
568/*
569 * ----------------------------------------------------------------------
570 *
571 * BarModeToString --
572 *
573 * Returns the mode style string based upon the mode flags.
574 *
575 * Results:
576 * The mode style string is returned.
577 *
578 * ----------------------------------------------------------------------
579 */
580/*ARGSUSED*/
581static char *
582BarModeToString(clientData, tkwin, widgRec, offset, freeProcPtr)
583 ClientData clientData; /* Not used. */
584 Tk_Window tkwin; /* Not used. */
585 char *widgRec; /* Row/column structure record */
586 int offset; /* Offset of mode in Partition record */
587 Tcl_FreeProc **freeProcPtr; /* Not used. */
588{
589 BarMode mode = *(BarMode *)(widgRec + offset);
590
591 return NameOfBarMode(mode);
592}
593
594
595/*
596 * Zero out the style's number of rectangles and errorbars.
597 */
598static void
599ClearPalette(palette)
600 Blt_Chain *palette;
601{
602 register BarPenStyle *stylePtr;
603 Blt_ChainLink *linkPtr;
604
605 for (linkPtr = Blt_ChainFirstLink(palette); linkPtr != NULL;
606 linkPtr = Blt_ChainNextLink(linkPtr)) {
607 stylePtr = Blt_ChainGetValue(linkPtr);
608 stylePtr->xErrorBarCnt = stylePtr->yErrorBarCnt = stylePtr->nRects = 0;
609 }
610}
611
612static int
613ConfigurePen(graphPtr, penPtr)
614 Graph *graphPtr;
615 Pen *penPtr;
616{
617 BarPen *bpPtr = (BarPen *)penPtr;
618 XGCValues gcValues;
619 unsigned long gcMask;
620 int fillStyle;
621 GC newGC;
622 long defColor;
623
624 Blt_ResetTextStyle(graphPtr->tkwin, &(bpPtr->valueStyle));
625 gcMask = GCForeground;
626 if (bpPtr->fgColor != NULL) {
627 defColor = bpPtr->fgColor->pixel;
628 gcValues.foreground = bpPtr->fgColor->pixel;
629 } else if (bpPtr->border != NULL) {
630 defColor = Tk_3DBorderColor(bpPtr->border)->pixel;
631 gcValues.foreground = Tk_3DBorderColor(bpPtr->border)->pixel;
632 } else {
633 defColor = BlackPixel(graphPtr->display,
634 Tk_ScreenNumber(graphPtr->tkwin));
635 }
636 if ((bpPtr->fgColor != NULL) && (bpPtr->border != NULL)) {
637 gcMask |= GCBackground;
638 gcValues.background = Tk_3DBorderColor(bpPtr->border)->pixel;
639 fillStyle = FillOpaqueStippled;
640 } else {
641 fillStyle = FillStippled;
642 }
643 if (bpPtr->stipple != None) {
644 gcValues.stipple = bpPtr->stipple;
645 gcValues.fill_style = fillStyle;
646 gcMask |= (GCStipple | GCFillStyle);
647 }
648 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
649 if (bpPtr->gc != NULL) {
650 Tk_FreeGC(graphPtr->display, bpPtr->gc);
651 }
652 bpPtr->gc = newGC;
653
654 gcMask = GCForeground | GCLineWidth;
655 if (bpPtr->errorBarColor == COLOR_DEFAULT) {
656 gcValues.foreground = defColor;
657 } else {
658 gcValues.foreground = bpPtr->errorBarColor->pixel;
659 }
660 gcValues.line_width = LineWidth(bpPtr->errorBarLineWidth);
661 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
662 if (bpPtr->errorBarGC != NULL) {
663 Tk_FreeGC(graphPtr->display, bpPtr->errorBarGC);
664 }
665 bpPtr->errorBarGC = newGC;
666
667 return TCL_OK;
668}
669
670static void
671DestroyPen(graphPtr, penPtr)
672 Graph *graphPtr;
673 Pen *penPtr;
674{
675 BarPen *bpPtr = (BarPen *)penPtr;
676
677 Blt_FreeTextStyle(graphPtr->display, &(bpPtr->valueStyle));
678 if (bpPtr->gc != NULL) {
679 Tk_FreeGC(graphPtr->display, bpPtr->gc);
680 }
681 if (bpPtr->errorBarGC != NULL) {
682 Tk_FreeGC(graphPtr->display, bpPtr->errorBarGC);
683 }
684}
685
686static void
687InitPen(penPtr)
688 BarPen *penPtr;
689{
690 Blt_InitTextStyle(&(penPtr->valueStyle));
691 penPtr->specsPtr = barPenConfigSpecs;
692 penPtr->configProc = ConfigurePen;
693 penPtr->destroyProc = DestroyPen;
694 penPtr->relief = TK_RELIEF_RAISED;
695 penPtr->flags = NORMAL_PEN;
696 penPtr->errorBarShow = SHOW_BOTH;
697 penPtr->valueShow = SHOW_NONE;
698 penPtr->borderWidth = 2;
699}
700
701Pen *
702Blt_BarPen(penName)
703 char *penName;
704{
705 BarPen *penPtr;
706
707 penPtr = Blt_Calloc(1, sizeof(BarPen));
708 assert(penPtr);
709 InitPen(penPtr);
710 penPtr->name = Blt_Strdup(penName);
711 if (strcmp(penName, "activeBar") == 0) {
712 penPtr->flags = ACTIVE_PEN;
713 }
714 return (Pen *) penPtr;
715}
716
717/*
718 * ----------------------------------------------------------------------
719 *
720 * CheckStacks --
721 *
722 * Check that the data limits are not superseded by the heights
723 * of stacked bar segments. The heights are calculated by
724 * Blt_ComputeStacks.
725 *
726 * Results:
727 * If the y-axis limits need to be adjusted for stacked segments,
728 * *minPtr* or *maxPtr* are updated.
729 *
730 * Side effects:
731 * Autoscaling of the y-axis is affected.
732 *
733 * ----------------------------------------------------------------------
734 */
735static void
736CheckStacks(graphPtr, pairPtr, minPtr, maxPtr)
737 Graph *graphPtr;
738 Axis2D *pairPtr;
739 double *minPtr, *maxPtr; /* Current minimum maximum for y-axis */
740{
741 FreqInfo *infoPtr;
742 register int i;
743
744 if ((graphPtr->mode != MODE_STACKED) || (graphPtr->nStacks == 0)) {
745 return;
746 }
747 infoPtr = graphPtr->freqArr;
748 for (i = 0; i < graphPtr->nStacks; i++) {
749 if ((infoPtr->axes.x == pairPtr->x) &&
750 (infoPtr->axes.y == pairPtr->y)) {
751 /*
752
753 * Check if any of the y-values (because of stacking) are
754 * greater than the current limits of the graph.
755 */
756 if (infoPtr->sum < 0.0) {
757 if (*minPtr > infoPtr->sum) {
758 *minPtr = infoPtr->sum;
759 }
760 } else {
761 if (*maxPtr < infoPtr->sum) {
762 *maxPtr = infoPtr->sum;
763 }
764 }
765 }
766 infoPtr++;
767 }
768}
769
770/*
771 * ----------------------------------------------------------------------
772 *
773 * ConfigureBar --
774 *
775 * Sets up the appropriate configuration parameters in the GC.
776 * It is assumed the parameters have been previously set by
777 * a call to Tk_ConfigureWidget.
778 *
779 * Results:
780 * The return value is a standard Tcl result. If TCL_ERROR is
781 * returned, then interp->result contains an error message.
782 *
783 * Side effects:
784 * Configuration information such as bar foreground/background
785 * color and stipple etc. get set in a new GC.
786 *
787 * ----------------------------------------------------------------------
788 */
789/*ARGSUSED*/
790static int
791ConfigureBar(graphPtr, elemPtr)
792 Graph *graphPtr;
793 register Element *elemPtr;
794{
795 Bar *barPtr = (Bar *)elemPtr;
796 Blt_ChainLink *linkPtr;
797
798 if (ConfigurePen(graphPtr, (Pen *)&(barPtr->builtinPen)) != TCL_OK) {
799 return TCL_ERROR;
800 }
801 /*
802 * Point to the static normal pen if no external pens have
803 * been selected.
804 */
805 if (barPtr->normalPenPtr == NULL) {
806 barPtr->normalPenPtr = &(barPtr->builtinPen);
807 }
808 linkPtr = Blt_ChainFirstLink(barPtr->palette);
809 if (linkPtr != NULL) {
810 BarPenStyle *stylePtr;
811
812 stylePtr = Blt_ChainGetValue(linkPtr);
813 stylePtr->penPtr = barPtr->normalPenPtr;
814 }
815 if (Blt_ConfigModified(barPtr->specsPtr, "-barwidth", "-*data",
816 "-map*", "-label", "-hide", "-x", "-y", (char *)NULL)) {
817 barPtr->flags |= MAP_ITEM;
818 }
819 return TCL_OK;
820}
821
822static void
823GetBarExtents(elemPtr, extsPtr)
824 Element *elemPtr;
825 Extents2D *extsPtr;
826{
827 Graph *graphPtr = elemPtr->graphPtr;
828 Bar *barPtr = (Bar *)elemPtr;
829 double middle, barWidth;
830 int nPoints;
831
832 extsPtr->top = extsPtr->left = DBL_MAX;
833 extsPtr->bottom = extsPtr->right = -DBL_MAX;
834
835 nPoints = NumberOfPoints(barPtr);
836 if (nPoints < 1) {
837 return; /* No data points */
838 }
839 barWidth = graphPtr->barWidth;
840 if (barPtr->barWidth > 0.0) {
841 barWidth = barPtr->barWidth;
842 }
843 middle = barWidth * 0.5;
844 extsPtr->left = barPtr->x.min - middle;
845 extsPtr->right = barPtr->x.max + middle;
846
847 extsPtr->top = barPtr->y.min;
848 extsPtr->bottom = barPtr->y.max;
849 if (extsPtr->bottom < graphPtr->baseline) {
850 extsPtr->bottom = graphPtr->baseline;
851 }
852 /*
853 * Handle "stacked" bar elements specially.
854 *
855 * If element is stacked, the sum of its ordinates may be outside
856 * the minimum/maximum limits of the element's data points.
857 */
858 if ((graphPtr->mode == MODE_STACKED) && (graphPtr->nStacks > 0)) {
859 CheckStacks(graphPtr, &(elemPtr->axes), &(extsPtr->top),
860 &(extsPtr->bottom));
861 }
862 /* Warning: You get what you deserve if the x-axis is logScale */
863 if (elemPtr->axes.x->logScale) {
864 extsPtr->left = Blt_FindElemVectorMinimum(&(barPtr->x), DBL_MIN) +
865 middle;
866 }
867 /* Fix y-min limits for barchart */
868 if (elemPtr->axes.y->logScale) {
869 if ((extsPtr->top <= 0.0) || (extsPtr->top > 1.0)) {
870 extsPtr->top = 1.0;
871 }
872 } else {
873 if (extsPtr->top > 0.0) {
874 extsPtr->top = 0.0;
875 }
876 }
877 /* Correct the extents for error bars if they exist. */
878 if (elemPtr->xError.nValues > 0) {
879 register int i;
880 double x;
881
882 /* Correct the data limits for error bars */
883 nPoints = MIN(elemPtr->xError.nValues, nPoints);
884 for (i = 0; i < nPoints; i++) {
885 x = elemPtr->x.valueArr[i] + elemPtr->xError.valueArr[i];
886 if (x > extsPtr->right) {
887 extsPtr->right = x;
888 }
889 x = elemPtr->x.valueArr[i] - elemPtr->xError.valueArr[i];
890 if (elemPtr->axes.x->logScale) {
891 if (x < 0.0) {
892 x = -x; /* Mirror negative values, instead
893 * of ignoring them. */
894 }
895 if ((x > DBL_MIN) && (x < extsPtr->left)) {
896 extsPtr->left = x;
897 }
898 } else if (x < extsPtr->left) {
899 extsPtr->left = x;
900 }
901 }
902 } else {
903 if ((elemPtr->xHigh.nValues > 0) &&
904 (elemPtr->xHigh.max > extsPtr->right)) {
905 extsPtr->right = elemPtr->xHigh.max;
906 }
907 if (elemPtr->xLow.nValues > 0) {
908 double left;
909
910 if ((elemPtr->xLow.min <= 0.0) &&
911 (elemPtr->axes.x->logScale)) {
912 left = Blt_FindElemVectorMinimum(&elemPtr->xLow, DBL_MIN);
913 } else {
914 left = elemPtr->xLow.min;
915 }
916 if (left < extsPtr->left) {
917 extsPtr->left = left;
918 }
919 }
920 }
921 if (elemPtr->yError.nValues > 0) {
922 register int i;
923 double y;
924
925 nPoints = MIN(elemPtr->yError.nValues, nPoints);
926 for (i = 0; i < nPoints; i++) {
927 y = elemPtr->y.valueArr[i] + elemPtr->yError.valueArr[i];
928 if (y > extsPtr->bottom) {
929 extsPtr->bottom = y;
930 }
931 y = elemPtr->y.valueArr[i] - elemPtr->yError.valueArr[i];
932 if (elemPtr->axes.y->logScale) {
933 if (y < 0.0) {
934 y = -y; /* Mirror negative values, instead
935 * of ignoring them. */
936 }
937 if ((y > DBL_MIN) && (y < extsPtr->left)) {
938 extsPtr->top = y;
939 }
940 } else if (y < extsPtr->top) {
941 extsPtr->top = y;
942 }
943 }
944 } else {
945 if ((elemPtr->yHigh.nValues > 0) &&
946 (elemPtr->yHigh.max > extsPtr->bottom)) {
947 extsPtr->bottom = elemPtr->yHigh.max;
948 }
949 if (elemPtr->yLow.nValues > 0) {
950 double top;
951
952 if ((elemPtr->yLow.min <= 0.0) &&
953 (elemPtr->axes.y->logScale)) {
954 top = Blt_FindElemVectorMinimum(&elemPtr->yLow, DBL_MIN);
955 } else {
956 top = elemPtr->yLow.min;
957 }
958 if (top < extsPtr->top) {
959 extsPtr->top = top;
960 }
961 }
962 }
963}
964
965/*
966 * ----------------------------------------------------------------------
967 *
968 * ClosestBar --
969 *
970 * Find the bar segment closest to the window coordinates point
971 * specified.
972 *
973 * Note: This does not return the height of the stacked segment
974 * (in graph coordinates) properly.
975 *
976 * Results:
977 * Returns 1 if the point is width any bar segment, otherwise 0.
978 *
979 * ----------------------------------------------------------------------
980 */
981/*ARGSUSED*/
982static void
983ClosestBar(graphPtr, elemPtr, searchPtr)
984 Graph *graphPtr; /* Graph widget record */
985 Element *elemPtr; /* Bar element */
986 ClosestSearch *searchPtr; /* Info of closest point in element */
987{
988 Bar *barPtr = (Bar *)elemPtr;
989 Point2D *pointPtr, *endPtr;
990 Point2D t, outline[5];
991 XRectangle *rectPtr;
992 double left, right, top, bottom;
993 double minDist, dist;
994 int imin;
995 register int i;
996
997 minDist = searchPtr->dist;
998 imin = 0;
999
1000 rectPtr = barPtr->rectangles;
1001 for (i = 0; i < barPtr->nRects; i++) {
1002 if (PointInRectangle(rectPtr, searchPtr->x, searchPtr->y)) {
1003 imin = barPtr->rectToData[i];
1004 minDist = 0.0;
1005 break;
1006 }
1007 left = rectPtr->x, top = rectPtr->y;
1008 right = (double)(rectPtr->x + rectPtr->width);
1009 bottom = (double)(rectPtr->y + rectPtr->height);
1010 outline[4].x = outline[3].x = outline[0].x = left;
1011 outline[4].y = outline[1].y = outline[0].y = top;
1012 outline[2].x = outline[1].x = right;
1013 outline[3].y = outline[2].y = bottom;
1014
1015 for (pointPtr = outline, endPtr = outline + 4; pointPtr < endPtr;
1016 pointPtr++) {
1017 t = Blt_GetProjection(searchPtr->x, searchPtr->y,
1018 pointPtr, pointPtr + 1);
1019 if (t.x > right) {
1020 t.x = right;
1021 } else if (t.x < left) {
1022 t.x = left;
1023 }
1024 if (t.y > bottom) {
1025 t.y = bottom;
1026 } else if (t.y < top) {
1027 t.y = top;
1028 }
1029 dist = hypot((t.x - searchPtr->x), (t.y - searchPtr->y));
1030 if (dist < minDist) {
1031 minDist = dist;
1032 imin = barPtr->rectToData[i];
1033 }
1034 }
1035 rectPtr++;
1036 }
1037 if (minDist < searchPtr->dist) {
1038 searchPtr->elemPtr = (Element *)elemPtr;
1039 searchPtr->dist = minDist;
1040 searchPtr->index = imin;
1041 searchPtr->point.x = (double)barPtr->x.valueArr[imin];
1042 searchPtr->point.y = (double)barPtr->y.valueArr[imin];
1043 }
1044}
1045
1046/*
1047 *----------------------------------------------------------------------
1048 *
1049 * MergePens --
1050 *
1051 * Reorders the both arrays of points and errorbars to merge pens.
1052 *
1053 * Results:
1054 * None.
1055 *
1056 * Side effects:
1057 * The old arrays are freed and new ones allocated containing
1058 * the reordered points and errorbars.
1059 *
1060 *----------------------------------------------------------------------
1061 */
1062static void
1063MergePens(barPtr, dataToStyle)
1064 Bar *barPtr;
1065 PenStyle **dataToStyle;
1066{
1067 BarPenStyle *stylePtr;
1068 Blt_ChainLink *linkPtr;
1069
1070 if (Blt_ChainGetLength(barPtr->palette) < 2) {
1071 linkPtr = Blt_ChainFirstLink(barPtr->palette);
1072 stylePtr = Blt_ChainGetValue(linkPtr);
1073 stylePtr->nRects = barPtr->nRects;
1074 stylePtr->rectangles = barPtr->rectangles;
1075 stylePtr->symbolSize = barPtr->rectangles->width / 2;
1076 stylePtr->xErrorBarCnt = barPtr->xErrorBarCnt;
1077 stylePtr->xErrorBars = barPtr->xErrorBars;
1078 stylePtr->yErrorBarCnt = barPtr->yErrorBarCnt;
1079 stylePtr->yErrorBars = barPtr->yErrorBars;
1080 return;
1081 }
1082 /* We have more than one style. Group bar segments of like pen
1083 * styles together. */
1084
1085 if (barPtr->nRects > 0) {
1086 XRectangle *rectangles;
1087 int *rectToData;
1088 int dataIndex;
1089 register XRectangle *rectPtr;
1090 register int *indexPtr;
1091 register int i;
1092
1093 rectangles = Blt_Malloc(barPtr->nRects * sizeof(XRectangle));
1094 rectToData = Blt_Malloc(barPtr->nRects * sizeof(int));
1095 assert(rectangles && rectToData);
1096
1097 rectPtr = rectangles, indexPtr = rectToData;
1098 for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL;
1099 linkPtr = Blt_ChainNextLink(linkPtr)) {
1100 stylePtr = Blt_ChainGetValue(linkPtr);
1101 stylePtr->symbolSize = rectPtr->width / 2;
1102 stylePtr->rectangles = rectPtr;
1103 for (i = 0; i < barPtr->nRects; i++) {
1104 dataIndex = barPtr->rectToData[i];
1105 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
1106 *rectPtr++ = barPtr->rectangles[i];
1107 *indexPtr++ = dataIndex;
1108 }
1109 }
1110 stylePtr->nRects = rectPtr - stylePtr->rectangles;
1111 }
1112 Blt_Free(barPtr->rectangles);
1113 barPtr->rectangles = rectangles;
1114 Blt_Free(barPtr->rectToData);
1115 barPtr->rectToData = rectToData;
1116 }
1117 if (barPtr->xErrorBarCnt > 0) {
1118 Segment2D *errorBars, *segPtr;
1119 int *errorToData, *indexPtr;
1120 int dataIndex;
1121 register int i;
1122
1123 errorBars = Blt_Malloc(barPtr->xErrorBarCnt * sizeof(Segment2D));
1124 errorToData = Blt_Malloc(barPtr->xErrorBarCnt * sizeof(int));
1125 assert(errorBars);
1126 segPtr = errorBars, indexPtr = errorToData;
1127 for (linkPtr = Blt_ChainFirstLink(barPtr->palette);
1128 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1129 stylePtr = Blt_ChainGetValue(linkPtr);
1130 stylePtr->xErrorBars = segPtr;
1131 for (i = 0; i < barPtr->xErrorBarCnt; i++) {
1132 dataIndex = barPtr->xErrorToData[i];
1133 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
1134 *segPtr++ = barPtr->xErrorBars[i];
1135 *indexPtr++ = dataIndex;
1136 }
1137 }
1138 stylePtr->xErrorBarCnt = segPtr - stylePtr->xErrorBars;
1139 }
1140 Blt_Free(barPtr->xErrorBars);
1141 barPtr->xErrorBars = errorBars;
1142 Blt_Free(barPtr->xErrorToData);
1143 barPtr->xErrorToData = errorToData;
1144 }
1145 if (barPtr->yErrorBarCnt > 0) {
1146 Segment2D *errorBars, *segPtr;
1147 int *errorToData, *indexPtr;
1148 int dataIndex;
1149 register int i;
1150
1151 errorBars = Blt_Malloc(barPtr->yErrorBarCnt * sizeof(Segment2D));
1152 errorToData = Blt_Malloc(barPtr->yErrorBarCnt * sizeof(int));
1153 assert(errorBars);
1154 segPtr = errorBars, indexPtr = errorToData;
1155 for (linkPtr = Blt_ChainFirstLink(barPtr->palette);
1156 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1157 stylePtr = Blt_ChainGetValue(linkPtr);
1158 stylePtr->yErrorBars = segPtr;
1159 for (i = 0; i < barPtr->yErrorBarCnt; i++) {
1160 dataIndex = barPtr->yErrorToData[i];
1161 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
1162 *segPtr++ = barPtr->yErrorBars[i];
1163 *indexPtr++ = dataIndex;
1164 }
1165 }
1166 stylePtr->yErrorBarCnt = segPtr - stylePtr->yErrorBars;
1167 }
1168 Blt_Free(barPtr->yErrorBars);
1169 barPtr->yErrorBars = errorBars;
1170 Blt_Free(barPtr->yErrorToData);
1171 barPtr->yErrorToData = errorToData;
1172 }
1173}
1174
1175/*
1176 *----------------------------------------------------------------------
1177 *
1178 * MapActiveBars --
1179 *
1180 * Creates an array of points of the active graph coordinates.
1181 *
1182 * Results:
1183 * None.
1184 *
1185 * Side effects:
1186 * Memory is freed and allocated for the active point array.
1187 *
1188 *----------------------------------------------------------------------
1189 */
1190static void
1191MapActiveBars(barPtr)
1192 Bar *barPtr;
1193{
1194 if (barPtr->activeRects != NULL) {
1195 Blt_Free(barPtr->activeRects);
1196 barPtr->activeRects = NULL;
1197 }
1198 if (barPtr->activeToData != NULL) {
1199 Blt_Free(barPtr->activeToData);
1200 barPtr->activeToData = NULL;
1201 }
1202 barPtr->nActive = 0;
1203
1204 if (barPtr->nActiveIndices > 0) {
1205 XRectangle *activeRects;
1206 int *activeToData;
1207 register int i, n;
1208 register int count;
1209
1210 activeRects = Blt_Malloc(sizeof(XRectangle) * barPtr->nActiveIndices);
1211 assert(activeRects);
1212 activeToData = Blt_Malloc(sizeof(int) * barPtr->nActiveIndices);
1213 assert(activeToData);
1214 count = 0;
1215 for (i = 0; i < barPtr->nRects; i++) {
1216 for (n = 0; n < barPtr->nActiveIndices; n++) {
1217 if (barPtr->rectToData[i] == barPtr->activeIndices[n]) {
1218 activeRects[count] = barPtr->rectangles[i];
1219 activeToData[count] = i;
1220 count++;
1221 }
1222 }
1223 }
1224 barPtr->nActive = count;
1225 barPtr->activeRects = activeRects;
1226 barPtr->activeToData = activeToData;
1227 }
1228 barPtr->flags &= ~ACTIVE_PENDING;
1229}
1230
1231static void
1232ResetBar(barPtr)
1233 Bar *barPtr;
1234{
1235 /* Release any storage associated with the display of the bar */
1236 ClearPalette(barPtr->palette);
1237 if (barPtr->activeRects != NULL) {
1238 Blt_Free(barPtr->activeRects);
1239 }
1240 if (barPtr->activeToData != NULL) {
1241 Blt_Free(barPtr->activeToData);
1242 }
1243 if (barPtr->xErrorBars != NULL) {
1244 Blt_Free(barPtr->xErrorBars);
1245 }
1246 if (barPtr->xErrorToData != NULL) {
1247 Blt_Free(barPtr->xErrorToData);
1248 }
1249 if (barPtr->yErrorBars != NULL) {
1250 Blt_Free(barPtr->yErrorBars);
1251 }
1252 if (barPtr->yErrorToData != NULL) {
1253 Blt_Free(barPtr->yErrorToData);
1254 }
1255 if (barPtr->rectangles != NULL) {
1256 Blt_Free(barPtr->rectangles);
1257 }
1258 if (barPtr->rectToData != NULL) {
1259 Blt_Free(barPtr->rectToData);
1260 }
1261 barPtr->activeToData = barPtr->xErrorToData = barPtr->yErrorToData =
1262 barPtr->rectToData = NULL;
1263 barPtr->activeRects = barPtr->rectangles = NULL;
1264 barPtr->xErrorBars = barPtr->yErrorBars = NULL;
1265 barPtr->nActive = barPtr->xErrorBarCnt = barPtr->yErrorBarCnt =
1266 barPtr->nRects = 0;
1267}
1268
1269/*
1270 * ----------------------------------------------------------------------
1271 *
1272 * MapBar --
1273 *
1274 * Calculates the actual window coordinates of the bar element.
1275 * The window coordinates are saved in the bar element structure.
1276 *
1277 * Results:
1278 * None.
1279 *
1280 * Notes:
1281 * A bar can have multiple segments (more than one x,y pairs).
1282 * In this case, the bar can be represented as either a set of
1283 * non-contiguous bars or a single multi-segmented (stacked) bar.
1284 *
1285 * The x-axis layout for a barchart may be presented in one of
1286 * two ways. If abscissas are used, the bars are placed at those
1287 * coordinates. Otherwise, the range will represent the number
1288 * of values.
1289 *
1290 * ----------------------------------------------------------------------
1291 */
1292static void
1293MapBar(graphPtr, elemPtr)
1294 Graph *graphPtr;
1295 Element *elemPtr;
1296{
1297 Bar *barPtr = (Bar *)elemPtr;
1298 FreqKey key;
1299 PenStyle **dataToStyle;
1300 Point2D c1, c2; /* Two opposite corners of the rectangle
1301 * in graph coordinates. */
1302 double *x, *y;
1303 double barWidth, barOffset;
1304 double baseline;
1305 double dx, dy;
1306 int *rectToData; /* Maps rectangles to data point indices */
1307 int height;
1308 int invertBar;
1309 int nPoints, count;
1310 register XRectangle *rectPtr, *rectangles;
1311 register int i;
1312 int size;
1313 Blt_ChainLink *linkPtr;
1314 BarPenStyle *stylePtr;
1315
1316 ResetBar(barPtr);
1317 nPoints = NumberOfPoints(barPtr);
1318 if (nPoints < 1) {
1319 return; /* No data points */
1320 }
1321 barWidth = graphPtr->barWidth;
1322 if (barPtr->barWidth > 0.0) {
1323 barWidth = barPtr->barWidth;
1324 }
1325 baseline = (barPtr->axes.y->logScale) ? 1.0 : graphPtr->baseline;
1326 barOffset = barWidth * 0.5;
1327
1328 /*
1329 * Create an array of rectangles representing the screen coordinates
1330 * of all the segments in the bar.
1331 */
1332 rectPtr = rectangles = Blt_Malloc(nPoints * sizeof(XRectangle));
1333 assert(rectangles);
1334 rectToData = Blt_Calloc(nPoints, sizeof(int));
1335 assert(rectToData);
1336
1337 x = barPtr->x.valueArr, y = barPtr->y.valueArr;
1338 count = 0;
1339 for (i = 0; i < nPoints; i++) {
1340 if (((x[i] - barWidth) > barPtr->axes.x->axisRange.max) ||
1341 ((x[i] + barWidth) < barPtr->axes.x->axisRange.min)) {
1342 continue; /* Abscissa is out of range of the x-axis */
1343 }
1344 c1.x = x[i] - barOffset;
1345 c1.y = y[i];
1346 c2.x = c1.x + barWidth;
1347 c2.y = baseline;
1348
1349 /*
1350 * If the mode is "aligned" or "stacked" we need to adjust the
1351 * x or y coordinates of the two corners.
1352 */
1353
1354 if ((graphPtr->nStacks > 0) && (graphPtr->mode != MODE_INFRONT)) {
1355 Blt_HashEntry *hPtr;
1356
1357 key.value = x[i];
1358 key.axes = barPtr->axes;
1359 hPtr = Blt_FindHashEntry(&(graphPtr->freqTable), (char *)&key);
1360 if (hPtr != NULL) {
1361 FreqInfo *infoPtr;
1362 double slice, width;
1363
1364 infoPtr = (FreqInfo *)Blt_GetHashValue(hPtr);
1365 switch (graphPtr->mode) {
1366 case MODE_STACKED:
1367 c2.y = infoPtr->lastY;
1368 c1.y += c2.y;
1369 infoPtr->lastY = c1.y;
1370 break;
1371
1372 case MODE_ALIGNED:
1373 infoPtr->count++;
1374 slice = barWidth / (double)infoPtr->freq;
1375 c1.x += slice * (infoPtr->freq - infoPtr->count);
1376 c2.x = c1.x + slice;
1377 break;
1378
1379 case MODE_OVERLAP:
1380 infoPtr->count++;
1381 slice = barWidth / (double)(infoPtr->freq * 2);
1382 width = slice * (infoPtr->freq + 1);
1383 c1.x += slice * (infoPtr->freq - infoPtr->count);
1384 c2.x = c1.x + width;
1385 break;
1386 case MODE_INFRONT:
1387 break;
1388 }
1389 }
1390 }
1391 invertBar = FALSE;
1392 if (c1.y < c2.y) {
1393 double temp;
1394
1395 /* Handle negative bar values by swapping ordinates */
1396 temp = c1.y, c1.y = c2.y, c2.y = temp;
1397 invertBar = TRUE;
1398 }
1399 /*
1400 * Get the two corners of the bar segment and compute the rectangle
1401 */
1402 c1 = Blt_Map2D(graphPtr, c1.x, c1.y, &barPtr->axes);
1403 c2 = Blt_Map2D(graphPtr, c2.x, c2.y, &barPtr->axes);
1404
1405 /* Bound the bars vertically by the size of the graph window */
1406 if (c1.y < 0.0) {
1407 c1.y = 0.0;
1408 } else if (c1.y > (double)graphPtr->height) {
1409 c1.y = (double)graphPtr->height;
1410 }
1411 if (c2.y < 0.0) {
1412 c2.y = 0.0;
1413 } else if (c2.y > (double)graphPtr->height) {
1414 c2.y = (double)graphPtr->height;
1415 }
1416 dx = c1.x - c2.x;
1417 dy = c1.y - c2.y;
1418 height = (int)Round(FABS(dy));
1419 if (invertBar) {
1420 rectPtr->y = (short int)MIN(c1.y, c2.y);
1421 } else {
1422 rectPtr->y = (short int)(MAX(c1.y, c2.y)) - height;
1423 }
1424 rectPtr->x = (short int)MIN(c1.x, c2.x);
1425 rectPtr->width = (short int)Round(FABS(dx)) + 1;
1426 if (rectPtr->width < 1) {
1427 rectPtr->width = 1;
1428 }
1429 rectPtr->height = height + 1;
1430 if (rectPtr->height < 1) {
1431 rectPtr->height = 1;
1432 }
1433 rectToData[count] = i; /* Save the data index corresponding to the
1434 * rectangle */
1435 rectPtr++;
1436 count++;
1437 }
1438 barPtr->nRects = count;
1439 barPtr->rectangles = rectangles;
1440 barPtr->rectToData = rectToData;
1441 if (barPtr->nActiveIndices > 0) {
1442 MapActiveBars(barPtr);
1443 }
1444
1445 size = 20;
1446 if (count > 0) {
1447 size = rectangles->width;
1448 }
1449 /* Set the symbol size of all the pen styles. */
1450 for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL;
1451 linkPtr = Blt_ChainNextLink(linkPtr)) {
1452 stylePtr = Blt_ChainGetValue(linkPtr);
1453 stylePtr->symbolSize = size;
1454 stylePtr->errorBarCapWidth = (stylePtr->penPtr->errorBarCapWidth > 0)
1455 ? stylePtr->penPtr->errorBarCapWidth : (int)(size * 0.6666666);
1456 stylePtr->errorBarCapWidth /= 2;
1457 }
1458 dataToStyle = Blt_StyleMap((Element *)barPtr);
1459 if (((barPtr->yHigh.nValues > 0) && (barPtr->yLow.nValues > 0)) ||
1460 ((barPtr->xHigh.nValues > 0) && (barPtr->xLow.nValues > 0)) ||
1461 (barPtr->xError.nValues > 0) || (barPtr->yError.nValues > 0)) {
1462 Blt_MapErrorBars(graphPtr, (Element *)barPtr, dataToStyle);
1463 }
1464 MergePens(barPtr, dataToStyle);
1465 Blt_Free(dataToStyle);
1466}
1467
1468/*
1469 * -----------------------------------------------------------------
1470 *
1471 * DrawSymbol --
1472 *
1473 * Draw a symbol centered at the given x,y window coordinate
1474 * based upon the element symbol type and size.
1475 *
1476 * Results:
1477 * None.
1478 *
1479 * Problems:
1480 * Most notable is the round-off errors generated when
1481 * calculating the centered position of the symbol.
1482 * -----------------------------------------------------------------
1483 */
1484/*ARGSUSED*/
1485static void
1486DrawSymbol(graphPtr, drawable, elemPtr, x, y, size)
1487 Graph *graphPtr;
1488 Drawable drawable; /* Pixmap or window to draw into */
1489 Element *elemPtr;
1490 int x, y;
1491 int size;
1492{
1493 BarPen *penPtr = ((Bar *)elemPtr)->normalPenPtr;
1494 int radius;
1495
1496 if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) {
1497 return;
1498 }
1499 radius = (size / 2);
1500 size--;
1501
1502 x -= radius;
1503 y -= radius;
1504 XSetTSOrigin(graphPtr->display, penPtr->gc, x, y);
1505 XFillRectangle(graphPtr->display, drawable, penPtr->gc, x, y,
1506 size, size);
1507 XSetTSOrigin(graphPtr->display, penPtr->gc, 0, 0);
1508}
1509
1510/*
1511 * -----------------------------------------------------------------
1512 *
1513 * DrawBarSegments --
1514 *
1515 * Draws each of the rectangular segments for the element.
1516 *
1517 * Results:
1518 * None.
1519 *
1520 * -----------------------------------------------------------------
1521 */
1522static void
1523DrawBarSegments(
1524 Graph *graphPtr,
1525 Drawable drawable, /* Pixmap or window to draw into */
1526 BarPen *penPtr,
1527 XRectangle *rectangles,
1528 int nRects)
1529{
1530 register XRectangle *rectPtr;
1531
1532 if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) {
1533 return;
1534 }
1535 XFillRectangles(graphPtr->display, drawable, penPtr->gc, rectangles,
1536 nRects);
1537 if ((penPtr->border != NULL) && (penPtr->borderWidth > 0) &&
1538 (penPtr->relief != TK_RELIEF_FLAT)) {
1539 XRectangle *endPtr;
1540
1541 for (rectPtr = rectangles, endPtr = rectangles + nRects;
1542 rectPtr < endPtr; rectPtr++) {
1543 Blt_Draw3DRectangle(graphPtr->tkwin, drawable, penPtr->border,
1544 rectPtr->x, rectPtr->y, rectPtr->width, rectPtr->height,
1545 penPtr->borderWidth, penPtr->relief);
1546 }
1547 }
1548}
1549
1550/*
1551 * -----------------------------------------------------------------
1552 *
1553 * DrawBarValues --
1554 *
1555 * Draws the numeric value of the bar.
1556 *
1557 * Results:
1558 * None.
1559 *
1560 * -----------------------------------------------------------------
1561 */
1562static void
1563DrawBarValues(
1564 Graph *graphPtr,
1565 Drawable drawable,
1566 Bar *barPtr,
1567 BarPen *penPtr,
1568 XRectangle *rectangles,
1569 int nRects,
1570 int *rectToData)
1571{
1572 XRectangle *rectPtr, *endPtr;
1573 int count;
1574 char *fmt;
1575 char string[TCL_DOUBLE_SPACE * 2 + 2];
1576 double x, y;
1577 Point2D anchorPos;
1578
1579 count = 0;
1580 fmt = penPtr->valueFormat;
1581 if (fmt == NULL) {
1582 fmt = "%g";
1583 }
1584 for (rectPtr = rectangles, endPtr = rectangles + nRects; rectPtr < endPtr;
1585 rectPtr++) {
1586 x = barPtr->x.valueArr[rectToData[count]];
1587 y = barPtr->y.valueArr[rectToData[count]];
1588 count++;
1589 if (penPtr->valueShow == SHOW_X) {
1590 sprintf(string, fmt, x);
1591 } else if (penPtr->valueShow == SHOW_Y) {
1592 sprintf(string, fmt, y);
1593 } else if (penPtr->valueShow == SHOW_BOTH) {
1594 sprintf(string, fmt, x);
1595 strcat(string, ",");
1596 sprintf(string + strlen(string), fmt, y);
1597 }
1598 if (graphPtr->inverted) {
1599 anchorPos.y = rectPtr->y + rectPtr->height * 0.5;
1600 anchorPos.x = rectPtr->x + rectPtr->width;
1601 if (y < graphPtr->baseline) {
1602 anchorPos.x -= rectPtr->width;
1603 }
1604 } else {
1605 anchorPos.x = rectPtr->x + rectPtr->width * 0.5;
1606 anchorPos.y = rectPtr->y;
1607 if (y < graphPtr->baseline) {
1608 anchorPos.y += rectPtr->height;
1609 }
1610 }
1611 Blt_DrawText(graphPtr->tkwin, drawable, string, &(penPtr->valueStyle),
1612 (int)anchorPos.x, (int)anchorPos.y);
1613 }
1614}
1615
1616
1617/*
1618 * ----------------------------------------------------------------------
1619 *
1620 * DrawNormalBar --
1621 *
1622 * Draws the rectangle representing the bar element. If the
1623 * relief option is set to "raised" or "sunken" and the bar
1624 * borderwidth is set (borderwidth > 0), a 3D border is drawn
1625 * around the bar.
1626 *
1627 * Don't draw bars that aren't visible (i.e. within the limits
1628 * of the axis).
1629 *
1630 * Results:
1631 * None.
1632 *
1633 * Side effects:
1634 * X drawing commands are output.
1635 *
1636 * ----------------------------------------------------------------------
1637 */
1638static void
1639DrawNormalBar(graphPtr, drawable, elemPtr)
1640 Graph *graphPtr;
1641 Drawable drawable;
1642 Element *elemPtr;
1643{
1644 Bar *barPtr = (Bar *)elemPtr;
1645 int count;
1646 Blt_ChainLink *linkPtr;
1647 register BarPenStyle *stylePtr;
1648 BarPen *penPtr;
1649
1650 count = 0;
1651 for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL;
1652 linkPtr = Blt_ChainNextLink(linkPtr)) {
1653 stylePtr = Blt_ChainGetValue(linkPtr);
1654 penPtr = stylePtr->penPtr;
1655 if (stylePtr->nRects > 0) {
1656 DrawBarSegments(graphPtr, drawable, penPtr, stylePtr->rectangles,
1657 stylePtr->nRects);
1658 }
1659 if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) {
1660 Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC,
1661 stylePtr->xErrorBars, stylePtr->xErrorBarCnt);
1662 }
1663 if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) {
1664 Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC,
1665 stylePtr->yErrorBars, stylePtr->yErrorBarCnt);
1666 }
1667 if (penPtr->valueShow != SHOW_NONE) {
1668 DrawBarValues(graphPtr, drawable, barPtr, penPtr,
1669 stylePtr->rectangles, stylePtr->nRects,
1670 barPtr->rectToData + count);
1671 }
1672 count += stylePtr->nRects;
1673 }
1674}
1675
1676/*
1677 * ----------------------------------------------------------------------
1678 *
1679 * DrawActiveBar --
1680 *
1681 * Draws rectangles representing the active segments of the
1682 * bar element. If the -relief option is set (other than "flat")
1683 * and the borderwidth is greater than 0, a 3D border is drawn
1684 * around the each bar segment.
1685 *
1686 * Results:
1687 * None.
1688 *
1689 * Side effects:
1690 * X drawing commands are output.
1691 *
1692 * ----------------------------------------------------------------------
1693 */
1694static void
1695DrawActiveBar(graphPtr, drawable, elemPtr)
1696 Graph *graphPtr;
1697 Drawable drawable;
1698 Element *elemPtr;
1699{
1700 Bar *barPtr = (Bar *)elemPtr;
1701
1702 if (barPtr->activePenPtr != NULL) {
1703 BarPen *penPtr = barPtr->activePenPtr;
1704
1705 if (barPtr->nActiveIndices > 0) {
1706 if (barPtr->flags & ACTIVE_PENDING) {
1707 MapActiveBars(barPtr);
1708 }
1709 DrawBarSegments(graphPtr, drawable, penPtr, barPtr->activeRects,
1710 barPtr->nActive);
1711 if (penPtr->valueShow != SHOW_NONE) {
1712 DrawBarValues(graphPtr, drawable, barPtr, penPtr,
1713 barPtr->activeRects, barPtr->nActive,
1714 barPtr->activeToData);
1715 }
1716 } else if (barPtr->nActiveIndices < 0) {
1717 DrawBarSegments(graphPtr, drawable, penPtr, barPtr->rectangles,
1718 barPtr->nRects);
1719 if (penPtr->valueShow != SHOW_NONE) {
1720 DrawBarValues(graphPtr, drawable, barPtr, penPtr,
1721 barPtr->rectangles, barPtr->nRects, barPtr->rectToData);
1722 }
1723 }
1724 }
1725}
1726
1727/*
1728 * -----------------------------------------------------------------
1729 *
1730 * SymbolToPostScript --
1731 *
1732 * Draw a symbol centered at the given x,y window coordinate
1733 * based upon the element symbol type and size.
1734 *
1735 * Results:
1736 * None.
1737 *
1738 * Problems:
1739 * Most notable is the round-off errors generated when
1740 * calculating the centered position of the symbol.
1741 *
1742 * -----------------------------------------------------------------
1743 */
1744/*ARGSUSED*/
1745static void
1746SymbolToPostScript(graphPtr, psToken, elemPtr, x, y, size)
1747 Graph *graphPtr;
1748 PsToken psToken;
1749 Element *elemPtr;
1750 int size;
1751 double x, y;
1752{
1753 Bar *barPtr = (Bar *)elemPtr;
1754 BarPen *bpPtr = barPtr->normalPenPtr;
1755
1756 if ((bpPtr->border == NULL) && (bpPtr->fgColor == NULL)) {
1757 return;
1758 }
1759 /*
1760 * Build a PostScript procedure to draw the fill and outline of
1761 * the symbol after the path of the symbol shape has been formed
1762 */
1763 Blt_AppendToPostScript(psToken, "\n",
1764 "/DrawSymbolProc {\n",
1765 " gsave\n ", (char *)NULL);
1766 if (bpPtr->stipple != None) {
1767 if (bpPtr->border != NULL) {
1768 Blt_BackgroundToPostScript(psToken,Tk_3DBorderColor(bpPtr->border));
1769 Blt_AppendToPostScript(psToken, " Fill\n ", (char *)NULL);
1770 }
1771 if (bpPtr->fgColor != NULL) {
1772 Blt_ForegroundToPostScript(psToken, bpPtr->fgColor);
1773 } else {
1774 Blt_ForegroundToPostScript(psToken,Tk_3DBorderColor(bpPtr->border));
1775 }
1776 Blt_StippleToPostScript(psToken, graphPtr->display, bpPtr->stipple);
1777 } else if (bpPtr->fgColor != NULL) {
1778 Blt_ForegroundToPostScript(psToken, bpPtr->fgColor);
1779 Blt_AppendToPostScript(psToken, " fill\n", (char *)NULL);
1780 }
1781 Blt_AppendToPostScript(psToken, " grestore\n", (char *)NULL);
1782 Blt_AppendToPostScript(psToken, "} def\n\n", (char *)NULL);
1783 Blt_FormatToPostScript(psToken, "%g %g %d Sq\n", x, y, size);
1784}
1785
1786static void
1787SegmentsToPostScript(graphPtr, psToken, penPtr, rectPtr, nRects)
1788 Graph *graphPtr;
1789 PsToken psToken;
1790 BarPen *penPtr;
1791 register XRectangle *rectPtr;
1792 int nRects;
1793{
1794 XRectangle *endPtr;
1795
1796 if ((penPtr->border == NULL) && (penPtr->fgColor == NULL)) {
1797 return;
1798 }
1799 for (endPtr = rectPtr + nRects; rectPtr < endPtr; rectPtr++) {
1800 if ((rectPtr->width < 1) || (rectPtr->height < 1)) {
1801 continue;
1802 }
1803 if (penPtr->stipple != None) {
1804 Blt_RegionToPostScript(psToken,
1805 (double)rectPtr->x, (double)rectPtr->y,
1806 (int)rectPtr->width - 1, (int)rectPtr->height - 1);
1807 if (penPtr->border != NULL) {
1808 Blt_BackgroundToPostScript(psToken,
1809 Tk_3DBorderColor(penPtr->border));
1810 Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
1811 }
1812 if (penPtr->fgColor != NULL) {
1813 Blt_ForegroundToPostScript(psToken, penPtr->fgColor);
1814 } else {
1815 Blt_ForegroundToPostScript(psToken,
1816 Tk_3DBorderColor(penPtr->border));
1817 }
1818 Blt_StippleToPostScript(psToken, graphPtr->display,
1819 penPtr->stipple);
1820 } else if (penPtr->fgColor != NULL) {
1821 Blt_ForegroundToPostScript(psToken, penPtr->fgColor);
1822 Blt_RectangleToPostScript(psToken,
1823 (double)rectPtr->x, (double)rectPtr->y,
1824 (int)rectPtr->width - 1, (int)rectPtr->height - 1);
1825 }
1826 if ((penPtr->border != NULL) && (penPtr->borderWidth > 0) &&
1827 (penPtr->relief != TK_RELIEF_FLAT)) {
1828 Blt_Draw3DRectangleToPostScript(psToken, penPtr->border,
1829 (double)rectPtr->x, (double)rectPtr->y,
1830 (int)rectPtr->width, (int)rectPtr->height,
1831 penPtr->borderWidth, penPtr->relief);
1832 }
1833 }
1834}
1835
1836static void
1837BarValuesToPostScript(
1838 Graph *graphPtr,
1839 PsToken psToken,
1840 Bar *barPtr,
1841 BarPen *penPtr,
1842 XRectangle *rectangles,
1843 int nRects,
1844 int *rectToData)
1845{
1846 XRectangle *rectPtr, *endPtr;
1847 int count;
1848 char *fmt;
1849 char string[TCL_DOUBLE_SPACE * 2 + 2];
1850 double x, y;
1851 Point2D anchorPos;
1852
1853 count = 0;
1854 fmt = penPtr->valueFormat;
1855 if (fmt == NULL) {
1856 fmt = "%g";
1857 }
1858 for (rectPtr = rectangles, endPtr = rectangles + nRects; rectPtr < endPtr;
1859 rectPtr++) {
1860 x = barPtr->x.valueArr[rectToData[count]];
1861 y = barPtr->y.valueArr[rectToData[count]];
1862 count++;
1863 if (penPtr->valueShow == SHOW_X) {
1864 sprintf(string, fmt, x);
1865 } else if (penPtr->valueShow == SHOW_Y) {
1866 sprintf(string, fmt, y);
1867 } else if (penPtr->valueShow == SHOW_BOTH) {
1868 sprintf(string, fmt, x);
1869 strcat(string, ",");
1870 sprintf(string + strlen(string), fmt, y);
1871 }
1872 if (graphPtr->inverted) {
1873 anchorPos.y = rectPtr->y + rectPtr->height * 0.5;
1874 anchorPos.x = rectPtr->x + rectPtr->width;
1875 if (y < graphPtr->baseline) {
1876 anchorPos.x -= rectPtr->width;
1877 }
1878 } else {
1879 anchorPos.x = rectPtr->x + rectPtr->width * 0.5;
1880 anchorPos.y = rectPtr->y;
1881 if (y < graphPtr->baseline) {
1882 anchorPos.y += rectPtr->height;
1883 }
1884 }
1885 Blt_TextToPostScript(psToken, string, &(penPtr->valueStyle),
1886 anchorPos.x, anchorPos.y);
1887 }
1888}
1889
1890/*
1891 * ----------------------------------------------------------------------
1892 *
1893 * ActiveBarToPostScript --
1894 *
1895 * Similar to the NormalBarToPostScript procedure, generates
1896 * PostScript commands to display the rectangles representing the
1897 * active bar segments of the element.
1898 *
1899 * Results:
1900 * None.
1901 *
1902 * Side effects:
1903 * PostScript pen width, dashes, and color settings are changed.
1904 *
1905 * ----------------------------------------------------------------------
1906 */
1907/*ARGSUSED*/
1908static void
1909ActiveBarToPostScript(graphPtr, psToken, elemPtr)
1910 Graph *graphPtr;
1911 PsToken psToken;
1912 Element *elemPtr;
1913{
1914 Bar *barPtr = (Bar *)elemPtr;
1915
1916 if (barPtr->activePenPtr != NULL) {
1917 BarPen *penPtr = barPtr->activePenPtr;
1918
1919 if (barPtr->nActiveIndices > 0) {
1920 if (barPtr->flags & ACTIVE_PENDING) {
1921 MapActiveBars(barPtr);
1922 }
1923 SegmentsToPostScript(graphPtr, psToken, penPtr,
1924 barPtr->activeRects, barPtr->nActive);
1925 if (penPtr->valueShow != SHOW_NONE) {
1926 BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr,
1927 barPtr->activeRects, barPtr->nActive, barPtr->activeToData);
1928 }
1929 } else if (barPtr->nActiveIndices < 0) {
1930 SegmentsToPostScript(graphPtr, psToken, penPtr,
1931 barPtr->rectangles, barPtr->nRects);
1932 if (penPtr->valueShow != SHOW_NONE) {
1933 BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr,
1934 barPtr->rectangles, barPtr->nRects, barPtr->rectToData);
1935 }
1936 }
1937 }
1938}
1939
1940/*
1941 * ----------------------------------------------------------------------
1942 *
1943 * NormalBarToPostScript --
1944 *
1945 * Generates PostScript commands to form the rectangles
1946 * representing the segments of the bar element.
1947 *
1948 * Results:
1949 * None.
1950 *
1951 * Side effects:
1952 * PostScript pen width, dashes, and color settings are changed.
1953 *
1954 * ----------------------------------------------------------------------
1955 */
1956/*ARGSUSED*/
1957static void
1958NormalBarToPostScript(graphPtr, psToken, elemPtr)
1959 Graph *graphPtr;
1960 PsToken psToken;
1961 Element *elemPtr;
1962{
1963 Bar *barPtr = (Bar *)elemPtr;
1964 Blt_ChainLink *linkPtr;
1965 register BarPenStyle *stylePtr;
1966 int count;
1967 BarPen *penPtr;
1968 XColor *colorPtr;
1969
1970 count = 0;
1971 for (linkPtr = Blt_ChainFirstLink(barPtr->palette); linkPtr != NULL;
1972 linkPtr = Blt_ChainNextLink(linkPtr)) {
1973 stylePtr = Blt_ChainGetValue(linkPtr);
1974 penPtr = stylePtr->penPtr;
1975 if (stylePtr->nRects > 0) {
1976 SegmentsToPostScript(graphPtr, psToken, penPtr,
1977 stylePtr->rectangles, stylePtr->nRects);
1978 }
1979 colorPtr = penPtr->errorBarColor;
1980 if (colorPtr == COLOR_DEFAULT) {
1981 colorPtr = penPtr->fgColor;
1982 }
1983 if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) {
1984 Blt_LineAttributesToPostScript(psToken, colorPtr,
1985 penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter);
1986 Blt_2DSegmentsToPostScript(psToken, stylePtr->xErrorBars,
1987 stylePtr->xErrorBarCnt);
1988 }
1989 if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) {
1990 Blt_LineAttributesToPostScript(psToken, colorPtr,
1991 penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter);
1992 Blt_2DSegmentsToPostScript(psToken, stylePtr->yErrorBars,
1993 stylePtr->yErrorBarCnt);
1994 }
1995 if (penPtr->valueShow != SHOW_NONE) {
1996 BarValuesToPostScript(graphPtr, psToken, barPtr, penPtr,
1997 stylePtr->rectangles, stylePtr->nRects,
1998 barPtr->rectToData + count);
1999 }
2000 count += stylePtr->nRects;
2001 }
2002}
2003
2004/*
2005 * ----------------------------------------------------------------------
2006 *
2007 * DestroyBar --
2008 *
2009 * Release memory and resources allocated for the bar element.
2010 *
2011 * Results:
2012 * None.
2013 *
2014 * Side effects:
2015 * Everything associated with the bar element is freed up.
2016 *
2017 * ----------------------------------------------------------------------
2018 */
2019#define FreeElemVector(v) \
2020 if ((v).clientId != NULL) { \
2021 Blt_FreeVectorId((v).clientId); \
2022 } else if ((v).valueArr != NULL) { \
2023 Blt_Free((v).valueArr); \
2024 }
2025
2026static void
2027DestroyBar(graphPtr, elemPtr)
2028 Graph *graphPtr;
2029 Element *elemPtr;
2030{
2031 Bar *barPtr = (Bar *)elemPtr;
2032
2033 if (barPtr->normalPenPtr != &(barPtr->builtinPen)) {
2034 Blt_FreePen(graphPtr, (Pen *)barPtr->normalPenPtr);
2035 }
2036 DestroyPen(graphPtr, (Pen *)&(barPtr->builtinPen));
2037 if (barPtr->activePenPtr != NULL) {
2038 Blt_FreePen(graphPtr, (Pen *)barPtr->activePenPtr);
2039 }
2040 FreeElemVector(barPtr->x);
2041 FreeElemVector(barPtr->y);
2042 FreeElemVector(barPtr->w);
2043 FreeElemVector(barPtr->xHigh);
2044 FreeElemVector(barPtr->xLow);
2045 FreeElemVector(barPtr->xError);
2046 FreeElemVector(barPtr->yHigh);
2047 FreeElemVector(barPtr->yLow);
2048 FreeElemVector(barPtr->yError);
2049
2050 ResetBar(barPtr);
2051 if (barPtr->activeIndices != NULL) {
2052 Blt_Free(barPtr->activeIndices);
2053 }
2054 if (barPtr->palette != NULL) {
2055 Blt_FreePalette(graphPtr, barPtr->palette);
2056 Blt_ChainDestroy(barPtr->palette);
2057 }
2058 if (barPtr->tags != NULL) {
2059 Blt_Free(barPtr->tags);
2060 }
2061}
2062
2063/*
2064 * ----------------------------------------------------------------------
2065 *
2066 * Blt_BarElement --
2067 *
2068 * Allocate memory and initialize methods for the new bar element.
2069 *
2070 * Results:
2071 * The pointer to the newly allocated element structure is returned.
2072 *
2073 * Side effects:
2074 * Memory is allocated for the bar element structure.
2075 *
2076 * ----------------------------------------------------------------------
2077 */
2078
2079static ElementProcs barProcs =
2080{
2081 ClosestBar,
2082 ConfigureBar,
2083 DestroyBar,
2084 DrawActiveBar,
2085 DrawNormalBar,
2086 DrawSymbol,
2087 GetBarExtents,
2088 ActiveBarToPostScript,
2089 NormalBarToPostScript,
2090 SymbolToPostScript,
2091 MapBar,
2092};
2093
2094
2095Element *
2096Blt_BarElement(graphPtr, name, type)
2097 Graph *graphPtr;
2098 char *name;
2099 Blt_Uid type;
2100{
2101 register Bar *barPtr;
2102
2103 barPtr = Blt_Calloc(1, sizeof(Bar));
2104 assert(barPtr);
2105 barPtr->normalPenPtr = &(barPtr->builtinPen);
2106 barPtr->procsPtr = &barProcs;
2107 barPtr->specsPtr = barElemConfigSpecs;
2108 barPtr->labelRelief = TK_RELIEF_FLAT;
2109 barPtr->classUid = type;
2110 /* By default, an element's name and label are the same. */
2111 barPtr->label = Blt_Strdup(name);
2112 barPtr->name = Blt_Strdup(name);
2113
2114 barPtr->graphPtr = graphPtr;
2115 barPtr->hidden = FALSE;
2116
2117 InitPen(barPtr->normalPenPtr);
2118 barPtr->palette = Blt_ChainCreate();
2119 return (Element *)barPtr;
2120}
2121
2122/*
2123 * ----------------------------------------------------------------------
2124 *
2125 * Blt_InitFreqTable --
2126 *
2127 * Generate a table of abscissa frequencies. Duplicate
2128 * x-coordinates (depending upon the bar drawing mode) indicate
2129 * that something special should be done with each bar segment
2130 * mapped to the same abscissa (i.e. it should be stacked,
2131 * aligned, or overlay-ed with other segments)
2132 *
2133 * Results:
2134 * None.
2135 *
2136 * Side effects:
2137 * Memory is allocated for the bar element structure.
2138 *
2139 * ----------------------------------------------------------------------
2140 */
2141void
2142Blt_InitFreqTable(graphPtr)
2143 Graph *graphPtr;
2144{
2145 register Element *elemPtr;
2146 Blt_ChainLink *linkPtr;
2147 Blt_HashEntry *hPtr;
2148 Blt_HashSearch cursor;
2149 Bar *barPtr;
2150 int isNew, count;
2151 int nStacks, nSegs;
2152 int nPoints;
2153 FreqKey key;
2154 Blt_HashTable freqTable;
2155 register int i;
2156 double *xArr;
2157 /*
2158 * Free resources associated with a previous frequency table. This
2159 * includes the array of frequency information and the table itself
2160 */
2161 if (graphPtr->freqArr != NULL) {
2162 Blt_Free(graphPtr->freqArr);
2163 graphPtr->freqArr = NULL;
2164 }
2165 if (graphPtr->nStacks > 0) {
2166 Blt_DeleteHashTable(&(graphPtr->freqTable));
2167 graphPtr->nStacks = 0;
2168 }
2169 if (graphPtr->mode == MODE_INFRONT) {
2170 return; /* No frequency table is needed for
2171 * "infront" mode */
2172 }
2173 Blt_InitHashTable(&(graphPtr->freqTable), sizeof(FreqKey) / sizeof(int));
2174
2175 /*
2176 * Initialize a hash table and fill it with unique abscissas.
2177 * Keep track of the frequency of each x-coordinate and how many
2178 * abscissas have duplicate mappings.
2179 */
2180 Blt_InitHashTable(&freqTable, sizeof(FreqKey) / sizeof(int));
2181 nSegs = nStacks = 0;
2182 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
2183 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2184 elemPtr = Blt_ChainGetValue(linkPtr);
2185 if ((elemPtr->hidden) || (elemPtr->classUid != bltBarElementUid)) {
2186 continue;
2187 }
2188 nSegs++;
2189 barPtr = (Bar *)elemPtr;
2190 xArr = barPtr->x.valueArr;
2191 nPoints = NumberOfPoints(barPtr);
2192 for (i = 0; i < nPoints; i++) {
2193 key.value = xArr[i];
2194 key.axes = barPtr->axes;
2195 hPtr = Blt_CreateHashEntry(&freqTable, (char *)&key, &isNew);
2196 assert(hPtr != NULL);
2197 if (isNew) {
2198 count = 1;
2199 } else {
2200 count = (int)Blt_GetHashValue(hPtr);
2201 if (count == 1) {
2202 nStacks++;
2203 }
2204 count++;
2205 }
2206 Blt_SetHashValue(hPtr, (ClientData)count);
2207 }
2208 }
2209 if (nSegs == 0) {
2210 return; /* No bar elements to be displayed */
2211 }
2212 if (nStacks > 0) {
2213 FreqInfo *infoPtr;
2214 FreqKey *keyPtr;
2215 Blt_HashEntry *h2Ptr;
2216
2217 graphPtr->freqArr = Blt_Calloc(nStacks, sizeof(FreqInfo));
2218 assert(graphPtr->freqArr);
2219 infoPtr = graphPtr->freqArr;
2220 for (hPtr = Blt_FirstHashEntry(&freqTable, &cursor); hPtr != NULL;
2221 hPtr = Blt_NextHashEntry(&cursor)) {
2222 count = (int)Blt_GetHashValue(hPtr);
2223 keyPtr = (FreqKey *)Blt_GetHashKey(&freqTable, hPtr);
2224 if (count > 1) {
2225 h2Ptr = Blt_CreateHashEntry(&(graphPtr->freqTable),
2226 (char *)keyPtr, &isNew);
2227 count = (int)Blt_GetHashValue(hPtr);
2228 infoPtr->freq = count;
2229 infoPtr->axes = keyPtr->axes;
2230 Blt_SetHashValue(h2Ptr, infoPtr);
2231 infoPtr++;
2232 }
2233 }
2234 }
2235 Blt_DeleteHashTable(&freqTable);
2236 graphPtr->nStacks = nStacks;
2237}
2238
2239/*
2240 * ----------------------------------------------------------------------
2241 *
2242 * Blt_ComputeStacks --
2243 *
2244 * Determine the height of each stack of bar segments. A stack
2245 * is created by designating two or more points with the same
2246 * abscissa. Each ordinate defines the height of a segment in
2247 * the stack. This procedure simply looks at all the data points
2248 * summing the heights of each stacked segment. The sum is saved
2249 * in the frequency information table. This value will be used
2250 * to calculate the y-axis limits (data limits aren't sufficient).
2251 *
2252 * Results:
2253 * None.
2254 *
2255 * Side effects:
2256 * The heights of each stack is computed. CheckStacks will
2257 * use this information to adjust the y-axis limits if necessary.
2258 *
2259 * ----------------------------------------------------------------------
2260 */
2261void
2262Blt_ComputeStacks(graphPtr)
2263 Graph *graphPtr;
2264{
2265 Element *elemPtr;
2266 Bar *barPtr;
2267 FreqKey key;
2268 Blt_ChainLink *linkPtr;
2269 Blt_HashEntry *hPtr;
2270 int nPoints;
2271 register int i;
2272 register FreqInfo *infoPtr;
2273 double *xArr, *yArr;
2274
2275 if ((graphPtr->mode != MODE_STACKED) || (graphPtr->nStacks == 0)) {
2276 return;
2277 }
2278 /* Reset the sums for all duplicate values to zero. */
2279
2280 infoPtr = graphPtr->freqArr;
2281 for (i = 0; i < graphPtr->nStacks; i++) {
2282 infoPtr->sum = 0.0;
2283 infoPtr++;
2284 }
2285
2286 /* Look at each bar point, adding the ordinates of duplicate abscissas */
2287
2288 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
2289 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2290 elemPtr = Blt_ChainGetValue(linkPtr);
2291 if ((elemPtr->hidden) || (elemPtr->classUid != bltBarElementUid)) {
2292 continue;
2293 }
2294 barPtr = (Bar *)elemPtr;
2295 xArr = barPtr->x.valueArr;
2296 yArr = barPtr->y.valueArr;
2297 nPoints = NumberOfPoints(barPtr);
2298 for (i = 0; i < nPoints; i++) {
2299 key.value = xArr[i];
2300 key.axes = barPtr->axes;
2301 hPtr = Blt_FindHashEntry(&(graphPtr->freqTable), (char *)&key);
2302 if (hPtr == NULL) {
2303 continue;
2304 }
2305 infoPtr = (FreqInfo *)Blt_GetHashValue(hPtr);
2306 infoPtr->sum += yArr[i];
2307 }
2308 }
2309}
2310
2311void
2312Blt_ResetStacks(graphPtr)
2313 Graph *graphPtr;
2314{
2315 register FreqInfo *infoPtr, *endPtr;
2316
2317 for (infoPtr = graphPtr->freqArr,
2318 endPtr = graphPtr->freqArr + graphPtr->nStacks;
2319 infoPtr < endPtr; infoPtr++) {
2320 infoPtr->lastY = 0.0;
2321 infoPtr->count = 0;
2322 }
2323}
2324
Note: See TracBrowser for help on using the repository browser.