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.

613 lines
17 KiB

  1. /*
  2. * standard table class.
  3. *
  4. * print functions.
  5. *
  6. * see table.h for interface description
  7. */
  8. #include <string.h>
  9. #include "windows.h"
  10. #include "commdlg.h"
  11. #include "gutils.h"
  12. #include "gutilsrc.h"
  13. #include "table.h"
  14. #include "tpriv.h"
  15. /* in tpaint.c, calls GetTextExtentPoint */
  16. extern int GetTextExtent(HDC, LPSTR, int);
  17. extern HANDLE hLibInst;
  18. /* function prototypes */
  19. lpTable gtab_printsetup(HWND hwnd, lpTable ptab, HANDLE heap,
  20. lpPrintContext pcontext);
  21. BOOL gtab_prtwidths(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext
  22. pcontext);
  23. void gtab_printjob(HWND hwnd, lpTable ptab, lpPrintContext pcontext);
  24. int APIENTRY AbortProc(HDC hpr, int code);
  25. int APIENTRY AbortDlg(HWND hdlg, UINT msg, UINT wParam, LONG lParam);
  26. BOOL gtab_printpage(HWND hwnd, lpTable ptab, lpPrintContext pcontext, int page);
  27. void gtab_setrects(lpPrintContext pcontext, LPRECT rcinner, LPRECT rcouter);
  28. void gtab_printhead(HWND hwnd, HDC hdc, lpTable ptab, lpTitle head, int page);
  29. /*
  30. * gtab_print
  31. */
  32. BOOL
  33. gtab_print(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext)
  34. {
  35. BOOL fNoContext, fNoMargin, fNoPD;
  36. BOOL fSuccess = TRUE;
  37. lpTable ptab_prt;
  38. fNoContext = FALSE;
  39. fNoPD = FALSE;
  40. fNoMargin = FALSE;
  41. if (pcontext == NULL) {
  42. fNoContext = TRUE;
  43. pcontext = (lpPrintContext) gmem_get(heap,
  44. sizeof(PrintContext));
  45. pcontext->head = pcontext->foot = NULL;
  46. pcontext->margin = NULL;
  47. pcontext->pd = NULL;
  48. pcontext->id = 0;
  49. }
  50. if (pcontext->pd == NULL) {
  51. fNoPD = TRUE;
  52. }
  53. if (pcontext->margin == NULL) {
  54. fNoMargin = TRUE;
  55. }
  56. ptab_prt = gtab_printsetup(hwnd, ptab, heap, pcontext);
  57. if (ptab_prt != NULL) {
  58. gtab_printjob(hwnd, ptab_prt, pcontext);
  59. gtab_deltable(hwnd, ptab_prt);
  60. } else fSuccess = FALSE;
  61. if (fNoMargin) {
  62. gmem_free(heap, (LPSTR)pcontext->margin,
  63. sizeof(Margin));
  64. pcontext->margin = NULL;
  65. }
  66. if (fNoPD) {
  67. if (pcontext->pd->hDevMode != NULL) {
  68. GlobalFree(pcontext->pd->hDevMode);
  69. }
  70. if (pcontext->pd->hDevNames != NULL) {
  71. GlobalFree(pcontext->pd->hDevNames);
  72. }
  73. gmem_free(heap, (LPSTR) pcontext->pd, sizeof(PRINTDLG));
  74. pcontext->pd = NULL;
  75. }
  76. if (fNoContext) {
  77. gmem_free(heap, (LPSTR) pcontext, sizeof(PrintContext));
  78. }
  79. return fSuccess;
  80. }
  81. /*
  82. * gtab_printsetup()
  83. *
  84. * sets up printercontext - builds lpTable for printer, incl. sizing
  85. * and initialises pcontext fields that may be null.
  86. */
  87. lpTable
  88. gtab_printsetup(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext)
  89. {
  90. lpTable pprttab;
  91. PRINTDLG FAR * pd;
  92. int ncols, i;
  93. ColPropsList cplist;
  94. /* set fields for context that user left null */
  95. if (pcontext->margin == NULL) {
  96. pcontext->margin = (lpMargin) gmem_get(heap, sizeof(Margin));
  97. if (pcontext->margin == NULL) {
  98. return(NULL);
  99. }
  100. pcontext->margin->left = 10;
  101. pcontext->margin->right = 10;
  102. pcontext->margin->top = 15;
  103. pcontext->margin->bottom = 15;
  104. pcontext->margin->topinner = 15;
  105. pcontext->margin->bottominner = 15;
  106. }
  107. if (pcontext->pd == NULL) {
  108. pd = (PRINTDLG FAR *) gmem_get(heap, sizeof(PRINTDLG));
  109. if (pd == NULL) {
  110. return(NULL);
  111. }
  112. pcontext->pd = pd;
  113. pd->lStructSize = sizeof(PRINTDLG);
  114. pd->hwndOwner = hwnd;
  115. pd->hDevMode = (HANDLE) NULL;
  116. pd->hDevNames = (HANDLE) NULL;
  117. pd->Flags = PD_RETURNDC|PD_RETURNDEFAULT;
  118. if (PrintDlg(pd) == FALSE) {
  119. return(NULL);
  120. }
  121. }
  122. /* now create a Table struct by querying the owner */
  123. pprttab = (lpTable) gmem_get(heap, sizeof(Table));
  124. if (pprttab == NULL) {
  125. return(NULL);
  126. }
  127. pprttab->hdr = ptab->hdr;
  128. /* get the row/column count from owner window */
  129. if (pcontext->id == 0) {
  130. pprttab->hdr.id = ptab->hdr.id;
  131. } else {
  132. pprttab->hdr.id = pcontext->id;
  133. }
  134. pprttab->hdr.props.valid = 0;
  135. pprttab->hdr.sendscroll = FALSE;
  136. if (gtab_sendtq(hwnd, TQ_GETSIZE, (LPARAM)&pprttab->hdr) == FALSE) {
  137. return(NULL);
  138. }
  139. /* alloc and init the col data structs */
  140. ncols = pprttab->hdr.ncols;
  141. pprttab->pcolhdr = (lpColProps) gmem_get(heap, sizeof(ColProps) * ncols);
  142. if (pprttab->pcolhdr == NULL) {
  143. gmem_free(heap, (LPSTR)pprttab, sizeof(Table));
  144. return(NULL);
  145. }
  146. /* init col properties to default */
  147. for (i=0; i < ncols; i++) {
  148. pprttab->pcolhdr[i].props.valid = 0;
  149. pprttab->pcolhdr[i].nchars = 0;
  150. }
  151. /* get the column props from owner */
  152. cplist.plist = pprttab->pcolhdr;
  153. cplist.id = pprttab->hdr.id;
  154. cplist.startcol = 0;
  155. cplist.ncols = ncols;
  156. gtab_sendtq(hwnd, TQ_GETCOLPROPS, (LPARAM)&cplist);
  157. pprttab->scrollscale = 1;
  158. pprttab->pcellpos = (lpCellPos) gmem_get(heap,
  159. sizeof(CellPos) * ptab->hdr.ncols);
  160. if (pprttab->pcellpos == NULL) {
  161. gmem_free(heap, (LPSTR) pprttab->pcolhdr, sizeof(ColProps) * ncols);
  162. gmem_free(heap, (LPSTR)pprttab, sizeof(Table));
  163. return(NULL);
  164. }
  165. pprttab->pdata = NULL;
  166. pprttab->nlines = 0;
  167. if (!gtab_prtwidths(hwnd, pprttab, heap, pcontext)) {
  168. gmem_free(heap, (LPSTR)pprttab->pcellpos,
  169. sizeof(CellPos) * ptab->hdr.ncols);
  170. gmem_free(heap, (LPSTR)pprttab, sizeof(Table));
  171. return(NULL);
  172. }
  173. return(pprttab);
  174. }
  175. /* calc the height/width settings and alloc line data */
  176. BOOL
  177. gtab_prtwidths(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext)
  178. {
  179. TEXTMETRIC tm;
  180. int cx, cxtotal, i, curx, cury;
  181. lpProps hdrprops, cellprops;
  182. lpCellPos xpos, ypos;
  183. RECT rcinner, rcouter;
  184. hdrprops = &ptab->hdr.props;
  185. GetTextMetrics(pcontext->pd->hDC, &tm);
  186. ptab->avewidth = tm.tmAveCharWidth;
  187. ptab->rowheight = tm.tmHeight + tm.tmExternalLeading;
  188. if (hdrprops->valid & P_HEIGHT) {
  189. ptab->rowheight = hdrprops->height;
  190. }
  191. /* set sizes for headers */
  192. gtab_setrects(pcontext, &rcinner, &rcouter);
  193. /* set width/pos for each col. */
  194. cxtotal = 0;
  195. curx = rcinner.left;
  196. for (i = 0; i < ptab->hdr.ncols; i++) {
  197. cellprops = &ptab->pcolhdr[i].props;
  198. xpos = &ptab->pcellpos[i];
  199. if (cellprops->valid & P_WIDTH) {
  200. cx = cellprops->width;
  201. } else if (hdrprops->valid & P_WIDTH) {
  202. cx = hdrprops->width;
  203. } else {
  204. cx = ptab->pcolhdr[i].nchars + 1;
  205. cx *= ptab->avewidth;
  206. }
  207. /* add 2 for intercol spacing */
  208. cx += 2;
  209. xpos->size = cx;
  210. xpos->start = curx + 1;
  211. xpos->clipstart = xpos->start;
  212. xpos->clipend = xpos->start + xpos->size - 2;
  213. xpos->clipend = min(xpos->clipend, rcinner.right);
  214. cxtotal += xpos->size;
  215. curx += xpos->size;
  216. }
  217. ptab->rowwidth = cxtotal;
  218. if (pcontext->head != NULL) {
  219. xpos = &pcontext->head->xpos;
  220. ypos = &pcontext->head->ypos;
  221. xpos->start = rcouter.left + 1;
  222. xpos->clipstart = rcouter.left + 1;
  223. xpos->clipend = rcouter.right - 1;
  224. xpos->size = rcouter.right - rcouter.left;
  225. ypos->start = rcouter.top;
  226. ypos->clipstart = rcouter.top;
  227. ypos->clipend = rcinner.top;
  228. ypos->size = ptab->rowheight;
  229. }
  230. if (pcontext->foot != NULL) {
  231. xpos = &pcontext->foot->xpos;
  232. ypos = &pcontext->foot->ypos;
  233. xpos->start = rcouter.left + 1;
  234. xpos->clipstart = rcouter.left + 1;
  235. xpos->clipend = rcouter.right - 1;
  236. xpos->size = rcouter.right - rcouter.left;
  237. ypos->start = rcouter.bottom - ptab->rowheight;
  238. ypos->clipstart = rcinner.bottom;
  239. ypos->clipend = rcouter.bottom;
  240. ypos->size = ptab->rowheight;
  241. }
  242. /* set nr of lines per page */
  243. ptab->nlines = (rcinner.bottom - rcinner.top) / ptab->rowheight;
  244. if (!gtab_alloclinedata(hwnd, heap, ptab)) {
  245. return(FALSE);
  246. }
  247. /* set line positions */
  248. cury = rcinner.top;
  249. for (i = 0; i < ptab->nlines; i++) {
  250. ypos = &ptab->pdata[i].linepos;
  251. ypos->start = cury;
  252. ypos->clipstart = ypos->start;
  253. ypos->clipend = ypos->start + ypos->size;
  254. ypos->clipend = min(ypos->clipend, rcinner.bottom);
  255. cury += ypos->size;
  256. }
  257. return(TRUE);
  258. }
  259. /* static information for this module */
  260. BOOL bAbort;
  261. FARPROC lpAbortProc;
  262. DLGPROC lpAbortDlg;
  263. HWND hAbortWnd;
  264. int npage;
  265. int pages;
  266. void
  267. gtab_printjob(HWND hwnd, lpTable ptab, lpPrintContext pcontext)
  268. {
  269. int moveables;
  270. int endpage;
  271. int startpage = 1;
  272. HDC hpr;
  273. int status;
  274. HANDLE hcurs;
  275. static char str[256];
  276. DOCINFO di;
  277. TCHAR szPage[60]; /* for LoadString */
  278. hcurs = SetCursor(LoadCursor(NULL, IDC_WAIT));
  279. moveables = ptab->nlines - ptab->hdr.fixedrows;
  280. pages = (int) (ptab->hdr.nrows - ptab->hdr.fixedrows + moveables - 1)
  281. / moveables;
  282. endpage = pages;
  283. if (pcontext->pd->Flags & PD_PAGENUMS) {
  284. startpage = pcontext->pd->nFromPage;
  285. endpage = pcontext->pd->nToPage;
  286. }
  287. hpr = pcontext->pd->hDC;
  288. lpAbortDlg = (DLGPROC) MakeProcInstance((WINPROCTYPE) AbortDlg, hLibInst);
  289. lpAbortProc = (FARPROC) MakeProcInstance((WINPROCTYPE)AbortProc, hLibInst);
  290. SetAbortProc(hpr, (ABORTPROC) lpAbortProc);
  291. di.lpszDocName = "Table";
  292. di.cbSize = lstrlen(di.lpszDocName);
  293. di.lpszOutput = NULL;
  294. di.lpszDatatype = NULL;
  295. di.fwType = 0;
  296. StartDoc(hpr, &di);
  297. bAbort = FALSE;
  298. /* add abort modeless dialog later!! */
  299. hAbortWnd = CreateDialog(hLibInst, "GABRTDLG", hwnd, lpAbortDlg);
  300. if (hAbortWnd != NULL) {
  301. ShowWindow(hAbortWnd, SW_NORMAL);
  302. EnableWindow(hwnd, FALSE);
  303. }
  304. SetCursor(hcurs);
  305. status = 0; /* kills a "used without init" diagnostic */
  306. for (npage = startpage; npage<=endpage; npage++) {
  307. LoadString(hLibInst,IDS_PAGE_STR,szPage,sizeof(szPage));
  308. wsprintf(str, szPage, npage, pages);
  309. if (hAbortWnd != NULL)
  310. SetDlgItemText(hAbortWnd, IDC_LPAGENR, str);
  311. status = gtab_printpage(hwnd, ptab, pcontext, npage);
  312. if (status < 0) {
  313. AbortDoc(hpr);
  314. break;
  315. }
  316. }
  317. if (status >= 0) {
  318. EndDoc(hpr);
  319. }
  320. if (hAbortWnd != NULL) {
  321. EnableWindow(hwnd, TRUE);
  322. DestroyWindow(hAbortWnd);
  323. }
  324. FreeProcInstance((WINPROCTYPE) lpAbortDlg);
  325. FreeProcInstance(lpAbortProc);
  326. DeleteDC(hpr);
  327. }
  328. int APIENTRY
  329. AbortProc(HDC hpr, int code)
  330. {
  331. MSG msg;
  332. if (!hAbortWnd) {
  333. return(TRUE);
  334. }
  335. while (!bAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  336. if (!IsDialogMessage(hAbortWnd, &msg)) {
  337. TranslateMessage(&msg);
  338. DispatchMessage(&msg);
  339. }
  340. }
  341. return(!bAbort);
  342. }
  343. int APIENTRY
  344. AbortDlg(HWND hdlg, UINT msg, UINT wParam, LONG lParam)
  345. {
  346. switch (msg) {
  347. case WM_COMMAND:
  348. bAbort = TRUE;
  349. EndDialog(hdlg, TRUE);
  350. return TRUE;
  351. case WM_INITDIALOG:
  352. return TRUE;
  353. }
  354. return(FALSE);
  355. }
  356. /*
  357. * print a single page. page number is 1-based
  358. */
  359. BOOL
  360. gtab_printpage(HWND hwnd, lpTable ptab, lpPrintContext pcontext, int page)
  361. {
  362. HDC hpr;
  363. int moveables, i;
  364. int x1, y1, x2, y2;
  365. hpr = pcontext->pd->hDC;
  366. StartPage(hpr);
  367. moveables = ptab->nlines - ptab->hdr.fixedrows;
  368. ptab->toprow = moveables * (page-1);
  369. gtab_invallines(hwnd, ptab, ptab->hdr.fixedrows, moveables);
  370. for (i =0; i < ptab->nlines; i++) {
  371. gtab_paintline(hwnd, hpr, ptab, i, FALSE);
  372. }
  373. if ((ptab->hdr.vseparator) && (ptab->hdr.fixedcols > 0)) {
  374. x1 = ptab->pcellpos[ptab->hdr.fixedcols -1].clipend+1;
  375. y1 = ptab->pdata[0].linepos.clipstart;
  376. y2 = ptab->pdata[ptab->nlines-1].linepos.clipend;
  377. MoveToEx(hpr, x1, y1, NULL);
  378. LineTo(hpr, x1, y2);
  379. }
  380. if ((ptab->hdr.hseparator) && (ptab->hdr.fixedrows > 0)) {
  381. y1 = ptab->pdata[ptab->hdr.fixedrows-1].linepos.clipend;
  382. x1 = ptab->pcellpos[0].clipstart;
  383. x2 = ptab->pcellpos[ptab->hdr.ncols-1].clipend;
  384. MoveToEx(hpr, x1, y1, NULL);
  385. LineTo(hpr, x2, y1);
  386. }
  387. if (pcontext->head != NULL) {
  388. gtab_printhead(hwnd, hpr, ptab, pcontext->head, page);
  389. }
  390. if (pcontext->foot != NULL) {
  391. gtab_printhead(hwnd, hpr, ptab, pcontext->foot, page);
  392. }
  393. return(EndPage(hpr));
  394. }
  395. /*
  396. * calculate the outline positions in pixels for the headers
  397. * (outer rect) and for the page itself (inner rect). Based on
  398. * page size and PrintContext margin info (which is in millimetres).
  399. */
  400. void
  401. gtab_setrects(lpPrintContext pcontext, LPRECT rcinner, LPRECT rcouter)
  402. {
  403. HDC hpr;
  404. int hpixels, hmms;
  405. int vpixels, vmms;
  406. int h_pixpermm, v_pixpermm;
  407. hpr = pcontext->pd->hDC;
  408. hpixels = GetDeviceCaps(hpr, HORZRES);
  409. vpixels = GetDeviceCaps(hpr, VERTRES);
  410. vmms = GetDeviceCaps(hpr, VERTSIZE);
  411. hmms = GetDeviceCaps(hpr, HORZSIZE);
  412. h_pixpermm = hpixels / hmms;
  413. v_pixpermm = vpixels / vmms;
  414. rcouter->top = (pcontext->margin->top * v_pixpermm);
  415. rcouter->bottom = vpixels - (pcontext->margin->bottom * v_pixpermm);
  416. rcouter->left = (pcontext->margin->left * h_pixpermm);
  417. rcouter->right = hpixels - (pcontext->margin->right * h_pixpermm);
  418. rcinner->left = rcouter->left;
  419. rcinner->right = rcouter->right;
  420. rcinner->top = rcouter->top +
  421. (pcontext->margin->topinner * v_pixpermm);
  422. rcinner->bottom = rcouter->bottom -
  423. (pcontext->margin->bottominner * v_pixpermm);
  424. }
  425. void
  426. gtab_printhead(HWND hwnd, HDC hdc, lpTable ptab, lpTitle head, int page)
  427. {
  428. RECT rc, rcbox;
  429. int i, cx, x, y, tab;
  430. UINT align;
  431. LPSTR chp, tabp;
  432. DWORD fcol, bkcol;
  433. char str[256];
  434. fcol = 0; bkcol = 0; /* eliminate spurious diagnostic - generate worse code */
  435. rc.top = head->ypos.clipstart;
  436. rc.bottom = head->ypos.clipend;
  437. rc.left = head->xpos.clipstart;
  438. rc.right = head->xpos.clipend;
  439. /* update page number */
  440. chp = str;
  441. for (i = 0; i < lstrlen(head->ptext); i++) {
  442. switch (head->ptext[i]) {
  443. case '#':
  444. chp += wsprintf(chp, "%d", page);
  445. break;
  446. case '$':
  447. chp += wsprintf(chp, "%d", pages);
  448. break;
  449. default:
  450. if (IsDBCSLeadByte(head->ptext[i]) &&
  451. head->ptext[i+1])
  452. {
  453. *chp = head->ptext[i];
  454. chp++;
  455. i++;
  456. }
  457. *chp++ = head->ptext[i];
  458. break;
  459. }
  460. }
  461. *chp = '\0';
  462. chp = str;
  463. if (head->props.valid & P_ALIGN) {
  464. align = head->props.alignment;
  465. } else {
  466. align = P_LEFT;
  467. }
  468. /* set colours if not default */
  469. if (head->props.valid & P_FCOLOUR) {
  470. fcol = SetTextColor(hdc, head->props.forecolour);
  471. }
  472. if (head->props.valid & P_BCOLOUR) {
  473. bkcol = SetBkColor(hdc, head->props.backcolour);
  474. }
  475. /* calc offset of text within cell for right-align or centering */
  476. if (align == P_LEFT) {
  477. cx = ptab->avewidth/2;
  478. } else {
  479. cx = LOWORD(GetTextExtent(hdc, chp, lstrlen(chp)));
  480. if (align == P_CENTRE) {
  481. cx = (head->xpos.size - cx) / 2;
  482. } else {
  483. cx = head->xpos.size - cx - (ptab->avewidth/2);
  484. }
  485. }
  486. cx += head->xpos.start;
  487. /* expand tabs on output */
  488. tab = ptab->avewidth * ptab->tabchars;
  489. x = 0;
  490. y = head->ypos.start;
  491. for ( ; (tabp = My_mbschr(chp, '\t')) != NULL; ) {
  492. /* perform output upto tab char */
  493. ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, (UINT)(tabp-chp), NULL);
  494. /* advance past the tab */
  495. x += LOWORD(GetTextExtent(hdc, chp, (INT)(tabp - chp)));
  496. x = ( (x + tab) / tab) * tab;
  497. chp = ++tabp;
  498. }
  499. /*no more tabs - output rest of string */
  500. ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, lstrlen(chp), NULL);
  501. /* reset colours to original if not default */
  502. if (head->props.valid & P_FCOLOUR) {
  503. SetTextColor(hdc, fcol);
  504. }
  505. if (head->props.valid & P_BCOLOUR) {
  506. SetBkColor(hdc, bkcol);
  507. }
  508. /* now box cell if marked */
  509. if (head->props.valid & P_BOX) {
  510. if (head->props.box != 0) {
  511. rcbox.top = head->ypos.start;
  512. rcbox.bottom = rcbox.top + head->ypos.size;
  513. rcbox.left = head->xpos.start;
  514. rcbox.right = rcbox.left + head->xpos.size;
  515. gtab_boxcell(hwnd, hdc, &rcbox, &rc, head->props.box);
  516. }
  517. }
  518. }