|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /****************************** Module Header ******************************* ! 13: * Module Name: TPAINT.C ! 14: * ! 15: * Paint functions ! 16: * ! 17: * Functions: ! 18: * ! 19: * GetTextExtent() ! 20: * gtab_updatecontig() ! 21: * gtab_delcr() ! 22: * gtab_updateline() ! 23: * gtab_updatecontig() ! 24: * gtab_boxcell() ! 25: * gtab_paintcell() ! 26: * gtab_paint() ! 27: * gtab_vsep() ! 28: * gtab_hsep() ! 29: * gtab_drawvertline() ! 30: * gtab_invertsel() ! 31: * ! 32: * Comments: ! 33: * ! 34: * See table.h for interface design. ! 35: * ! 36: ****************************************************************************/ ! 37: #include <string.h> ! 38: #include <windows.h> ! 39: #include <commdlg.h> ! 40: ! 41: #include "gutils.h" ! 42: #include "table.h" ! 43: #include "tpriv.h" ! 44: ! 45: ! 46: /*************************************************************************** ! 47: * Function: GetTextExtent ! 48: * ! 49: * Purpose: ! 50: * ! 51: * Calls GetTextExtentPoint - for ease of porting. ! 52: */ ! 53: int ! 54: GetTextExtent(HDC hdc, LPSTR text, int len) ! 55: { ! 56: SIZE sz; ! 57: ! 58: GetTextExtentPoint(hdc, text, len, &sz); ! 59: return(sz.cx); ! 60: } ! 61: ! 62: void gtab_updatecontig(HWND hwnd, lpTable ptab, int line, int cell1, int count); ! 63: ! 64: /*************************************************************************** ! 65: * Function: gtab_delcr ! 66: * ! 67: * Purpose: ! 68: * ! 69: * change all cr/lf chars in input text to spaces ! 70: */ ! 71: void gtab_delcr(LPSTR ptext) ! 72: { ! 73: LPSTR chp; ! 74: ! 75: if (ptext == NULL) { ! 76: return; ! 77: } ! 78: for(chp = ptext; (chp = strchr(chp, '\r')) != NULL; ) { ! 79: *chp = ' '; ! 80: } ! 81: for(chp = ptext; (chp = strchr(chp, '\n')) != NULL; ) { ! 82: *chp = ' '; ! 83: } ! 84: } ! 85: ! 86: /*************************************************************************** ! 87: * Function: gtab_updateline ! 88: * ! 89: * Purpose: ! 90: * ! 91: * Ensures that all visible cells in the given line have valid ! 92: * text and property contents. loop through the cells, picking out ! 93: * contiguous blocks of visible, invalid cells and call ! 94: * gtab_updatecontig to update these from the owner window. ! 95: */ ! 96: void ! 97: gtab_updateline(HWND hwnd, lpTable ptab, int line) ! 98: { ! 99: lpCellPos ppos; ! 100: int cell1, cellcount; ! 101: lpLineData pline; ! 102: lpCellData cd; ! 103: int i; ! 104: ! 105: pline = &ptab->pdata[line]; ! 106: cell1 = 0; ! 107: cellcount = 0; ! 108: for (i = 0; i < ptab->hdr.ncols; i++) { ! 109: ppos = &ptab->pcellpos[i]; ! 110: cd = &pline->pdata[i]; ! 111: if (ppos->clipstart < ppos->clipend) { ! 112: if ((cd->flags & CELL_VALID) == 0) { ! 113: /* add a cell to the list to be updated*/ ! 114: if (cellcount++ == 0) { ! 115: cell1 = i; ! 116: } ! 117: } else { ! 118: /* this cell already valid - so end of ! 119: * a contig block. if the contig ! 120: * block just ended contained cells to update, ! 121: * do it now ! 122: */ ! 123: if (cellcount > 0) { ! 124: gtab_updatecontig(hwnd, ptab, ! 125: line, cell1, cellcount); ! 126: } ! 127: cellcount = 0; ! 128: } ! 129: } ! 130: /* cell not visible - end of a contig block. If it was a ! 131: * non-empty contig block, then update it now. ! 132: */ ! 133: if (cellcount > 0) { ! 134: gtab_updatecontig(hwnd, ptab, line, cell1, cellcount); ! 135: cellcount = 0; ! 136: } ! 137: } ! 138: if (cellcount > 0) { ! 139: gtab_updatecontig(hwnd, ptab, line, cell1, cellcount); ! 140: cellcount = 0; ! 141: } ! 142: } ! 143: ! 144: /*************************************************************************** ! 145: * Function: gtab_updatecontig ! 146: * ! 147: * Purpose: ! 148: * ! 149: * Updates a contiguous block of invalid cells by calling the owner window ! 150: */ ! 151: void ! 152: gtab_updatecontig(HWND hwnd, lpTable ptab, int line, int cell1, int count) ! 153: { ! 154: lpLineData pline; ! 155: lpCellData cd; ! 156: CellDataList list; ! 157: lpProps colprops; ! 158: int i; ! 159: ! 160: pline = &ptab->pdata[line]; ! 161: cd = &pline->pdata[cell1]; ! 162: ! 163: list.id = ptab->hdr.id; ! 164: list.row = gtab_linetorow(hwnd, ptab, line); ! 165: list.startcell = cell1; ! 166: list.ncells = count; ! 167: list.plist = cd; ! 168: ! 169: /* clear out prop flags */ ! 170: for (i = 0; i < count; i++) { ! 171: cd[i].props.valid = 0; ! 172: if (cd[i].nchars > 0) { ! 173: cd[i].ptext[0] = '\0'; ! 174: } ! 175: } ! 176: ! 177: if (list.row < ptab->hdr.nrows) { ! 178: gtab_sendtq(hwnd, TQ_GETDATA, (long) (LPSTR) &list); ! 179: } ! 180: ! 181: /* for each cell, mark valid and set properties */ ! 182: for (i = 0; i < count; i++) { ! 183: cd[i].flags |= CELL_VALID; ! 184: gtab_delcr(cd[i].ptext); ! 185: /* fetch properties from hdr and colhdr */ ! 186: colprops = &ptab->pcolhdr[i + cell1].props; ! 187: if (!(cd[i].props.valid & P_FCOLOUR)) { ! 188: if (colprops->valid & P_FCOLOUR) { ! 189: cd[i].props.valid |= P_FCOLOUR; ! 190: cd[i].props.forecolour = colprops->forecolour; ! 191: } else if (ptab->hdr.props.valid & P_FCOLOUR) { ! 192: cd[i].props.valid |= P_FCOLOUR; ! 193: cd[i].props.forecolour = ! 194: ptab->hdr.props.forecolour; ! 195: } ! 196: } ! 197: ! 198: if (!(cd[i].props.valid & P_BCOLOUR)) { ! 199: if (colprops->valid & P_BCOLOUR) { ! 200: cd[i].props.valid |= P_BCOLOUR; ! 201: cd[i].props.backcolour = colprops->backcolour; ! 202: } else if (ptab->hdr.props.valid & P_BCOLOUR) { ! 203: cd[i].props.valid |= P_BCOLOUR; ! 204: cd[i].props.backcolour = ! 205: ptab->hdr.props.backcolour; ! 206: } ! 207: } ! 208: ! 209: if (!(cd[i].props.valid & P_FONT)) { ! 210: if (colprops->valid & P_FONT) { ! 211: cd[i].props.valid |= P_FONT; ! 212: cd[i].props.hFont = colprops->hFont; ! 213: } else if (ptab->hdr.props.valid & P_FONT) { ! 214: cd[i].props.valid |= P_FONT; ! 215: cd[i].props.hFont = ptab->hdr.props.hFont; ! 216: } ! 217: } ! 218: ! 219: if (!(cd[i].props.valid & P_ALIGN)) { ! 220: if (colprops->valid & P_ALIGN) { ! 221: cd[i].props.valid |= P_ALIGN; ! 222: cd[i].props.alignment = colprops->alignment; ! 223: } else if (ptab->hdr.props.valid & P_ALIGN) { ! 224: cd[i].props.valid |= P_ALIGN; ! 225: cd[i].props.alignment = ! 226: ptab->hdr.props.alignment; ! 227: } ! 228: } ! 229: ! 230: if (!(cd[i].props.valid & P_BOX)) { ! 231: if (colprops->valid & P_BOX) { ! 232: cd[i].props.valid |= P_BOX; ! 233: cd[i].props.box = colprops->box; ! 234: } else if (ptab->hdr.props.valid & P_BOX) { ! 235: cd[i].props.valid |= P_BOX; ! 236: cd[i].props.box = ptab->hdr.props.box; ! 237: } ! 238: } ! 239: /* you can't set width/height per cell - this ! 240: * is ignored at cell level. ! 241: */ ! 242: } ! 243: ! 244: } ! 245: ! 246: /*************************************************************************** ! 247: * Function: gtab_boxcell ! 248: * ! 249: * Purpose: ! 250: * ! 251: * Draws box around a cell in a table. ! 252: */ ! 253: void ! 254: gtab_boxcell(HWND hwnd, HDC hdc, LPRECT rcp, LPRECT pclip, UINT boxmode) ! 255: { ! 256: if (boxmode & P_BOXTOP) { ! 257: MoveToEx(hdc, max(rcp->left, pclip->left), ! 258: max(rcp->top, pclip->top), NULL); ! 259: LineTo(hdc, min(rcp->right, pclip->right), ! 260: max(rcp->top, pclip->top)); ! 261: } ! 262: if (boxmode & P_BOXBOTTOM) { ! 263: MoveToEx(hdc, max(rcp->left, pclip->left), ! 264: min(rcp->bottom, pclip->bottom), NULL); ! 265: LineTo(hdc, min(rcp->right, pclip->right), ! 266: min(rcp->bottom, pclip->bottom)); ! 267: } ! 268: if (boxmode & P_BOXLEFT) { ! 269: MoveToEx(hdc, max(rcp->left, pclip->left), ! 270: max(rcp->top, pclip->top), NULL); ! 271: MoveToEx(hdc, max(rcp->left, pclip->left), ! 272: min(rcp->bottom, pclip->bottom), NULL); ! 273: } ! 274: if (boxmode & P_BOXRIGHT) { ! 275: MoveToEx(hdc, min(rcp->right, pclip->right), ! 276: max(rcp->top, pclip->top), NULL); ! 277: LineTo(hdc, min(rcp->right, pclip->right), ! 278: min(rcp->bottom, pclip->bottom)); ! 279: } ! 280: } ! 281: ! 282: /*************************************************************************** ! 283: * Function: gtab_paintcell ! 284: * ! 285: * Purpose: ! 286: * ! 287: * Paints a cell. ! 288: */ ! 289: void ! 290: gtab_paintcell(HWND hwnd, HDC hdc, lpTable ptab, int line, int cell) ! 291: { ! 292: lpLineData pline; ! 293: lpCellData cd; ! 294: lpCellPos ppos; ! 295: RECT rc, rcbox; ! 296: int cx, x, y, tabwidth; ! 297: UINT align; ! 298: LPSTR chp, tabp; ! 299: DWORD fcol, bkcol; ! 300: HFONT hfont; ! 301: TEXTMETRIC tm; ! 302: HBRUSH hbr; ! 303: ! 304: /* init pointers to cell text and properties */ ! 305: pline = &ptab->pdata[line]; ! 306: cd = &pline->pdata[cell]; ! 307: ppos = &ptab->pcellpos[cell]; ! 308: ! 309: /* clip all output to this rectangle */ ! 310: rc.top = pline->linepos.clipstart; ! 311: rc.bottom = pline->linepos.clipend; ! 312: rc.left = ppos->clipstart; ! 313: rc.right = ppos->clipend; ! 314: ! 315: ! 316: /* check cell properties and colours */ ! 317: if (cd->props.valid & P_ALIGN) { ! 318: align = cd->props.alignment; ! 319: } else { ! 320: align = P_LEFT; ! 321: } ! 322: if (cd->props.valid & P_FONT) { ! 323: hfont = SelectObject(hdc, cd->props.hFont); ! 324: GetTextMetrics(hdc, &tm); ! 325: tabwidth = tm.tmAveCharWidth * 8; ! 326: } else { ! 327: tabwidth = ptab->avewidth * 8; ! 328: } ! 329: ! 330: /* set colours if not default */ ! 331: if (cd->props.valid & P_FCOLOUR) { ! 332: fcol = SetTextColor(hdc, cd->props.forecolour); ! 333: } ! 334: if (cd->props.valid & P_BCOLOUR) { ! 335: /* there is a non-default background colour. ! 336: * create a brush and fill the entire cell with it ! 337: */ ! 338: hbr = CreateSolidBrush(cd->props.backcolour); ! 339: FillRect(hdc, &rc, hbr); ! 340: DeleteObject(hbr); ! 341: ! 342: /* also set colour as background colour for the text */ ! 343: bkcol = SetBkColor(hdc, cd->props.backcolour); ! 344: } ! 345: ! 346: /* calc offset of text within cell for right-align or centering */ ! 347: if (align == P_LEFT) { ! 348: cx = ptab->avewidth/2; ! 349: } else { ! 350: if (cd->ptext == NULL) { ! 351: cx = 0; ! 352: } else { ! 353: cx = LOWORD(GetTextExtent(hdc, cd->ptext, ! 354: lstrlen(cd->ptext))); ! 355: } ! 356: if (align == P_CENTRE) { ! 357: cx = (ppos->size - cx) / 2; ! 358: } else { ! 359: cx = ppos->size - cx - (ptab->avewidth/2); ! 360: } ! 361: } ! 362: cx += ppos->start; ! 363: ! 364: /* expand tabs on output */ ! 365: x = 0; ! 366: y = pline->linepos.start; ! 367: ! 368: for (chp = cd->ptext; ! 369: ((chp != NULL) && ((tabp = strchr(chp, '\t')) != NULL)); ) { ! 370: /* perform output upto tab char */ ! 371: ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, tabp-chp, NULL); ! 372: ! 373: /* advance past the tab */ ! 374: x += LOWORD(GetTextExtent(hdc, chp, tabp - chp)); ! 375: x = ( (x + tabwidth) / tabwidth) * tabwidth; ! 376: chp = ++tabp; ! 377: } ! 378: ! 379: /*no more tabs - output rest of string */ ! 380: if (chp != NULL) { ! 381: ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, ! 382: chp, lstrlen(chp), NULL); ! 383: } ! 384: ! 385: /* reset colours to original if not default */ ! 386: if (cd->props.valid & P_FCOLOUR) { ! 387: SetTextColor(hdc, fcol); ! 388: } ! 389: if (cd->props.valid & P_BCOLOUR) { ! 390: SetBkColor(hdc, bkcol); ! 391: } ! 392: if (cd->props.valid & P_FONT) { ! 393: SelectObject(hdc, hfont); ! 394: } ! 395: ! 396: /* now box cell if marked */ ! 397: if (cd->props.valid & P_BOX) { ! 398: if (cd->props.box != 0) { ! 399: rcbox.top = pline->linepos.start; ! 400: rcbox.bottom = rcbox.top + pline->linepos.size; ! 401: rcbox.left = ppos->start; ! 402: rcbox.right = ppos->start + ppos->size; ! 403: gtab_boxcell(hwnd, hdc, &rcbox, &rc, cd->props.box); ! 404: } ! 405: } ! 406: } ! 407: ! 408: /*************************************************************************** ! 409: * Function: gtab_paint ! 410: * ! 411: * Purpose: ! 412: * ! 413: * Fetch and paint the specified line ! 414: */ ! 415: void ! 416: gtab_paint(HWND hwnd, HDC hdc, lpTable ptab, int line) ! 417: { ! 418: lpCellPos ppos; ! 419: int i; ! 420: ! 421: gtab_updateline(hwnd, ptab, line); ! 422: ! 423: for (i = 0; i < ptab->hdr.ncols; i++) { ! 424: ppos = &ptab->pcellpos[i]; ! 425: if (ppos->clipstart < ppos->clipend) { ! 426: gtab_paintcell(hwnd, hdc, ptab, line, i); ! 427: } ! 428: } ! 429: } ! 430: ! 431: ! 432: /*************************************************************************** ! 433: * Function: gtab_vsep ! 434: * ! 435: * Purpose: ! 436: * ! 437: */ ! 438: void ! 439: gtab_vsep(HWND hwnd, lpTable ptab, HDC hdc) ! 440: { ! 441: int x; ! 442: RECT rc; ! 443: ! 444: if (ptab->hdr.fixedcols < 1) { ! 445: return; ! 446: } ! 447: x = ptab->pcellpos[ptab->hdr.fixedcols - 1].clipend+1; ! 448: GetClientRect(hwnd, &rc); ! 449: MoveToEx(hdc, x, rc.top, NULL); ! 450: LineTo(hdc, x, rc.bottom); ! 451: } ! 452: ! 453: /*************************************************************************** ! 454: * Function: gtab_hsep ! 455: * ! 456: * Purpose: ! 457: */ ! 458: void ! 459: gtab_hsep(HWND hwnd, lpTable ptab, HDC hdc) ! 460: { ! 461: int y; ! 462: RECT rc; ! 463: ! 464: if (ptab->hdr.fixedrows < 1) { ! 465: return; ! 466: } ! 467: y = ptab->rowheight * ptab->hdr.fixedrows; ! 468: GetClientRect(hwnd, &rc); ! 469: MoveToEx(hdc, rc.left, y-1, NULL); ! 470: LineTo(hdc, rc.right, y-1); ! 471: } ! 472: ! 473: /*************************************************************************** ! 474: * Function: gtab_drawverline ! 475: * ! 476: * Purpose: ! 477: * ! 478: * Draw in (inverting) the dotted selection lines for tracking a col width ! 479: */ ! 480: void ! 481: gtab_drawvertline(HWND hwnd, lpTable ptab) ! 482: { ! 483: RECT rc; ! 484: HDC hdc; ! 485: HPEN hpen; ! 486: ! 487: hdc = GetDC(hwnd); ! 488: SetROP2(hdc, R2_XORPEN); ! 489: hpen = SelectObject(hdc, hpenDotted); ! 490: GetClientRect(hwnd, &rc); ! 491: ! 492: MoveToEx(hdc, ptab->trackline1, rc.top, NULL); ! 493: LineTo(hdc, ptab->trackline1, rc.bottom); ! 494: if (ptab->trackline2 != -1) { ! 495: MoveToEx(hdc, ptab->trackline2, rc.top, NULL); ! 496: LineTo(hdc, ptab->trackline2, rc.bottom); ! 497: } ! 498: ! 499: SelectObject(hdc, hpen); ! 500: ReleaseDC(hwnd, hdc); ! 501: } ! 502: ! 503: ! 504: /*************************************************************************** ! 505: * Function: gtab_invertsel ! 506: * ! 507: * Purpose: ! 508: * ! 509: * Mark the selected line, if visible, in the style chosen by the ! 510: * client app. This can be TM_SOLID, meaning an inversion of ! 511: * the whole selected area or TM_FOCUS, meaning, inversion of the first ! 512: * cell, and then a dotted focus rectangle for the rest. ! 513: * ! 514: * This function inverts either style, and so will turn the selection ! 515: * both on and off. ! 516: */ ! 517: void ! 518: gtab_invertsel(HWND hwnd, lpTable ptab, HDC hdc_in) ! 519: { ! 520: HDC hdc; ! 521: int line; ! 522: RECT rc; ! 523: int lastcell; ! 524: ! 525: ! 526: /* is row visible on screen ? */ ! 527: line = gtab_rowtoline(hwnd, ptab, ptab->select.startrow); ! 528: if (line < 0) { ! 529: return; ! 530: } ! 531: ! 532: /* selection mode includes a flag TM_FOCUS indicating we should ! 533: * use a focus rect instead of the traditional inversion for ! 534: * selections in this table. This interferes with multiple backgrnd ! 535: * colours less. However we still do inversion for fixedcols. ! 536: */ ! 537: ! 538: lastcell = (int)(ptab->select.startcell + ptab->select.ncells - 1); ! 539: ! 540: rc.top = ptab->pdata[line].linepos.clipstart; ! 541: rc.bottom = ptab->pdata[line].linepos.clipend; ! 542: ! 543: /* ! 544: * invert the whole area for TM_SOLID or just the first ! 545: * cell for TM_FOCUS ! 546: */ ! 547: rc.left = ptab->pcellpos[ptab->select.startcell].clipstart; ! 548: if (ptab->hdr.selectmode & TM_FOCUS) { ! 549: rc.right = ptab->pcellpos[ptab->select.startcell].clipend; ! 550: }else { ! 551: rc.right = ptab->pcellpos[lastcell].clipend; ! 552: } ! 553: ! 554: if (hdc_in == NULL) { ! 555: hdc = GetDC(hwnd); ! 556: } else { ! 557: hdc = hdc_in; ! 558: } ! 559: ! 560: InvertRect(hdc, &rc); ! 561: ! 562: /* ! 563: * draw focus rectangle around remaining cells on this line, if there ! 564: * are any ! 565: */ ! 566: if (ptab->hdr.selectmode & TM_FOCUS) { ! 567: if (ptab->select.ncells > 1) { ! 568: rc.left = ptab->pcellpos[ptab->select.startcell+1].clipstart; ! 569: rc.right = ptab->pcellpos[lastcell].clipend; ! 570: DrawFocusRect(hdc, &rc); ! 571: } ! 572: } ! 573: ! 574: if (hdc_in == NULL) { ! 575: ReleaseDC(hwnd, hdc); ! 576: } ! 577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.