|
|
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: TABLE.C
14: *
15: * Standard table class and main interface functions.
16: *
17: * Functions:
18: *
19: * gtab_init()
20: * gtab_deltools()
21: * gtab_sendtq()
22: * gtab_freelinedata()
23: * gtab_wndproc()
24: * gtab_createtools()
25: * gtab_deltable()
26: * gtab_buildtable()
27: * gtab_setsize()
28: * gtab_newsize()
29: * gtab_calcwidths()
30: * gtab_alloclinedata()
31: * gtab_invallines()
32: * gtab_append()
33: *
34: * Comments:
35: *
36: * The table class communicates with its 'owner' window to
37: * get the layout info and the data to display. The owner window handle
38: * can be sent as the lParam in CreateWindow - if not, the parent window will
39: * be used.
40: *
41: * After creating the window, send it a TM_NEWID message, with a 'data id'
42: * as the lParam. This is any non-zero 32-bit value. The table will then call
43: * back to its owner window to find out how many rows/columns, then to fetch
44: * the name/properties of each column, and finally to get the data to display.
45: *
46: * Send TM_NEWID of 0 to close (or destroy the window) - wait for TQ_CLOSE
47: * (in either case) before discarding data. Send
48: * TM_REFRESH if data or row-count changes; send TM_NEWLAYOUT if column
49: * properties or nr cols change etc - this is the same as sending TM_NEWID
50: * except that no TQ_CLOSE happens on TM_NEWLAYOUT.
51: *
52: * TQ_SELECT is sent whenever the current selection changes. TQ_ENTER is sent
53: * when enter or double-click occurs.
54: *
55: ****************************************************************************/
56:
57: #include <windows.h>
58: #include <commdlg.h>
59:
60: #include "gutils.h"
61: #include "table.h"
62: #include "tpriv.h"
63:
64: /* global tools etc */
65: extern HANDLE hLibInst;
66: HANDLE hVertCurs;
67: HANDLE hNormCurs;
68: HPEN hpenDotted;
69: UINT gtab_msgcode;
70:
71: /* function prototypes */
72: long FAR PASCAL gtab_wndproc(HWND, UINT, UINT, long);
73: void gtab_createtools(void);
74: void gtab_deltable(HWND hwnd, lpTable ptab);
75: lpTable gtab_buildtable(HWND hwnd, DWORD id);
76: void gtab_setsize(HWND hwnd, lpTable ptab);
77: void gtab_newsize(HWND hwnd, lpTable ptab);
78: void gtab_calcwidths(HWND hwnd, lpTable ptab);
79: BOOL gtab_alloclinedata(HWND hwnd, HANDLE heap, lpTable ptab);
80: void gtab_invallines(HWND hwnd, lpTable ptab, int start, int count);
81: void gtab_append(HWND hwnd, lpTable ptab, int rows, DWORD id);
82:
83: /***************************************************************************
84: * Function: gtab_init
85: *
86: * Purpose:
87: *
88: * Initialise window class - called from DLL main init
89: */
90: void
91: gtab_init(void)
92: {
93: WNDCLASS wc;
94:
95: gtab_createtools();
96: gtab_msgcode = RegisterWindowMessage(TableMessage);
97:
98: wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
99: wc.lpfnWndProc = gtab_wndproc;
100: wc.cbClsExtra = 0;
101: wc.cbWndExtra = WLTOTAL;
102: wc.hInstance = hLibInst;
103: wc.hIcon = NULL;
104: wc.hCursor = NULL;
105: wc.hbrBackground = GetStockObject(WHITE_BRUSH);
106: wc.lpszClassName = TableClassName;
107: wc.lpszMenuName = NULL;
108:
109: RegisterClass(&wc);
110: }
111:
112: /***************************************************************************
113: * Function: gtab_createtools
114: *
115: * Purpose:
116: *
117: * Load cursors and pens.
118: */
119: void
120: gtab_createtools(void)
121: {
122: hVertCurs = LoadCursor(hLibInst, "VertLine");
123: hNormCurs = LoadCursor(NULL, IDC_ARROW);
124:
125: hpenDotted = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
126: }
127:
128: /***************************************************************************
129: * Function: gtab_deltools
130: *
131: * Purpose:
132: *
133: * Delete pen
134: */
135: void
136: gtab_deltools(void)
137: {
138: DeleteObject(hpenDotted);
139: }
140:
141:
142: /***************************************************************************
143: * Function: gtab_wndproc
144: *
145: * Purpose:
146: *
147: * Window procedure for table
148: */
149: long FAR PASCAL
150: gtab_wndproc(HWND hwnd, UINT msg, UINT wParam, long lParam)
151: {
152: CREATESTRUCT FAR * csp;
153: HWND hOwner;
154: lpTable ptab;
155: HANDLE hHeap;
156: PAINTSTRUCT ps;
157: int y, y2, i;
158: HDC hDC;
159: lpTableSelection pselect;
160: long oldtop;
161: long change;
162:
163: switch(msg) {
164:
165: case WM_CREATE:
166: /* create window. set the wnd extra bytes to
167: * contain the owner window, a heap and a null table.
168: * Owner window is either in lParam or the parent.
169: * Then wait for TM_NEWID.
170: */
171: csp = (CREATESTRUCT FAR *) lParam;
172: if (csp->lpCreateParams == NULL) {
173: hOwner = GetParent(hwnd);
174: } else {
175: hOwner = (HWND) (long) csp->lpCreateParams;
176: }
177: ptab = NULL;
178: hHeap = gmem_init();
179: SetWindowLong(hwnd, WL_TABLE, (LONG) ptab);
180: SetWindowLong(hwnd, WW_OWNER, (LONG) hOwner);
181: SetWindowLong(hwnd, WW_HEAP, (LONG) hHeap);
182:
183: SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
184: SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
185: break;
186:
187: case TM_NEWID:
188: /* complete change of table.
189: * close old table, discard memory and
190: * build new table
191: */
192: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
193: if (ptab != NULL) {
194: gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id);
195: gtab_deltable(hwnd, ptab);
196: SetCursor(hNormCurs);
197: SetWindowLong(hwnd, WL_TABLE, 0);
198: }
199: if ( (ptab = gtab_buildtable(hwnd, lParam)) != NULL) {
200: SetWindowLong(hwnd, WL_TABLE, (long) (LPSTR) ptab);
201: gtab_setsize(hwnd, ptab);
202: } else {
203: SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
204: SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
205: }
206: InvalidateRect(hwnd, NULL, TRUE);
207: break;
208:
209: case TM_NEWLAYOUT:
210: /* change of layout but for same id. no TQ_CLOSE,
211: * but otherwise same as TM_NEWID
212: */
213: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
214: if (ptab != NULL) {
215: gtab_deltable(hwnd, ptab);
216: SetCursor(hNormCurs);
217: SetWindowLong(hwnd, WL_TABLE, 0);
218: }
219: if ( (ptab = gtab_buildtable(hwnd, lParam)) != NULL) {
220: SetWindowLong(hwnd, WL_TABLE, (long) (LPSTR) ptab);
221: gtab_setsize(hwnd, ptab);
222: } else {
223: SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
224: SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
225: }
226: InvalidateRect(hwnd, NULL, TRUE);
227: break;
228:
229: case TM_REFRESH:
230: /* data in table has changed. nrows may have
231: * changed. ncols and col types have not changed
232: */
233: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
234: if (ptab != NULL) {
235: gtab_newsize(hwnd, ptab);
236: }
237: InvalidateRect(hwnd, NULL, TRUE);
238: break;
239:
240: case TM_SELECT:
241: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
242: if (ptab != NULL) {
243: pselect = (lpTableSelection) lParam;
244:
245: /*
246: * we only support TM_SINGLE - so force the
247: * selection to a single row or cell.
248: */
249: gtab_select(hwnd, ptab, pselect->startrow,
250: pselect->startcell,
251: 1,
252: (ptab->hdr.selectmode & TM_ROW) ?
253: ptab->hdr.ncols : 1,
254: TRUE);
255: gtab_showsel_middle(hwnd, ptab);
256: }
257: break;
258:
259: case TM_PRINT:
260: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
261: hHeap = (HANDLE) GetWindowLong(hwnd, WW_HEAP);
262: if (ptab != NULL) {
263: gtab_print(hwnd, ptab, hHeap, (lpPrintContext) lParam);
264: return(TRUE);
265: }
266:
267: case TM_TOPROW:
268:
269: /* return top row. if wParam is TRUE, set lParam
270: * as the new toprow
271: */
272: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
273: if (ptab == NULL) {
274: return(0);
275: }
276: oldtop = ptab->toprow;
277: if ((wParam) && (lParam < ptab->hdr.nrows)) {
278: change = lParam - ptab->toprow;
279: change -= ptab->hdr.fixedrows;
280: gtab_dovscroll(hwnd, ptab, change);
281: }
282: return(oldtop);
283:
284: case TM_ENDROW:
285: /* return the last visible row in the window */
286: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
287: if (ptab == NULL) {
288: return(0);
289: }
290: return(ptab->nlines + ptab->toprow - 1);
291:
292:
293: case TM_APPEND:
294: /* new rows have been added to the end of the
295: * table, but the rest of the table has no
296: * been change. Update without forcing redraw of
297: * everything.
298: * lParam contains the new total nr of rows
299: */
300: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
301: if (ptab != NULL) {
302: gtab_append(hwnd, ptab, wParam, lParam);
303: return(TRUE);
304: }
305: break;
306:
307: case WM_SIZE:
308: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
309: if (ptab != NULL) {
310: gtab_setsize(hwnd, ptab);
311: }
312: break;
313:
314: case WM_DESTROY:
315: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
316: if (ptab != NULL) {
317: gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id);
318: gtab_deltable(hwnd, ptab);
319: }
320: hHeap = (HANDLE) GetWindowLong(hwnd, WW_HEAP);
321: gmem_freeall(hHeap);
322: break;
323:
324: case WM_PAINT:
325: hDC = BeginPaint(hwnd, &ps);
326: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
327: if (ptab != NULL) {
328: /* separator lines between fixed rows/columns
329: * (ie headers) and the rest - if enabled
330: */
331: /* paint here first for good impression,
332: * and again after to clean up!!
333: */
334: if (ptab->hdr.vseparator) {
335: gtab_vsep(hwnd, ptab, hDC);
336: }
337: if (ptab->hdr.hseparator) {
338: gtab_hsep(hwnd, ptab, hDC);
339: }
340:
341: /* paint only the rows that need painting */
342: for (i = 0; i < ptab->nlines; i++) {
343: y = ptab->pdata[i].linepos.start;
344: y2 = y + ptab->pdata[i].linepos.size;
345: if ( (y <= ps.rcPaint.bottom) &&
346: (y2 >= ps.rcPaint.top)) {
347: gtab_paint(hwnd, hDC, ptab, i);
348: }
349: }
350: if (ptab->hdr.vseparator) {
351: gtab_vsep(hwnd, ptab, hDC);
352: }
353: if (ptab->hdr.hseparator) {
354: gtab_hsep(hwnd, ptab, hDC);
355: }
356: if (ptab->selvisible) {
357: gtab_invertsel(hwnd, ptab, hDC);
358: }
359: }
360:
361: EndPaint(hwnd, &ps);
362: break;
363:
364: case WM_HSCROLL:
365: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
366: if (ptab != NULL) {
367: gtab_msg_hscroll(hwnd, ptab,
368: GET_SCROLL_OPCODE(wParam, lParam),
369: GET_SCROLL_POS(wParam, lParam));
370: }
371: break;
372:
373: case WM_VSCROLL:
374: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
375: if (ptab != NULL) {
376: gtab_msg_vscroll(hwnd, ptab,
377: GET_SCROLL_OPCODE(wParam, lParam),
378: GET_SCROLL_POS(wParam, lParam));
379: }
380: break;
381:
382: case WM_MOUSEMOVE:
383: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
384: if (ptab != NULL) {
385: gtab_move(hwnd, ptab, LOWORD(lParam), HIWORD(lParam));
386: } else {
387: SetCursor(hNormCurs);
388: }
389: break;
390:
391: case WM_LBUTTONDOWN:
392: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
393: if (ptab != NULL) {
394: gtab_press(hwnd, ptab, LOWORD(lParam), HIWORD(lParam));
395: }
396: break;
397:
398: case WM_LBUTTONUP:
399: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
400: if (ptab != NULL) {
401: gtab_release(hwnd, ptab,
402: LOWORD(lParam), HIWORD(lParam));
403: }
404: break;
405:
406: case WM_LBUTTONDBLCLK:
407: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
408: if (ptab != NULL) {
409: gtab_dblclick(hwnd, ptab,
410: LOWORD(lParam), HIWORD(lParam));
411: }
412: break;
413:
414: case WM_KEYDOWN:
415: /* handle key presses for cursor movement about
416: * the table, and return/space for selection.
417: * Any key we don't handle is passed to the owner window
418: * for him to handle.
419: * The table window should have the focus
420: */
421: ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
422: if (ptab != NULL) {
423: if (gtab_key(hwnd, ptab, wParam) != 0) {
424: /* pass key to owner since
425: * we don't know what to do with it
426: */
427: hOwner = (HANDLE) GetWindowLong(hwnd, WW_OWNER);
428: return(SendMessage(hOwner, WM_KEYDOWN,
429: wParam, lParam));
430: } else {
431: return(0);
432: }
433: }
434: break;
435:
436: default:
437: return(DefWindowProc(hwnd, msg, wParam, lParam));
438: }
439: return(TRUE);
440: }
441:
442: /***************************************************************************
443: * Function: gtab_sendtq
444: *
445: * Purpose:
446: *
447: * Send a table-query message to the owner window. Returns message
448: * value.
449: */
450: long
451: gtab_sendtq(HWND hwnd, UINT cmd, long lParam)
452: {
453: HWND hOwner;
454:
455: hOwner = (HANDLE) GetWindowLong(hwnd, WW_OWNER);
456: return (SendMessage(hOwner, gtab_msgcode, cmd, lParam));
457: }
458:
459: /***************************************************************************
460: * Function: gtab_freelinedata
461: *
462: * Purpose:
463: *
464: * Free the memory allocated for the array of lines (each containing
465: * an array of Cells, each containing an array of chars for the actual
466: * data). Called on any occasion that would change the number of visible lines
467: */
468: void
469: gtab_freelinedata(HANDLE hHeap, lpTable ptab)
470: {
471: int i, j, ncols;
472: lpCellData cd;
473:
474:
475: ncols = ptab->hdr.ncols;
476:
477: /* for each line */
478: for(i = 0; i < ptab->nlines; i++) {
479: /* for each cell */
480: for (j = 0; j < ncols; j++) {
481: /* free up the actual text space */
482: cd = &ptab->pdata[i].pdata[j];
483: gmem_free(hHeap, (LPSTR) cd->ptext, cd->nchars);
484: }
485: /* dealloc array of CellData */
486: gmem_free(hHeap, (LPSTR) ptab->pdata[i].pdata,
487: sizeof(CellData) * ncols);
488: }
489: /* de-alloc array of linedatas */
490: gmem_free(hHeap, (LPSTR) ptab->pdata,
491: sizeof(LineData) * ptab->nlines);
492: ptab->pdata = NULL;
493: }
494:
495: /***************************************************************************
496: * Function: gtab_alloclinedata
497: *
498: * Purpose:
499: *
500: * Allocate and init array of linedatas (include cell array
501: * and text for each cell)
502: */
503: BOOL
504: gtab_alloclinedata(HWND hwnd, HANDLE heap, lpTable ptab)
505: {
506: lpLineData pline;
507: lpCellData cd;
508: int i, j;
509:
510: ptab->pdata = (lpLineData) gmem_get(heap,
511: sizeof(LineData) * ptab->nlines);
512: if (ptab->pdata == NULL) {
513: return(FALSE);
514: }
515: for (i = 0; i < ptab->nlines; i++) {
516: pline = &ptab->pdata[i];
517: pline->linepos.size = ptab->rowheight;
518: pline->pdata = (lpCellData) gmem_get(heap,
519: sizeof(CellData) * ptab->hdr.ncols);
520: if (pline->pdata == NULL) {
521: return(FALSE);
522: }
523: for (j = 0; j < ptab->hdr.ncols; j++) {
524: cd = &pline->pdata[j];
525: cd->props.valid = 0;
526: cd->flags = 0;
527: cd->nchars = ptab->pcolhdr[j].nchars;
528: if (cd->nchars > 0) {
529: cd->ptext = gmem_get(heap, cd->nchars);
530: if (cd->ptext == NULL) {
531: return(FALSE);
532: }
533: }
534: }
535: }
536: }
537:
538: /***************************************************************************
539: * Function: gtab_deltable
540: *
541: * Purpose:
542: *
543: * Free up all table data structures. Called for new layout or new data.
544: */
545: void
546: gtab_deltable(HWND hwnd, lpTable ptab)
547: {
548: HANDLE hHeap;
549: int ncols;
550:
551: if (ptab == NULL) {
552: return;
553: }
554: hHeap = (HANDLE) GetWindowLong(hwnd, WW_HEAP);
555: ncols = ptab->hdr.ncols;
556:
557: if (ptab->pcolhdr != NULL) {
558: gmem_free(hHeap, (LPSTR) ptab->pcolhdr,
559: sizeof(ColProps) * ncols);
560: }
561: if (ptab->pcellpos != NULL) {
562: gmem_free(hHeap, (LPSTR) ptab->pcellpos,
563: sizeof(CellPos) * ncols);
564: }
565: if (ptab->pdata != NULL) {
566: gtab_freelinedata(hHeap, ptab);
567: }
568: gmem_free(hHeap, (LPSTR) ptab, sizeof(Table));
569: }
570:
571:
572: /***************************************************************************
573: * Function: gtab_buildtable
574: *
575: * Purpose:
576: *
577: * Build up a Table struct (excluding data allocation and
578: * anything to do with font or window size).
579: * Return ptr to this or NULL if error
580: */
581: lpTable
582: gtab_buildtable(HWND hwnd, DWORD id)
583: {
584: lpTable ptab;
585: HANDLE hHeap;
586: int ncols, i;
587: ColPropsList cplist;
588:
589: hHeap = (HANDLE) GetWindowLong(hwnd, WW_HEAP);
590: ptab = (lpTable) gmem_get(hHeap, sizeof(Table));
591: if (ptab == NULL) {
592: return(NULL);
593: }
594:
595: /* get the row/column count from owner window */
596: ptab->hdr.id = id;
597: ptab->hdr.props.valid = 0;
598: ptab->hdr.sendscroll = FALSE;
599: if (gtab_sendtq(hwnd, TQ_GETSIZE, (long) (LPSTR)&ptab->hdr) == FALSE) {
600: return(NULL);
601: }
602:
603: ncols = ptab->hdr.ncols;
604: ptab->pcolhdr = (lpColProps) gmem_get(hHeap, sizeof(ColProps) * ncols);
605: if (ptab->pcolhdr == NULL) {
606: /* should prob send TQ_CLOSE at this point */
607: return(NULL);
608: }
609:
610: /* init col properties to default */
611: for (i=0; i < ncols; i++) {
612: ptab->pcolhdr[i].props.valid = 0;
613: ptab->pcolhdr[i].nchars = 0;
614: }
615: /* get the column props from owner */
616: cplist.plist = ptab->pcolhdr;
617: cplist.id = id;
618: cplist.startcol = 0;
619: cplist.ncols = ncols;
620: gtab_sendtq(hwnd, TQ_GETCOLPROPS, (long) (LPSTR)&cplist);
621:
622: /* init remaining fields */
623: ptab->pcellpos = (lpCellPos) gmem_get(hHeap, sizeof(CellPos) * ncols);
624: if (ptab->pcellpos == NULL) {
625: return(NULL);
626: }
627:
628: ptab->scrollscale = 1;
629: ptab->scroll_dx = 0;
630: ptab->toprow = 0;
631: ptab->pdata = NULL;
632: ptab->nlines = 0;
633: ptab->trackmode = TRACK_NONE;
634:
635: /* we have to notify owner of the current selection
636: * whenever it is changed
637: */
638: ptab->select.id = id;
639: gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
640:
641: /* calc ave height/width, cell widths and min height.
642: * these change only when cell properties / col count changes -
643: * ie only on rebuild-header events
644: */
645: gtab_calcwidths(hwnd, ptab);
646: return(ptab);
647: }
648:
649: /***************************************************************************
650: * Function: gtab_setsize
651: *
652: * Purpose:
653: *
654: * Set sizes that are based on window size and scroll pos
655: * set:
656: * winwidth
657: * nlines
658: * cellpos start, clip start/end
659: * Alloc linedata and init
660: */
661: void
662: gtab_setsize(HWND hwnd, lpTable ptab)
663: {
664: RECT rc;
665: int nlines;
666: HANDLE heap;
667: long range, change;
668:
669: GetClientRect(hwnd, &rc);
670: ptab->winwidth = rc.right - rc.left;
671: nlines = (rc.bottom - rc.top) / ptab->rowheight;
672: /* nlines is the number of whole lines - add one extra
673: * for the partial line at the bottom
674: */
675: nlines += 1;
676:
677: /* alloc space for nlines of data - if nlines has changed */
678: if (nlines != ptab->nlines) {
679: heap = (HANDLE) GetWindowLong(hwnd, WW_HEAP);
680: gtab_freelinedata(heap, ptab);
681: ptab->nlines = nlines;
682: if (!gtab_alloclinedata(hwnd, heap, ptab)) {
683: ptab->nlines = 0;
684: return;
685: }
686: }
687:
688: /* set scroll vertical range */
689: range = ptab->hdr.nrows - (ptab->nlines - 1);
690: if (range < 0) {
691: range = 0;
692: change = -(ptab->toprow);
693: } else if (ptab->toprow > range) {
694: change = range - ptab->toprow;
695: } else {
696: change = 0;
697: }
698: /* the scroll range must be 16-bits for Win3
699: * scale until this is true
700: */
701: ptab->scrollscale = 1;
702: while (range > 32766) {
703: ptab->scrollscale *= 16;
704: range /= 16;
705: }
706:
707: SetScrollRange(hwnd, SB_VERT, 0, (int) range, TRUE);
708: gtab_dovscroll(hwnd, ptab, change);
709:
710: /* set horz scroll range */
711: range = ptab->rowwidth - ptab->winwidth;
712: if (range < 0) {
713: range = 0;
714: change = -(ptab->scroll_dx);
715: } else if (ptab->scroll_dx > range) {
716: change = range - ptab->scroll_dx;
717: } else {
718: change = 0;
719: }
720: /* horz scroll range will always be < 16 bits */
721: SetScrollRange(hwnd, SB_HORZ, 0, (int) range, TRUE);
722: gtab_dohscroll(hwnd, ptab, change);
723: }
724:
725: /***************************************************************************
726: * Function: gtab_calcwidths
727: *
728: * Purpose:
729: *
730: * Set column widths/height and totals (based on column props)
731: * - no assumption of window size (see gtab_setsize)
732: * sets avewidth,rowheight,cellpos.size,rowwidth (total of cellpos.size)
733: */
734: void
735: gtab_calcwidths(HWND hwnd, lpTable ptab)
736: {
737: int i, cxtotal, cx, ave;
738: TEXTMETRIC tm, tmcol;
739: HDC hdc;
740: lpProps hdrprops, cellprops;
741: HFONT hfont;
742:
743: hdrprops = &ptab->hdr.props;
744: hdc = GetDC(hwnd);
745: if (hdrprops->valid & P_FONT) {
746: hfont = SelectObject(hdc, hdrprops->hFont);
747: }
748: GetTextMetrics(hdc, &tm);
749: if (hdrprops->valid & P_FONT) {
750: SelectObject(hdc, hfont);
751: }
752: ReleaseDC(hwnd, hdc);
753:
754: /* get width and height of average character */
755: ptab->avewidth = tm.tmAveCharWidth;
756: ptab->rowheight = tm.tmHeight + tm.tmExternalLeading;
757: if (hdrprops->valid & P_HEIGHT) {
758: ptab->rowheight = hdrprops->height;
759: }
760:
761: /* set pixel width of each cell (and add up for row total)
762: * based on ave width * nr chars, unless P_WIDTH set
763: */
764: cxtotal = 0;
765: for (i = 0; i < ptab->hdr.ncols; i++) {
766: cellprops = &ptab->pcolhdr[i].props;
767:
768: if (cellprops->valid & P_WIDTH) {
769: cx = cellprops->width;
770: } else if (hdrprops->valid & P_WIDTH) {
771: cx = hdrprops->width;
772: } else {
773:
774: if (cellprops->valid & P_FONT) {
775: hdc = GetDC(hwnd);
776: hfont = SelectObject(hdc, cellprops->hFont);
777: GetTextMetrics(hdc, &tmcol);
778: SelectObject(hdc, hfont);
779: ReleaseDC(hwnd, hdc);
780: ave = tmcol.tmAveCharWidth;
781: } else {
782: ave = ptab->avewidth;
783: }
784: /* ave width * nchars */
785: cx = ptab->pcolhdr[i].nchars + 1;
786: cx *= ave;
787: }
788: /* add 2 pixels for box lines */
789: cx += 2;
790: ptab->pcellpos[i].size = cx;
791: cxtotal += cx;
792: }
793: ptab->rowwidth = cxtotal;
794: }
795:
796: /***************************************************************************
797: * Function: gtab_newsize
798: *
799: * Purpose:
800: *
801: * Called when row data + possible nrows changes.
802: * other changes are ignored
803: */
804: void
805: gtab_newsize(HWND hwnd, lpTable ptab)
806: {
807: TableHdr hdr;
808:
809: /* get new row count */
810: hdr = ptab->hdr;
811: gtab_sendtq(hwnd, TQ_GETSIZE, (long) (LPSTR) &hdr);
812: if (hdr.nrows != ptab->hdr.nrows) {
813: ptab->hdr.nrows = hdr.nrows;
814: gtab_setsize(hwnd, ptab);
815: }
816:
817: gtab_invallines(hwnd, ptab, 0, ptab->nlines);
818:
819: InvalidateRect(hwnd, NULL, TRUE);
820: }
821:
822: void
823: gtab_invallines(HWND hwnd, lpTable ptab, int start, int count)
824: {
825: int i, j;
826:
827: for (i = start; i < start + count; i++) {
828: for (j = 0; j < ptab->hdr.ncols; j++) {
829: ptab->pdata[i].pdata[j].flags = 0;
830: }
831: }
832: }
833:
834: /***************************************************************************
835: * Function: gtab_append
836: *
837: * Purpose:
838: *
839: * New rows have been added to the table. Adjust the scroll range and
840: * position, and redraw the rows if the end of the table is currently
841: * visible.
842: * rows = the new total row count.
843: */
844: void
845: gtab_append(HWND hwnd, lpTable ptab, int rows, DWORD id)
846: {
847: long range;
848: long oldrows;
849: int line, nupdates;
850: RECT rc;
851:
852:
853: /* change to the new id */
854: ptab->hdr.id = id;
855: ptab->select.id = id;
856:
857: /* update the header, but remember the old nr of rows
858: * so we know where to start updating
859: */
860: oldrows = ptab->hdr.nrows;
861:
862: /* check that the new nr of rows is not smaller. this is
863: * illegal at this point and should be ignored
864: */
865: if (oldrows >= rows) {
866: return;
867: }
868:
869: ptab->hdr.nrows = rows;
870:
871: /* set the vertical scroll range */
872: range = rows - (ptab->nlines - 1);
873:
874: if (range < 0) {
875: range = 0;
876: }
877:
878: /* force the scroll range into 16-bits for win 3.1 */
879: ptab->scrollscale = 1;
880: while (range > 32766) {
881: ptab->scrollscale *= 16;
882: range /= 16;
883: }
884:
885: /* now set the scroll bar range and position */
886: SetScrollRange(hwnd, SB_VERT, 0, (int) range, TRUE);
887: if (range > 0) {
888: SetScrollPos(hwnd, SB_VERT,
889: (int) (ptab->toprow / ptab->scrollscale), TRUE);
890: }
891:
892: /* calculate which screen lines need to be updated - find what
893: * screen line the start of the new section is at
894: */
895: line = gtab_rowtoline(hwnd, ptab, oldrows);
896: if (line == -1) {
897: /* not visible -> no more to do */
898: return;
899: }
900:
901: /* how many lines to update - rest of screen or nr of
902: * new lines if less than rest of screen
903: */
904: nupdates = min((ptab->nlines - line), (int)(rows - oldrows));
905:
906: /* invalidate the screen line buffers to indicate data
907: * needs to be refetch from parent window
908: */
909: gtab_invallines(hwnd, ptab, line, nupdates);
910:
911: /* calculate the region of the screen to be repainted -
912: * left and right are same as window. top and bottom
913: * need to be calculated from screen line height
914: */
915:
916: GetClientRect(hwnd, &rc);
917: rc.top += line * ptab->rowheight;
918: rc.bottom = rc.top + (nupdates * ptab->rowheight);
919:
920: /* force a repaint of the updated region */
921: InvalidateRect(hwnd, &rc, TRUE);
922: }
923:
924:
925:
926:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.