?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

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
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3