| 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