/******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright (C) 1993-1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ /****************************** Module Header ******************************* * Module Name: TPRINT.C * * Print functions. * * Functions: * * gtab_print() * gtab_printsetup() * gtab_prtwidths() * gtab_printjob() * AbortProc() * AbortDlg() * gtab_printpage() * gtab_setrects() * gtab_printhead() * * Comments: * * See table.h for interface description. * ****************************************************************************/ #include #include #include #include "gutils.h" #include "gutilsrc.h" #include "table.h" #include "tpriv.h" /* in tpaint.c, calls GetTextExtentPoint */ extern int GetTextExtent(HDC, LPSTR, int); extern HANDLE hLibInst; /* function prototypes */ lpTable gtab_printsetup(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext); BOOL gtab_prtwidths(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext); void gtab_printjob(HWND hwnd, lpTable ptab, lpPrintContext pcontext); int APIENTRY AbortProc(HDC hpr, int code); int APIENTRY AbortDlg(HWND hdlg, UINT msg, UINT wParam, LONG lParam); BOOL gtab_printpage(HWND hwnd, lpTable ptab, lpPrintContext pcontext, int page); void gtab_setrects(lpPrintContext pcontext, LPRECT rcinner, LPRECT rcouter); void gtab_printhead(HWND hwnd, HDC hdc, lpTable ptab, lpTitle head, int page); /*************************************************************************** * Function: gtab_print * * Purpose: * * Prints a table. */ void gtab_print(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext) { BOOL fNoContext, fNoMargin, fNoPD; lpTable ptab_prt; fNoContext = FALSE; fNoPD = FALSE; fNoMargin = FALSE; if (pcontext == NULL) { fNoContext = TRUE; pcontext = (lpPrintContext) gmem_get(heap, sizeof(PrintContext)); pcontext->head = pcontext->foot = NULL; pcontext->margin = NULL; pcontext->pd = NULL; pcontext->id = 0; } if (pcontext->pd == NULL) { fNoPD = TRUE; } if (pcontext->margin == NULL) { fNoMargin = TRUE; } ptab_prt = gtab_printsetup(hwnd, ptab, heap, pcontext); if (ptab_prt != NULL) { gtab_printjob(hwnd, ptab_prt, pcontext); gtab_deltable(hwnd, ptab_prt); } if (fNoMargin) { gmem_free(heap, (LPSTR)pcontext->margin, sizeof(Margin)); pcontext->margin = NULL; } if (fNoPD) { if (pcontext->pd->hDevMode != NULL) { GlobalFree(pcontext->pd->hDevMode); } if (pcontext->pd->hDevNames != NULL) { GlobalFree(pcontext->pd->hDevNames); } gmem_free(heap, (LPSTR) pcontext->pd, sizeof(PRINTDLG)); pcontext->pd = NULL; } if (fNoContext) { gmem_free(heap, (LPSTR) pcontext, sizeof(PrintContext)); } } /*************************************************************************** * Function: gtab_printsetup * * Purpose: * * Sets up printercontext - builds lpTable for printer, incl. sizing * and initialises pcontext fields that may be null. */ lpTable gtab_printsetup(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext) { lpTable pprttab; PRINTDLG FAR * pd; int ncols, i; ColPropsList cplist; /* set fields for context that user left null */ if (pcontext->margin == NULL) { pcontext->margin = (lpMargin) gmem_get(heap, sizeof(Margin)); if (pcontext->margin == NULL) { return(NULL); } pcontext->margin->left = 10; pcontext->margin->right = 10; pcontext->margin->top = 15; pcontext->margin->bottom = 15; pcontext->margin->topinner = 15; pcontext->margin->bottominner = 15; } if (pcontext->pd == NULL) { pd = (PRINTDLG FAR *) gmem_get(heap, sizeof(PRINTDLG)); if (pd == NULL) { return(NULL); } pcontext->pd = pd; pd->lStructSize = sizeof(PRINTDLG); pd->hwndOwner = hwnd; pd->hDevMode = (HANDLE) NULL; pd->hDevNames = (HANDLE) NULL; pd->Flags = PD_RETURNDC|PD_RETURNDEFAULT; if (PrintDlg(pd) == FALSE) { return(NULL); } } /* now create a Table struct by querying the owner */ pprttab = (lpTable) gmem_get(heap, sizeof(Table)); if (pprttab == NULL) { return(NULL); } pprttab->hdr = ptab->hdr; /* get the row/column count from owner window */ if (pcontext->id == 0) { pprttab->hdr.id = ptab->hdr.id; } else { pprttab->hdr.id = pcontext->id; } pprttab->hdr.props.valid = 0; pprttab->hdr.sendscroll = FALSE; if (gtab_sendtq(hwnd, TQ_GETSIZE, (long) (LPSTR)&pprttab->hdr) == FALSE) { return(NULL); } /* alloc and init the col data structs */ ncols = pprttab->hdr.ncols; pprttab->pcolhdr = (lpColProps) gmem_get(heap, sizeof(ColProps) * ncols); if (pprttab->pcolhdr == NULL) { gmem_free(heap, (LPSTR)pprttab, sizeof(Table)); return(NULL); } /* init col properties to default */ for (i=0; i < ncols; i++) { pprttab->pcolhdr[i].props.valid = 0; pprttab->pcolhdr[i].nchars = 0; } /* get the column props from owner */ cplist.plist = pprttab->pcolhdr; cplist.id = pprttab->hdr.id; cplist.startcol = 0; cplist.ncols = ncols; gtab_sendtq(hwnd, TQ_GETCOLPROPS, (long) (LPSTR)&cplist); pprttab->scrollscale = 1; pprttab->pcellpos = (lpCellPos) gmem_get(heap, sizeof(CellPos) * ptab->hdr.ncols); if (pprttab->pcellpos == NULL) { gmem_free(heap, (LPSTR) pprttab->pcolhdr, sizeof(ColProps) * ncols); gmem_free(heap, (LPSTR)pprttab, sizeof(Table)); return(NULL); } pprttab->pdata = NULL; pprttab->nlines = 0; if (!gtab_prtwidths(hwnd, pprttab, heap, pcontext)) { gmem_free(heap, (LPSTR)pprttab->pcellpos, sizeof(CellPos) * ptab->hdr.ncols); gmem_free(heap, (LPSTR)pprttab, sizeof(Table)); return(NULL); } return(pprttab); } /*************************************************************************** * Function: gtab_prtwidths * * Purpose: * * Calc the height/width settings and alloc line data */ BOOL gtab_prtwidths(HWND hwnd, lpTable ptab, HANDLE heap, lpPrintContext pcontext) { TEXTMETRIC tm; int cx, cxtotal, i, curx, cury; lpProps hdrprops, cellprops; lpCellPos xpos, ypos; RECT rcinner, rcouter; hdrprops = &ptab->hdr.props; GetTextMetrics(pcontext->pd->hDC, &tm); ptab->avewidth = tm.tmAveCharWidth; ptab->rowheight = tm.tmHeight + tm.tmExternalLeading; if (hdrprops->valid & P_HEIGHT) { ptab->rowheight = hdrprops->height; } /* set sizes for headers */ gtab_setrects(pcontext, &rcinner, &rcouter); /* set width/pos for each col. */ cxtotal = 0; curx = rcinner.left; for (i = 0; i < ptab->hdr.ncols; i++) { cellprops = &ptab->pcolhdr[i].props; xpos = &ptab->pcellpos[i]; if (cellprops->valid & P_WIDTH) { cx = cellprops->width; } else if (hdrprops->valid & P_WIDTH) { cx = hdrprops->width; } else { cx = ptab->pcolhdr[i].nchars + 1; cx *= ptab->avewidth; } /* add 2 for intercol spacing */ cx += 2; xpos->size = cx; xpos->start = curx + 1; xpos->clipstart = xpos->start; xpos->clipend = xpos->start + xpos->size - 2; xpos->clipend = min(xpos->clipend, rcinner.right); cxtotal += xpos->size; curx += xpos->size; } ptab->rowwidth = cxtotal; if(pcontext->head != NULL) { xpos = &pcontext->head->xpos; ypos = &pcontext->head->ypos; xpos->start = rcouter.left + 1; xpos->clipstart = rcouter.left + 1; xpos->clipend = rcouter.right - 1; xpos->size = rcouter.right - rcouter.left; ypos->start = rcouter.top; ypos->clipstart = rcouter.top; ypos->clipend = rcinner.top; ypos->size = ptab->rowheight; } if (pcontext->foot != NULL) { xpos = &pcontext->foot->xpos; ypos = &pcontext->foot->ypos; xpos->start = rcouter.left + 1; xpos->clipstart = rcouter.left + 1; xpos->clipend = rcouter.right - 1; xpos->size = rcouter.right - rcouter.left; ypos->start = rcouter.bottom - ptab->rowheight; ypos->clipstart = rcinner.bottom; ypos->clipend = rcouter.bottom; ypos->size = ptab->rowheight; } /* set nr of lines per page */ ptab->nlines = (rcinner.bottom - rcinner.top) / ptab->rowheight; if (!gtab_alloclinedata(hwnd, heap, ptab)) { return(FALSE); } /* set line positions */ cury = rcinner.top; for (i = 0; i < ptab->nlines; i++) { ypos = &ptab->pdata[i].linepos; ypos->start = cury; ypos->clipstart = ypos->start; ypos->clipend = ypos->start + ypos->size; ypos->clipend = min(ypos->clipend, rcinner.bottom); cury += ypos->size; } return(TRUE); } /* static information for this module */ BOOL bAbort; FARPROC lpAbortProc; DLGPROC lpAbortDlg; HWND hAbortWnd; int npage; int pages; /*************************************************************************** * Function: gtab_printjob * * Purpose: * * Sets up print job and dialogs */ void gtab_printjob(HWND hwnd, lpTable ptab, lpPrintContext pcontext) { int moveables; int endpage; int startpage = 1; HDC hpr; int status; HANDLE hcurs; static char str[256]; DOCINFO di; CHAR szPage[60]; /* for LoadString */ hcurs = SetCursor(LoadCursor(NULL, IDC_WAIT)); moveables = ptab->nlines - ptab->hdr.fixedrows; pages = (int) (ptab->hdr.nrows - ptab->hdr.fixedrows + moveables - 1) / moveables; endpage = pages; if (pcontext->pd->Flags & PD_PAGENUMS) { startpage = pcontext->pd->nFromPage; endpage = pcontext->pd->nToPage; } hpr = pcontext->pd->hDC; lpAbortDlg = (DLGPROC) MakeProcInstance((WNDPROC) AbortDlg, hLibInst); lpAbortProc = (FARPROC) MakeProcInstance((WNDPROC)AbortProc, hLibInst); SetAbortProc(hpr, (ABORTPROC) lpAbortProc); ZeroMemory( &di, sizeof( DOCINFO ) ); di.lpszDocName = "Table"; di.cbSize = sizeof( DOCINFO ); di.lpszOutput = NULL; StartDoc(hpr, &di); bAbort = FALSE; /* add abort modeless dialog later!! */ hAbortWnd = CreateDialog(hLibInst, "GABRTDLG", hwnd, lpAbortDlg); if (hAbortWnd != NULL) { ShowWindow(hAbortWnd, SW_NORMAL); EnableWindow(hwnd, FALSE); } SetCursor(hcurs); for (npage = startpage; npage<=endpage; npage++) { LoadString(hLibInst, IDS_PAGE_STR, szPage, sizeof(szPage)); wsprintf(str, szPage, npage, pages); SetDlgItemText(hAbortWnd, IDC_LPAGENR, str); status = gtab_printpage(hwnd, ptab, pcontext, npage); if (status < 0) { AbortDoc(hpr); break; } } if (status >= 0) { EndDoc(hpr); } if (hAbortWnd != NULL) { EnableWindow(hwnd, TRUE); DestroyWindow(hAbortWnd); } FreeProcInstance((WNDPROC) lpAbortDlg); FreeProcInstance(lpAbortProc); DeleteDC(hpr); } /*************************************************************************** * Function: AbortProc * * Purpose: * * Abort procedure for print job */ int APIENTRY AbortProc(HDC hpr, int code) { MSG msg; if (!hAbortWnd) { return(TRUE); } while (!bAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (!IsDialogMessage(hAbortWnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return(!bAbort); } /*************************************************************************** * Function: AbortDlg * * Purpose: * * Dialog for abort procedure */ int APIENTRY AbortDlg(HWND hdlg, UINT msg, UINT wParam, LONG lParam) { switch(msg) { case WM_COMMAND: bAbort = TRUE; DestroyWindow (hdlg); return TRUE; case WM_INITDIALOG: return TRUE; } return(FALSE); } /*************************************************************************** * Function: gtab_printpage * * Purpose: * * Print a single page. page number is 1-based */ BOOL gtab_printpage(HWND hwnd, lpTable ptab, lpPrintContext pcontext, int page) { HDC hpr; int moveables, i; int x1, y1, x2, y2; hpr = pcontext->pd->hDC; StartPage(hpr); moveables = ptab->nlines - ptab->hdr.fixedrows; ptab->toprow = moveables * (page-1); gtab_invallines(hwnd, ptab, ptab->hdr.fixedrows, moveables); for (i =0; i < ptab->nlines; i++) { gtab_paint(hwnd, hpr, ptab, i); } if ((ptab->hdr.vseparator) && (ptab->hdr.fixedcols > 0)) { x1 = ptab->pcellpos[ptab->hdr.fixedcols -1].clipend+1; y1 = ptab->pdata[0].linepos.clipstart; y2 = ptab->pdata[ptab->nlines-1].linepos.clipend; MoveToEx(hpr, x1, y1, NULL); LineTo(hpr, x1, y2); } if ((ptab->hdr.hseparator) && (ptab->hdr.fixedrows > 0)) { y1 = ptab->pdata[ptab->hdr.fixedrows-1].linepos.clipend; x1 = ptab->pcellpos[0].clipstart; x2 = ptab->pcellpos[ptab->hdr.ncols-1].clipend; MoveToEx(hpr, x1, y1, NULL); LineTo(hpr, x2, y1); } if (pcontext->head != NULL) { gtab_printhead(hwnd, hpr, ptab, pcontext->head, page); } if (pcontext->foot != NULL) { gtab_printhead(hwnd, hpr, ptab, pcontext->foot, page); } return(EndPage(hpr)); } /*************************************************************************** * Function: gtab_setrects * * Purpose: * * Calculate the outline positions in pixels for the headers * (outer rect) and for the page itself (inner rect). Based on * page size and PrintContext margin info (which is in millimetres). */ void gtab_setrects(lpPrintContext pcontext, LPRECT rcinner, LPRECT rcouter) { HDC hpr; int hpixels, hmms; int vpixels, vmms; int h_pixpermm, v_pixpermm; hpr = pcontext->pd->hDC; hpixels = GetDeviceCaps(hpr, HORZRES); vpixels = GetDeviceCaps(hpr, VERTRES); vmms = GetDeviceCaps(hpr, VERTSIZE); hmms = GetDeviceCaps(hpr, HORZSIZE); h_pixpermm = hpixels / hmms; v_pixpermm = vpixels / vmms; rcouter->top = (pcontext->margin->top * v_pixpermm); rcouter->bottom = vpixels - (pcontext->margin->bottom * v_pixpermm); rcouter->left = (pcontext->margin->left * h_pixpermm); rcouter->right = hpixels - (pcontext->margin->right * h_pixpermm); rcinner->left = rcouter->left; rcinner->right = rcouter->right; rcinner->top = rcouter->top + (pcontext->margin->topinner * v_pixpermm); rcinner->bottom = rcouter->bottom - (pcontext->margin->bottominner * v_pixpermm); } /*************************************************************************** * Function: gtab_printhead * * Purpose: * * Print header information */ void gtab_printhead(HWND hwnd, HDC hdc, lpTable ptab, lpTitle head, int page) { RECT rc, rcbox; int i, cx, x, y, tab; UINT align; LPSTR chp, tabp; DWORD fcol, bkcol; char str[256]; rc.top = head->ypos.clipstart; rc.bottom = head->ypos.clipend; rc.left = head->xpos.clipstart; rc.right = head->xpos.clipend; /* update page number */ chp = str; for (i = 0; i < lstrlen(head->ptext); i++) { switch(head->ptext[i]) { case '#': chp += wsprintf(chp, "%d", page); break; case '$': chp += wsprintf(chp, "%d", pages); break; default: if (IsDBCSLeadByte(head->ptext[i]) && head->ptext[i+1]) { *chp = head->ptext[i]; chp++; i++; } *chp++ = head->ptext[i]; break; } } *chp = '\0'; chp = str; if (head->props.valid & P_ALIGN) { align = head->props.alignment; } else { align = P_LEFT; } /* set colours if not default */ if (head->props.valid & P_FCOLOUR) { fcol = SetTextColor(hdc, head->props.forecolour); } if (head->props.valid & P_BCOLOUR) { bkcol = SetBkColor(hdc, head->props.backcolour); } /* calc offset of text within cell for right-align or centering */ if (align == P_LEFT) { cx = ptab->avewidth/2; } else { cx = LOWORD(GetTextExtent(hdc, chp, lstrlen(chp))); if (align == P_CENTRE) { cx = (head->xpos.size - cx) / 2; } else { cx = head->xpos.size - cx - (ptab->avewidth/2); } } cx += head->xpos.start; /* expand tabs on output */ tab = ptab->avewidth * 8; x = 0; y = head->ypos.start; for ( ; (tabp = strchr(chp, '\t')) != NULL; ) { /* perform output upto tab char */ ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, tabp-chp, NULL); /* advance past the tab */ x += LOWORD(GetTextExtent(hdc, chp, tabp - chp)); x = ( (x + tab) / tab) * tab; chp = ++tabp; } /*no more tabs - output rest of string */ ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, lstrlen(chp), NULL); /* reset colours to original if not default */ if (head->props.valid & P_FCOLOUR) { SetTextColor(hdc, fcol); } if (head->props.valid & P_BCOLOUR) { SetBkColor(hdc, bkcol); } /* now box cell if marked */ if (head->props.valid & P_BOX) { if (head->props.box != 0) { rcbox.top = head->ypos.start; rcbox.bottom = rcbox.top + head->ypos.size; rcbox.left = head->xpos.start; rcbox.right = rcbox.left + head->xpos.size; gtab_boxcell(hwnd, hdc, &rcbox, &rc, head->props.box); } } }