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.

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