Source code of Windows XP (NT5)
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.

925 lines
26 KiB

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