Leaked source code of windows server 2003
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.

908 lines
26 KiB

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