home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / WRITEPAD.PAK / PREVIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  28.5 KB  |  1,013 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   preview.c
  9. //
  10. //  PURPOSE:  Implement WYSIWYG print preview using the RichEdit control
  11. //
  12. //  FUNCTIONS:
  13. //    InitPreview             - Register the preview window class
  14. //    GetNextPage             - Format a page for previewing
  15. //    PrintPreview            - Do the print preview
  16. //    EnableNextPrev          - Update Next & Prev buttons in preview dialog
  17. //    SetStatbarPage          - Update page # on status bar
  18. //    CmdPreviewNext          - Handle "Next" button click
  19. //    CmdPreviewPrev          - Handle "Prev" button click
  20. //    CmdPreviewFilePrint     - Handle "Print..." button click
  21. //    CmdPreviewClose         - Handle "Close" button click
  22. //    MsgPreviewInitDialog    - Handle WM_INITDIALOG for preview dialog
  23. //    MsgPreviewSize          - Handle WM_SIZE for preview dialog
  24. //    MsgPreviewCtlColorDlg   - Handle WM_CTLCOLORDLG for preview dialog
  25. //    MsgPreviewDestroy       - Handle WM_DESTROY for preview dialog
  26. //    PaintPreview            - Paint contents of the preview window
  27. //    MsgPrevWndNCCreate      - Handle WM_NCCREATE for preview window
  28. //    MsgPrevWndPaint         - Handle WM_PAINT for preview window
  29. //    MsgPreviewCommand       - Handle WM_COMMAND for preview dialog
  30. //    PreviewDlgProc          - Dialog proc for the preview dialog
  31. //    PreviewWndProc          - Window proc for the preview window
  32. //
  33. //  COMMENTS:
  34. //
  35.  
  36. #include <windows.h>
  37. #include <windowsx.h>
  38. #include <commctrl.h>
  39. #include <richedit.h>
  40. #include "globals.h"
  41. #include "resource.h"
  42.  
  43. #define RECTWIDTH(pr)  ((pr)->right - (pr)->left)
  44. #define RECTHEIGHT(pr) ((pr)->bottom - (pr)->top)
  45.  
  46. BOOL CALLBACK PreviewDlgProc(HWND, UINT, WPARAM, LPARAM);
  47. LRESULT CALLBACK PreviewWndProc(HWND, UINT, WPARAM, LPARAM);
  48.  
  49. // Global variables local to this module
  50. static HBRUSH hbrPattern = NULL;
  51. static TCHAR szPrevClass[] = TEXT("PrevWndClass");
  52.  
  53. // ID of the status bar on the preview dialog
  54. #define IDC_PREVSTATBAR 2100
  55.  
  56. // allocate memory for this many pages at a time
  57. #define PAGECHUNK 8
  58.  
  59. // define structure to hold data for the print preview
  60. typedef struct _PREVINFO
  61. {
  62.     HWND hwndOwner;     // window that owns us
  63.     FORMATRANGE fr;     // used with EM_FORMATRANGE for printing
  64.     HWND hEdit;         // RichEdit control window
  65.     int cchText;        // # of chars in hEdit
  66.     SIZE sizePhysPage;  // full size of print paper (pixels)
  67.     SIZE sizePhysInch;  // resolution (DPI) of printer (pixels)
  68.     int iCurPage;       // page currently being previewed
  69.     BOOL fAllPages;     // TRUE indicates all pages formatted
  70.     int cPages;         // # of pages formatted so far (starts from zero)
  71.     int cPageMax;       // # of elements in pPageIndex
  72.     LPINT pPageIndex;   // starting character indexes of each page
  73. } PREVINFO, *LPPREVINFO;
  74.  
  75.  
  76. //
  77. //  FUNCTION: InitPreview(HINSTANCE)
  78. //
  79. //  PURPOSE: Register a window class used during print preview
  80. //
  81. //  PARAMETERS:
  82. //    hInstance - Application instance
  83. //
  84. //  RETURN VALUE:
  85. //    TRUE on success, otherwise FALSE
  86. //
  87. //  COMMENTS:
  88. //
  89. //
  90.  
  91. BOOL InitPreview(HINSTANCE hInstance)
  92. {
  93.     WNDCLASS wc;
  94.  
  95.     wc.style         = CS_HREDRAW | CS_VREDRAW; // Class style(s).
  96.     wc.lpfnWndProc   = (WNDPROC)PreviewWndProc; // Window Procedure
  97.     wc.cbClsExtra    = 0;                       // No per-class extra data.
  98.     wc.cbWndExtra    = 0;                       // No per-window extra data.
  99.     wc.hInstance     = hInstance;               // Owner of this class
  100.     wc.hIcon         = NULL;                    // no icon
  101.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  102.     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  103.     wc.lpszMenuName  = NULL;
  104.     wc.lpszClassName = szPrevClass;             // Name to register as
  105.  
  106.     // Register the window class and return FALSE if unsuccesful.
  107.  
  108.     return RegisterClass(&wc);
  109. }
  110.  
  111.  
  112. //
  113. //  FUNCTION: GetNextPage(LPPREVINFO)
  114. //
  115. //  PURPOSE: Format another page for previewing and update PREVINFO.
  116. //
  117. //  PARAMETERS:
  118. //    ppi           - pointer to PREVINFO struct
  119. //    fPaint        - FALSE prevents drawing to pi.fr.hdc (format only)
  120. //
  121. //  RETURN VALUE:
  122. //    TRUE for success, FALSE if all pages already formatted.
  123. //    Also sets pi.fr.chrg to range of characters for new page and
  124. //    updates pi.cPages.
  125. //
  126. //  COMMENTS:
  127. //    pi and pi.fr must be initialized appropriately before calling
  128. //    this function.
  129. //
  130. //
  131.  
  132. BOOL GetNextPage(LPPREVINFO ppi, BOOL fPaint)
  133. {
  134.     LPVOID pv;
  135.     RECT rcTmp;
  136.  
  137.     // Are there any more pages to format?
  138.     if (ppi->fAllPages)
  139.         return FALSE;
  140.  
  141.     // Make sure there's room in ppi->pPageIndex for another page
  142.     if (ppi->cPages >= ppi->cPageMax - 1)
  143.     {
  144.         pv = (LPVOID)LocalReAlloc((HLOCAL)ppi->pPageIndex,
  145.                                   (ppi->cPageMax + PAGECHUNK) * sizeof(int),
  146.                                   LMEM_MOVEABLE);
  147.         if (!pv)
  148.             return FALSE;
  149.  
  150.         ppi->pPageIndex = pv;
  151.         ppi->cPageMax += PAGECHUNK;
  152.     }
  153.  
  154.     // Set the CHARRANGE to format the next page
  155.     ppi->fr.chrg.cpMin = ppi->pPageIndex[ppi->cPages];
  156.     ppi->fr.chrg.cpMax = -1;
  157.  
  158.     rcTmp = ppi->fr.rc; // EM_FORMATRANGE tends to modify fr.rc.bottom
  159.  
  160.     // Tell the RichEdit control for format the page
  161.     ppi->fr.chrg.cpMax = SendMessage(ppi->hEdit, 
  162.                                      EM_FORMATRANGE, 
  163.                                      fPaint,
  164.                                      (LPARAM)&ppi->fr);
  165.  
  166.     ppi->fr.rc = rcTmp; // restore fr.rc
  167.  
  168.     // Update page info
  169.     ppi->cPages++;
  170.     ppi->pPageIndex[ppi->cPages] = ppi->fr.chrg.cpMax;
  171.  
  172.     // All pages formatted?
  173.     ppi->fAllPages = ppi->fr.chrg.cpMax >= ppi->cchText;
  174.  
  175.     return TRUE;
  176. }
  177.  
  178.  
  179. //
  180. //  FUNCTION: PrintPreview(HWND, HWND, HDC)
  181. //
  182. //  PURPOSE: Do WYSIWYG print preview for the current document
  183. //
  184. //  PARAMETERS:
  185. //    hwndOwner     - Window that will own the preview dialog
  186. //    hwndEdit      - RichEdit control that contains the document to preview
  187. //    hdcTarget     - DC (usually printer DC) used for formatting the text
  188. //
  189. //  RETURN VALUE:
  190. //    If the function succeeds, the return value is the nResult parameter
  191. //    given in the call to the EndDialog function used to terminate the
  192. //    dialog box; otherwise, it is -1. 
  193. //
  194. //  COMMENTS:
  195. //
  196. //
  197.  
  198. int PrintPreview(HWND hwndOwner, HWND hwndEdit, HDC hdcTarget)
  199. {
  200.     PREVINFO pi;
  201.     HCURSOR hcurSave;
  202.     int iCurSel;
  203.     int nResult;
  204.  
  205.     hcurSave = SetCursor(hcursHourGlass);
  206.  
  207.     // Set up PREVINFO struct for the preview dialog
  208.     pi.hwndOwner = hwndOwner;
  209.     pi.fr.hdc = NULL;
  210.     pi.fr.hdcTarget = hdcTarget;
  211.     pi.hEdit = hwndEdit;
  212.  
  213.     pi.sizePhysPage.cx = GetDeviceCaps(hdcTarget, PHYSICALWIDTH);
  214.     if (!pi.sizePhysPage.cx)
  215.         pi.sizePhysPage.cx = GetDeviceCaps(hdcTarget, HORZRES);
  216.     pi.sizePhysPage.cy = GetDeviceCaps(hdcTarget, PHYSICALHEIGHT);
  217.     if (!pi.sizePhysPage.cy)
  218.         pi.sizePhysPage.cy = GetDeviceCaps(hdcTarget, VERTRES);
  219.     pi.sizePhysInch.cx = GetDeviceCaps(hdcTarget, LOGPIXELSX);
  220.     pi.sizePhysInch.cy = GetDeviceCaps(hdcTarget, LOGPIXELSY);
  221.  
  222.     pi.iCurPage = -1;
  223.     pi.fAllPages = FALSE;
  224.     pi.cPages = 0;
  225.     pi.cPageMax = PAGECHUNK;
  226.     pi.pPageIndex = (LPINT)LocalAlloc(LPTR, pi.cPageMax*sizeof(int));
  227.     if (!pi.pPageIndex)
  228.     {
  229.         SetCursor(hcurSave);      // Remove the hourglass
  230.         return -1;
  231.     }
  232.     pi.pPageIndex[0] = 0;   // first page always starts at zero
  233.  
  234.     // Set page rect to phys page size in twips
  235.     pi.fr.rcPage.left   = 0;
  236.     pi.fr.rcPage.top    = 0;
  237.     pi.fr.rcPage.right  = MulDiv(pi.sizePhysPage.cx, 1440, pi.sizePhysInch.cx);
  238.     pi.fr.rcPage.bottom = MulDiv(pi.sizePhysPage.cy, 1440, pi.sizePhysInch.cy);
  239.  
  240.     // Set up 3/4" horizontal and 1" vertical margins, but leave a minimum of 1"
  241.     // printable space in each direction.  Otherwise, use full page.
  242.     pi.fr.rc = pi.fr.rcPage; // start with full page
  243.     if (pi.fr.rcPage.right > 2*3*1440/4 + 1440)
  244.         pi.fr.rc.right -= (pi.fr.rc.left = 3*1440/4);
  245.     if (pi.fr.rcPage.bottom > 3*1440)
  246.         pi.fr.rc.bottom -= (pi.fr.rc.top = 1440);
  247.  
  248.     // Find out real size of document in characters
  249.     pi.cchText = SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
  250.  
  251.     // OPTIONAL:
  252.     // Format through the page containing the beginning of the current
  253.     // selection (iCurSel).  Other pages will be formatted later as necessary.
  254.  
  255. #ifndef NOCURSEL
  256.     // Get current selection for preview (show this page first)
  257.     SendMessage(hwndEdit, EM_EXGETSEL, 0, (LPARAM)&pi.fr.chrg);
  258.     iCurSel = pi.fr.chrg.cpMin; // remember first char of selection
  259. #else
  260.     iCurSel = 0;    // always preview first page first
  261. #endif
  262.  
  263.     // Get a screen DC to work with
  264.     pi.fr.hdc = GetDC(NULL);
  265.  
  266.     while (GetNextPage(&pi, FALSE))
  267.     {
  268.         pi.iCurPage++;
  269.     
  270.         if (pi.fr.chrg.cpMax > iCurSel)
  271.             break;
  272.     }
  273.  
  274.     ReleaseDC(NULL, pi.fr.hdc);
  275.     pi.fr.hdc = NULL;
  276.  
  277.     SetCursor(hcurSave);      // Remove the hourglass
  278.  
  279.     // Do the preview
  280.     nResult = DialogBoxParam(hInst,
  281.                              MAKEINTRESOURCE(IDD_PRINTPREVIEW),
  282.                              hwndOwner,
  283.                              PreviewDlgProc,
  284.                              (LPARAM)&pi);
  285.  
  286.     // Done with this now
  287.     LocalFree((HLOCAL)pi.pPageIndex);
  288.  
  289.     return nResult;
  290. }
  291.  
  292.  
  293. //
  294. //  FUNCTION: EnableNextPrev(HWND, LPPREVINFO)
  295. //
  296. //  PURPOSE: Helper function to enable/disable the Next & Prev buttons
  297. //
  298. //  PARAMETERS:
  299. //    hDlg          - handle to preview dialog
  300. //    ppi           - pointer to PREVINFO struct
  301. //
  302. //  RETURN VALUE:
  303. //    none
  304. //
  305. //  COMMENTS:
  306. //
  307. //
  308.  
  309. void EnableNextPrev(HWND hDlg, LPPREVINFO ppi)
  310. {
  311.     EnableWindow(GetDlgItem(hDlg, IDC_PREVIEW_NEXT),
  312.                  !ppi->fAllPages || ppi->iCurPage < ppi->cPages - 1);
  313.  
  314.     EnableWindow(GetDlgItem(hDlg, IDC_PREVIEW_PREV),
  315.                  ppi->iCurPage > 0);
  316. }
  317.  
  318.  
  319. //
  320. //  FUNCTION: SetStatbarPage(HWND, int)
  321. //
  322. //  PURPOSE: Helper function to set the page # on the status bar
  323. //
  324. //  PARAMETERS:
  325. //    hDlg          - handle to preview dialog
  326. //    iPage         - page number to display (zero based)
  327. //
  328. //  RETURN VALUE:
  329. //    none
  330. //
  331. //  COMMENTS:
  332. //
  333. //
  334.  
  335. void SetStatbarPage(HWND hDlg, int iPage)
  336. {
  337.     TCHAR szPage[32];
  338.     HWND hwndStatbar = GetDlgItem(hDlg, IDC_PREVSTATBAR);
  339.  
  340.     if (hwndStatbar)
  341.     {
  342.         wsprintf(szPage, TEXT("Page %d"), iPage + 1);
  343.         SendMessage(hwndStatbar,
  344.                     SB_SETTEXT,
  345.                     0,
  346.                     (LPARAM)szPage);
  347.     }
  348. }
  349.  
  350.  
  351. //
  352. //  FUNCTION: CmdPreviewNext(HWND, WORD, WORD, HWND)
  353. //
  354. //  PURPOSE: Handle clicks on "Next" button in preview dialog.
  355. //
  356. //  PARAMETERS:
  357. //    hwnd     - The window.
  358. //    wCommand - IDC_PREVIEW_PREV (unused)
  359. //    wNotify  - EN_*
  360. //    hwndCtrl - NULL (unused)
  361. //
  362. //  RETURN VALUE:
  363. //
  364. //  COMMENTS:
  365. //
  366.  
  367. #pragma argsused
  368. LRESULT CmdPreviewNext(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  369. {
  370.      LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hdlg, GWL_USERDATA);
  371.     HWND hwndPreview;
  372.  
  373.     if (!ppi->fAllPages || ppi->iCurPage < ppi->cPages - 1)
  374.     {
  375.         ppi->iCurPage++;
  376.  
  377.           hwndPreview = GetDlgItem(hdlg, IDC_PREVIEW);
  378.           if (hwndPreview)
  379.             InvalidateRect(hwndPreview, NULL, TRUE);
  380.  
  381.         EnableNextPrev(hdlg, ppi);
  382.         SetStatbarPage(hdlg, ppi->iCurPage);
  383.     }
  384.  
  385.      return TRUE;
  386. }
  387.  
  388.  
  389. //
  390. //  FUNCTION: CmdPreviewPrev(HWND, WORD, WORD, HWND)
  391. //
  392. //  PURPOSE: Handle clicks on "Prev" button in preview dialog.
  393. //
  394. //  PARAMETERS:
  395. //    hwnd     - The window.
  396. //    wCommand - IDC_PREVIEW_PREV (unused)
  397. //    wNotify  - EN_*
  398. //    hwndCtrl - NULL (unused)
  399. //
  400. //  RETURN VALUE:
  401. //
  402. //  COMMENTS:
  403. //
  404.  
  405. #pragma argsused
  406. LRESULT CmdPreviewPrev(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  407. {
  408.      LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hdlg, GWL_USERDATA);
  409.      HWND hwndPreview;
  410.  
  411.      if (ppi->iCurPage > 0)
  412.      {
  413.           ppi->iCurPage--;
  414.  
  415.           hwndPreview = GetDlgItem(hdlg, IDC_PREVIEW);
  416.           if (hwndPreview)
  417.                 InvalidateRect(hwndPreview, NULL, TRUE);
  418.  
  419.           EnableNextPrev(hdlg, ppi);
  420.           SetStatbarPage(hdlg, ppi->iCurPage);
  421.     }
  422.     return TRUE;
  423. }
  424.  
  425.  
  426. //
  427. //  FUNCTION: CmdPreviewFilePrint(HWND, WORD, WORD, HWND)
  428. //
  429. //  PURPOSE: Handle clicks on "Print" button in preview dialog.
  430. //
  431. //  PARAMETERS:
  432. //    hwnd     - The window.
  433. //    wCommand - IDC_PREVIEW_PREV (unused)
  434. //    wNotify  - EN_*
  435. //    hwndCtrl - NULL (unused)
  436. //
  437. //  RETURN VALUE:
  438. //
  439. //  COMMENTS:
  440. //
  441.  
  442. #pragma argsused
  443. LRESULT CmdPreviewFilePrint(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  444. {
  445.      LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hdlg, GWL_USERDATA);
  446.  
  447.     PostMessage(ppi->hwndOwner, WM_COMMAND, IDM_FILEPRINT, 0);
  448.     return EndDialog(hdlg, TRUE);
  449. }
  450.  
  451.  
  452. //
  453. //  FUNCTION: CmdPreviewClose(HWND, WORD, WORD, HWND)
  454. //
  455. //  PURPOSE: Handle clicks on "Close" button in preview dialog.
  456. //
  457. //  PARAMETERS:
  458. //    hwnd     - The window.
  459. //    wCommand - IDC_PREVIEW_PREV (unused)
  460. //    wNotify  - EN_*
  461. //    hwndCtrl - NULL (unused)
  462. //
  463. //  RETURN VALUE:
  464. //
  465. //  COMMENTS:
  466. //
  467.  
  468. #pragma argsused
  469. LRESULT CmdPreviewClose(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  470. {
  471.     return EndDialog(hdlg, TRUE);
  472. }
  473.  
  474.  
  475. //
  476. //  FUNCTION: MsgPreviewInitDialog(HWND, UINT, WPARAM, LPARAM)
  477. //
  478. //  PURPOSE: Handle WM_INITDIALOG message for the preview dialog.
  479. //
  480. //  PARAMETERS:
  481. //    hwnd     - The window handing the message.
  482. //    uMessage - The message number. (unused).
  483. //    wparam   - Message specific data (unused).
  484. //    lparam   - Message specific data (unused).
  485. //
  486. //  RETURN VALUE:
  487. //
  488. //  COMMENTS:
  489. //
  490. //
  491.  
  492. #pragma argsused
  493. LRESULT MsgPreviewInitDialog(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  494. {
  495.      LPPREVINFO ppi;
  496.      RECT rc;
  497.      HWND hwnd;
  498.      TCHAR szTitle[MAX_PATH];
  499.      HBITMAP hbm;
  500.      WORD wBitPattern[] = { 0x55,    // alternating pixel checkerboard
  501.                            0xaa,
  502.                            0x55,
  503.                            0xaa,
  504.                            0x55,
  505.                            0xaa,
  506.                            0x55,
  507.                            0xaa };
  508.  
  509.     // Save the PREVINFO pointer in window extra bytes
  510.      SetWindowLong(hdlg, GWL_USERDATA, lparam);
  511.     ppi = (LPPREVINFO)lparam;
  512.     if (!ppi)
  513.         return EndDialog(hdlg, 0);
  514.  
  515.      // Create pattern brush for drawing margins
  516.      hbm = CreateBitmap(8, 8, 1, 1, wBitPattern);
  517.      if (hbm)
  518.     {
  519.         hbrPattern = CreatePatternBrush(hbm);
  520.         DeleteObject(hbm);
  521.     }
  522.  
  523.     // Add the WS_EX_STATICEDGE & SS_ETCHEDHORZ styles to IDC_SEPARATOR. This
  524.     // makes a nice separator line between the buttons and the preview area.
  525.      // (Wish VC++ would do this for me in the dialog script...)
  526.      hwnd = GetDlgItem(hdlg, IDC_SEPARATOR);
  527.      if (hwnd)
  528.     {
  529.         SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_STATICEDGE);
  530.           SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | SS_ETCHEDHORZ);
  531.     }
  532.  
  533.     // Disable stuff that won't be implemented here...
  534.     EnableWindow(GetDlgItem(hdlg, IDC_PREVIEW_NUMPAGE), FALSE);
  535.     EnableWindow(GetDlgItem(hdlg, IDC_PREVIEW_ZOOMIN),  FALSE);
  536.     EnableWindow(GetDlgItem(hdlg, IDC_PREVIEW_ZOOMOUT), FALSE);
  537.  
  538.     // Set the caption text to "doc name - app name"
  539.     if (!GetFileTitle(GetFName(), szTitle, MAX_PATH))
  540.     {
  541.         lstrcat(szTitle, TEXT(" - "));
  542.         lstrcat(szTitle, szAppName);
  543.         SetWindowText(hdlg, szTitle);
  544.     }
  545.  
  546.     // Create status window to display page numbers
  547.     CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER | SBS_SIZEGRIP,
  548.                        szTitle,
  549.                        hdlg,
  550.                        IDC_PREVSTATBAR);
  551.     SetStatbarPage(hdlg, ppi->iCurPage);
  552.  
  553.     // Create preview window
  554.     CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
  555.                    szPrevClass,             // window class name
  556.                    "",                      // no caption text
  557.                    WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,   // style
  558.                    0, 0, 100, 100,          // temporary size/position
  559.                    hdlg,                    // parent
  560.                          (HMENU)IDC_PREVIEW,      // child ID
  561.                    hInst,                   // owning instance
  562.                    ppi);            // user data
  563.  
  564.     // Adjust dialog to cover entire main window
  565.     GetWindowRect(ppi->hwndOwner, &rc);
  566.     MoveWindow(hdlg,
  567.                rc.left,
  568.                rc.top,
  569.                RECTWIDTH(&rc),
  570.                RECTHEIGHT(&rc),
  571.                FALSE);
  572.  
  573.     // Enable/disable Next and Prev buttons as appropriate
  574.     EnableNextPrev(hdlg, ppi);
  575.  
  576.     return TRUE;
  577. }
  578.  
  579.  
  580. //
  581. //  FUNCTION: MsgPreviewSize(HWND, UINT, WPARAM, LPARAM)
  582. //
  583. //  PURPOSE: Handle WM_SIZE message for the preview dialog.
  584. //
  585. //  PARAMETERS:
  586. //    hwnd     - The window handing the message.
  587. //    uMessage - The message number. (unused).
  588. //    wparam   - Message specific data (unused).
  589. //    lparam   - Message specific data (unused).
  590. //
  591. //  RETURN VALUE:
  592. //
  593. //  COMMENTS:
  594. //
  595. //
  596.  
  597. #pragma argsused
  598. LRESULT MsgPreviewSize(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  599. {
  600.     LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hdlg, GWL_USERDATA);
  601.     HWND hwnd;
  602.     RECT rc, rcStatbar = {0, 0, 0, 0};
  603.     int nTmp, cyEdge = GetSystemMetrics(SM_CYEDGE);
  604.  
  605.     // Tell status bar to reposition itself
  606.     hwnd = GetDlgItem(hdlg, IDC_PREVSTATBAR);
  607.     if (hwnd)
  608.     {
  609.           SendMessage(hwnd, WM_SIZE, wparam, lparam);
  610.         GetWindowRect(hwnd, &rcStatbar);    // get new coordinates
  611.     }
  612.  
  613.     // Adjust size/position of separator
  614.     hwnd = GetDlgItem(hdlg, IDC_SEPARATOR);
  615.     GetWindowRect(hwnd, &rc);
  616.     MapWindowPoints(GetDesktopWindow(), hdlg, (LPPOINT)&rc, 2);
  617.      MoveWindow(hwnd, 0, rc.top, LOWORD(lparam), cyEdge, TRUE);
  618.  
  619.      // Adjust size/position of preview window
  620.      hwnd = GetDlgItem(hdlg, IDC_PREVIEW);
  621.      if (hwnd)
  622.     {
  623.         // Calculate available client area for preview window
  624.           nTmp = rc.top + 2*cyEdge;
  625.         GetClientRect(hdlg, &rc);
  626.         rc.top = nTmp;
  627.         rc.bottom -= cyEdge + RECTHEIGHT(&rcStatbar);
  628.         rc.right -= (rc.left = GetSystemMetrics(SM_CXEDGE));
  629.             
  630.         // Calculate the rect for the preview "page" to be as large as
  631.         // possible but still with the correct aspect ratio and centered
  632.         // within the client area.
  633.         if (rc.bottom * ppi->sizePhysPage.cx < rc.right * ppi->sizePhysPage.cy)
  634.         {
  635.             nTmp = rc.right;
  636.             rc.right = MulDiv(rc.bottom, ppi->sizePhysPage.cx, ppi->sizePhysPage.cy);
  637.             rc.left = (nTmp - rc.right) / 2;
  638.             rc.right += rc.left;
  639.           }
  640.         else
  641.         {
  642.             nTmp = rc.bottom;
  643.             rc.bottom = MulDiv(rc.right, ppi->sizePhysPage.cy, ppi->sizePhysPage.cx);
  644.             rc.top = (nTmp - rc.bottom) / 2;
  645.             rc.bottom += rc.top;
  646.         }
  647.        
  648.         // Move preview window to new position
  649.         MoveWindow(hwnd,
  650.                    rc.left,
  651.                    rc.top,
  652.                    RECTWIDTH(&rc),
  653.                    RECTHEIGHT(&rc),
  654.                          TRUE);
  655.     }
  656.  
  657.     return TRUE;
  658. }
  659.  
  660.  
  661. //
  662. //  FUNCTION: MsgPreviewCtlColorDlg(HWND, UINT, WPARAM, LPARAM)
  663. //
  664. //  PURPOSE: Handle WM_CTLCOLORDLG message for the preview dialog.
  665. //
  666. //  PARAMETERS:
  667. //    hwnd     - The window handing the message.
  668. //    uMessage - The message number. (unused).
  669. //    wparam   - Message specific data (unused).
  670. //    lparam   - Message specific data (unused).
  671. //
  672. //  RETURN VALUE:
  673. //
  674. //  COMMENTS:
  675. //
  676. //
  677.  
  678. #pragma argsused
  679. LRESULT MsgPreviewCtlColorDlg(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  680. {
  681.     return (LRESULT)GetSysColorBrush(COLOR_BTNFACE);
  682. }
  683.  
  684.  
  685. //
  686. //  FUNCTION: MsgPreviewDestroy(HWND, UINT, WPARAM, LPARAM)
  687. //
  688. //  PURPOSE: Handle WM_DESTROY message for the preview dialog.
  689. //
  690. //  PARAMETERS:
  691. //    hwnd     - The window handing the message.
  692. //    uMessage - The message number. (unused).
  693. //    wparam   - Message specific data (unused).
  694. //    lparam   - Message specific data (unused).
  695. //
  696. //  RETURN VALUE:
  697. //
  698. //  COMMENTS:
  699. //
  700. //
  701.  
  702. #pragma argsused
  703. LRESULT MsgPreviewDestroy(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  704. {
  705.      LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hdlg, GWL_USERDATA);
  706.  
  707.      // Reset the RichEdit control
  708.      SendMessage(ppi->hEdit, EM_FORMATRANGE, TRUE, 0);
  709.  
  710.      if (hbrPattern)
  711.      {
  712.         DeleteObject(hbrPattern);
  713.         hbrPattern = NULL;
  714.     }
  715.  
  716.     return TRUE;
  717. }
  718.  
  719.  
  720. //
  721. //  FUNCTION: PaintPreview(HDC, LPPREVINFO)
  722. //
  723. //  PURPOSE: Paint the current text page in the preview window
  724. //
  725. //  PARAMETERS:
  726. //    hdc           - device context to draw to
  727. //    ppi           - pointer to PREVINFO struct
  728. //
  729. //  RETURN VALUE:
  730. //    none
  731. //
  732. //  COMMENTS:
  733. //
  734. //
  735.  
  736. void PaintPreview(HWND hwnd, HDC hdc, LPPREVINFO ppi)
  737. {
  738.     HDC hdcT;
  739.     RECT rcMargin, rcClient;
  740.     BOOL bFormatDone = FALSE;
  741.  
  742.     if (!hwnd || !hdc || !ppi)
  743.         return;
  744.  
  745.     if (ppi->iCurPage < 0 || (ppi->fAllPages && ppi->iCurPage > ppi->cPages - 1))
  746.         return;
  747.  
  748.     GetClientRect(hwnd, &rcClient);
  749.  
  750.     // Set up the DC
  751.     SetTextColor(hdc, RGB(0,0,0));
  752.     SetBkColor(hdc, RGB(255,255,255));
  753.     SetBkMode(hdc, TRANSPARENT);
  754.  
  755.     // Make the window the same logical size as the page
  756.     SetMapMode(hdc, MM_ANISOTROPIC);
  757.     SetWindowExtEx(hdc,
  758.                    MulDiv(ppi->sizePhysPage.cx,
  759.                           GetDeviceCaps(hdc, LOGPIXELSX),
  760.                           ppi->sizePhysInch.cx),
  761.                    MulDiv(ppi->sizePhysPage.cy,
  762.                           GetDeviceCaps(hdc, LOGPIXELSY),
  763.                           ppi->sizePhysInch.cy),
  764.                    NULL);
  765.     SetViewportExtEx(hdc, rcClient.right, rcClient.bottom, NULL);
  766.  
  767.     // Prepare for drawing
  768.     hdcT = ppi->fr.hdc;
  769.     ppi->fr.hdc = hdc;
  770.     rcMargin = ppi->fr.rc;
  771.  
  772.     // Do we need to format a page we haven't formatted yet?
  773.     if (ppi->iCurPage > ppi->cPages - 1)
  774.     {
  775.         bFormatDone = GetNextPage(ppi, TRUE);   // TRUE ==> do drawing here
  776.  
  777.         // Make sure everything is set correctly
  778.         ppi->iCurPage = ppi->cPages - 1;
  779.         EnableNextPrev(GetParent(hwnd), ppi);
  780.     }
  781.  
  782.     // If we didn't draw the page during GetNextPage above, draw it now
  783.     if (!bFormatDone)
  784.     {
  785.         // Set the CHARRANGE for the page to format
  786.         ppi->fr.chrg.cpMin = ppi->pPageIndex[ppi->iCurPage];
  787.         ppi->fr.chrg.cpMax = ppi->pPageIndex[ppi->iCurPage + 1];
  788.  
  789.         // Tell the RichEdit control to format the page.
  790.         SendMessage(ppi->hEdit,
  791.                     EM_FORMATRANGE,
  792.                     TRUE,
  793.                     (LPARAM)&ppi->fr);
  794.     }
  795.  
  796.     // Restore these now
  797.     ppi->fr.hdc = hdcT;
  798.     ppi->fr.rc = rcMargin;  // EM_FORMATRANGE tends to change fr.rc.bottom
  799.  
  800.     // Set up for drawing margins
  801.  
  802.     if (hbrPattern)
  803.         SelectObject(hdc, hbrPattern);  // alternating pixels
  804.  
  805.     SetMapMode(hdc, MM_TEXT);
  806.  
  807.     // convert rcMargin to screen pixels
  808.     rcMargin.left   = MulDiv(rcMargin.left,
  809.                              ppi->sizePhysInch.cx * rcClient.right,
  810.                              1440 * ppi->sizePhysPage.cx);
  811.     rcMargin.top    = MulDiv(rcMargin.top,
  812.                              ppi->sizePhysInch.cy * rcClient.bottom,
  813.                              1440 * ppi->sizePhysPage.cy);
  814.     rcMargin.right  = MulDiv(rcMargin.right,
  815.                              ppi->sizePhysInch.cx * rcClient.right,
  816.                              1440 * ppi->sizePhysPage.cx);
  817.     rcMargin.bottom = MulDiv(rcMargin.bottom,
  818.                              ppi->sizePhysInch.cy * rcClient.bottom,
  819.                              1440 * ppi->sizePhysPage.cy);
  820.  
  821.     // Draw margins
  822.     PatBlt(hdc, 0, rcMargin.top,    rcClient.right, 1, PATCOPY);
  823.     PatBlt(hdc, 0, rcMargin.bottom, rcClient.right, 1, PATCOPY);
  824.     PatBlt(hdc, rcMargin.left,  0, 1, rcClient.bottom, PATCOPY);
  825.     PatBlt(hdc, rcMargin.right, 0, 1, rcClient.bottom, PATCOPY);
  826.  
  827.     // deselect hbrPattern
  828.     SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  829. }
  830.  
  831.  
  832. //
  833. //  FUNCTION: MsgPrevWndNCCreate(HWND, UINT, WPARAM, LPARAM)
  834. //
  835. //  PURPOSE: Handle WM_NCCREATE message for the preview window. Stores the
  836. //    user data in the CREATESTRUCT pointed to by lparam in the window
  837. //    extra bytes.
  838. //
  839. //  PARAMETERS:
  840. //    hwnd     - The window handing the message.
  841. //    uMessage - The message number. (unused).
  842. //    wparam   - Message specific data (unused).
  843. //    lparam   - Message specific data (unused).
  844. //
  845. //  RETURN VALUE:
  846. //
  847. //  COMMENTS:
  848. //
  849. //
  850.  
  851. #pragma argsused
  852. LRESULT MsgPrevWndNCCreate(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  853. {
  854.     SetWindowLong(hwnd,
  855.                   GWL_USERDATA,
  856.                   (LPARAM)((LPCREATESTRUCT)lparam)->lpCreateParams);
  857.     return 1;
  858. }
  859.  
  860.  
  861. //
  862. //  FUNCTION: MsgPrevWndPaint(HWND, UINT, WPARAM, LPARAM)
  863. //
  864. //  PURPOSE: Handle WM_PAINT messages for the preview window
  865. //
  866. //  PARAMETERS:
  867. //    hwnd     - The window handing the message.
  868. //    uMessage - The message number. (unused).
  869. //    wparam   - Message specific data (unused).
  870. //    lparam   - Message specific data (unused).
  871. //
  872. //  RETURN VALUE:
  873. //
  874. //  COMMENTS:
  875. //
  876. //
  877.  
  878. #pragma argsused
  879. LRESULT MsgPrevWndPaint(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  880. {
  881.     LPPREVINFO ppi = (LPPREVINFO)GetWindowLong(hwnd, GWL_USERDATA);
  882.     PAINTSTRUCT ps;
  883.  
  884.     BeginPaint(hwnd, &ps);
  885.     PaintPreview(hwnd, ps.hdc, ppi);
  886.     EndPaint(hwnd, &ps);
  887.     return 0;
  888. }
  889.  
  890.  
  891. //
  892. // Message dispatch tables, window procedures, and command dispatch handlers
  893. //
  894.  
  895. static CMD rgcmdPreviewDlg[] =
  896. {
  897.     {IDC_PREVIEW_NEXT, CmdPreviewNext},
  898.     {IDC_PREVIEW_PREV, CmdPreviewPrev},
  899.     {IDM_FILEPRINT,    CmdPreviewFilePrint},
  900.     {IDCANCEL,         CmdPreviewClose},
  901.     {IDOK,             CmdPreviewClose},
  902. };
  903.  
  904. CMDI cmdiPreviewDlg =
  905. {
  906.     sizeof(rgcmdPreviewDlg) / sizeof(CMD),
  907.     rgcmdPreviewDlg,
  908.     edwpNone
  909. };
  910.  
  911.  
  912. //
  913. //  FUNCTION: MsgPreviewCommand(HWND, UINT, WPARAM, LPARAM)
  914. //
  915. //  PURPOSE: Handle the WM_COMMAND messages for the preview dialog.
  916. //
  917. //  PARAMETERS:
  918. //    hwnd     - window handle
  919. //    uMessage - message number (Unused)
  920. //    GET_WM_COMMAND_ID(wparam,lparam)   - Command identifier
  921. //    GET_WM_COMMAND_HWND(wparam,lparam) - Control handle
  922. //
  923. //  RETURN VALUE:
  924. //
  925. //  COMMENTS:
  926. //    Uses the combination of the command structure defined in mditable.c
  927. //    and the DispCommand function defined in WndProc.c to handle all
  928. //    commands directed to an MDI child window.
  929. //
  930. //
  931.  
  932. #pragma argsused
  933. LRESULT MsgPreviewCommand(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  934. {
  935.     return DispCommand(&cmdiPreviewDlg, hdlg, wparam, lparam);
  936. }
  937.  
  938.  
  939. static MSD rgmsdPreviewDlg[] =
  940. {
  941.     {WM_COMMAND,     MsgPreviewCommand    },
  942.     {WM_CTLCOLORDLG, MsgPreviewCtlColorDlg},
  943.     {WM_SIZE,        MsgPreviewSize       },
  944.     {WM_INITDIALOG,  MsgPreviewInitDialog },
  945.     {WM_DESTROY,     MsgPreviewDestroy    },
  946. };
  947.  
  948. MSDI msdiPreviewDlg =
  949. {
  950.     sizeof(rgmsdPreviewDlg) / sizeof(MSD),
  951.     rgmsdPreviewDlg,
  952.     edwpNone
  953. };
  954.  
  955.  
  956. //
  957. //  FUNCTION: PreviewDlgProc(HWND, UINT, WPARAM, LPARAM)
  958. //
  959. //  PURPOSE: Dialog procedure for the preview dialog
  960. //
  961. //  PARAMETERS:
  962. //    standard window params
  963. //
  964. //  RETURN VALUE:
  965. //    TRUE if message processed, otherwise FALSE
  966. //
  967. //  COMMENTS:
  968. //
  969. //
  970.  
  971. BOOL CALLBACK PreviewDlgProc(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
  972. {
  973.     return DispMessage(&msdiPreviewDlg, hdlg, uMessage, wparam, lparam);
  974. }
  975.  
  976.  
  977. static MSD rgmsdPrevWnd[] =
  978. {
  979.     {WM_PAINT,      MsgPrevWndPaint   },
  980.     {WM_NCCREATE,   MsgPrevWndNCCreate},
  981. };
  982.  
  983. MSDI msdiPrevWnd =
  984. {
  985.     sizeof(rgmsdPrevWnd) / sizeof(MSD),
  986.     rgmsdPrevWnd,
  987.     edwpWindow
  988. };
  989.  
  990.  
  991. //
  992. //  FUNCTION: PreviewWndProc(HWND, UINT, WPARAM, LPARAM)
  993. //
  994. //  PURPOSE: Window procedure for the preview window in the preview dialog
  995. //
  996. //  PARAMETERS:
  997. //    standard window params
  998. //
  999. //  RETURN VALUE:
  1000. //    depends on message
  1001. //
  1002. //  COMMENTS:
  1003. //
  1004. //
  1005.  
  1006. LRESULT CALLBACK PreviewWndProc(HWND hwnd,
  1007.                                 UINT uMessage,
  1008.                                 WPARAM wparam,
  1009.                                 LPARAM lparam)
  1010. {
  1011.     return DispMessage(&msdiPrevWnd, hwnd, uMessage, wparam, lparam);
  1012. }
  1013.