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