|
|
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.