Line No. | Rev | Author | Line |
---|---|---|---|
1 | 32 | kaklik | /***************************************************************************** |
2 | * Module for Microchip Graphics Library |
||
3 | * GOL Layer |
||
4 | * Chart |
||
5 | ***************************************************************************** |
||
6 | * FileName: Chart.c |
||
7 | * Dependencies: Chart.h |
||
8 | * Processor: PIC24F, PIC24H, dsPIC, PIC32 |
||
9 | * Compiler: MPLAB C30 Version 3.00, C32 |
||
10 | * Linker: MPLAB LINK30, LINK32 |
||
11 | * Company: Microchip Technology Incorporated |
||
12 | * |
||
13 | * Software License Agreement |
||
14 | * |
||
15 | * Copyright © 2008 Microchip Technology Inc. All rights reserved. |
||
16 | * Microchip licenses to you the right to use, modify, copy and distribute |
||
17 | * Software only when embedded on a Microchip microcontroller or digital |
||
18 | * signal controller, which is integrated into your product or third party |
||
19 | * product (pursuant to the sublicense terms in the accompanying license |
||
20 | * agreement). |
||
21 | * |
||
22 | * You should refer to the license agreement accompanying this Software |
||
23 | * for additional information regarding your rights and obligations. |
||
24 | * |
||
25 | * SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY |
||
26 | * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY |
||
27 | * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR |
||
28 | * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR |
||
29 | * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, |
||
30 | * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT |
||
31 | * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, |
||
32 | * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, |
||
33 | * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY |
||
34 | * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), |
||
35 | * OR OTHER SIMILAR COSTS. |
||
36 | * |
||
37 | * Author Date Comment |
||
38 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
39 | * Paolo A. Tamayo |
||
40 | * Anton Alkhimenok 4/8/08 ... |
||
41 | * PAT 8/8/08 Centered values displayed on bar charts |
||
42 | * Removed line drawn on pie chart when no slices |
||
43 | * are present. |
||
44 | * PAT 9/30/08 3-D bar depth is now equal to chart depth. |
||
45 | * Flushed 2-D Bars to equal max height of chart |
||
46 | * when equal or greater than. |
||
47 | * PAT 6/29/09 Modified Draw Sector function to be state based. |
||
48 | *****************************************************************************/ |
||
49 | #include "Graphics\Graphics.h" |
||
50 | #include <math.h> |
||
51 | |||
52 | #ifdef USE_CHART |
||
53 | |||
54 | // internal functions and macros |
||
55 | WORD word2xchar(WORD pSmple, XCHAR *xcharArray, WORD cnt); |
||
56 | void GetCirclePoint(SHORT radius, SHORT angle, SHORT *x, SHORT *y); |
||
57 | WORD DrawSector(SHORT cx, SHORT cy, SHORT radius, SHORT angleFrom, SHORT angleTo, WORD outLineColor); |
||
58 | WORD GetColorShade(WORD color, BYTE shade); |
||
59 | WORD ChParseShowData(DATASERIES *pData); |
||
60 | DATASERIES *ChGetNextShowData(DATASERIES *pData); |
||
61 | SHORT ChSetDataSeries(CHART *pCh, WORD seriesNum, BYTE status); |
||
62 | |||
63 | // array used to define the default colors used to draw the bars or sectors of the chart |
||
64 | const WORD ChartVarClr[16] = { CH_CLR0, CH_CLR1, CH_CLR2, CH_CLR3, |
||
65 | CH_CLR4, CH_CLR5, CH_CLR6, CH_CLR7, |
||
66 | CH_CLR8, CH_CLR9, CH_CLR10,CH_CLR11, |
||
67 | CH_CLR12,CH_CLR13,CH_CLR14,CH_CLR15}; |
||
68 | |||
69 | /********************************************************************* |
||
70 | * Function: CHART *ChCreate(WORD ID, SHORT left, SHORT top, SHORT right, |
||
71 | * SHORT bottom, WORD state ,CHARTDATA *pData, |
||
72 | * GOL_SCHEME *pScheme) |
||
73 | * |
||
74 | * |
||
75 | * Notes: Creates a CHART object and adds it to the current active list. |
||
76 | * If the creation is successful, the pointer to the created Object |
||
77 | * is returned. If not successful, NULL is returned. |
||
78 | * |
||
79 | ********************************************************************/ |
||
80 | CHART *ChCreate |
||
81 | ( |
||
82 | WORD ID, |
||
83 | SHORT left, |
||
84 | SHORT top, |
||
85 | SHORT right, |
||
86 | SHORT bottom, |
||
87 | WORD state, |
||
88 | DATASERIES *pData, |
||
89 | CHARTPARAM *pParam, |
||
90 | GOL_SCHEME *pScheme |
||
91 | ) |
||
92 | { |
||
93 | CHART *pCh = NULL; |
||
94 | |||
95 | pCh = (CHART *)GFX_malloc(sizeof(CHART)); |
||
96 | |||
97 | if(pCh == NULL) |
||
98 | return (NULL); |
||
99 | |||
100 | pCh->hdr.ID = ID; // unique id assigned for referencing |
||
101 | pCh->hdr.pNxtObj = NULL; // initialize pointer to NULL |
||
102 | pCh->hdr.type = OBJ_CHART; // set object type |
||
103 | pCh->hdr.left = left; // left position |
||
104 | pCh->hdr.top = top; // top position |
||
105 | pCh->hdr.right = right; // right position |
||
106 | pCh->hdr.bottom = bottom; // bottom position |
||
107 | pCh->hdr.state = state; // state |
||
108 | if(pParam != NULL) |
||
109 | { |
||
110 | pCh->prm.pTitle = pParam->pTitle; |
||
111 | pCh->prm.pSmplLabel = pParam->pSmplLabel; |
||
112 | pCh->prm.pValLabel = pParam->pValLabel; |
||
113 | pCh->prm.smplStart = pParam->smplStart; |
||
114 | pCh->prm.smplEnd = pParam->smplEnd; |
||
115 | pCh->prm.valMax = pParam->valMax; |
||
116 | pCh->prm.valMin = pParam->valMin; |
||
117 | pCh->prm.pColor = pParam->pColor; |
||
118 | pCh->prm.pTitleFont = pParam->pTitleFont; |
||
119 | pCh->prm.pAxisLabelsFont = pParam->pAxisLabelsFont; |
||
120 | pCh->prm.pGridLabelsFont = pParam->pGridLabelsFont; |
||
121 | } |
||
122 | else |
||
123 | { |
||
124 | pCh->prm.pTitle = NULL; |
||
125 | pCh->prm.pSmplLabel = NULL; |
||
126 | pCh->prm.pValLabel = NULL; |
||
127 | pCh->prm.smplStart = 0; |
||
128 | pCh->prm.smplEnd = 0; |
||
129 | pCh->prm.valMax = 0; |
||
130 | pCh->prm.valMin = 0; |
||
131 | |||
132 | // use the default color table |
||
133 | pCh->prm.pColor = (WORD *)ChartVarClr; |
||
134 | pCh->prm.pTitleFont = _pDefaultGolScheme->pFont; |
||
135 | pCh->prm.pAxisLabelsFont = _pDefaultGolScheme->pFont; |
||
136 | pCh->prm.pGridLabelsFont = _pDefaultGolScheme->pFont; |
||
137 | } |
||
138 | |||
139 | pCh->pChData = pData; // assign the chart data |
||
140 | |||
141 | // check if how variables have SHOW_DATA flag set |
||
142 | pCh->prm.seriesCount = ChParseShowData(pData); |
||
143 | |||
144 | // Set the color scheme to be used |
||
145 | if(pScheme == NULL) |
||
146 | { |
||
147 | pCh->hdr.pGolScheme = _pDefaultGolScheme; |
||
148 | } |
||
149 | else |
||
150 | { |
||
151 | pCh->hdr.pGolScheme = (GOL_SCHEME *)pScheme; |
||
152 | pCh->prm.pTitleFont = pCh->hdr.pGolScheme->pFont; |
||
153 | pCh->prm.pAxisLabelsFont = pCh->hdr.pGolScheme->pFont; |
||
154 | pCh->prm.pGridLabelsFont = pCh->hdr.pGolScheme->pFont; |
||
155 | } |
||
156 | |||
157 | GOLAddObject((OBJ_HEADER *)pCh); |
||
158 | |||
159 | return (pCh); |
||
160 | } |
||
161 | |||
162 | /********************************************************************* |
||
163 | * Function: WORD ChTranslateMsg(CHART *pCh, GOL_MSG *pMsg) |
||
164 | * |
||
165 | * Notes: Evaluates the message if the object will be affected by the |
||
166 | * message or not. |
||
167 | * |
||
168 | ********************************************************************/ |
||
169 | WORD ChTranslateMsg(CHART *pCh, GOL_MSG *pMsg) |
||
170 | { |
||
171 | |||
172 | // Evaluate if the message is for the static text |
||
173 | // Check if disabled first |
||
174 | if(GetState(pCh, CH_DISABLED)) |
||
175 | return (OBJ_MSG_INVALID); |
||
176 | |||
177 | #ifdef USE_TOUCHSCREEN |
||
178 | if(pMsg->type == TYPE_TOUCHSCREEN) |
||
179 | { |
||
180 | |||
181 | // Check if it falls in static text control borders |
||
182 | if |
||
183 | ( |
||
184 | (pCh->hdr.left < pMsg->param1) && |
||
185 | (pCh->hdr.right > pMsg->param1) && |
||
186 | (pCh->hdr.top < pMsg->param2) && |
||
187 | (pCh->hdr.bottom > pMsg->param2) |
||
188 | ) |
||
189 | { |
||
190 | return (CH_MSG_SELECTED); |
||
191 | } |
||
192 | } |
||
193 | |||
194 | #endif |
||
195 | return (OBJ_MSG_INVALID); |
||
196 | } |
||
197 | |||
198 | //////////////////////////////////////////////// |
||
199 | |||
200 | // internal functions |
||
201 | //////////////////////////////////////////////// |
||
202 | DATASERIES *ChGetNextShowData(DATASERIES *pData) |
||
203 | { |
||
204 | DATASERIES *pVar = pData; |
||
205 | |||
206 | // find the next data series that will be shown |
||
207 | while(pVar->show != SHOW_DATA) |
||
208 | { |
||
209 | if((pVar = (DATASERIES *)pVar->pNextData) == NULL) |
||
210 | return (NULL); |
||
211 | } |
||
212 | |||
213 | return (pVar); |
||
214 | } |
||
215 | |||
216 | /* */ |
||
217 | WORD ChParseShowData(DATASERIES *pData) |
||
218 | { |
||
219 | DATASERIES *pParse; |
||
220 | WORD sCnt = 0; |
||
221 | |||
222 | if(pData != NULL) |
||
223 | { |
||
224 | pParse = pData; |
||
225 | while(pParse != NULL) |
||
226 | { |
||
227 | if(pParse->show == SHOW_DATA) |
||
228 | sCnt++; |
||
229 | pParse = (DATASERIES *)pParse->pNextData; |
||
230 | } |
||
231 | } |
||
232 | |||
233 | return (sCnt); |
||
234 | } |
||
235 | |||
236 | /* */ |
||
237 | WORD GetLongestNameLength(CHART *pCh) |
||
238 | { |
||
239 | WORD temp = 0; |
||
240 | DATASERIES *pVar; |
||
241 | |||
242 | if(!GetState(pCh, CH_LEGEND)) |
||
243 | return (0); |
||
244 | |||
245 | // find the data series with the longest name |
||
246 | pVar = pCh->pChData; |
||
247 | |||
248 | while(pVar) |
||
249 | { |
||
250 | |||
251 | // check if the data series is to be shown |
||
252 | if(pVar->show == SHOW_DATA) |
||
253 | { |
||
254 | if(temp < GetTextWidth((XCHAR *)pVar->pSData, pCh->hdr.pGolScheme->pFont)) |
||
255 | temp = GetTextWidth((XCHAR *)pVar->pSData, pCh->hdr.pGolScheme->pFont); |
||
256 | } |
||
257 | |||
258 | pVar = pVar->pNextData; |
||
259 | } |
||
260 | |||
261 | return (temp); |
||
262 | } |
||
263 | |||
264 | /* */ |
||
265 | WORD word2xchar(WORD pSmple, XCHAR *xcharArray, WORD cnt) |
||
266 | { |
||
267 | WORD j, z; |
||
268 | static XCHAR *pXchar; |
||
269 | |||
270 | pXchar = xcharArray; |
||
271 | |||
272 | // this implements sprintf(strVal, "%d", temp); faster |
||
273 | // note that this is just for values >= 0, while sprintf covers negative values. |
||
274 | j = 1; |
||
275 | z = pSmple; |
||
276 | |||
277 | pXchar = &(*xcharArray) + (cnt - j); |
||
278 | do |
||
279 | { |
||
280 | *pXchar = (z % 10) + '0'; |
||
281 | *pXchar--; |
||
282 | if((z /= 10) == 0) |
||
283 | break; |
||
284 | j++; |
||
285 | } while(j <= cnt); |
||
286 | return (j); |
||
287 | } |
||
288 | |||
289 | /********************************************************************* |
||
290 | * Function: WORD GetColorShade(WORD color, BYTE shade) |
||
291 | * |
||
292 | * |
||
293 | * Notes: This function gets the given color in 5-6-5 (RGB) format |
||
294 | * and computes the shade of the same color by shifting |
||
295 | * the rgb values depending on the shade value. |
||
296 | * The idea here is to get the given r,g and b colors and |
||
297 | * make them approach the gray color by shifting the each value |
||
298 | * closer to 128. If rgb values are > 128 we subtract and add |
||
299 | * if < 128 we add. |
||
300 | * |
||
301 | ********************************************************************/ |
||
302 | WORD GetColorShade(WORD color, BYTE shade) |
||
303 | { |
||
304 | WORD newColor; |
||
305 | BYTE rgb[3]; |
||
306 | |||
307 | rgb[0] = ((color >> 11) << 3); // red |
||
308 | rgb[1] = ((color >> 5) << 2); // green |
||
309 | rgb[2] = ((color) << 3); // blue |
||
310 | BYTE i; |
||
311 | |||
312 | for(i = 0; i < 3; i++) |
||
313 | { |
||
314 | if(rgb[i] > 128) |
||
315 | rgb[i] = rgb[i] - ((rgb[i] - 128) >> (shade)); |
||
316 | else |
||
317 | rgb[i] = rgb[i] + ((128 - rgb[i]) >> (shade)); |
||
318 | } |
||
319 | |||
320 | newColor = RGB565CONVERT(rgb[0], rgb[1], rgb[2]); |
||
321 | return (newColor); |
||
322 | } |
||
323 | |||
324 | /********************************************************************* |
||
325 | * Function: WORD ChDraw(CHART *pCh) |
||
326 | * |
||
327 | * |
||
328 | * Notes: This is the state machine to draw the button. |
||
329 | * |
||
330 | ********************************************************************/ |
||
331 | #define STR_CHAR_CNT 11 |
||
332 | #define DCLR_STR_CHAR_CNT (STR_CHAR_CNT + 1) |
||
333 | |||
334 | /* */ |
||
335 | |||
336 | WORD ChDraw(CHART *pCh) |
||
337 | { |
||
338 | typedef enum |
||
339 | { |
||
340 | REMOVE, |
||
341 | FRAME_DRAW_PREP, |
||
342 | FRAME_DRAW, |
||
343 | CHECK_CHART_TYPE, |
||
344 | |||
345 | // BAR type states |
||
346 | GRID_PREP, |
||
347 | SAMPLE_GRID_DRAW1, |
||
348 | VALUE_GRID_DRAW1, |
||
349 | SAMPLE_GRID_DRAW2, |
||
350 | VALUE_GRID_DRAW2, |
||
351 | VALUE_GRID_3D_DRAW, |
||
352 | TITLE_LABEL_DRAW_SET, |
||
353 | TITLE_LABEL_DRAW_RUN, |
||
354 | SAMPLE_LABEL_DRAW_SET, |
||
355 | SAMPLE_LABEL_DRAW_RUN, |
||
356 | VALUE_LABEL_DRAW_INIT, |
||
357 | VALUE_LABEL_DRAW_SET, |
||
358 | VALUE_LABEL_DRAW_RUN, |
||
359 | XAXIS_LABEL_DRAW_RUN, |
||
360 | XAXIS_LABEL_DRAW_SET, |
||
361 | YAXIS_LABEL_DRAW_RUN, |
||
362 | YAXIS_LABEL_DRAW_SET, |
||
363 | LEGEND_DRAW_BOX, |
||
364 | LEGEND_DRAW_RUN, |
||
365 | LEGEND_DRAW_UPDATE_VAR, |
||
366 | DATA_DRAW_INIT, |
||
367 | DATA_DRAW_SET, |
||
368 | BAR_DATA_DRAW, |
||
369 | BAR_DATA_DRAW_CHECK, |
||
370 | BAR_DATA_DRAW_3D_PREP, |
||
371 | BAR_DATA_DRAW_3D_LOOP_1, |
||
372 | BAR_DATA_DRAW_3D_LOOP_2, |
||
373 | BAR_DATA_DRAW_3D_OUTLINE1, |
||
374 | BAR_DATA_DRAW_3D_OUTLINE2, |
||
375 | BAR_DATA_DRAW_3D_OUTLINE3, |
||
376 | BAR_DATA_DRAW_3D_OUTLINE4, |
||
377 | BAR_DATA_DRAW_3D_OUTLINE5, |
||
378 | PIE_DONUT_HOLE_DRAW, |
||
379 | BAR_DATA_DRAW_VALUE, |
||
380 | BAR_DATA_DRAW_VALUE_RUN, |
||
381 | |||
382 | // PIE type states |
||
383 | PIE_PREP, |
||
384 | PIE_DRAW_OUTLINE1, |
||
385 | PIE_DRAW_SECTOR, |
||
386 | PIE_DRAW_SECTOR_LOOP, |
||
387 | PIE_DRAW_SECTOR_ACTUAL, |
||
388 | PIE_DRAW_SECTOR_LOOP_CONTINUE, |
||
389 | PIE_DRAW_SECTOR_LOOP_CREATE_STRINGS, |
||
390 | PIE_DRAW_SECTOR_LOOP_STRINGS_RUN, |
||
391 | } CH_DRAW_STATES; |
||
392 | |||
393 | static XCHAR tempXchar[2] = {'B',0}; |
||
394 | static XCHAR temp2Xchar[2] = {'M',0}; |
||
395 | static XCHAR tempStr[DCLR_STR_CHAR_CNT] = {'0','0','0','0','0','0','0','0','0','0',0}; |
||
396 | |||
397 | static CH_DRAW_STATES state = REMOVE; |
||
398 | static WORD x, y, z, xStart, yStart, ctr, ctry, samplesMax, temp; |
||
399 | static SHORT uLocator; |
||
400 | static WORD splDelta, valDelta; |
||
401 | static WORD barWidth, barDepth, chart3DDepth; |
||
402 | |||
403 | static DATASERIES *pVar; |
||
404 | static WORD *pSmple; |
||
405 | static XCHAR *pXcharTemp; |
||
406 | static DWORD dTemp; |
||
407 | static SHORT varCtr, pieX, pieY; |
||
408 | static DWORD dPercent; |
||
409 | static WORD j = 0, k = 0, h = 0, i, m; |
||
410 | static void *pVarFont; |
||
411 | |||
412 | static WORD pieLabelXPos; |
||
413 | static WORD pieLabelYPos, pieLabelYPos2, pieLabelYPos3; |
||
414 | static WORD pieSectorXPos; |
||
415 | static WORD pieSectorYPos; |
||
416 | |||
417 | if(IsDeviceBusy()) |
||
418 | return (0); |
||
419 | |||
420 | switch(state) |
||
421 | { |
||
422 | case REMOVE: |
||
423 | if(IsDeviceBusy()) |
||
424 | return (0); |
||
425 | |||
426 | if(GetState(pCh, CH_HIDE)) |
||
427 | { // Hide the Chart (remove from screen) |
||
428 | SetColor(pCh->hdr.pGolScheme->CommonBkColor); |
||
429 | if(!Bar(pCh->hdr.left, pCh->hdr.top, pCh->hdr.right, pCh->hdr.bottom)) |
||
430 | return (0); |
||
431 | return (1); |
||
432 | } |
||
433 | |||
434 | SetLineThickness(NORMAL_LINE); |
||
435 | SetLineType(SOLID_LINE); |
||
436 | |||
437 | // check if we only need to refresh the data on the chart |
||
438 | if(GetState(pCh, CH_DRAW_DATA)) |
||
439 | { |
||
440 | |||
441 | // this is only performed when refreshing data in the chart |
||
442 | // erase the current contents |
||
443 | SetColor(pCh->hdr.pGolScheme->CommonBkColor); |
||
444 | |||
445 | // get the ending x position where redraw will take place (if legend is drawn, |
||
446 | // we do not need to redraw this area) |
||
447 | i = GetLongestNameLength(pCh) + GetTextHeight(pCh->hdr.pGolScheme->pFont) + GOL_EMBOSS_SIZE + (CH_MARGIN << 1); |
||
448 | |||
449 | if(GetState(pCh, CH_BAR)) |
||
450 | { |
||
451 | |||
452 | // get the starting x position where redraw will take place |
||
453 | h = xStart - GetTextWidth(tempXchar, pCh->prm.pGridLabelsFont) - (GetTextWidth(temp2Xchar, pCh->prm.pGridLabelsFont) >> 1); |
||
454 | |||
455 | // get the starting y position |
||
456 | j = yStart - ((ChGetSampleRange(pCh) + 1) * splDelta); |
||
457 | if(GetState(pCh, CH_3D_ENABLE)) |
||
458 | { |
||
459 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
460 | { |
||
461 | |||
462 | // adjust for 3D effects |
||
463 | j -= chart3DDepth; |
||
464 | if((GetState(pCh, CH_LEGEND)) && (ChGetShowSeriesCount(pCh) != 1)) |
||
465 | { |
||
466 | if(!Bar(h, j, pCh->hdr.right - i, yStart)) |
||
467 | return (0); |
||
468 | } |
||
469 | else |
||
470 | { |
||
471 | if(!Bar(h, j, pCh->hdr.right - CH_MARGIN, yStart)) |
||
472 | return (0); |
||
473 | } |
||
474 | } |
||
475 | else |
||
476 | { |
||
477 | if |
||
478 | ( |
||
479 | !Bar |
||
480 | ( |
||
481 | xStart, |
||
482 | yStart - ((CH_YGRIDCOUNT - 1) * valDelta) - chart3DDepth - (GetTextHeight(pCh->hdr.pGolScheme->pFont)), |
||
483 | xStart + splDelta * (ChGetSampleRange(pCh) + 1) + chart3DDepth, |
||
484 | yStart + GetTextHeight(pCh->prm.pGridLabelsFont) |
||
485 | ) |
||
486 | ) return (0); |
||
487 | } |
||
488 | } |
||
489 | else |
||
490 | { |
||
491 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
492 | { |
||
493 | if((GetState(pCh, CH_LEGEND)) && (ChGetShowSeriesCount(pCh) != 1)) |
||
494 | { |
||
495 | if(!Bar(h, j, pCh->hdr.right - i, yStart)) |
||
496 | return (0); |
||
497 | } |
||
498 | else |
||
499 | { |
||
500 | if(!Bar(h, j, pCh->hdr.right - CH_MARGIN, yStart)) |
||
501 | return (0); |
||
502 | } |
||
503 | } |
||
504 | else |
||
505 | { |
||
506 | if |
||
507 | ( |
||
508 | !Bar |
||
509 | ( |
||
510 | xStart, |
||
511 | yStart - ((CH_YGRIDCOUNT - 1) * valDelta) - (GetTextHeight(pCh->hdr.pGolScheme->pFont)), |
||
512 | xStart + splDelta * (ChGetSampleRange(pCh) + 1), |
||
513 | yStart + GetTextHeight(pCh->prm.pGridLabelsFont) |
||
514 | ) |
||
515 | ) return (0); |
||
516 | } |
||
517 | } |
||
518 | } |
||
519 | else |
||
520 | { |
||
521 | if((GetState(pCh, CH_LEGEND)) && (ChGetShowSeriesCount(pCh) != 1)) |
||
522 | i = pCh->hdr.right - i; |
||
523 | else |
||
524 | i = pCh->hdr.right - GOL_EMBOSS_SIZE - CH_MARGIN; |
||
525 | h = pCh->hdr.left + GOL_EMBOSS_SIZE; |
||
526 | j = pCh->hdr.top + GOL_EMBOSS_SIZE + CH_MARGIN + GetTextHeight(pCh->prm.pTitleFont); |
||
527 | |||
528 | // erase the current pie chart drawn |
||
529 | if(!Bar(h, j, i, pCh->hdr.bottom - CH_MARGIN)) |
||
530 | return (0); |
||
531 | } |
||
532 | |||
533 | // check the type of chart |
||
534 | if(GetState(pCh, CH_BAR)) |
||
535 | { |
||
536 | state = GRID_PREP; |
||
537 | goto chrt_grid_prep; |
||
538 | } |
||
539 | else |
||
540 | { |
||
541 | state = PIE_PREP; |
||
542 | goto chrt_pie_prep; |
||
543 | } |
||
544 | } |
||
545 | |||
546 | state = FRAME_DRAW_PREP; |
||
547 | |||
548 | /*========================================================================*/ |
||
549 | |||
550 | // Draw the frame |
||
551 | |||
552 | /*========================================================================*/ |
||
553 | case FRAME_DRAW_PREP: |
||
554 | |||
555 | // check how many data series do we need to display |
||
556 | pCh->prm.seriesCount = ChParseShowData(pCh->pChData); |
||
557 | |||
558 | // set up the frame drawing |
||
559 | GOLPanelDraw |
||
560 | ( |
||
561 | pCh->hdr.left, |
||
562 | pCh->hdr.top, |
||
563 | pCh->hdr.right, |
||
564 | pCh->hdr.bottom, |
||
565 | 0, |
||
566 | pCh->hdr.pGolScheme->CommonBkColor, |
||
567 | pCh->hdr.pGolScheme->EmbossLtColor, |
||
568 | pCh->hdr.pGolScheme->EmbossDkColor, |
||
569 | NULL, |
||
570 | 1 |
||
571 | ); |
||
572 | |||
573 | state = FRAME_DRAW; |
||
574 | |||
575 | case FRAME_DRAW: |
||
576 | if(!GOLPanelDrawTsk()) |
||
577 | { |
||
578 | return (0); |
||
579 | } |
||
580 | |||
581 | state = TITLE_LABEL_DRAW_SET; |
||
582 | |||
583 | /*========================================================================*/ |
||
584 | |||
585 | // Draw the Chart Title |
||
586 | |||
587 | /*========================================================================*/ |
||
588 | case TITLE_LABEL_DRAW_SET: |
||
589 | |||
590 | // find the location of the title |
||
591 | MoveTo |
||
592 | ( |
||
593 | pCh->hdr.left + ((pCh->hdr.right + pCh->hdr.left - GetTextWidth((XCHAR *)pCh->prm.pTitle, pCh->prm.pTitleFont)) >> 1), |
||
594 | pCh->hdr.top + CH_MARGIN |
||
595 | ); |
||
596 | state = TITLE_LABEL_DRAW_RUN; |
||
597 | |||
598 | case TITLE_LABEL_DRAW_RUN: |
||
599 | |||
600 | // Set the font |
||
601 | SetFont(pCh->prm.pTitleFont); |
||
602 | |||
603 | // NOTE: we use the emboss dark color here to draw the chart title. |
||
604 | SetColor(pCh->hdr.pGolScheme->EmbossDkColor); |
||
605 | |||
606 | if(!OutText(pCh->prm.pTitle)) |
||
607 | return (0); |
||
608 | |||
609 | // check if legend will be drawn |
||
610 | if(GetState(pCh, CH_LEGEND) && (ChGetShowSeriesCount(pCh) != 1)) |
||
611 | { |
||
612 | |||
613 | // position the x and y points to the start of the first variable |
||
614 | temp = GetLongestNameLength(pCh); |
||
615 | |||
616 | x = pCh->hdr.right - (CH_MARGIN << 1) - temp - GetTextHeight(pCh->hdr.pGolScheme->pFont); |
||
617 | y = ((pCh->hdr.bottom + pCh->hdr.top) >> 1) - ((pCh->prm.seriesCount * GetTextHeight(pCh->hdr.pGolScheme->pFont)) >> 1); |
||
618 | |||
619 | // initialize the variable counter for the legend drawing |
||
620 | temp = 0; |
||
621 | pVar = (DATASERIES *)pCh->pChData; |
||
622 | state = LEGEND_DRAW_BOX; |
||
623 | } |
||
624 | else |
||
625 | { |
||
626 | |||
627 | // legend will not be drawn, go to data drawing next |
||
628 | state = CHECK_CHART_TYPE; |
||
629 | goto chrt_check_chart_type; |
||
630 | } |
||
631 | |||
632 | /*========================================================================*/ |
||
633 | |||
634 | // Draw the Legend |
||
635 | |||
636 | /*========================================================================*/ |
||
637 | chrt_draw_legend: |
||
638 | |||
639 | case LEGEND_DRAW_BOX: |
||
640 | |||
641 | // check if we will be showing this data series |
||
642 | if(ChGetShowSeriesStatus(pVar) == SHOW_DATA) |
||
643 | { |
||
644 | SetColor(*(&(*pCh->prm.pColor) + temp)); |
||
645 | if((ChGetShowSeriesCount(pCh) == 1) && (GetState(pCh, CH_PIE))) |
||
646 | { } |
||
647 | else |
||
648 | { |
||
649 | if |
||
650 | ( |
||
651 | !Bar |
||
652 | ( |
||
653 | x, |
||
654 | y + (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 2), |
||
655 | x + (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 1), |
||
656 | y + |
||
657 | ( |
||
658 | GetTextHeight(pCh->hdr.pGolScheme->pFont) - |
||
659 | (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 2) |
||
660 | ) |
||
661 | ) |
||
662 | ) return (0); |
||
663 | } |
||
664 | |||
665 | MoveTo(x + 2 + (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 1), y); |
||
666 | state = LEGEND_DRAW_RUN; |
||
667 | } |
||
668 | else |
||
669 | { |
||
670 | state = LEGEND_DRAW_UPDATE_VAR; |
||
671 | goto chrt_draw_legend_update; |
||
672 | } |
||
673 | |||
674 | case LEGEND_DRAW_RUN: |
||
675 | SetColor(pCh->hdr.pGolScheme->TextColor1); |
||
676 | SetFont(pCh->hdr.pGolScheme->pFont); |
||
677 | |||
678 | if(!OutText(pVar->pSData)) |
||
679 | return (0); |
||
680 | |||
681 | // increment the variable counter |
||
682 | temp++; |
||
683 | if(temp == ChGetShowSeriesCount(pCh)) |
||
684 | { |
||
685 | state = CHECK_CHART_TYPE; |
||
686 | goto chrt_check_chart_type; |
||
687 | } |
||
688 | else |
||
689 | state = LEGEND_DRAW_UPDATE_VAR; |
||
690 | |||
691 | chrt_draw_legend_update: |
||
692 | |||
693 | case LEGEND_DRAW_UPDATE_VAR: |
||
694 | |||
695 | // update the data series pointer and y position |
||
696 | if(ChGetShowSeriesStatus(pVar) == SHOW_DATA) |
||
697 | y += GetTextHeight(pCh->hdr.pGolScheme->pFont); |
||
698 | pVar = (DATASERIES *)pVar->pNextData; |
||
699 | state = LEGEND_DRAW_BOX; |
||
700 | goto chrt_draw_legend; |
||
701 | |||
702 | chrt_check_chart_type: |
||
703 | |||
704 | case CHECK_CHART_TYPE: |
||
705 | if(GetState(pCh, CH_BAR)) |
||
706 | { |
||
707 | state = GRID_PREP; |
||
708 | } |
||
709 | else if(GetState(pCh, CH_PIE)) |
||
710 | { |
||
711 | state = PIE_PREP; |
||
712 | goto chrt_pie_prep; |
||
713 | } |
||
714 | else |
||
715 | { |
||
716 | state = REMOVE; |
||
717 | return (1); |
||
718 | } |
||
719 | |||
720 | /**************************************************************************/ |
||
721 | |||
722 | // BAR CHART states |
||
723 | |||
724 | /**************************************************************************/ |
||
725 | |||
726 | /*========================================================================*/ |
||
727 | |||
728 | // Draw the grids |
||
729 | |||
730 | /*========================================================================*/ |
||
731 | chrt_grid_prep: |
||
732 | |||
733 | case GRID_PREP: |
||
734 | |||
735 | /* NOTE: X or Y Grid Labels - label for each division in the x or y axis |
||
736 | X or Y Axis Labels - label to name the x or y axis. Text is |
||
737 | user given in the CHART structure, |
||
738 | CHARTPARAM member. |
||
739 | */ |
||
740 | |||
741 | // count the number of characters needed for the axis label that |
||
742 | // represents the value of the samples (or bars) |
||
743 | // get the width of one character |
||
744 | temp = GetTextWidth((XCHAR *)tempXchar, pCh->prm.pGridLabelsFont); |
||
745 | |||
746 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
747 | { |
||
748 | |||
749 | // if in the horizontal orientation width will only be |
||
750 | // max of 2 characters (1, 2, 3...10, 11... or A, B, C...) |
||
751 | if((ChGetSampleEnd(pCh) - ChGetSampleStart(pCh)) > 9) |
||
752 | y = 2; |
||
753 | else |
||
754 | y = 1; |
||
755 | } |
||
756 | else |
||
757 | { |
||
758 | if(GetState(pCh, CH_PERCENT)) |
||
759 | { |
||
760 | |||
761 | // include in the computation the space that will be occupied by '%' sign |
||
762 | y = 4; |
||
763 | } |
||
764 | else |
||
765 | { |
||
766 | x = ChGetValueRange(pCh); |
||
767 | y = 1; |
||
768 | |||
769 | // count the number of characters needed |
||
770 | while(x /= 10) |
||
771 | ++y; |
||
772 | } |
||
773 | } |
||
774 | |||
775 | // estimate the space that will be occupied by the y grid labels |
||
776 | temp = temp * y; |
||
777 | |||
778 | // get x starting position |
||
779 | xStart = CH_MARGIN + temp + pCh->hdr.left; |
||
780 | |||
781 | // adjust x start to accomodate Y axis label |
||
782 | xStart += (GetTextHeight(pCh->prm.pAxisLabelsFont) + (GetTextWidth(temp2Xchar, pCh->prm.pGridLabelsFont) >> 1)); |
||
783 | |||
784 | // now get y starting position |
||
785 | yStart = pCh->hdr.bottom - (GetTextHeight(pCh->prm.pGridLabelsFont) + GetTextHeight(pCh->prm.pAxisLabelsFont) + CH_MARGIN); |
||
786 | |||
787 | // ======================================================================= |
||
788 | // Sample delta (splDelta) and Value delta (valDelta) will depend if the |
||
789 | // chart is drawn horizontally or vertically. |
||
790 | // ======================================================================= |
||
791 | // find the variable with the longest name |
||
792 | // to add space for the names of variables in the legend |
||
793 | // Text Height here refers to the legend for colors (the drawn filled rectangle) |
||
794 | if((ChGetShowSeriesCount(pCh) == 1) || (GetState(pCh, CH_LEGEND) != CH_LEGEND)) |
||
795 | temp = 0; |
||
796 | else |
||
797 | temp = GetLongestNameLength(pCh) + GetTextHeight(pCh->hdr.pGolScheme->pFont); |
||
798 | |||
799 | // get sample delta (space between data) and value delta (defines the grid for the value) |
||
800 | // check first if we compute in the x-axis or y-axis |
||
801 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
802 | { |
||
803 | |||
804 | // if horizontally drawn sample delta is not affected by the legend |
||
805 | splDelta = (yStart - (pCh->hdr.top + CH_MARGIN + GetTextHeight(pCh->prm.pTitleFont))); |
||
806 | |||
807 | // adjust space for displayed values |
||
808 | if(GetState(pCh, CH_VALUE)) |
||
809 | { |
||
810 | temp += (GetTextWidth(tempXchar, pCh->hdr.pGolScheme->pFont) * 4); |
||
811 | } |
||
812 | |||
813 | // get the value delta, |
||
814 | valDelta = (pCh->hdr.right - xStart - CH_MARGIN - temp); |
||
815 | } |
||
816 | else |
||
817 | { |
||
818 | if(GetState(pCh, CH_LEGEND) && (ChGetShowSeriesCount(pCh) != 1)) |
||
819 | { |
||
820 | splDelta = |
||
821 | ( |
||
822 | pCh->hdr.right - |
||
823 | xStart - |
||
824 | ((CH_MARGIN << 2) + temp + GetTextHeight(pCh->hdr.pGolScheme->pFont)) |
||
825 | ); |
||
826 | } |
||
827 | else |
||
828 | { |
||
829 | splDelta = (pCh->hdr.right - xStart - (CH_MARGIN << 2)); |
||
830 | } |
||
831 | |||
832 | // get the value delta |
||
833 | valDelta = |
||
834 | ( |
||
835 | yStart - |
||
836 | (pCh->hdr.top + CH_MARGIN + GetTextHeight(pCh->prm.pTitleFont) + GetTextHeight(pCh->hdr.pGolScheme->pFont)) |
||
837 | ); |
||
838 | } |
||
839 | |||
840 | // adjust the splDelta for 3D effects, 12 here is the maximum depth of a bar for the 3D effect |
||
841 | if(GetState(pCh, CH_3D_ENABLE)) |
||
842 | { |
||
843 | splDelta -= 12; |
||
844 | valDelta -= 12; |
||
845 | } |
||
846 | |||
847 | // get the final splDelta value by checking the number of samples to display |
||
848 | splDelta /= (ChGetSampleRange(pCh) + 1); |
||
849 | |||
850 | // get the final valDelta value by checking the number of samples to display |
||
851 | valDelta /= (CH_YGRIDCOUNT - 1); |
||
852 | |||
853 | // initilize the counter for the sample axis drawing |
||
854 | temp = ChGetSampleRange(pCh) + 2; |
||
855 | x = xStart; |
||
856 | y = yStart; |
||
857 | state = SAMPLE_GRID_DRAW1; |
||
858 | |||
859 | case SAMPLE_GRID_DRAW1: |
||
860 | |||
861 | // draw the small grids on the x-axis |
||
862 | while(temp) |
||
863 | { |
||
864 | SetColor(pCh->hdr.pGolScheme->Color0); |
||
865 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
866 | { |
||
867 | if(!Bar(x, y, x + 3, y + 1)) |
||
868 | return (0); |
||
869 | y -= splDelta; |
||
870 | } |
||
871 | else |
||
872 | { |
||
873 | if(!Bar(x, y, x + 1, y + 3)) |
||
874 | return (0); |
||
875 | x += splDelta; |
||
876 | } |
||
877 | |||
878 | --temp; |
||
879 | } |
||
880 | |||
881 | // get the bar width (bar here refers to the sample data represented as bars, where the height |
||
882 | // of the bar represents the value of the sample) |
||
883 | barWidth = splDelta / (2 + ChGetShowSeriesCount(pCh)); |
||
884 | |||
885 | temp = CH_YGRIDCOUNT; |
||
886 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
887 | y = yStart; |
||
888 | else |
||
889 | x = xStart; |
||
890 | |||
891 | if(GetState(pCh, CH_3D_ENABLE)) |
||
892 | { |
||
893 | |||
894 | // limit the 3-D depth to only 12 pixels. |
||
895 | chart3DDepth = (barWidth > 12) ? 12 : barWidth; |
||
896 | chart3DDepth = chart3DDepth >> 1; |
||
897 | |||
898 | // set the bar 3-D depth. |
||
899 | barDepth = chart3DDepth; |
||
900 | state = VALUE_GRID_3D_DRAW; |
||
901 | } |
||
902 | else |
||
903 | { |
||
904 | state = VALUE_GRID_DRAW1; |
||
905 | goto chrt_value_grid_draw1; |
||
906 | } |
||
907 | |||
908 | case VALUE_GRID_3D_DRAW: |
||
909 | |||
910 | // draw the 3D grids on the value-axis |
||
911 | while(temp) |
||
912 | { |
||
913 | SetColor(pCh->hdr.pGolScheme->Color0); |
||
914 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
915 | { |
||
916 | if |
||
917 | ( |
||
918 | !Bar |
||
919 | ( |
||
920 | x + (chart3DDepth), |
||
921 | y - (chart3DDepth) - (splDelta * (ChGetSampleRange(pCh) + 1)), |
||
922 | x + (chart3DDepth), |
||
923 | y - (chart3DDepth) |
||
924 | ) |
||
925 | ) return (0); |
||
926 | x += valDelta; |
||
927 | } |
||
928 | else |
||
929 | { |
||
930 | if |
||
931 | ( |
||
932 | !Bar |
||
933 | ( |
||
934 | x + (chart3DDepth), |
||
935 | y - (chart3DDepth), |
||
936 | x + (chart3DDepth) + (splDelta * (ChGetSampleRange(pCh) + 1)), |
||
937 | y - (chart3DDepth) |
||
938 | ) |
||
939 | ) return (0); |
||
940 | y -= valDelta; |
||
941 | } |
||
942 | |||
943 | --temp; |
||
944 | } |
||
945 | |||
946 | temp = CH_YGRIDCOUNT; |
||
947 | x = xStart; |
||
948 | y = yStart; |
||
949 | state = VALUE_GRID_DRAW1; |
||
950 | |||
951 | chrt_value_grid_draw1: |
||
952 | |||
953 | case VALUE_GRID_DRAW1: |
||
954 | |||
955 | // draw the grids on the y-axis |
||
956 | if(GetState(pCh, CH_3D_ENABLE)) |
||
957 | { |
||
958 | |||
959 | // just draw the first one to define the x-axis |
||
960 | SetColor(pCh->hdr.pGolScheme->Color0); |
||
961 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
962 | { |
||
963 | if(!Bar(x, y - (splDelta * (ChGetSampleRange(pCh) + 1)), x, y)) |
||
964 | return (0); |
||
965 | } |
||
966 | else |
||
967 | { |
||
968 | if(!Bar(x, y, x + (splDelta * (ChGetSampleRange(pCh) + 1)), y)) |
||
969 | return (0); |
||
970 | } |
||
971 | } |
||
972 | else |
||
973 | { |
||
974 | while(temp) |
||
975 | { |
||
976 | SetColor(pCh->hdr.pGolScheme->Color0); |
||
977 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
978 | { |
||
979 | if(!Bar(x, y - (splDelta * (ChGetSampleRange(pCh) + 1)), x, y)) |
||
980 | return (0); |
||
981 | x += valDelta; |
||
982 | } |
||
983 | else |
||
984 | { |
||
985 | if(!Bar(x, y, x + (splDelta * (ChGetSampleRange(pCh) + 1)), y)) |
||
986 | return (0); |
||
987 | y -= valDelta; |
||
988 | } |
||
989 | |||
990 | --temp; |
||
991 | } |
||
992 | } |
||
993 | |||
994 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
995 | { |
||
996 | x = xStart; |
||
997 | } |
||
998 | else |
||
999 | { |
||
1000 | y = yStart; |
||
1001 | } |
||
1002 | |||
1003 | if(GetState(pCh, CH_3D_ENABLE)) |
||
1004 | { |
||
1005 | temp = CH_YGRIDCOUNT + 1; |
||
1006 | state = VALUE_GRID_DRAW2; |
||
1007 | } |
||
1008 | else |
||
1009 | { |
||
1010 | temp = 2; |
||
1011 | state = SAMPLE_GRID_DRAW2; |
||
1012 | goto chrt_xgrid_draw2; |
||
1013 | } |
||
1014 | |||
1015 | case VALUE_GRID_DRAW2: |
||
1016 | |||
1017 | // draw the 3-D effect on the y axis of the chart |
||
1018 | SetColor(pCh->hdr.pGolScheme->Color0); |
||
1019 | while(temp) |
||
1020 | { |
||
1021 | if(temp == (CH_YGRIDCOUNT + 1)) |
||
1022 | { |
||
1023 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1024 | { |
||
1025 | if |
||
1026 | ( |
||
1027 | !Line |
||
1028 | ( |
||
1029 | x, |
||
1030 | y - (splDelta * (ChGetSampleRange(pCh) + 1)), |
||
1031 | x + chart3DDepth, |
||
1032 | y - (splDelta * (ChGetSampleRange(pCh) + 1)) - chart3DDepth |
||
1033 | ) |
||
1034 | ) return (0); |
||
1035 | } |
||
1036 | else |
||
1037 | { |
||
1038 | if |
||
1039 | ( |
||
1040 | !Line |
||
1041 | ( |
||
1042 | x + (splDelta * (ChGetSampleRange(pCh) + 1)), |
||
1043 | y, |
||
1044 | x + (chart3DDepth) + (splDelta * (ChGetSampleRange(pCh) + 1)), |
||
1045 | y - chart3DDepth |
||
1046 | ) |
||
1047 | ) return (0); |
||
1048 | } |
||
1049 | |||
1050 | --temp; |
||
1051 | continue; |
||
1052 | } |
||
1053 | else if(!Line(x, y, x + chart3DDepth, y - chart3DDepth)) |
||
1054 | return (0); |
||
1055 | |||
1056 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1057 | { |
||
1058 | x += valDelta; |
||
1059 | } |
||
1060 | else |
||
1061 | { |
||
1062 | y -= valDelta; |
||
1063 | } |
||
1064 | |||
1065 | --temp; |
||
1066 | } |
||
1067 | |||
1068 | temp = 3; |
||
1069 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1070 | { |
||
1071 | x = xStart; |
||
1072 | } |
||
1073 | else |
||
1074 | { |
||
1075 | y = yStart; |
||
1076 | } |
||
1077 | |||
1078 | state = SAMPLE_GRID_DRAW2; |
||
1079 | |||
1080 | chrt_xgrid_draw2: |
||
1081 | |||
1082 | case SAMPLE_GRID_DRAW2: |
||
1083 | |||
1084 | // draw the left and right edges of the chart |
||
1085 | while(temp) |
||
1086 | { |
||
1087 | if(GetState(pCh, CH_3D_ENABLE)) |
||
1088 | { |
||
1089 | if(temp == 3) |
||
1090 | { |
||
1091 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1092 | { |
||
1093 | if(!Bar(x, y, x + ((CH_YGRIDCOUNT - 1) * valDelta), y)) |
||
1094 | return (0); |
||
1095 | } |
||
1096 | else |
||
1097 | { |
||
1098 | if(!Bar(x, y - ((CH_YGRIDCOUNT - 1) * valDelta), x, y)) |
||
1099 | return (0); |
||
1100 | } |
||
1101 | |||
1102 | --temp; |
||
1103 | continue; |
||
1104 | } |
||
1105 | else if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1106 | { |
||
1107 | if |
||
1108 | ( |
||
1109 | !Bar |
||
1110 | ( |
||
1111 | x + chart3DDepth, |
||
1112 | y - chart3DDepth, |
||
1113 | x + chart3DDepth + ((CH_YGRIDCOUNT - 1) * valDelta), |
||
1114 | y - chart3DDepth |
||
1115 | ) |
||
1116 | ) return (0); |
||
1117 | } |
||
1118 | else |
||
1119 | { |
||
1120 | if |
||
1121 | ( |
||
1122 | !Bar |
||
1123 | ( |
||
1124 | x + chart3DDepth, |
||
1125 | y - ((CH_YGRIDCOUNT - 1) * valDelta) - chart3DDepth, |
||
1126 | x + chart3DDepth, |
||
1127 | y - chart3DDepth |
||
1128 | ) |
||
1129 | ) return (0); |
||
1130 | } |
||
1131 | } |
||
1132 | else |
||
1133 | { |
||
1134 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1135 | { |
||
1136 | if(!Bar(x, y, x + ((CH_YGRIDCOUNT - 1) * valDelta), y)) |
||
1137 | return (0); |
||
1138 | } |
||
1139 | else |
||
1140 | { |
||
1141 | if(!Bar(x, y - ((CH_YGRIDCOUNT - 1) * valDelta), x, y)) |
||
1142 | return (0); |
||
1143 | } |
||
1144 | } |
||
1145 | |||
1146 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1147 | { |
||
1148 | y -= (splDelta * (ChGetSampleRange(pCh) + 1)); |
||
1149 | } |
||
1150 | else |
||
1151 | { |
||
1152 | x += (splDelta * (ChGetSampleRange(pCh) + 1)); |
||
1153 | } |
||
1154 | |||
1155 | --temp; |
||
1156 | } |
||
1157 | |||
1158 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1159 | #ifdef USE_HORZ_ASCENDING_ORDER |
||
1160 | y = yStart - (ChGetSampleRange(pCh) * splDelta); |
||
1161 | #else |
||
1162 | y = yStart; |
||
1163 | #endif |
||
1164 | else |
||
1165 | x = xStart; |
||
1166 | ctr = ChGetSampleStart(pCh); |
||
1167 | |||
1168 | state = SAMPLE_LABEL_DRAW_SET; |
||
1169 | |||
1170 | /*========================================================================*/ |
||
1171 | |||
1172 | // Draw the Sample Grid labels |
||
1173 | |||
1174 | /*========================================================================*/ |
||
1175 | chrt_sample_label_draw_set: |
||
1176 | |||
1177 | case SAMPLE_LABEL_DRAW_SET: |
||
1178 | |||
1179 | // for data only redraw, we need to refresh the x-axis labels to indicate |
||
1180 | // the correct sample points being shown |
||
1181 | SetFont(pCh->prm.pGridLabelsFont); |
||
1182 | |||
1183 | if(GetState(pCh, CH_NUMERIC)) |
||
1184 | { |
||
1185 | j = word2xchar(ctr, tempStr, STR_CHAR_CNT); |
||
1186 | } |
||
1187 | else |
||
1188 | { |
||
1189 | |||
1190 | // note that we will only have A-Z labels. |
||
1191 | tempStr[STR_CHAR_CNT - 1] = 'A' + (ctr - 1); |
||
1192 | j = 1; |
||
1193 | } |
||
1194 | |||
1195 | temp = GetTextWidth((&tempStr[STR_CHAR_CNT - j]), pCh->prm.pGridLabelsFont); |
||
1196 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1197 | { |
||
1198 | MoveTo(x - temp, y - ((splDelta + GetTextHeight(pCh->prm.pGridLabelsFont)) >> 1)); |
||
1199 | } |
||
1200 | else |
||
1201 | { |
||
1202 | MoveTo(x + ((splDelta - temp) >> 1), y); |
||
1203 | } |
||
1204 | |||
1205 | state = SAMPLE_LABEL_DRAW_RUN; |
||
1206 | |||
1207 | case SAMPLE_LABEL_DRAW_RUN: |
||
1208 | |||
1209 | // draw the x axis grid numbers |
||
1210 | SetColor(pCh->hdr.pGolScheme->TextColor0); |
||
1211 | if(!OutText(&tempStr[STR_CHAR_CNT - j])) |
||
1212 | return (0); |
||
1213 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1214 | { |
||
1215 | #ifdef USE_HORZ_ASCENDING_ORDER |
||
1216 | y += splDelta; |
||
1217 | #else |
||
1218 | y -= splDelta; |
||
1219 | #endif |
||
1220 | } |
||
1221 | else |
||
1222 | { |
||
1223 | x += splDelta; |
||
1224 | } |
||
1225 | |||
1226 | ctr++; |
||
1227 | if(ctr > ChGetSampleEnd(pCh)) |
||
1228 | { |
||
1229 | |||
1230 | // check if we only need to redraw the data |
||
1231 | if(GetState(pCh, CH_DRAW_DATA)) |
||
1232 | { |
||
1233 | state = DATA_DRAW_INIT; |
||
1234 | goto chrt_data_draw_init; |
||
1235 | } |
||
1236 | else |
||
1237 | { |
||
1238 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1239 | { |
||
1240 | state = YAXIS_LABEL_DRAW_SET; |
||
1241 | goto chrt_yaxis_label_draw_set; |
||
1242 | } |
||
1243 | else |
||
1244 | { |
||
1245 | state = XAXIS_LABEL_DRAW_SET; |
||
1246 | } |
||
1247 | } |
||
1248 | } |
||
1249 | else |
||
1250 | { |
||
1251 | temp = x; |
||
1252 | goto chrt_sample_label_draw_set; |
||
1253 | } |
||
1254 | |||
1255 | /*========================================================================*/ |
||
1256 | |||
1257 | // Draw the X - Axis labels |
||
1258 | |||
1259 | /*========================================================================*/ |
||
1260 | chrt_xaxis_label_draw_set: |
||
1261 | |||
1262 | case XAXIS_LABEL_DRAW_SET: |
||
1263 | |||
1264 | // find the location of the label |
||
1265 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1266 | { |
||
1267 | pXcharTemp = pCh->prm.pValLabel; |
||
1268 | uLocator = valDelta * (CH_YGRIDCOUNT - 1); |
||
1269 | } |
||
1270 | else |
||
1271 | { |
||
1272 | pXcharTemp = pCh->prm.pSmplLabel; |
||
1273 | uLocator = splDelta * (ChGetSampleRange(pCh) + 1); |
||
1274 | } |
||
1275 | |||
1276 | temp = GetTextWidth(pXcharTemp, pCh->prm.pAxisLabelsFont); |
||
1277 | |||
1278 | if(temp > uLocator) |
||
1279 | temp = xStart; |
||
1280 | else |
||
1281 | temp = xStart + ((uLocator - temp) >> 1); |
||
1282 | |||
1283 | MoveTo(temp, yStart + GetTextHeight(pCh->prm.pGridLabelsFont)); |
||
1284 | state = XAXIS_LABEL_DRAW_RUN; |
||
1285 | |||
1286 | case XAXIS_LABEL_DRAW_RUN: |
||
1287 | SetFont(pCh->prm.pAxisLabelsFont); |
||
1288 | |||
1289 | // enable clipping and set region |
||
1290 | SetClip(CLIP_ENABLE); |
||
1291 | SetClipRgn(pCh->hdr.left, pCh->hdr.top, pCh->hdr.right, pCh->hdr.bottom); |
||
1292 | |||
1293 | SetColor(pCh->hdr.pGolScheme->TextColor1); |
||
1294 | if(!OutText(pXcharTemp)) |
||
1295 | return (0); |
||
1296 | |||
1297 | SetClip(CLIP_DISABLE); |
||
1298 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1299 | { |
||
1300 | state = DATA_DRAW_INIT; |
||
1301 | goto chrt_data_draw_init; |
||
1302 | } |
||
1303 | else |
||
1304 | { |
||
1305 | state = VALUE_LABEL_DRAW_INIT; |
||
1306 | } |
||
1307 | |||
1308 | chrt_value_label_draw_init: |
||
1309 | |||
1310 | case VALUE_LABEL_DRAW_INIT: |
||
1311 | ctr = 0; |
||
1312 | |||
1313 | // x is used here to represent change in value grid labels |
||
1314 | // Note that we add a multiplier of 10 to compute for round off errors. |
||
1315 | // It will not be perfect but approximations is better unless you work with |
||
1316 | // figures divisible by 5. |
||
1317 | if(GetState(pCh, CH_PERCENT)) |
||
1318 | { |
||
1319 | |||
1320 | // Scaling of the labels is included here |
||
1321 | x = ChGetPercentRange(pCh) * 100 / (CH_YGRIDCOUNT - 1); |
||
1322 | } |
||
1323 | else |
||
1324 | { |
||
1325 | x = (ChGetValueRange(pCh) * 100) / (CH_YGRIDCOUNT - 1); |
||
1326 | } |
||
1327 | |||
1328 | // compute for round off error, the adjustment for the factor 100 is done in |
||
1329 | // conversion of the integer to string below. |
||
1330 | if((x % 10) < 5) |
||
1331 | x += 10; |
||
1332 | |||
1333 | state = VALUE_LABEL_DRAW_SET; |
||
1334 | |||
1335 | /*========================================================================*/ |
||
1336 | |||
1337 | // Draw the Value Grid labels |
||
1338 | |||
1339 | /*========================================================================*/ |
||
1340 | chrt_value_label_draw_set: |
||
1341 | |||
1342 | case VALUE_LABEL_DRAW_SET: |
||
1343 | |||
1344 | // note that the adjustment of the 100 factor is done here. |
||
1345 | if(GetState(pCh, CH_PERCENT)) |
||
1346 | { |
||
1347 | |||
1348 | // add the percent sign on the label |
||
1349 | tempStr[STR_CHAR_CNT - 1] = '%'; |
||
1350 | |||
1351 | // we have a plus 1 here since we add '%' sign already |
||
1352 | j = 1 + word2xchar((ctr * x / 100) + ChGetPercentMin(pCh), tempStr, STR_CHAR_CNT - 1); |
||
1353 | } |
||
1354 | else |
||
1355 | { |
||
1356 | j = word2xchar((ctr * x / 100) + ChGetValueMin(pCh), tempStr, STR_CHAR_CNT); |
||
1357 | } |
||
1358 | |||
1359 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1360 | { |
||
1361 | temp = GetTextWidth((&tempStr[STR_CHAR_CNT - j]), pCh->prm.pGridLabelsFont); |
||
1362 | |||
1363 | MoveTo(xStart + ((valDelta * ctr) - (temp >> 1)), yStart); |
||
1364 | } |
||
1365 | else |
||
1366 | { |
||
1367 | temp = GetTextHeight(pCh->prm.pGridLabelsFont); |
||
1368 | MoveTo |
||
1369 | ( |
||
1370 | xStart - GetTextWidth((&tempStr[STR_CHAR_CNT - j]), pCh->prm.pGridLabelsFont), |
||
1371 | yStart - ((valDelta * ctr) + (temp >> 1)) |
||
1372 | ); |
||
1373 | } |
||
1374 | |||
1375 | SetFont(pCh->prm.pGridLabelsFont); |
||
1376 | state = VALUE_LABEL_DRAW_RUN; |
||
1377 | |||
1378 | case VALUE_LABEL_DRAW_RUN: |
||
1379 | |||
1380 | // draw the y axis grid numbers |
||
1381 | SetColor(pCh->hdr.pGolScheme->TextColor0); |
||
1382 | if(!OutText(&tempStr[STR_CHAR_CNT - j])) |
||
1383 | return (0); |
||
1384 | ctr++; |
||
1385 | if(ctr >= CH_YGRIDCOUNT) |
||
1386 | { |
||
1387 | state = XAXIS_LABEL_DRAW_SET; |
||
1388 | } |
||
1389 | else |
||
1390 | { |
||
1391 | goto chrt_value_label_draw_set; |
||
1392 | } |
||
1393 | |||
1394 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1395 | { |
||
1396 | state = XAXIS_LABEL_DRAW_SET; |
||
1397 | goto chrt_xaxis_label_draw_set; |
||
1398 | } |
||
1399 | else |
||
1400 | { |
||
1401 | state = YAXIS_LABEL_DRAW_SET; |
||
1402 | } |
||
1403 | |||
1404 | /*========================================================================*/ |
||
1405 | |||
1406 | // Draw the Y - Axis labels |
||
1407 | |||
1408 | /*========================================================================*/ |
||
1409 | chrt_yaxis_label_draw_set: |
||
1410 | |||
1411 | case YAXIS_LABEL_DRAW_SET: |
||
1412 | |||
1413 | // find the location of the label |
||
1414 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1415 | { |
||
1416 | pXcharTemp = pCh->prm.pSmplLabel; |
||
1417 | uLocator = splDelta * (ChGetSampleRange(pCh) + 1); |
||
1418 | } |
||
1419 | else |
||
1420 | { |
||
1421 | pXcharTemp = pCh->prm.pValLabel; |
||
1422 | uLocator = valDelta * CH_YGRIDCOUNT; |
||
1423 | } |
||
1424 | |||
1425 | temp = GetTextWidth(pXcharTemp, pCh->prm.pAxisLabelsFont); |
||
1426 | |||
1427 | if(temp > uLocator) |
||
1428 | temp = (pCh->hdr.bottom + pCh->hdr.top + temp) >> 1; |
||
1429 | else |
||
1430 | { |
||
1431 | temp = yStart - ((uLocator - temp) >> 1); |
||
1432 | } |
||
1433 | |||
1434 | MoveTo |
||
1435 | ( |
||
1436 | xStart - GetTextWidth((&tempStr[STR_CHAR_CNT - j]), pCh->prm.pGridLabelsFont) - (GetTextWidth(temp2Xchar, pCh->prm.pGridLabelsFont) >> 1) - GetTextHeight(pCh->prm.pAxisLabelsFont), |
||
1437 | temp |
||
1438 | ); |
||
1439 | |||
1440 | state = YAXIS_LABEL_DRAW_RUN; |
||
1441 | |||
1442 | case YAXIS_LABEL_DRAW_RUN: |
||
1443 | SetFont(pCh->prm.pAxisLabelsFont); |
||
1444 | |||
1445 | // enable clipping and set region |
||
1446 | SetClip(CLIP_ENABLE); |
||
1447 | SetClipRgn(pCh->hdr.left, pCh->hdr.top, pCh->hdr.right, pCh->hdr.bottom); |
||
1448 | |||
1449 | // set the orientation of text to vertical |
||
1450 | SetFontOrientation(ORIENT_VER); |
||
1451 | SetColor(pCh->hdr.pGolScheme->TextColor1); |
||
1452 | if(!OutText(pXcharTemp)) |
||
1453 | return (0); |
||
1454 | |||
1455 | SetClip(CLIP_DISABLE); |
||
1456 | |||
1457 | // place back the orientation of text to horizontal |
||
1458 | SetFontOrientation(ORIENT_HOR); |
||
1459 | |||
1460 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1461 | { |
||
1462 | state = VALUE_LABEL_DRAW_INIT; |
||
1463 | goto chrt_value_label_draw_init; |
||
1464 | } |
||
1465 | else |
||
1466 | { |
||
1467 | state = DATA_DRAW_INIT; |
||
1468 | } |
||
1469 | |||
1470 | /*========================================================================*/ |
||
1471 | |||
1472 | // Draw the bars representing the data/samples |
||
1473 | |||
1474 | /*========================================================================*/ |
||
1475 | chrt_data_draw_init: |
||
1476 | |||
1477 | case DATA_DRAW_INIT: |
||
1478 | |||
1479 | /* pSmple - points to the sample data of the variables |
||
1480 | ctr - the sample counter |
||
1481 | varCtr - variable counter |
||
1482 | temp - the width of the bars |
||
1483 | dTemp - the height of the bars |
||
1484 | x or y - the location of the first bar per sample. For single variables |
||
1485 | there will be only one bar per sample. x for vertical bars and y for horizontal bars. |
||
1486 | */ |
||
1487 | ctr = 0; |
||
1488 | temp = splDelta / (2 + ChGetShowSeriesCount(pCh)); // <---- note this! this can be used to calculate the minimum size limit of the chart |
||
1489 | state = DATA_DRAW_SET; |
||
1490 | |||
1491 | chrt_data_draw_set: |
||
1492 | |||
1493 | case DATA_DRAW_SET: |
||
1494 | varCtr = 0; |
||
1495 | |||
1496 | pVar = ChGetNextShowData(pCh->pChData); |
||
1497 | |||
1498 | // set the position to start bar drawing |
||
1499 | // x and y here are used in horizontal drawing and vertical drawing as the variable |
||
1500 | // that refers to the position of the bar being drawn. |
||
1501 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1502 | { |
||
1503 | #ifdef USE_HORZ_ASCENDING_ORDER |
||
1504 | y = yStart - temp - ((ChGetSampleRange(pCh) - ctr) * splDelta); |
||
1505 | #else |
||
1506 | y = yStart - (ctr * splDelta) - temp; |
||
1507 | #endif |
||
1508 | } |
||
1509 | else |
||
1510 | { |
||
1511 | x = xStart + (ctr * splDelta) + temp; |
||
1512 | } |
||
1513 | |||
1514 | state = BAR_DATA_DRAW; |
||
1515 | |||
1516 | chrt_data_draw: |
||
1517 | |||
1518 | case BAR_DATA_DRAW: |
||
1519 | |||
1520 | // get sample data from current variable |
||
1521 | pSmple = (&(*pVar->pData) + (ctr + ChGetSampleStart(pCh) - 1)); |
||
1522 | |||
1523 | // calculate the total value of the samples to compute the percentages |
||
1524 | if(GetState(pCh, CH_PERCENT)) |
||
1525 | { |
||
1526 | j = ChGetSampleStart(pCh); |
||
1527 | samplesMax = 0; |
||
1528 | |||
1529 | while(j <= (ChGetSampleRange(pCh) + ChGetSampleStart(pCh))) |
||
1530 | { |
||
1531 | samplesMax += (*(&(*pVar->pData) + (j - 1))); |
||
1532 | j++; |
||
1533 | } |
||
1534 | |||
1535 | // Get the percentage of the sample |
||
1536 | dTemp = ((DWORD) (*pSmple) * 100) / samplesMax; |
||
1537 | |||
1538 | // check if scaling is needed |
||
1539 | if(ChGetPercentMax(pCh) <= dTemp) |
||
1540 | dTemp = ChGetPercentRange(pCh); |
||
1541 | else |
||
1542 | { |
||
1543 | if(dTemp < ChGetPercentMin(pCh)) |
||
1544 | dTemp = 0; |
||
1545 | else |
||
1546 | dTemp = dTemp - ChGetPercentMin(pCh); |
||
1547 | } |
||
1548 | |||
1549 | dTemp = ((DWORD) (dTemp) * (valDelta * (CH_YGRIDCOUNT - 1))) / (ChGetPercentRange(pCh)); |
||
1550 | } |
||
1551 | else |
||
1552 | { |
||
1553 | |||
1554 | // get the height of the current bar to draw |
||
1555 | // this should be adjusted to the min and max set values |
||
1556 | if(ChGetValueMax(pCh) <= (*pSmple)) |
||
1557 | { |
||
1558 | dTemp = ChGetValueRange(pCh); |
||
1559 | } |
||
1560 | else |
||
1561 | { |
||
1562 | if((*pSmple) < ChGetValueMin(pCh)) |
||
1563 | dTemp = 0; |
||
1564 | else |
||
1565 | dTemp = (*pSmple) - ChGetValueMin(pCh); |
||
1566 | } |
||
1567 | |||
1568 | dTemp = ((DWORD) (dTemp) * (valDelta * (CH_YGRIDCOUNT - 1)) / ChGetValueRange(pCh)); |
||
1569 | } |
||
1570 | |||
1571 | // draw the front side of the bar |
||
1572 | if(ChGetShowSeriesCount(pCh) > 1) |
||
1573 | { |
||
1574 | SetColor(*(&(*pCh->prm.pColor) + varCtr)); |
||
1575 | } |
||
1576 | else |
||
1577 | { |
||
1578 | SetColor(*(&(*pCh->prm.pColor) + ctr)); |
||
1579 | } |
||
1580 | |||
1581 | if(GetState(pCh, CH_3D_ENABLE)) |
||
1582 | { |
||
1583 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1584 | { |
||
1585 | if(!Bar(xStart, y - (temp * (varCtr + 1)), xStart + dTemp, y - (temp * varCtr))) |
||
1586 | return (0); |
||
1587 | } |
||
1588 | else |
||
1589 | { |
||
1590 | if(!Bar(x + 1 + 1 + (temp * varCtr), yStart - dTemp, x + (temp * (varCtr + 1)), yStart)) |
||
1591 | return (0); |
||
1592 | } |
||
1593 | |||
1594 | state = BAR_DATA_DRAW_3D_PREP; |
||
1595 | } |
||
1596 | else |
||
1597 | { |
||
1598 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1599 | { |
||
1600 | if(!Bar(xStart, y - (temp * (varCtr + 1)), xStart + dTemp, y - 1 - (temp * varCtr))) |
||
1601 | return (0); |
||
1602 | } |
||
1603 | else |
||
1604 | { |
||
1605 | if(!Bar(x + 1 + (temp * varCtr), yStart - dTemp, x + (temp * (varCtr + 1)), yStart)) |
||
1606 | return (0); |
||
1607 | } |
||
1608 | |||
1609 | if((GetState(pCh, CH_VALUE)) || (GetState(pCh, CH_PERCENT))) |
||
1610 | { |
||
1611 | state = BAR_DATA_DRAW_VALUE; |
||
1612 | goto chrt_bar_data_draw_value; |
||
1613 | } |
||
1614 | else |
||
1615 | { |
||
1616 | state = BAR_DATA_DRAW_CHECK; |
||
1617 | goto chrt_bar_data_draw_check; |
||
1618 | } |
||
1619 | } |
||
1620 | |||
1621 | case BAR_DATA_DRAW_3D_PREP: |
||
1622 | |||
1623 | // draw the 3-D component |
||
1624 | // draw the 45 degree lines |
||
1625 | // we will use y here as the variable to move the line drawn |
||
1626 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1627 | { |
||
1628 | z = y; |
||
1629 | x = xStart + dTemp; |
||
1630 | } |
||
1631 | else |
||
1632 | { |
||
1633 | z = x + 1; |
||
1634 | y = yStart - dTemp; |
||
1635 | } |
||
1636 | |||
1637 | state = BAR_DATA_DRAW_3D_LOOP_1; |
||
1638 | |||
1639 | chrt_bar_data_draw_3d_loop_1: |
||
1640 | |||
1641 | case BAR_DATA_DRAW_3D_LOOP_1: |
||
1642 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1643 | { |
||
1644 | if(x <= xStart + dTemp + barDepth) |
||
1645 | { |
||
1646 | if((x == (xStart + dTemp)) || (x == (xStart + dTemp + barDepth))) |
||
1647 | { |
||
1648 | SetColor(BLACK); |
||
1649 | } |
||
1650 | else |
||
1651 | { |
||
1652 | if(ChGetShowSeriesCount(pCh) > 1) |
||
1653 | { |
||
1654 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + varCtr), 2)); |
||
1655 | } |
||
1656 | else |
||
1657 | { |
||
1658 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + ctr), 2)); |
||
1659 | } |
||
1660 | } |
||
1661 | |||
1662 | if(!Bar(x, z - (temp * (varCtr + 1)), x, z - (temp * varCtr))) |
||
1663 | return (0); |
||
1664 | |||
1665 | state = BAR_DATA_DRAW_3D_LOOP_2; |
||
1666 | } |
||
1667 | else |
||
1668 | { |
||
1669 | state = BAR_DATA_DRAW_3D_OUTLINE1; |
||
1670 | goto chrt_bar_data_draw_3d_outline_1; |
||
1671 | } |
||
1672 | } |
||
1673 | else |
||
1674 | { |
||
1675 | if(y >= yStart - dTemp - barDepth) |
||
1676 | { |
||
1677 | if((y == (yStart - dTemp)) || (y == (yStart - dTemp - barDepth))) |
||
1678 | { |
||
1679 | SetColor(BLACK); |
||
1680 | } |
||
1681 | else |
||
1682 | { |
||
1683 | if(ChGetShowSeriesCount(pCh) > 1) |
||
1684 | { |
||
1685 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + varCtr), 2)); |
||
1686 | } |
||
1687 | else |
||
1688 | { |
||
1689 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + ctr), 2)); |
||
1690 | } |
||
1691 | } |
||
1692 | |||
1693 | if(!Bar(z + 1 + (temp * varCtr), y, z - 1 + (temp * (varCtr + 1)), y)) |
||
1694 | return (0); |
||
1695 | |||
1696 | state = BAR_DATA_DRAW_3D_LOOP_2; |
||
1697 | } |
||
1698 | else |
||
1699 | { |
||
1700 | state = BAR_DATA_DRAW_3D_OUTLINE1; |
||
1701 | goto chrt_bar_data_draw_3d_outline_1; |
||
1702 | } |
||
1703 | } |
||
1704 | |||
1705 | case BAR_DATA_DRAW_3D_LOOP_2: |
||
1706 | |||
1707 | // check if we are going to draw the outline or the shade |
||
1708 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1709 | { |
||
1710 | if((x == (xStart + dTemp)) || (x == (xStart + dTemp + barDepth))) |
||
1711 | { |
||
1712 | SetColor(BLACK); |
||
1713 | } |
||
1714 | else |
||
1715 | { |
||
1716 | if(ChGetShowSeriesCount(pCh) > 1) |
||
1717 | { |
||
1718 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + varCtr), 1)); |
||
1719 | } |
||
1720 | else |
||
1721 | { |
||
1722 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + ctr), 1)); |
||
1723 | } |
||
1724 | } |
||
1725 | } |
||
1726 | else |
||
1727 | { |
||
1728 | if((y == (yStart - dTemp)) || (y == (yStart - dTemp - barDepth))) |
||
1729 | { |
||
1730 | SetColor(BLACK); |
||
1731 | } |
||
1732 | else |
||
1733 | { |
||
1734 | if(ChGetShowSeriesCount(pCh) > 1) |
||
1735 | { |
||
1736 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + varCtr), 1)); |
||
1737 | } |
||
1738 | else |
||
1739 | { |
||
1740 | SetColor(GetColorShade(*(&(*pCh->prm.pColor) + ctr), 1)); |
||
1741 | } |
||
1742 | } |
||
1743 | } |
||
1744 | |||
1745 | // draw the outline or shade |
||
1746 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1747 | { |
||
1748 | if(!Bar(x - dTemp, z - (temp * (varCtr + 1)), x, z - (temp * (varCtr + 1)))) |
||
1749 | return (0); |
||
1750 | } |
||
1751 | else |
||
1752 | { |
||
1753 | if(!Bar(z + (temp * (varCtr + 1)), y, z + (temp * (varCtr + 1)), y + dTemp)) |
||
1754 | return (0); |
||
1755 | } |
||
1756 | |||
1757 | // update the loop variables |
||
1758 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1759 | { |
||
1760 | x++; |
||
1761 | z--; |
||
1762 | } |
||
1763 | else |
||
1764 | { |
||
1765 | y--; |
||
1766 | z++; |
||
1767 | } |
||
1768 | |||
1769 | state = BAR_DATA_DRAW_3D_LOOP_1; |
||
1770 | goto chrt_bar_data_draw_3d_loop_1; |
||
1771 | |||
1772 | chrt_bar_data_draw_3d_outline_1: |
||
1773 | |||
1774 | case BAR_DATA_DRAW_3D_OUTLINE1: |
||
1775 | SetColor(BLACK); |
||
1776 | |||
1777 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1778 | { |
||
1779 | if(!Line(x - 1, y - (temp * varCtr) - barDepth, x - 1 - barDepth, y - (temp * varCtr))) |
||
1780 | return (0); |
||
1781 | } |
||
1782 | else |
||
1783 | { |
||
1784 | if |
||
1785 | ( |
||
1786 | !Line |
||
1787 | ( |
||
1788 | x + 1 + (temp * varCtr), |
||
1789 | yStart - dTemp, |
||
1790 | x + 1 + (temp * varCtr) + barDepth, |
||
1791 | yStart - dTemp - barDepth |
||
1792 | ) |
||
1793 | ) return (0); |
||
1794 | } |
||
1795 | |||
1796 | state = BAR_DATA_DRAW_3D_OUTLINE2; |
||
1797 | |||
1798 | case BAR_DATA_DRAW_3D_OUTLINE2: |
||
1799 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1800 | { |
||
1801 | if(!Line(x - 1, y - (temp * (varCtr + 1)) - barDepth, x - 1 - barDepth, y - (temp * (varCtr + 1)))) |
||
1802 | return (0); |
||
1803 | } |
||
1804 | else |
||
1805 | { |
||
1806 | if |
||
1807 | ( |
||
1808 | !Line |
||
1809 | ( |
||
1810 | x + 1 + (temp * (varCtr + 1)), |
||
1811 | (yStart - dTemp), |
||
1812 | x + 1 + (temp * (varCtr + 1)) + barDepth, |
||
1813 | (yStart - dTemp) - barDepth |
||
1814 | ) |
||
1815 | ) return (0); |
||
1816 | } |
||
1817 | |||
1818 | state = BAR_DATA_DRAW_3D_OUTLINE3; |
||
1819 | |||
1820 | case BAR_DATA_DRAW_3D_OUTLINE3: |
||
1821 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1822 | { |
||
1823 | if |
||
1824 | ( |
||
1825 | !Line |
||
1826 | ( |
||
1827 | x - dTemp - 1, |
||
1828 | y - (temp * (varCtr + 1)) - barDepth, |
||
1829 | x - dTemp - barDepth - 1, |
||
1830 | y - (temp * (varCtr + 1)) |
||
1831 | ) |
||
1832 | ) return (0); |
||
1833 | } |
||
1834 | else |
||
1835 | { |
||
1836 | if |
||
1837 | ( |
||
1838 | !Line |
||
1839 | ( |
||
1840 | x + 1 + (temp * (varCtr + 1)), |
||
1841 | yStart, |
||
1842 | x + 1 + (temp * (varCtr + 1)) + barDepth, |
||
1843 | yStart - barDepth |
||
1844 | ) |
||
1845 | ) return (0); |
||
1846 | } |
||
1847 | |||
1848 | state = BAR_DATA_DRAW_3D_OUTLINE4; |
||
1849 | |||
1850 | case BAR_DATA_DRAW_3D_OUTLINE4: |
||
1851 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1852 | { |
||
1853 | if |
||
1854 | ( |
||
1855 | !Bar |
||
1856 | ( |
||
1857 | x - dTemp - barDepth - 1, |
||
1858 | y - (temp * (varCtr + 1)), |
||
1859 | x - dTemp - barDepth - 1, |
||
1860 | y - (temp * (varCtr + 1)) + temp |
||
1861 | ) |
||
1862 | ) return (0); |
||
1863 | } |
||
1864 | else |
||
1865 | { |
||
1866 | if(!Bar(x + 1 + (temp * varCtr), yStart - dTemp, x + 1 + (temp * varCtr), yStart)) |
||
1867 | return (0); |
||
1868 | } |
||
1869 | |||
1870 | state = BAR_DATA_DRAW_3D_OUTLINE5; |
||
1871 | |||
1872 | case BAR_DATA_DRAW_3D_OUTLINE5: |
||
1873 | |||
1874 | // draw the horizontal lines |
||
1875 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1876 | { |
||
1877 | if |
||
1878 | ( |
||
1879 | !Bar |
||
1880 | ( |
||
1881 | x - dTemp - barDepth - 1, |
||
1882 | y - (temp * (varCtr + 1)) + temp, |
||
1883 | x - barDepth - 1, |
||
1884 | y - (temp * (varCtr + 1)) + temp |
||
1885 | ) |
||
1886 | ) return (0); |
||
1887 | } |
||
1888 | else |
||
1889 | { |
||
1890 | if(!Bar(x + 1 + (temp * varCtr), yStart, x + 1 + (temp * (varCtr + 1)), yStart)) |
||
1891 | return (0); |
||
1892 | } |
||
1893 | |||
1894 | if((GetState(pCh, CH_VALUE)) || (GetState(pCh, CH_PERCENT))) |
||
1895 | state = BAR_DATA_DRAW_VALUE; |
||
1896 | else |
||
1897 | { |
||
1898 | state = BAR_DATA_DRAW_CHECK; |
||
1899 | goto chrt_bar_data_draw_check; |
||
1900 | } |
||
1901 | |||
1902 | chrt_bar_data_draw_value: |
||
1903 | |||
1904 | case BAR_DATA_DRAW_VALUE: |
||
1905 | if(GetState(pCh, CH_VALUE)) |
||
1906 | { |
||
1907 | j = word2xchar(*pSmple, tempStr, STR_CHAR_CNT); |
||
1908 | } |
||
1909 | else |
||
1910 | { |
||
1911 | |||
1912 | // add the percent sign on the label |
||
1913 | tempStr[STR_CHAR_CNT - 1] = '%'; |
||
1914 | |||
1915 | // compute for the percentage |
||
1916 | if(ChGetValueMax(pCh) <= (*pSmple)) |
||
1917 | dPercent = ChGetValueRange(pCh); |
||
1918 | else |
||
1919 | { |
||
1920 | if((*pSmple) < ChGetValueMin(pCh)) |
||
1921 | dPercent = 0; |
||
1922 | else |
||
1923 | dPercent = (*pSmple) - ChGetValueMin(pCh); |
||
1924 | } |
||
1925 | |||
1926 | dPercent = ((DWORD) (dPercent * 1000)) / samplesMax; |
||
1927 | |||
1928 | // check if we need to round up or not |
||
1929 | if((dPercent % 10) < 5) |
||
1930 | dPercent = (dPercent / 10); // do not round up to next number |
||
1931 | else |
||
1932 | dPercent = (dPercent / 10) + 1; // round up the value |
||
1933 | |||
1934 | // we have a plus 1 here since we add '%' sign already |
||
1935 | j = 1 + word2xchar(dPercent, tempStr, STR_CHAR_CNT - 1); |
||
1936 | } |
||
1937 | |||
1938 | if(GetState(pCh, CH_3D_ENABLE)) |
||
1939 | { |
||
1940 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1941 | { |
||
1942 | MoveTo |
||
1943 | ( |
||
1944 | xStart + dTemp + barDepth + 3, |
||
1945 | y - (temp * varCtr) - ((temp + GetTextHeight(pCh->hdr.pGolScheme->pFont)) >> 1) - barDepth |
||
1946 | ); |
||
1947 | } |
||
1948 | else |
||
1949 | { |
||
1950 | MoveTo |
||
1951 | ( |
||
1952 | x + barDepth + (temp * varCtr) + (temp >> 1) - (GetTextWidth(&tempStr[STR_CHAR_CNT - j], pCh->hdr.pGolScheme->pFont) >> 1), |
||
1953 | (yStart - 1) - dTemp - GetTextHeight(pCh->hdr.pGolScheme->pFont) - (barDepth) |
||
1954 | ); |
||
1955 | } |
||
1956 | } |
||
1957 | else |
||
1958 | { |
||
1959 | if(GetState(pCh, CH_BAR_HOR) == CH_BAR_HOR) |
||
1960 | { |
||
1961 | MoveTo |
||
1962 | ( |
||
1963 | xStart + dTemp + 3, |
||
1964 | y - (temp * varCtr) - (temp >> 1) - (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 1) |
||
1965 | ); |
||
1966 | } |
||
1967 | else |
||
1968 | { |
||
1969 | MoveTo |
||
1970 | ( |
||
1971 | x + |
||
1972 | ((temp >> 1) - (GetTextWidth(&tempStr[STR_CHAR_CNT - j], pCh->hdr.pGolScheme->pFont) >> 1)) + |
||
1973 | (temp * varCtr), |
||
1974 | (yStart - 1) - dTemp - (GetTextHeight(pCh->hdr.pGolScheme->pFont)) |
||
1975 | ); |
||
1976 | } |
||
1977 | } |
||
1978 | |||
1979 | state = BAR_DATA_DRAW_VALUE_RUN; |
||
1980 | |||
1981 | case BAR_DATA_DRAW_VALUE_RUN: |
||
1982 | |||
1983 | // draw the values on top of the bars |
||
1984 | // NOTE: we use the emboss light color here to draw the values. |
||
1985 | SetColor(pCh->hdr.pGolScheme->EmbossLtColor); |
||
1986 | SetFont(pCh->hdr.pGolScheme->pFont); |
||
1987 | if(!OutText(&tempStr[STR_CHAR_CNT - j])) |
||
1988 | return (0); |
||
1989 | state = BAR_DATA_DRAW_CHECK; |
||
1990 | |||
1991 | chrt_bar_data_draw_check: |
||
1992 | |||
1993 | case BAR_DATA_DRAW_CHECK: |
||
1994 | |||
1995 | // find the next data series that will be shown |
||
1996 | pVar = ChGetNextShowData(pVar); |
||
1997 | if(pVar == NULL) |
||
1998 | { |
||
1999 | state = REMOVE; |
||
2000 | return (1); |
||
2001 | } |
||
2002 | |||
2003 | // increment the variable counter |
||
2004 | varCtr++; |
||
2005 | if(varCtr < ChGetShowSeriesCount(pCh)) |
||
2006 | { |
||
2007 | pVar = (DATASERIES *)pVar->pNextData; |
||
2008 | state = BAR_DATA_DRAW; |
||
2009 | goto chrt_data_draw; |
||
2010 | } |
||
2011 | |||
2012 | // increment the sample counter |
||
2013 | ctr++; |
||
2014 | if(ctr < ChGetSampleRange(pCh) + 1) |
||
2015 | { |
||
2016 | x += (splDelta + 1); |
||
2017 | state = DATA_DRAW_SET; |
||
2018 | goto chrt_data_draw_set; |
||
2019 | } |
||
2020 | |||
2021 | state = REMOVE; |
||
2022 | return (1); |
||
2023 | |||
2024 | /**************************************************************************/ |
||
2025 | |||
2026 | // PIE CHART states |
||
2027 | |||
2028 | /**************************************************************************/ |
||
2029 | |||
2030 | /*========================================================================*/ |
||
2031 | |||
2032 | // Draw the pie |
||
2033 | |||
2034 | /*========================================================================*/ |
||
2035 | chrt_pie_prep: |
||
2036 | |||
2037 | case PIE_PREP: |
||
2038 | |||
2039 | /* If more than two data series have their SHOW_DATA flag set |
||
2040 | the pie chart is drawn to represent the values of each variable |
||
2041 | at Start sample point . End sample point is ignored in this case. |
||
2042 | If only one data series is set to be shown the pie chart is drawn |
||
2043 | from the sample start point and sample end point (inclusive). |
||
2044 | |||
2045 | Pie chart is drawn as a percentage of the data samples. |
||
2046 | Therefore: percentage is computed depending on the sample |
||
2047 | points used. |
||
2048 | Only 1 data series is set to be shown |
||
2049 | total = summation of the variable sample points from |
||
2050 | sample start point to sample end point inclusive. |
||
2051 | More than 1 data series is set to be shown |
||
2052 | total = summation of the sample points for each variable |
||
2053 | using the sample start point. |
||
2054 | */ |
||
2055 | |||
2056 | /* For PIE chart variables used are the following |
||
2057 | ctr = x position of the center of the pie chart |
||
2058 | ctry = y position of the center of the pie chart |
||
2059 | z = radius of the pie chart |
||
2060 | j = start angle |
||
2061 | k = end angle |
||
2062 | */ |
||
2063 | |||
2064 | // calculate the needed variables |
||
2065 | // radius z is affected by the following: CH_LEGEND, CH_VALUE and CH_PERCENT |
||
2066 | temp = CH_MARGIN << 1; |
||
2067 | |||
2068 | // check the largest/longest sample |
||
2069 | // use x here as a counter |
||
2070 | varCtr = ChGetShowSeriesCount(pCh); |
||
2071 | if(varCtr == 1) |
||
2072 | { |
||
2073 | varCtr = ChGetSampleRange(pCh) + 1; |
||
2074 | } |
||
2075 | |||
2076 | pVar = ChGetNextShowData(pCh->pChData); |
||
2077 | |||
2078 | // y and z is used here as a temporary variable |
||
2079 | y = 0; |
||
2080 | |||
2081 | // find the sample value that is largest (place in y) |
||
2082 | // also while doing this get the total of the selected data (put in dTemp) |
||
2083 | dTemp = 0; |
||
2084 | while(varCtr >= 0) |
||
2085 | { |
||
2086 | if(ChGetShowSeriesCount(pCh) > 1) |
||
2087 | { |
||
2088 | z = *(&(*pVar->pData) + ChGetSampleStart(pCh) - 1); |
||
2089 | } |
||
2090 | else |
||
2091 | { |
||
2092 | z = *(&(*pVar->pData) + ChGetSampleEnd(pCh) - varCtr); |
||
2093 | } |
||
2094 | |||
2095 | dTemp += z; |
||
2096 | varCtr--; |
||
2097 | |||
2098 | // check if we get a larger value |
||
2099 | if(z > y) |
||
2100 | y = z; |
||
2101 | if(varCtr == 0) |
||
2102 | break; |
||
2103 | |||
2104 | if(ChGetShowSeriesCount(pCh) > 1) |
||
2105 | { |
||
2106 | pVar = ChGetNextShowData((DATASERIES *)pVar->pNextData); |
||
2107 | } |
||
2108 | |||
2109 | // this is insurance (in case the link list is corrupted) |
||
2110 | if(pVar == NULL) |
||
2111 | { |
||
2112 | break; |
||
2113 | } |
||
2114 | } |
||
2115 | |||
2116 | // initialize pVarFont to use pGridLabelsFont |
||
2117 | pVarFont = pCh->prm.pGridLabelsFont; |
||
2118 | |||
2119 | // get the space occupied by the value |
||
2120 | if(GetState(pCh, CH_VALUE)) |
||
2121 | { |
||
2122 | z = word2xchar(y, tempStr, STR_CHAR_CNT); |
||
2123 | x = (GetTextWidth(&tempStr[STR_CHAR_CNT - z], pVarFont)); |
||
2124 | } |
||
2125 | else |
||
2126 | x = 0; |
||
2127 | |||
2128 | // get the space occupied by percent value |
||
2129 | if(GetState(pCh, CH_PERCENT)) |
||
2130 | { |
||
2131 | |||
2132 | // 7 is derived from "X:100%," - seven possible characters, 1 is added for buffer |
||
2133 | y = (8 * GetTextWidth((XCHAR *)tempXchar, pVarFont)); |
||
2134 | } |
||
2135 | else |
||
2136 | y = 0; |
||
2137 | |||
2138 | // get the space occupied by the legend |
||
2139 | if((GetState(pCh, CH_LEGEND)) && (ChGetShowSeriesCount(pCh) > 1)) |
||
2140 | temp += ((GetLongestNameLength(pCh) + (GetTextHeight(pCh->hdr.pGolScheme->pFont) >> 1))); |
||
2141 | |||
2142 | // calculate the center of the pie chart |
||
2143 | ctr = (pCh->hdr.left + pCh->hdr.right - temp) >> 1; |
||
2144 | ctry = ((pCh->hdr.bottom + (pCh->hdr.top + GetTextHeight(pVarFont))) >> 1) + CH_MARGIN; |
||
2145 | |||
2146 | // radius size is checked against the x and y area |
||
2147 | if |
||
2148 | ( |
||
2149 | ((pCh->hdr.right - pCh->hdr.left) - temp - ((x + y) << 1)) < |
||
2150 | ( |
||
2151 | (pCh->hdr.bottom - pCh->hdr.top - GetTextHeight(pCh->prm.pTitleFont)) - temp - |
||
2152 | (GetTextHeight(pVarFont) << 1) |
||
2153 | ) |
||
2154 | ) |
||
2155 | { |
||
2156 | |||
2157 | // use dimension in the x axis |
||
2158 | if(x + y) |
||
2159 | { |
||
2160 | z = ctr - (pCh->hdr.left + (x + y) + CH_MARGIN); |
||
2161 | } |
||
2162 | else |
||
2163 | { |
||
2164 | z = ctr - pCh->hdr.left + CH_MARGIN; |
||
2165 | } |
||
2166 | } |
||
2167 | else |
||
2168 | { |
||
2169 | |||
2170 | // use dimension in the y axis |
||
2171 | if(x + y) |
||
2172 | z = ctry - |
||
2173 | ( |
||
2174 | pCh->hdr.top + (CH_MARGIN << 1) + GetTextHeight(pCh->prm.pTitleFont) + |
||
2175 | (GetTextHeight(pVarFont) << 1) |
||
2176 | ); |
||
2177 | else |
||
2178 | z = ctry - (pCh->hdr.top + (CH_MARGIN << 1) + (GetTextHeight(pCh->prm.pTitleFont) << 1)); |
||
2179 | } |
||
2180 | |||
2181 | state = PIE_DRAW_OUTLINE1; |
||
2182 | |||
2183 | case PIE_DRAW_OUTLINE1: |
||
2184 | |||
2185 | // Required items before the pie chart can be drawn |
||
2186 | SetColor(LIGHTGRAY); |
||
2187 | |||
2188 | // Draw pie-chart outline |
||
2189 | if(!Circle(ctr, ctry, z)) |
||
2190 | return (0); |
||
2191 | state = PIE_DRAW_SECTOR; |
||
2192 | |||
2193 | /*========================================================================*/ |
||
2194 | |||
2195 | // Draw the sectors of the pie |
||
2196 | |||
2197 | /*========================================================================*/ |
||
2198 | case PIE_DRAW_SECTOR: |
||
2199 | |||
2200 | // now we are ready to draw the sectors |
||
2201 | // calculate the sector that a value will need |
||
2202 | k = 0; |
||
2203 | |||
2204 | // check if more than one data series set to be shown , draw the pie chart of |
||
2205 | // the data series that are set to be shown. |
||
2206 | pVar = ChGetNextShowData(pCh->pChData); |
||
2207 | y = dTemp; |
||
2208 | varCtr = ChGetShowSeriesCount(pCh); |
||
2209 | if(varCtr == 1) |
||
2210 | { |
||
2211 | varCtr = ChGetSampleRange(pCh) + 1; |
||
2212 | } |
||
2213 | else if(varCtr == 0) |
||
2214 | { |
||
2215 | pVar = NULL; |
||
2216 | y = 0; |
||
2217 | } |
||
2218 | |||
2219 | // we start at 0 degree. |
||
2220 | j = 0; |
||
2221 | |||
2222 | // initialize the variables that position the pie sector labels. |
||
2223 | // this is used to minimize the occurrence of overlapped labels. |
||
2224 | pieLabelYPos = ctry; |
||
2225 | pieLabelYPos2 = pCh->hdr.bottom - (GOL_EMBOSS_SIZE + 1) - GetTextHeight(pVarFont); |
||
2226 | pieLabelYPos3 = pCh->hdr.top + GOL_EMBOSS_SIZE + CH_MARGIN + GetTextHeight(pCh->prm.pTitleFont) + GetTextHeight(pVarFont); |
||
2227 | |||
2228 | state = PIE_DRAW_SECTOR_LOOP; |
||
2229 | |||
2230 | chrt_pie_draw_sector_loop: |
||
2231 | |||
2232 | case PIE_DRAW_SECTOR_LOOP: |
||
2233 | if(varCtr >= 0) |
||
2234 | { |
||
2235 | |||
2236 | // get the value to be computed |
||
2237 | if(ChGetShowSeriesCount(pCh) > 1) |
||
2238 | { |
||
2239 | temp = *(&(*pVar->pData) + ChGetSampleStart(pCh) - 1); |
||
2240 | } |
||
2241 | else |
||
2242 | { |
||
2243 | temp = *(&(*pVar->pData) + ChGetSampleEnd(pCh) - varCtr); |
||
2244 | } |
||
2245 | |||
2246 | // calculate the sector that the value will occupy |
||
2247 | dTemp = ((DWORD) (temp) * (3600)) / y; |
||
2248 | |||
2249 | // check if we need to round up or not |
||
2250 | if((dTemp % 10) < 5) |
||
2251 | dTemp = (dTemp / 10); // do not round up to next number |
||
2252 | else |
||
2253 | dTemp = (dTemp / 10) + 1; // round up the value |
||
2254 | |||
2255 | // set the color to the color of the variable |
||
2256 | SetColor(*(&(*pCh->prm.pColor) + k)); |
||
2257 | |||
2258 | // check if the sector has zero angle if it is zero just draw the |
||
2259 | // line. |
||
2260 | if(dTemp == 0) |
||
2261 | { |
||
2262 | state = PIE_DRAW_SECTOR_LOOP_CONTINUE; |
||
2263 | goto chrt_pie_draw_sector_loop_continue; |
||
2264 | } |
||
2265 | |||
2266 | // go to the state that draws only. Doing this separates the setup of static variables |
||
2267 | // and rendering. So in cases when the rendering cannot continue, the variables |
||
2268 | // are still set to correct values. |
||
2269 | state = PIE_DRAW_SECTOR_ACTUAL; |
||
2270 | goto pie_draw_sector_actual; |
||
2271 | } |
||
2272 | else |
||
2273 | { |
||
2274 | if(GetState(pCh, CH_DONUT) == CH_DONUT) |
||
2275 | { |
||
2276 | state = PIE_DONUT_HOLE_DRAW; |
||
2277 | goto chrt_pie_donut_hole_draw; |
||
2278 | } |
||
2279 | else |
||
2280 | { |
||
2281 | state = REMOVE; |
||
2282 | return (1); |
||
2283 | } |
||
2284 | } |
||
2285 | |||
2286 | case PIE_DRAW_SECTOR_ACTUAL: |
||
2287 | pie_draw_sector_actual : |
||
2288 | |||
2289 | // check if it is the last sector to be drawn |
||
2290 | if((varCtr == 1) || ((j + dTemp) >= 358)) |
||
2291 | { |
||
2292 | if(!DrawSector(ctr, ctry, z, j, 360, LIGHTGRAY)) |
||
2293 | return (0); |
||
2294 | } |
||
2295 | else |
||
2296 | { |
||
2297 | if(!DrawSector(ctr, ctry, z, j, (j + dTemp), LIGHTGRAY)) |
||
2298 | return (0); |
||
2299 | } |
||
2300 | |||
2301 | state = PIE_DRAW_SECTOR_LOOP_CREATE_STRINGS; |
||
2302 | |||
2303 | case PIE_DRAW_SECTOR_LOOP_CREATE_STRINGS: |
||
2304 | |||
2305 | // create the strings of the values if needed |
||
2306 | if(GetState(pCh, CH_VALUE) || GetState(pCh, CH_PERCENT)) |
||
2307 | { |
||
2308 | h = 0; |
||
2309 | GetCirclePoint(z, (j + (dTemp >> 1)), &pieX, &pieY); |
||
2310 | |||
2311 | pieX += ctr; |
||
2312 | pieY += ctry; |
||
2313 | |||
2314 | // do we need to show the values? create the strings here |
||
2315 | if(GetState(pCh, CH_VALUE)) |
||
2316 | { |
||
2317 | h = word2xchar(temp, tempStr, STR_CHAR_CNT); |
||
2318 | } |
||
2319 | |||
2320 | // do we need to show the percentage? create the strings here |
||
2321 | if(GetState(pCh, CH_PERCENT)) |
||
2322 | { |
||
2323 | |||
2324 | // add the % sign |
||
2325 | // check if we need to add comma |
||
2326 | if(GetState(pCh, CH_VALUE)) |
||
2327 | { |
||
2328 | h += 1; // adjust h |
||
2329 | tempStr[STR_CHAR_CNT - h] = ','; |
||
2330 | } |
||
2331 | |||
2332 | h += 1; // adjust h |
||
2333 | tempStr[STR_CHAR_CNT - h] = '%'; |
||
2334 | |||
2335 | // now add the percentage |
||
2336 | dPercent = (DWORD) (dTemp * 1000) / 360; |
||
2337 | |||
2338 | // check if we need to round up or not |
||
2339 | if((dPercent % 10) < 5) |
||
2340 | dPercent = (dPercent / 10); // do not round up to next number |
||
2341 | else |
||
2342 | dPercent = (dPercent / 10) + 1; // round up the value |
||
2343 | i = word2xchar((WORD) dPercent, tempStr, STR_CHAR_CNT - h); |
||
2344 | |||
2345 | // adjust the h position |
||
2346 | h += i; |
||
2347 | } |
||
2348 | |||
2349 | #ifdef USE_PIE_ENABLE_LABEL |
||
2350 | |||
2351 | // add the labels |
||
2352 | h += 1; // adjust h |
||
2353 | tempStr[STR_CHAR_CNT - h] = ':'; |
||
2354 | h += 1; // adjust h |
||
2355 | tempStr[STR_CHAR_CNT - h] = 'A' + (ChGetSampleStart(pCh) - 1 + k); |
||
2356 | #endif |
||
2357 | SetColor(BLACK); |
||
2358 | |||
2359 | m = j; |
||
2360 | |||
2361 | // we have to relocate the text depending on the position |
||
2362 | if((m + (dTemp >> 1) >= 0) && (m + (dTemp >> 1) <= 90)) |
||
2363 | { |
||
2364 | |||
2365 | // check if we need to draw a line |
||
2366 | if((dTemp < GetTextHeight(pVarFont)) || (pieLabelYPos > pieY)) |
||
2367 | { |
||
2368 | pieLabelXPos = ctr + z + GetTextHeight(pVarFont); |
||
2369 | pieSectorXPos = pieX + 3; |
||
2370 | if((m + (dTemp >> 1)) < 45) |
||
2371 | pieSectorYPos = pieY + 1; |
||
2372 | else |
||
2373 | pieSectorYPos = pieY + 3; |
||
2374 | |||
2375 | // The label will now exceed the chart dimension, so force the value to be printed near the sector |
||
2376 | pieLabelXPos = ctr + z + GetTextHeight(pVarFont); |
||
2377 | if((pieLabelYPos + GetTextHeight(pVarFont)) > (pCh->hdr.bottom - (GOL_EMBOSS_SIZE + 1))) |
||
2378 | { |
||
2379 | MoveTo(pieX, pieY + 1); |
||
2380 | } |
||
2381 | else |
||
2382 | { |
||
2383 | |||
2384 | // draw the line |
||
2385 | if |
||
2386 | ( |
||
2387 | !Line |
||
2388 | ( |
||
2389 | pieSectorXPos, |
||
2390 | pieSectorYPos, |
||
2391 | pieLabelXPos, |
||
2392 | pieLabelYPos + (GetTextHeight(pVarFont) >> 1) |
||
2393 | ) |
||
2394 | ) return (0); |
||
2395 | |||
2396 | MoveTo(pieLabelXPos, pieLabelYPos); |
||
2397 | pieLabelYPos += GetTextHeight(pVarFont); |
||
2398 | } |
||
2399 | } |
||
2400 | else |
||
2401 | { |
||
2402 | MoveTo(pieX + GetTextWidth(tempXchar, pVarFont), pieY); |
||
2403 | pieLabelYPos = pieY + GetTextHeight(pVarFont); |
||
2404 | } |
||
2405 | } |
||
2406 | else if((m + (dTemp >> 1) > 90) && (m + (dTemp >> 1) <= 180)) |
||
2407 | { |
||
2408 | |||
2409 | // check if we need to draw a line |
||
2410 | if((dTemp < GetTextHeight(pVarFont)) || (pieLabelYPos2 < pieY)) |
||
2411 | { |
||
2412 | pieLabelXPos = ctr - z - 3; |
||
2413 | |||
2414 | pieSectorXPos = pieX - 3; |
||
2415 | |||
2416 | if((m + (dTemp >> 1)) < 135) |
||
2417 | pieSectorYPos = pieY + 3; |
||
2418 | else |
||
2419 | pieSectorYPos = pieY; |
||
2420 | |||
2421 | // check if slope of line is greater than -1. |
||
2422 | // if it is we must adjust position of text to avoid the line |
||
2423 | // intersecting the circumference of the pie chart |
||
2424 | if((m + (dTemp >> 1)) < 180) |
||
2425 | { |
||
2426 | |||
2427 | // make the slope equal to 1, this will make sure it does not intersect the circumference |
||
2428 | if((abs(pieY - pieLabelYPos2) / abs(pieX - pieLabelXPos)) >= 1) |
||
2429 | { |
||
2430 | pieLabelXPos = pieX - abs(pieY - pieLabelYPos2); |
||
2431 | if |
||
2432 | ( |
||
2433 | (SHORT) (pieLabelXPos - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont)) <= |
||
2434 | (pCh->hdr.left + CH_MARGIN) |
||
2435 | ) |
||
2436 | { |
||
2437 | pieLabelXPos = |
||
2438 | ( |
||
2439 | pCh->hdr.left + |
||
2440 | CH_MARGIN + |
||
2441 | GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) |
||
2442 | ); |
||
2443 | } |
||
2444 | } |
||
2445 | } |
||
2446 | |||
2447 | // draw the line |
||
2448 | if |
||
2449 | ( |
||
2450 | !Line |
||
2451 | ( |
||
2452 | pieSectorXPos, |
||
2453 | pieSectorYPos, |
||
2454 | pieLabelXPos, |
||
2455 | pieLabelYPos2 + (GetTextHeight(pVarFont) >> 1) |
||
2456 | ) |
||
2457 | ) return (0); |
||
2458 | |||
2459 | MoveTo(pieLabelXPos - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont), pieLabelYPos2); |
||
2460 | pieLabelYPos2 -= GetTextHeight(pVarFont); |
||
2461 | } |
||
2462 | else |
||
2463 | { |
||
2464 | MoveTo |
||
2465 | ( |
||
2466 | pieX - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) - GetTextWidth |
||
2467 | ( |
||
2468 | tempXchar, |
||
2469 | pVarFont |
||
2470 | ), |
||
2471 | pieY |
||
2472 | ); |
||
2473 | pieLabelYPos2 = pieY - GetTextHeight(pVarFont); |
||
2474 | } |
||
2475 | } |
||
2476 | else if((m + (dTemp >> 1) > 180) && (m + (dTemp >> 1) <= 270)) |
||
2477 | { |
||
2478 | |||
2479 | // check if we need to draw a line |
||
2480 | if((dTemp < GetTextHeight(pVarFont)) || (pieLabelYPos2 < pieY)) |
||
2481 | { |
||
2482 | pieLabelXPos = ctr - z - 5; |
||
2483 | |||
2484 | if((m + (dTemp >> 1)) < 225) |
||
2485 | { |
||
2486 | pieSectorXPos = pieX - 3; |
||
2487 | pieSectorYPos = pieY; |
||
2488 | } |
||
2489 | else |
||
2490 | { |
||
2491 | pieSectorXPos = pieX; |
||
2492 | pieSectorYPos = pieY - 3; |
||
2493 | } |
||
2494 | |||
2495 | // check if slope of line is greater than -1. |
||
2496 | // if it is we must adjust position of text to avoid the line |
||
2497 | // intersecting the circumference of the pie chart |
||
2498 | if((m + (dTemp >> 1)) < 270) |
||
2499 | { |
||
2500 | |||
2501 | // make the slope equal to 1, this will make sure it does not intersect the circumference |
||
2502 | if((abs(pieY - pieLabelYPos2) / abs(pieX - pieLabelXPos)) >= 1) |
||
2503 | { |
||
2504 | pieLabelXPos = ctr - (z + (z >> 1)) - 5; |
||
2505 | if |
||
2506 | ( |
||
2507 | (SHORT) (pieLabelXPos - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont)) <= |
||
2508 | (pCh->hdr.left + CH_MARGIN) |
||
2509 | ) |
||
2510 | { |
||
2511 | pieLabelXPos = |
||
2512 | ( |
||
2513 | pCh->hdr.left + |
||
2514 | CH_MARGIN + |
||
2515 | GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) |
||
2516 | ); |
||
2517 | } |
||
2518 | } |
||
2519 | } |
||
2520 | |||
2521 | // The label will now exceed the chart dimension, so force the value to be printed aligned in |
||
2522 | // y position with the previous value printed |
||
2523 | if |
||
2524 | ( |
||
2525 | (pieLabelYPos2) < |
||
2526 | (pCh->hdr.top + GOL_EMBOSS_SIZE + CH_MARGIN + GetTextHeight(pCh->prm.pTitleFont)) |
||
2527 | ) |
||
2528 | { |
||
2529 | if |
||
2530 | ( |
||
2531 | !Line |
||
2532 | ( |
||
2533 | pieSectorXPos, |
||
2534 | pieSectorYPos, |
||
2535 | pieLabelXPos + (GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) >> 1), |
||
2536 | pieLabelYPos2 + ((GetTextHeight(pVarFont) >> 1) * 3) |
||
2537 | ) |
||
2538 | ) return (0); |
||
2539 | |||
2540 | MoveTo |
||
2541 | ( |
||
2542 | pieLabelXPos + (GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) >> 1), |
||
2543 | pieLabelYPos2 + GetTextHeight(pVarFont) |
||
2544 | ); |
||
2545 | |||
2546 | // adjust the next marker |
||
2547 | pieLabelYPos3 += GetTextHeight(pVarFont); |
||
2548 | } |
||
2549 | else |
||
2550 | { |
||
2551 | |||
2552 | // draw the line |
||
2553 | if |
||
2554 | ( |
||
2555 | !Line |
||
2556 | ( |
||
2557 | pieSectorXPos, |
||
2558 | pieSectorYPos, |
||
2559 | pieLabelXPos, |
||
2560 | pieLabelYPos2 + (GetTextHeight(pVarFont) >> 1) |
||
2561 | ) |
||
2562 | ) return (0); |
||
2563 | |||
2564 | MoveTo(pieLabelXPos - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont), pieLabelYPos2); |
||
2565 | pieLabelYPos2 -= GetTextHeight(pVarFont); |
||
2566 | } |
||
2567 | } |
||
2568 | else |
||
2569 | { |
||
2570 | MoveTo |
||
2571 | ( |
||
2572 | pieX - GetTextWidth(&tempStr[STR_CHAR_CNT - h], pVarFont) - GetTextWidth |
||
2573 | ( |
||
2574 | tempXchar, |
||
2575 | pVarFont |
||
2576 | ), |
||
2577 | pieY - GetTextHeight(pVarFont) |
||
2578 | ); |
||
2579 | pieLabelYPos2 = pieY - (GetTextHeight(pVarFont) << 1); |
||
2580 | } |
||
2581 | } |
||
2582 | else if((m + (dTemp >> 1) > 270) && (m + (dTemp >> 1) <= 360)) |
||
2583 | { |
||
2584 | |||
2585 | // check if we need to draw a line |
||
2586 | if((dTemp < GetTextHeight(pVarFont)) || (pieLabelYPos3 > pieY)) |
||
2587 | { |
||
2588 | pieLabelXPos = ctr + z + GetTextHeight(pVarFont); |
||
2589 | |||
2590 | pieSectorXPos = pieX + 3; |
||
2591 | pieSectorYPos = pieY - 2; |
||
2592 | |||
2593 | // draw the line |
||
2594 | if |
||
2595 | ( |
||
2596 | !Line |
||
2597 | ( |
||
2598 | pieSectorXPos, |
||
2599 | pieSectorYPos, |
||
2600 | pieLabelXPos, |
||
2601 | pieLabelYPos3 - (GetTextHeight(pVarFont) >> 1) |
||
2602 | ) |
||
2603 | ) return (0); |
||
2604 | |||
2605 | MoveTo(pieLabelXPos, pieLabelYPos3 - GetTextHeight(pVarFont)); |
||
2606 | pieLabelYPos3 += GetTextHeight(pVarFont); |
||
2607 | } |
||
2608 | else |
||
2609 | { |
||
2610 | MoveTo(pieX + 5, pieY - GetTextHeight(pVarFont)); |
||
2611 | pieLabelYPos3 = pieY + GetTextHeight(pVarFont); |
||
2612 | } |
||
2613 | } |
||
2614 | |||
2615 | state = PIE_DRAW_SECTOR_LOOP_STRINGS_RUN; |
||
2616 | } |
||
2617 | else |
||
2618 | { |
||
2619 | state = PIE_DRAW_SECTOR_LOOP_CONTINUE; |
||
2620 | goto chrt_pie_draw_sector_loop_continue; |
||
2621 | } |
||
2622 | |||
2623 | case PIE_DRAW_SECTOR_LOOP_STRINGS_RUN: |
||
2624 | |||
2625 | // now draw the strings of the values and/or percentages |
||
2626 | SetColor(BLACK); |
||
2627 | SetFont(pVarFont); |
||
2628 | |||
2629 | if(!OutText(&tempStr[STR_CHAR_CNT - h])) |
||
2630 | return (0); |
||
2631 | |||
2632 | state = PIE_DRAW_SECTOR_LOOP_CONTINUE; |
||
2633 | |||
2634 | chrt_pie_draw_sector_loop_continue: |
||
2635 | |||
2636 | case PIE_DRAW_SECTOR_LOOP_CONTINUE: |
||
2637 | j += dTemp; |
||
2638 | varCtr--; |
||
2639 | if(varCtr == 0) |
||
2640 | { |
||
2641 | if(GetState(pCh, CH_DONUT) == CH_DONUT) |
||
2642 | { |
||
2643 | state = PIE_DONUT_HOLE_DRAW; |
||
2644 | goto chrt_pie_donut_hole_draw; |
||
2645 | } |
||
2646 | else |
||
2647 | { |
||
2648 | state = REMOVE; |
||
2649 | return (1); |
||
2650 | } |
||
2651 | } |
||
2652 | |||
2653 | // check if more than one data series to be shown |
||
2654 | if(ChGetShowSeriesCount(pCh) > 1) |
||
2655 | { |
||
2656 | pVar = ChGetNextShowData((DATASERIES *)pVar->pNextData); |
||
2657 | if(pVar == NULL) |
||
2658 | { |
||
2659 | break; |
||
2660 | } |
||
2661 | } |
||
2662 | |||
2663 | k++; |
||
2664 | state = PIE_DRAW_SECTOR_LOOP; |
||
2665 | goto chrt_pie_draw_sector_loop; |
||
2666 | |||
2667 | chrt_pie_donut_hole_draw: |
||
2668 | |||
2669 | case PIE_DONUT_HOLE_DRAW: |
||
2670 | SetColor(LIGHTGRAY); |
||
2671 | if(!Circle(ctr, ctry, (z >> 1) - (z >> 3))) |
||
2672 | return (0); |
||
2673 | SetColor(pCh->hdr.pGolScheme->CommonBkColor); |
||
2674 | if(!FillCircle(ctr, ctry, ((z >> 1) - (z >> 3)) - 1)) |
||
2675 | return (0); |
||
2676 | |||
2677 | state = REMOVE; |
||
2678 | return (1); |
||
2679 | } |
||
2680 | |||
2681 | return (1); |
||
2682 | } |
||
2683 | |||
2684 | /********************************************************************* |
||
2685 | * Function: ChAddDataSeries(CHART *pCh, WORD nSamples, WORD *pData, XCHAR *pName) |
||
2686 | * |
||
2687 | * |
||
2688 | * Notes: Adds a new variable data structure in the linked list |
||
2689 | * of variable datas. Number of samples is given with the |
||
2690 | * array of the samples. If there is only one data |
||
2691 | * nSamples is set to 1 with the address of the variable data. |
||
2692 | * |
||
2693 | * |
||
2694 | ********************************************************************/ |
||
2695 | DATASERIES *ChAddDataSeries(CHART *pCh, WORD nSamples, WORD *pData, XCHAR *pName) |
||
2696 | { |
||
2697 | DATASERIES *pVar = NULL, *pListVar; |
||
2698 | |||
2699 | pVar = (DATASERIES *)GFX_malloc(sizeof(DATASERIES)); |
||
2700 | |||
2701 | if(pVar == NULL) |
||
2702 | return (NULL); |
||
2703 | |||
2704 | // add the other parameters of the variable data |
||
2705 | pVar->pSData = (XCHAR *)pName; |
||
2706 | pVar->samples = nSamples; |
||
2707 | pVar->pData = (WORD *)pData; |
||
2708 | pVar->show = SHOW_DATA; |
||
2709 | pVar->pNextData = NULL; |
||
2710 | |||
2711 | pListVar = pCh->pChData; |
||
2712 | if(pCh->pChData == NULL) |
||
2713 | pCh->pChData = pVar; |
||
2714 | else |
||
2715 | { |
||
2716 | |||
2717 | // search the end of the list and append the new data |
||
2718 | while(pListVar->pNextData != NULL) |
||
2719 | pListVar = pListVar->pNextData; |
||
2720 | pListVar->pNextData = pVar; |
||
2721 | } |
||
2722 | |||
2723 | // update the variable count before exiting |
||
2724 | pCh->prm.seriesCount++; |
||
2725 | return (DATASERIES *)pVar; |
||
2726 | } |
||
2727 | |||
2728 | /********************************************************************* |
||
2729 | * Function: ChRemoveDataSeries(CHART *pCh, WORD number) |
||
2730 | * |
||
2731 | * |
||
2732 | * Notes: Removes a data series structure in the linked list |
||
2733 | * of data series. |
||
2734 | * |
||
2735 | ********************************************************************/ |
||
2736 | void ChRemoveDataSeries(CHART *pCh, WORD number) |
||
2737 | { |
||
2738 | DATASERIES *pVar = NULL, *pPrevVar = NULL; |
||
2739 | WORD ctr = 1; |
||
2740 | |||
2741 | pVar = pCh->pChData; |
||
2742 | |||
2743 | // check if the list is empty |
||
2744 | if(pVar == NULL) |
||
2745 | return; |
||
2746 | |||
2747 | // check if there is only one entry |
||
2748 | if(pVar->pNextData == NULL) |
||
2749 | { |
||
2750 | GFX_free(pVar); |
||
2751 | pCh->pChData = NULL; |
||
2752 | return; |
||
2753 | } |
||
2754 | |||
2755 | if(number == 0) |
||
2756 | { |
||
2757 | |||
2758 | // remove all |
||
2759 | while(pVar != NULL) |
||
2760 | { |
||
2761 | pPrevVar = pVar; |
||
2762 | pVar = pVar->pNextData; |
||
2763 | |||
2764 | // free the memory used by the item |
||
2765 | GFX_free(pPrevVar); |
||
2766 | } |
||
2767 | |||
2768 | return; |
||
2769 | } |
||
2770 | |||
2771 | // there are more than one entry, remove the entry specified |
||
2772 | while(ctr < number) |
||
2773 | { |
||
2774 | pPrevVar = pVar; |
||
2775 | pVar = pVar->pNextData; |
||
2776 | ctr++; |
||
2777 | } |
||
2778 | |||
2779 | // remove the item from the list |
||
2780 | pPrevVar->pNextData = pVar->pNextData; |
||
2781 | |||
2782 | // free the memory used by the item |
||
2783 | GFX_free(pVar); |
||
2784 | |||
2785 | return; |
||
2786 | } |
||
2787 | |||
2788 | /********************************************************************* |
||
2789 | * Function: ChSetDataSeries(CHART *pCh, WORD seriesNum, BYTE status) |
||
2790 | * |
||
2791 | * |
||
2792 | * Notes: Sets the specified data series number show flag to be set to |
||
2793 | * SHOW_DATA or HIDE_DATA depending on the status. |
||
2794 | * If the seriesNum is 0, it sets all the data series |
||
2795 | * entries in the data series linked list. Returns the same passed |
||
2796 | * number if successful otherwise -1 if unsuccesful. |
||
2797 | * |
||
2798 | ********************************************************************/ |
||
2799 | SHORT ChSetDataSeries(CHART *pCh, WORD seriesNum, BYTE status) |
||
2800 | { |
||
2801 | DATASERIES *pListSer; |
||
2802 | WORD ctr = 1; |
||
2803 | |||
2804 | pListSer = pCh->pChData; |
||
2805 | |||
2806 | // check if the list is empty |
||
2807 | if(pListSer == NULL) |
||
2808 | return (-1); |
||
2809 | |||
2810 | while(pListSer != NULL) |
||
2811 | { |
||
2812 | |||
2813 | // check if we need to show all |
||
2814 | if(seriesNum == 0) |
||
2815 | pListSer->show = status; |
||
2816 | else if(seriesNum == ctr) |
||
2817 | { |
||
2818 | pListSer->show = status; |
||
2819 | break; |
||
2820 | } |
||
2821 | |||
2822 | ctr++; |
||
2823 | pListSer = pListSer->pNextData; |
||
2824 | } |
||
2825 | |||
2826 | if(seriesNum == ctr) |
||
2827 | return (seriesNum); |
||
2828 | else |
||
2829 | return (-1); |
||
2830 | } |
||
2831 | |||
2832 | /********************************************************************* |
||
2833 | * Function: ChSetSampleRange(CHART *pCh, WORD start, WORD end) |
||
2834 | * |
||
2835 | * |
||
2836 | * Notes: Sets the sampling start and end points when drawing the chart. |
||
2837 | * Depending on the number of data series with SHOW_DATA flag |
||
2838 | * set and the values of end and start samples a single |
||
2839 | * data series is drawn or multiple data series are drawn. |
||
2840 | * |
||
2841 | ********************************************************************/ |
||
2842 | void ChSetSampleRange(CHART *pCh, WORD start, WORD end) |
||
2843 | { |
||
2844 | pCh->prm.smplStart = start; |
||
2845 | if(end < start) |
||
2846 | pCh->prm.smplEnd = start; |
||
2847 | else |
||
2848 | pCh->prm.smplEnd = end; |
||
2849 | } |
||
2850 | |||
2851 | /********************************************************************* |
||
2852 | * Function: ChSetValueRange(CHART *pCh, WORD min, WORD max) |
||
2853 | * |
||
2854 | * |
||
2855 | * Notes: Sets the sampling start and end points when drawing the chart. |
||
2856 | * Depending on the number of data series with SHOW_DATA flag |
||
2857 | * set and the values of end and start samples a single |
||
2858 | * data series is drawn or multiple data series are drawn. |
||
2859 | * |
||
2860 | ********************************************************************/ |
||
2861 | void ChSetValueRange(CHART *pCh, WORD min, WORD max) |
||
2862 | { |
||
2863 | pCh->prm.valMin = min; |
||
2864 | if(max < min) |
||
2865 | pCh->prm.valMax = min; |
||
2866 | else |
||
2867 | pCh->prm.valMax = max; |
||
2868 | } |
||
2869 | |||
2870 | /********************************************************************* |
||
2871 | * Function: ChSetPercentRange(CHART *pCh, WORD min, WORD max) |
||
2872 | * |
||
2873 | * |
||
2874 | * Notes: Sets the percentage range when drawing the chart. This affects |
||
2875 | * bar charts only and CH_PERCENTAGE bit state is set. |
||
2876 | * |
||
2877 | ********************************************************************/ |
||
2878 | void ChSetPercentRange(CHART *pCh, WORD min, WORD max) |
||
2879 | { |
||
2880 | pCh->prm.perMin = min; |
||
2881 | if(max < min) |
||
2882 | pCh->prm.perMax = min; |
||
2883 | else |
||
2884 | pCh->prm.perMax = max; |
||
2885 | } |
||
2886 | |||
2887 | ///////////////////// SIN and COS Tables from 0 to 45 deg ///////////////////// |
||
2888 | const WORD sinTable[] __attribute__((aligned(2))) = |
||
2889 | { |
||
2890 | 0, |
||
2891 | 1143, |
||
2892 | 2287, |
||
2893 | 3429, |
||
2894 | 4571, |
||
2895 | 5711, |
||
2896 | 6850, |
||
2897 | 7986, |
||
2898 | 9120, |
||
2899 | 10251, |
||
2900 | 11380, |
||
2901 | 12504, |
||
2902 | 13625, |
||
2903 | 14742, |
||
2904 | 15854, |
||
2905 | 16961, |
||
2906 | 18063, |
||
2907 | 19160, |
||
2908 | 20251, |
||
2909 | 21336, |
||
2910 | 22414, |
||
2911 | 23485, |
||
2912 | 24549, |
||
2913 | 25606, |
||
2914 | 26655, |
||
2915 | 27696, |
||
2916 | 28728, |
||
2917 | 29752, |
||
2918 | 30766, |
||
2919 | 31771, |
||
2920 | 32767, |
||
2921 | 33753, |
||
2922 | 34728, |
||
2923 | 35692, |
||
2924 | 36646, |
||
2925 | 37589, |
||
2926 | 38520, |
||
2927 | 39439, |
||
2928 | 40347, |
||
2929 | 41242, |
||
2930 | 42125, |
||
2931 | 42994, |
||
2932 | 43851, |
||
2933 | 44694, |
||
2934 | 45524, |
||
2935 | 46340 |
||
2936 | }; |
||
2937 | |||
2938 | const WORD cosTable[] __attribute__((aligned(2))) = |
||
2939 | { |
||
2940 | 65535, |
||
2941 | 65525, |
||
2942 | 65495, |
||
2943 | 65445, |
||
2944 | 65375, |
||
2945 | 65285, |
||
2946 | 65175, |
||
2947 | 65046, |
||
2948 | 64897, |
||
2949 | 64728, |
||
2950 | 64539, |
||
2951 | 64330, |
||
2952 | 64102, |
||
2953 | 63855, |
||
2954 | 63588, |
||
2955 | 63301, |
||
2956 | 62996, |
||
2957 | 62671, |
||
2958 | 62327, |
||
2959 | 61964, |
||
2960 | 61582, |
||
2961 | 61182, |
||
2962 | 60762, |
||
2963 | 60325, |
||
2964 | 59869, |
||
2965 | 59394, |
||
2966 | 58902, |
||
2967 | 58392, |
||
2968 | 57863, |
||
2969 | 57318, |
||
2970 | 56754, |
||
2971 | 56174, |
||
2972 | 55576, |
||
2973 | 54962, |
||
2974 | 54330, |
||
2975 | 53683, |
||
2976 | 53018, |
||
2977 | 52338, |
||
2978 | 51642, |
||
2979 | 50930, |
||
2980 | 50202, |
||
2981 | 49459, |
||
2982 | 48701, |
||
2983 | 47929, |
||
2984 | 47141, |
||
2985 | 46340 |
||
2986 | }; |
||
2987 | |||
2988 | /* */ |
||
2989 | |||
2990 | void FillSector(SHORT x, SHORT y, WORD outLineColor) |
||
2991 | { |
||
2992 | WORD pixel; |
||
2993 | SHORT left, right; |
||
2994 | SHORT top, bottom; |
||
2995 | SHORT xc, yc; |
||
2996 | |||
2997 | // scan down |
||
2998 | top = bottom = yc = y; |
||
2999 | left = right = xc = x; |
||
3000 | while(1) |
||
3001 | { |
||
3002 | pixel = GetPixel(xc, yc); |
||
3003 | if(pixel == outLineColor) |
||
3004 | { |
||
3005 | for(xc = left + 1; xc < right; xc++) |
||
3006 | { |
||
3007 | pixel = GetPixel(xc, yc); |
||
3008 | if(pixel != outLineColor) |
||
3009 | { |
||
3010 | break; |
||
3011 | } |
||
3012 | } |
||
3013 | |||
3014 | if(xc == right) |
||
3015 | break; |
||
3016 | } |
||
3017 | |||
3018 | // left scan |
||
3019 | left = xc; |
||
3020 | do |
||
3021 | { |
||
3022 | left--; |
||
3023 | pixel = GetPixel(left, yc); |
||
3024 | } while(pixel != outLineColor); |
||
3025 | while(!Line(xc, yc, left + 1, yc)); |
||
3026 | |||
3027 | // right scan |
||
3028 | right = xc; |
||
3029 | pixel = GetPixel(right, yc); |
||
3030 | do |
||
3031 | { |
||
3032 | right++; |
||
3033 | pixel = GetPixel(right, yc); |
||
3034 | } while(pixel != outLineColor); |
||
3035 | while(!Line(xc, yc, right - 1, yc)); |
||
3036 | |||
3037 | xc = (left + right) >> 1; |
||
3038 | yc++; |
||
3039 | } |
||
3040 | |||
3041 | // scan up |
||
3042 | yc = y; |
||
3043 | xc = x; |
||
3044 | while(1) |
||
3045 | { |
||
3046 | pixel = GetPixel(xc, yc); |
||
3047 | if(pixel == outLineColor) |
||
3048 | { |
||
3049 | for(xc = left + 1; xc < right; xc++) |
||
3050 | { |
||
3051 | pixel = GetPixel(xc, yc); |
||
3052 | if(pixel != outLineColor) |
||
3053 | { |
||
3054 | break; |
||
3055 | } |
||
3056 | } |
||
3057 | |||
3058 | if(xc == right) |
||
3059 | break; |
||
3060 | } |
||
3061 | |||
3062 | // left scan |
||
3063 | left = xc; |
||
3064 | do |
||
3065 | { |
||
3066 | left--; |
||
3067 | pixel = GetPixel(left, yc); |
||
3068 | } while(pixel != outLineColor); |
||
3069 | while(!Line(xc, yc, left + 1, yc)); |
||
3070 | |||
3071 | // right scan |
||
3072 | right = xc; |
||
3073 | pixel = GetPixel(right, yc); |
||
3074 | do |
||
3075 | { |
||
3076 | right++; |
||
3077 | pixel = GetPixel(right, yc); |
||
3078 | } while(pixel != outLineColor); |
||
3079 | while(!Line(xc, yc, right - 1, yc)); |
||
3080 | |||
3081 | xc = (left + right) >> 1; |
||
3082 | yc--; |
||
3083 | } |
||
3084 | } |
||
3085 | |||
3086 | /* */ |
||
3087 | void GetCirclePoint(SHORT radius, SHORT angle, SHORT *x, SHORT *y) |
||
3088 | { |
||
3089 | DWORD rad; |
||
3090 | |||
3091 | //DWORD_VAL ss; |
||
3092 | SHORT ang; |
||
3093 | SHORT temp; |
||
3094 | |||
3095 | ang = angle % 45; |
||
3096 | if((angle / 45) & 0x01) |
||
3097 | ang = 45 - ang; |
||
3098 | |||
3099 | rad = radius; |
||
3100 | rad *= cosTable[ang]; |
||
3101 | |||
3102 | *x = ((DWORD_VAL) rad).w[1]; |
||
3103 | |||
3104 | //ss.Val = rad; |
||
3105 | //*x = ss.w[1]; |
||
3106 | rad = radius; |
||
3107 | rad *= sinTable[ang]; |
||
3108 | |||
3109 | *y = ((DWORD_VAL) rad).w[1]; |
||
3110 | |||
3111 | //ss.Val = rad; |
||
3112 | //*y = ss.w[1]; |
||
3113 | if(((angle > 45) && (angle < 135)) || ((angle > 225) && (angle < 315))) |
||
3114 | { |
||
3115 | temp = *x; |
||
3116 | *x = *y; |
||
3117 | *y = temp; |
||
3118 | } |
||
3119 | |||
3120 | if((angle > 90) && (angle < 270)) |
||
3121 | { |
||
3122 | *x = -*x; |
||
3123 | } |
||
3124 | |||
3125 | if((angle > 180) && (angle < 360)) |
||
3126 | { |
||
3127 | *y = -*y; |
||
3128 | } |
||
3129 | } |
||
3130 | |||
3131 | /* */ |
||
3132 | WORD DrawSector(SHORT cx, SHORT cy, SHORT outRadius, SHORT angleFrom, SHORT angleTo, WORD outLineColor) |
||
3133 | { |
||
3134 | typedef enum |
||
3135 | { |
||
3136 | SEC_DRAW_IDLE, |
||
3137 | SEC_DRAW_EDGE1, |
||
3138 | SEC_DRAW_EDGE2, |
||
3139 | SEC_DRAW_EDGE3, |
||
3140 | SEC_DRAW_EDGE4, |
||
3141 | SEC_DRAW_EDGE5, |
||
3142 | SEC_DRAW_FILLINIT, |
||
3143 | SEC_DRAW_FILL, |
||
3144 | } DRAW_SECTOR_STATES; |
||
3145 | |||
3146 | static SHORT x1, y1, x2, y2, x3, y3; |
||
3147 | static SHORT angleMid; |
||
3148 | static WORD tempColor; |
||
3149 | LONG temp; |
||
3150 | |||
3151 | static DRAW_SECTOR_STATES sectorState = SEC_DRAW_IDLE; |
||
3152 | |||
3153 | switch(sectorState) |
||
3154 | { |
||
3155 | case SEC_DRAW_IDLE: |
||
3156 | |||
3157 | // calculate points |
||
3158 | angleMid = (angleTo + angleFrom) >> 1; |
||
3159 | GetCirclePoint(outRadius, angleFrom, &x1, &y1); |
||
3160 | GetCirclePoint(outRadius, angleTo, &x2, &y2); |
||
3161 | x1 += cx; |
||
3162 | y1 += cy; |
||
3163 | x2 += cx; |
||
3164 | y2 += cy; |
||
3165 | |||
3166 | // grab the current color value for later use |
||
3167 | tempColor = GetColor(); |
||
3168 | |||
3169 | // check if we need to draw the edges |
||
3170 | // special case for single data shown on pie chart |
||
3171 | // we remove the line drawn at angle 0 |
||
3172 | if(!((angleFrom == 0) && (angleTo == 360))) |
||
3173 | { |
||
3174 | sectorState = SEC_DRAW_EDGE1; |
||
3175 | |||
3176 | // special case for small angles |
||
3177 | GetCirclePoint(outRadius - 1, angleFrom + 1, &x3, &y3); |
||
3178 | x3 += cx; |
||
3179 | y3 += cy; |
||
3180 | goto sec_draw_edge1; |
||
3181 | } |
||
3182 | else |
||
3183 | { |
||
3184 | sectorState = SEC_DRAW_FILLINIT; |
||
3185 | goto sec_draw_fillinit; |
||
3186 | } |
||
3187 | |||
3188 | case SEC_DRAW_EDGE1: |
||
3189 | sec_draw_edge1 : if(!Line(x3, y3, cx, cy)) return (0); |
||
3190 | GetCirclePoint(outRadius - 1, angleTo - 1, &x3, &y3); |
||
3191 | x3 += cx; |
||
3192 | y3 += cy; |
||
3193 | sectorState = SEC_DRAW_EDGE2; |
||
3194 | |||
3195 | case SEC_DRAW_EDGE2: |
||
3196 | if(!Line(x3, y3, cx, cy)) |
||
3197 | return (0); |
||
3198 | GetCirclePoint(outRadius - 1, angleMid, &x3, &y3); |
||
3199 | x3 += cx; |
||
3200 | y3 += cy; |
||
3201 | sectorState = SEC_DRAW_EDGE3; |
||
3202 | |||
3203 | case SEC_DRAW_EDGE3: |
||
3204 | if(!Line(x3, y3, cx, cy)) |
||
3205 | return (0); |
||
3206 | SetColor(outLineColor); |
||
3207 | sectorState = SEC_DRAW_EDGE4; |
||
3208 | |||
3209 | case SEC_DRAW_EDGE4: |
||
3210 | if(!Line(x1, y1, cx, cy)) |
||
3211 | return (0); |
||
3212 | sectorState = SEC_DRAW_EDGE5; |
||
3213 | |||
3214 | case SEC_DRAW_EDGE5: |
||
3215 | if(!Line(x2, y2, cx, cy)) |
||
3216 | return (0); |
||
3217 | sectorState = SEC_DRAW_FILLINIT; |
||
3218 | |||
3219 | case SEC_DRAW_FILLINIT: |
||
3220 | sec_draw_fillinit : SetColor(tempColor); |
||
3221 | |||
3222 | temp = ((x1 - x2) * (x1 - x2)); |
||
3223 | temp += ((y1 - y2) * (y1 - y2)); |
||
3224 | |||
3225 | if(((DWORD) temp <= (DWORD) 16) && ((angleTo - angleFrom) < 90)) |
||
3226 | { |
||
3227 | sectorState = SEC_DRAW_IDLE; |
||
3228 | return (1); |
||
3229 | } |
||
3230 | |||
3231 | GetCirclePoint(outRadius - 2, angleMid, &x3, &y3); |
||
3232 | x3 += cx; |
||
3233 | y3 += cy; |
||
3234 | sectorState = SEC_DRAW_FILL; |
||
3235 | |||
3236 | case SEC_DRAW_FILL: |
||
3237 | |||
3238 | // FillSector() is a blocking call |
||
3239 | // making it non-blocking will further add delay to the rendering |
||
3240 | FillSector(x3, y3, outLineColor); |
||
3241 | sectorState = SEC_DRAW_IDLE; |
||
3242 | break; |
||
3243 | } // end of switch() |
||
3244 | |||
3245 | return (1); |
||
3246 | } |
||
3247 | |||
3248 | #endif // USE_CHART |
Powered by WebSVN v2.8.3