Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

831 lines
27 KiB

4 years ago
  1. /*
  2. * standard table class.
  3. *
  4. * main interface functions.
  5. *
  6. * see table.h for interface description
  7. */
  8. #include "windows.h"
  9. #include "commdlg.h"
  10. #include "gutils.h"
  11. #include "table.h"
  12. #include "tpriv.h"
  13. /* global tools etc */
  14. extern HANDLE hLibInst;
  15. HANDLE hVertCurs;
  16. HANDLE hNormCurs;
  17. HPEN hpenDotted;
  18. UINT gtab_msgcode;
  19. /* function prototypes */
  20. long FAR PASCAL gtab_wndproc(HWND, UINT, UINT, long);
  21. void gtab_createtools(void);
  22. void gtab_deltable(HWND hwnd, lpTable ptab);
  23. lpTable gtab_buildtable(HWND hwnd, DWORD id);
  24. void gtab_setsize(HWND hwnd, lpTable ptab);
  25. void gtab_newsize(HWND hwnd, lpTable ptab);
  26. void gtab_calcwidths(HWND hwnd, lpTable ptab);
  27. BOOL gtab_alloclinedata(HWND hwnd, HANDLE heap, lpTable ptab);
  28. void gtab_invallines(HWND hwnd, lpTable ptab, int start, int count);
  29. void gtab_append(HWND hwnd, lpTable ptab, int rows, DWORD id);
  30. /*
  31. * initialise window class - called from DLL main init
  32. */
  33. void
  34. gtab_init(void)
  35. {
  36. WNDCLASS wc;
  37. gtab_createtools();
  38. gtab_msgcode = RegisterWindowMessage(TableMessage);
  39. wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
  40. wc.lpfnWndProc = gtab_wndproc;
  41. wc.cbClsExtra = 0;
  42. wc.cbWndExtra = WLTOTAL;
  43. wc.hInstance = hLibInst;
  44. wc.hIcon = NULL;
  45. wc.hCursor = NULL;
  46. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  47. wc.lpszClassName = TableClassName;
  48. wc.lpszMenuName = NULL;
  49. RegisterClass(&wc);
  50. }
  51. void
  52. gtab_createtools(void)
  53. {
  54. hVertCurs = LoadCursor(hLibInst, "VertLine");
  55. hNormCurs = LoadCursor(NULL, IDC_ARROW);
  56. hpenDotted = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
  57. }
  58. void
  59. gtab_deltools(void)
  60. {
  61. DeleteObject(hpenDotted);
  62. }
  63. long FAR PASCAL
  64. gtab_wndproc(HWND hwnd, UINT msg, UINT wParam, long lParam)
  65. {
  66. CREATESTRUCT FAR * csp;
  67. HWND hOwner;
  68. lpTable ptab;
  69. HANDLE hHeap;
  70. PAINTSTRUCT ps;
  71. int y, y2, i;
  72. HDC hDC;
  73. lpTableSelection pselect;
  74. long oldtop;
  75. long change;
  76. switch(msg) {
  77. case WM_CREATE:
  78. /* create window. set the wnd extra bytes to
  79. * contain the owner window, a heap and a null table.
  80. * Owner window is either in lParam or the parent.
  81. * Then wait for TM_NEWID.
  82. */
  83. csp = (CREATESTRUCT FAR *) lParam;
  84. if (csp->lpCreateParams == NULL) {
  85. hOwner = GetParent(hwnd);
  86. } else {
  87. hOwner = (HWND) (long) csp->lpCreateParams;
  88. }
  89. ptab = NULL;
  90. hHeap = gmem_init();
  91. SetWindowLong(hwnd, WL_TABLE, (long) ptab);
  92. SetWindowHandle(hwnd, WW_OWNER, (UINT) hOwner);
  93. SetWindowHandle(hwnd, WW_HEAP, (UINT) hHeap);
  94. SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
  95. SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
  96. break;
  97. case TM_NEWID:
  98. /* complete change of table.
  99. * close old table, discard memory and
  100. * build new table
  101. */
  102. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  103. if (ptab != NULL) {
  104. gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id);
  105. gtab_deltable(hwnd, ptab);
  106. SetCursor(hNormCurs);
  107. SetWindowLong(hwnd, WL_TABLE, 0);
  108. }
  109. if ( (ptab = gtab_buildtable(hwnd, lParam)) != NULL) {
  110. SetWindowLong(hwnd, WL_TABLE, (long) (LPSTR) ptab);
  111. gtab_setsize(hwnd, ptab);
  112. } else {
  113. SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
  114. SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
  115. }
  116. InvalidateRect(hwnd, NULL, TRUE);
  117. break;
  118. case TM_NEWLAYOUT:
  119. /* change of layout but for same id. no TQ_CLOSE,
  120. * but otherwise same as TM_NEWID
  121. */
  122. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  123. if (ptab != NULL) {
  124. gtab_deltable(hwnd, ptab);
  125. SetCursor(hNormCurs);
  126. SetWindowLong(hwnd, WL_TABLE, 0);
  127. }
  128. if ( (ptab = gtab_buildtable(hwnd, lParam)) != NULL) {
  129. SetWindowLong(hwnd, WL_TABLE, (long) (LPSTR) ptab);
  130. gtab_setsize(hwnd, ptab);
  131. } else {
  132. SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
  133. SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
  134. }
  135. InvalidateRect(hwnd, NULL, TRUE);
  136. break;
  137. case TM_REFRESH:
  138. /* data in table has changed. nrows may have
  139. * changed. ncols and col types have not changed
  140. */
  141. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  142. if (ptab != NULL) {
  143. gtab_newsize(hwnd, ptab);
  144. }
  145. InvalidateRect(hwnd, NULL, TRUE);
  146. break;
  147. case TM_SELECT:
  148. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  149. if (ptab != NULL) {
  150. pselect = (lpTableSelection) lParam;
  151. gtab_select(hwnd, ptab, pselect->startrow,
  152. pselect->startcell,
  153. pselect->nrows,
  154. pselect->ncells,
  155. TRUE);
  156. gtab_showsel_middle(hwnd, ptab);
  157. }
  158. break;
  159. case TM_GETSELECTION:
  160. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  161. if (ptab != NULL) {
  162. pselect = (lpTableSelection) lParam;
  163. *pselect = ptab->select;
  164. }
  165. break;
  166. case TM_PRINT:
  167. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  168. hHeap = (HANDLE) GetWindowHandle(hwnd, WW_HEAP);
  169. if (ptab != NULL) {
  170. return gtab_print(hwnd, ptab, hHeap, (lpPrintContext) lParam);
  171. }
  172. case TM_TOPROW:
  173. /* return top row. if wParam is TRUE, set lParam
  174. * as the new toprow
  175. */
  176. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  177. if (ptab == NULL) {
  178. return(0);
  179. }
  180. oldtop = ptab->toprow;
  181. if ((wParam) && (lParam < ptab->hdr.nrows)) {
  182. change = lParam - ptab->toprow;
  183. change -= ptab->hdr.fixedrows;
  184. gtab_dovscroll(hwnd, ptab, change);
  185. }
  186. return(oldtop);
  187. case TM_ENDROW:
  188. /* return the last visible row in the window */
  189. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  190. if (ptab == NULL) {
  191. return(0);
  192. }
  193. return(ptab->nlines + ptab->toprow - 1);
  194. case TM_APPEND:
  195. /* new rows have been added to the end of the
  196. * table, but the rest of the table has not
  197. * been changed. Update without forcing redraw of
  198. * everything.
  199. * lParam contains the new total nr of rows
  200. */
  201. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  202. if (ptab != NULL) {
  203. gtab_append(hwnd, ptab, wParam, lParam);
  204. return(TRUE);
  205. }
  206. break;
  207. case WM_SIZE:
  208. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  209. if (ptab != NULL) {
  210. gtab_setsize(hwnd, ptab);
  211. }
  212. break;
  213. case WM_DESTROY:
  214. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  215. if (ptab != NULL) {
  216. gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id);
  217. gtab_deltable(hwnd, ptab);
  218. }
  219. hHeap = (HANDLE) GetWindowHandle(hwnd, WW_HEAP);
  220. gmem_freeall(hHeap);
  221. break;
  222. case WM_PAINT:
  223. hDC = BeginPaint(hwnd, &ps);
  224. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  225. if (ptab != NULL) {
  226. /* separator lines between fixed rows/columns
  227. * (ie headers) and the rest - if enabled
  228. */
  229. /* paint here first for good impression,
  230. * and again after to clean up!!
  231. */
  232. if (ptab->hdr.vseparator) {
  233. gtab_vsep(hwnd, ptab, hDC);
  234. }
  235. if (ptab->hdr.hseparator) {
  236. gtab_hsep(hwnd, ptab, hDC);
  237. }
  238. /* paint only the rows that need painting */
  239. for (i = 0; i < ptab->nlines; i++) {
  240. y = ptab->pdata[i].linepos.start;
  241. y2 = y + ptab->pdata[i].linepos.size;
  242. if ( (y <= ps.rcPaint.bottom) &&
  243. (y2 >= ps.rcPaint.top)) {
  244. gtab_paint(hwnd, hDC, ptab, i);
  245. }
  246. }
  247. if (ptab->hdr.vseparator) {
  248. gtab_vsep(hwnd, ptab, hDC);
  249. }
  250. if (ptab->hdr.hseparator) {
  251. gtab_hsep(hwnd, ptab, hDC);
  252. }
  253. if (ptab->selvisible) {
  254. gtab_invertsel(hwnd, ptab, hDC);
  255. }
  256. }
  257. EndPaint(hwnd, &ps);
  258. break;
  259. case WM_HSCROLL:
  260. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  261. if (ptab != NULL) {
  262. gtab_msg_hscroll(hwnd, ptab,
  263. GET_SCROLL_OPCODE(wParam, lParam),
  264. GET_SCROLL_POS(wParam, lParam));
  265. }
  266. break;
  267. case WM_VSCROLL:
  268. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  269. if (ptab != NULL) {
  270. gtab_msg_vscroll(hwnd, ptab,
  271. GET_SCROLL_OPCODE(wParam, lParam),
  272. GET_SCROLL_POS(wParam, lParam));
  273. }
  274. break;
  275. case WM_MOUSEMOVE:
  276. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  277. if (ptab != NULL) {
  278. gtab_move(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
  279. } else {
  280. SetCursor(hNormCurs);
  281. }
  282. break;
  283. case WM_LBUTTONDOWN:
  284. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  285. if (ptab != NULL) {
  286. gtab_press(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
  287. }
  288. break;
  289. case WM_RBUTTONDOWN:
  290. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  291. if (ptab != NULL) {
  292. gtab_rightclick(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
  293. }
  294. break;
  295. case WM_LBUTTONUP:
  296. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  297. if (ptab != NULL) {
  298. gtab_release(hwnd, ptab,
  299. (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
  300. }
  301. break;
  302. case WM_LBUTTONDBLCLK:
  303. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  304. if (ptab != NULL) {
  305. gtab_dblclick(hwnd, ptab,
  306. (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
  307. }
  308. break;
  309. case WM_KEYDOWN:
  310. /* handle key presses for cursor movement about
  311. * the table, and return/space for selection.
  312. * Any key we don't handle is passed to the owner window
  313. * for him to handle.
  314. * The table window should have the focus
  315. */
  316. ptab = (lpTable) GetWindowLong(hwnd, WL_TABLE);
  317. if (ptab != NULL) {
  318. if (gtab_key(hwnd, ptab, wParam) != 0) {
  319. /* pass key to owner since
  320. * we don't know what to do with it
  321. */
  322. hOwner = (HANDLE) GetWindowHandle(hwnd, WW_OWNER);
  323. return(SendMessage(hOwner, WM_KEYDOWN,
  324. wParam, lParam));
  325. } else {
  326. return(0);
  327. }
  328. }
  329. break;
  330. default:
  331. return(DefWindowProc(hwnd, msg, wParam, lParam));
  332. }
  333. return(TRUE);
  334. }
  335. /*
  336. * send a table-query message to the owner window. returns message
  337. * value.
  338. */
  339. long
  340. gtab_sendtq(HWND hwnd, UINT cmd, long lParam)
  341. {
  342. HWND hOwner;
  343. hOwner = (HANDLE) GetWindowHandle(hwnd, WW_OWNER);
  344. return (SendMessage(hOwner, gtab_msgcode, cmd, lParam));
  345. }
  346. /*
  347. * free the memory allocated for the array of lines (each containing
  348. * an array of Cells, each containing an array of chars for the actual
  349. * data). Called on any occasion that would change the number of visible lines
  350. */
  351. void
  352. gtab_freelinedata(HANDLE hHeap, lpTable ptab)
  353. {
  354. int i, j, ncols;
  355. lpCellData cd;
  356. ncols = ptab->hdr.ncols;
  357. /* for each line */
  358. for(i = 0; i < ptab->nlines; i++) {
  359. /* for each cell */
  360. for (j = 0; j < ncols; j++) {
  361. /* free up the actual text space */
  362. cd = &ptab->pdata[i].pdata[j];
  363. gmem_free(hHeap, (LPSTR) cd->ptext, cd->nchars);
  364. }
  365. /* dealloc array of CellData */
  366. gmem_free(hHeap, (LPSTR) ptab->pdata[i].pdata,
  367. sizeof(CellData) * ncols);
  368. }
  369. /* de-alloc array of linedatas */
  370. gmem_free(hHeap, (LPSTR) ptab->pdata,
  371. sizeof(LineData) * ptab->nlines);
  372. ptab->pdata = NULL;
  373. }
  374. /* allocate and init array of linedatas (include cell array
  375. * and text for each cell)
  376. */
  377. BOOL
  378. gtab_alloclinedata(HWND hwnd, HANDLE heap, lpTable ptab)
  379. {
  380. lpLineData pline;
  381. lpCellData cd;
  382. int i, j;
  383. ptab->pdata = (lpLineData) gmem_get(heap,
  384. sizeof(LineData) * ptab->nlines);
  385. if (ptab->pdata == NULL) {
  386. return(FALSE);
  387. }
  388. for (i = 0; i < ptab->nlines; i++) {
  389. pline = &ptab->pdata[i];
  390. pline->linepos.size = ptab->rowheight;
  391. pline->pdata = (lpCellData) gmem_get(heap,
  392. sizeof(CellData) * ptab->hdr.ncols);
  393. if (pline->pdata == NULL) {
  394. return(FALSE);
  395. }
  396. for (j = 0; j < ptab->hdr.ncols; j++) {
  397. cd = &pline->pdata[j];
  398. cd->props.valid = 0;
  399. cd->flags = 0;
  400. cd->nchars = ptab->pcolhdr[j].nchars;
  401. if (cd->nchars > 0) {
  402. cd->ptext = gmem_get(heap, cd->nchars);
  403. if (cd->ptext == NULL) {
  404. return(FALSE);
  405. }
  406. }
  407. }
  408. }
  409. }
  410. /*
  411. * free up all table data structures. Called for new layout or new data.
  412. */
  413. void
  414. gtab_deltable(HWND hwnd, lpTable ptab)
  415. {
  416. HANDLE hHeap;
  417. int ncols;
  418. if (ptab == NULL) {
  419. return;
  420. }
  421. hHeap = (HANDLE) GetWindowHandle(hwnd, WW_HEAP);
  422. ncols = ptab->hdr.ncols;
  423. if (ptab->pcolhdr != NULL) {
  424. gmem_free(hHeap, (LPSTR) ptab->pcolhdr,
  425. sizeof(ColProps) * ncols);
  426. }
  427. if (ptab->pcellpos != NULL) {
  428. gmem_free(hHeap, (LPSTR) ptab->pcellpos,
  429. sizeof(CellPos) * ncols);
  430. }
  431. if (ptab->pdata != NULL) {
  432. gtab_freelinedata(hHeap, ptab);
  433. }
  434. gmem_free(hHeap, (LPSTR) ptab, sizeof(Table));
  435. }
  436. /*
  437. * build up a Table struct (excluding data allocation and
  438. * anything to do with font or window size).
  439. * return ptr to this or NULL if error
  440. */
  441. lpTable
  442. gtab_buildtable(HWND hwnd, DWORD id)
  443. {
  444. lpTable ptab;
  445. HANDLE hHeap;
  446. int ncols, i;
  447. ColPropsList cplist;
  448. hHeap = (HANDLE) GetWindowHandle(hwnd, WW_HEAP);
  449. ptab = (lpTable) gmem_get(hHeap, sizeof(Table));
  450. if (ptab == NULL) {
  451. return(NULL);
  452. }
  453. // get the tab width. most clients will not support this
  454. if (gtab_sendtq(hwnd, TQ_TABS, (long) &ptab->tabchars) == FALSE) {
  455. ptab->tabchars = 8;
  456. }
  457. /* get the row/column count from owner window */
  458. ptab->hdr.id = id;
  459. ptab->hdr.props.valid = 0;
  460. ptab->hdr.sendscroll = FALSE;
  461. if (gtab_sendtq(hwnd, TQ_GETSIZE, (long) (LPSTR)&ptab->hdr) == FALSE) {
  462. return(NULL);
  463. }
  464. ncols = ptab->hdr.ncols;
  465. ptab->pcolhdr = (lpColProps) gmem_get(hHeap, sizeof(ColProps) * ncols);
  466. if (ptab->pcolhdr == NULL) {
  467. /* should prob send TQ_CLOSE at this point */
  468. return(NULL);
  469. }
  470. /* init col properties to default */
  471. for (i=0; i < ncols; i++) {
  472. ptab->pcolhdr[i].props.valid = 0;
  473. ptab->pcolhdr[i].nchars = 0;
  474. }
  475. /* get the column props from owner */
  476. cplist.plist = ptab->pcolhdr;
  477. cplist.id = id;
  478. cplist.startcol = 0;
  479. cplist.ncols = ncols;
  480. gtab_sendtq(hwnd, TQ_GETCOLPROPS, (long) (LPSTR)&cplist);
  481. /* init remaining fields */
  482. ptab->pcellpos = (lpCellPos) gmem_get(hHeap, sizeof(CellPos) * ncols);
  483. if (ptab->pcellpos == NULL) {
  484. return(NULL);
  485. }
  486. ptab->scrollscale = 1;
  487. ptab->scroll_dx = 0;
  488. ptab->toprow = 0;
  489. ptab->pdata = NULL;
  490. ptab->nlines = 0;
  491. ptab->trackmode = TRACK_NONE;
  492. /* we have to notify owner of the current selection
  493. * whenever it is changed
  494. */
  495. ptab->select.id = id;
  496. gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
  497. /* calc ave height/width, cell widths and min height.
  498. * these change only when cell properties / col count changes -
  499. * ie only on rebuild-header events
  500. */
  501. gtab_calcwidths(hwnd, ptab);
  502. return(ptab);
  503. }
  504. /* set sizes that are based on window size and scroll pos
  505. * set:
  506. * winwidth
  507. * nlines
  508. * cellpos start, clip start/end
  509. * alloc linedata and init
  510. */
  511. void
  512. gtab_setsize(HWND hwnd, lpTable ptab)
  513. {
  514. RECT rc;
  515. int nlines;
  516. HANDLE heap;
  517. long range, change;
  518. GetClientRect(hwnd, &rc);
  519. ptab->winwidth = rc.right - rc.left;
  520. nlines = (rc.bottom - rc.top) / ptab->rowheight;
  521. /* nlines is the number of whole lines - add one extra
  522. * for the partial line at the bottom
  523. */
  524. nlines += 1;
  525. /* alloc space for nlines of data - if nlines has changed */
  526. if (nlines != ptab->nlines) {
  527. heap = (HANDLE) GetWindowHandle(hwnd, WW_HEAP);
  528. gtab_freelinedata(heap, ptab);
  529. ptab->nlines = nlines;
  530. if (!gtab_alloclinedata(hwnd, heap, ptab)) {
  531. ptab->nlines = 0;
  532. return;
  533. }
  534. }
  535. /* set scroll vertical range */
  536. range = ptab->hdr.nrows - (ptab->nlines - 1);
  537. if (range < 0) {
  538. range = 0;
  539. change = -(ptab->toprow);
  540. } else if (ptab->toprow > range) {
  541. change = range - ptab->toprow;
  542. } else {
  543. change = 0;
  544. }
  545. /* the scroll range must be 16-bits for Win3
  546. * scale until this is true
  547. */
  548. ptab->scrollscale = 1;
  549. while (range > 32766) {
  550. ptab->scrollscale *= 16;
  551. range /= 16;
  552. }
  553. SetScrollRange(hwnd, SB_VERT, 0, (int) range, TRUE);
  554. gtab_dovscroll(hwnd, ptab, change);
  555. /* set horz scroll range */
  556. range = ptab->rowwidth - ptab->winwidth;
  557. if (range < 0) {
  558. range = 0;
  559. change = -(ptab->scroll_dx);
  560. } else if (ptab->scroll_dx > range) {
  561. change = range - ptab->scroll_dx;
  562. } else {
  563. change = 0;
  564. }
  565. /* horz scroll range will always be < 16 bits */
  566. SetScrollRange(hwnd, SB_HORZ, 0, (int) range, TRUE);
  567. gtab_dohscroll(hwnd, ptab, change);
  568. }
  569. /* set column widths/height and totals (based on column props)
  570. * - no assumption of window size (see gtab_setsize)
  571. * sets avewidth,rowheight,cellpos.size,rowwidth (total of cellpos.size)
  572. */
  573. void
  574. gtab_calcwidths(HWND hwnd, lpTable ptab)
  575. {
  576. int i, cxtotal, cx, ave;
  577. TEXTMETRIC tm, tmcol;
  578. HDC hdc;
  579. lpProps hdrprops, cellprops;
  580. HFONT hfont;
  581. hfont = NULL; /* eliminate spurious diagnostic, make code worse */
  582. hdrprops = &ptab->hdr.props;
  583. hdc = GetDC(hwnd);
  584. if (hdrprops->valid & P_FONT) {
  585. hfont = SelectObject(hdc, hdrprops->hFont);
  586. }
  587. GetTextMetrics(hdc, &tm);
  588. if (hdrprops->valid & P_FONT) {
  589. SelectObject(hdc, hfont);
  590. }
  591. ReleaseDC(hwnd, hdc);
  592. /* get width and height of average character */
  593. ptab->avewidth = tm.tmAveCharWidth;
  594. ptab->rowheight = tm.tmHeight + tm.tmExternalLeading;
  595. if (hdrprops->valid & P_HEIGHT) {
  596. ptab->rowheight = hdrprops->height;
  597. }
  598. /* set pixel width of each cell (and add up for row total)
  599. * based on ave width * nr chars, unless P_WIDTH set
  600. */
  601. cxtotal = 0;
  602. for (i = 0; i < ptab->hdr.ncols; i++) {
  603. cellprops = &ptab->pcolhdr[i].props;
  604. if (cellprops->valid & P_WIDTH) {
  605. cx = cellprops->width;
  606. } else if (hdrprops->valid & P_WIDTH) {
  607. cx = hdrprops->width;
  608. } else {
  609. if (cellprops->valid & P_FONT) {
  610. hdc = GetDC(hwnd);
  611. hfont = SelectObject(hdc, cellprops->hFont);
  612. GetTextMetrics(hdc, &tmcol);
  613. SelectObject(hdc, hfont);
  614. ReleaseDC(hwnd, hdc);
  615. ave = tmcol.tmAveCharWidth;
  616. } else {
  617. ave = ptab->avewidth;
  618. }
  619. /* ave width * nchars */
  620. cx = ptab->pcolhdr[i].nchars + 1;
  621. cx *= ave;
  622. }
  623. /* add 2 pixels for box lines */
  624. cx += 2;
  625. ptab->pcellpos[i].size = cx;
  626. cxtotal += cx;
  627. }
  628. ptab->rowwidth = cxtotal;
  629. }
  630. /* called when row data + possible nrows changes.
  631. * other changes are ignored
  632. */
  633. void
  634. gtab_newsize(HWND hwnd, lpTable ptab)
  635. {
  636. TableHdr hdr;
  637. /* get new row count */
  638. hdr = ptab->hdr;
  639. gtab_sendtq(hwnd, TQ_GETSIZE, (long) (LPSTR) &hdr);
  640. if (hdr.nrows != ptab->hdr.nrows) {
  641. ptab->hdr.nrows = hdr.nrows;
  642. gtab_setsize(hwnd, ptab);
  643. }
  644. gtab_invallines(hwnd, ptab, 0, ptab->nlines);
  645. InvalidateRect(hwnd, NULL, TRUE);
  646. }
  647. void
  648. gtab_invallines(HWND hwnd, lpTable ptab, int start, int count)
  649. {
  650. int i, j;
  651. for (i = start; i < start + count; i++) {
  652. for (j = 0; j < ptab->hdr.ncols; j++) {
  653. ptab->pdata[i].pdata[j].flags = 0;
  654. }
  655. }
  656. }
  657. /* new rows have been added to the table. adjust the scroll range and
  658. * position, and redraw the rows if the end of the table is currently
  659. * visible.
  660. * rows = the new total row count.
  661. */
  662. void
  663. gtab_append(HWND hwnd, lpTable ptab, int rows, DWORD id)
  664. {
  665. long range;
  666. long oldrows;
  667. int line, nupdates;
  668. RECT rc;
  669. /* change to the new id */
  670. ptab->hdr.id = id;
  671. ptab->select.id = id;
  672. /* update the header, but remember the old nr of rows
  673. * so we know where to start updating
  674. */
  675. oldrows = ptab->hdr.nrows;
  676. /* check that the new nr of rows is not smaller. this is
  677. * illegal at this point and should be ignored
  678. */
  679. if (oldrows >= rows) {
  680. return;
  681. }
  682. ptab->hdr.nrows = rows;
  683. /* set the vertical scroll range */
  684. range = rows - (ptab->nlines - 1);
  685. if (range < 0) {
  686. range = 0;
  687. }
  688. /* force the scroll range into 16-bits for win 3.1 */
  689. ptab->scrollscale = 1;
  690. while (range > 32766) {
  691. ptab->scrollscale *= 16;
  692. range /= 16;
  693. }
  694. /* now set the scroll bar range and position */
  695. SetScrollRange(hwnd, SB_VERT, 0, (int) range, TRUE);
  696. if (range > 0) {
  697. SetScrollPos(hwnd, SB_VERT,
  698. (int) (ptab->toprow / ptab->scrollscale), TRUE);
  699. }
  700. /* calculate which screen lines need to be updated - find what
  701. * screen line the start of the new section is at
  702. */
  703. line = gtab_rowtoline(hwnd, ptab, oldrows);
  704. if (line == -1) {
  705. /* not visible -> no more to do */
  706. return;
  707. }
  708. /* how many lines to update - rest of screen or nr of
  709. * new lines if less than rest of screen
  710. */
  711. nupdates = min((ptab->nlines - line), (int)(rows - oldrows));
  712. /* invalidate the screen line buffers to indicate data
  713. * needs to be refetch from parent window
  714. */
  715. gtab_invallines(hwnd, ptab, line, nupdates);
  716. /* calculate the region of the screen to be repainted -
  717. * left and right are same as window. top and bottom
  718. * need to be calculated from screen line height
  719. */
  720. GetClientRect(hwnd, &rc);
  721. rc.top += line * ptab->rowheight;
  722. rc.bottom = rc.top + (nupdates * ptab->rowheight);
  723. /* force a repaint of the updated region */
  724. InvalidateRect(hwnd, &rc, TRUE);
  725. }