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

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.5  $
  6. //
  7. // Implementation of print preview classes
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_PREVIEW_H)
  11. # include <owl/preview.h>
  12. #endif
  13. #if !defined(OWL_PRINTER_H)
  14. # include <owl/printer.h>
  15. #endif
  16. #if !defined(OWL_GDIOBJEC_H)
  17. # include <owl/gdiobjec.h>
  18. #endif
  19. #if !defined(OWL_DC_H)
  20. # include <owl/dc.h>
  21. #endif
  22. #if !defined(OWL_PRINTDIA_H)
  23. # include <owl/printdia.h>
  24. #endif
  25. #include <math.h>
  26.  
  27. OWL_DIAGINFO;
  28.  
  29. //
  30. // Some inlines to provide platform independence since we drop directly to API
  31. // calls to implement some of TPrintPreviewDC.
  32. //
  33. #if defined(BI_PLAT_WIN32)
  34.   inline bool SetWindowExt(HDC hdc, int w, int h) {return ::SetWindowExtEx(hdc, w, h, 0);}
  35.   inline bool SetWindowOrg(HDC hdc, int w, int h) {return ::SetWindowOrgEx(hdc, w, h, 0);}
  36.   inline bool SetViewportExt(HDC hdc, int w, int h) {return ::SetViewportExtEx(hdc, w, h, 0);}
  37.   inline bool SetViewportOrg(HDC hdc, int x, int y) {return ::SetViewportOrgEx(hdc, x, y, 0);}
  38. #endif
  39.  
  40.  
  41. //
  42. // Construct a basic Preview DC
  43. //
  44. TPreviewDCBase::TPreviewDCBase(TDC&      screen,
  45.                                TPrintDC& printdc)
  46. :
  47.   TPrintDC(screen),
  48.   PrnDC(printdc)
  49. {}
  50.  
  51. //
  52. //
  53. //
  54. HDC
  55. TPreviewDCBase::GetAttributeHDC() const
  56. {
  57.   return PrnDC;
  58. }
  59.  
  60. //
  61. // Construct a Print Preview Device context
  62. //
  63. TPrintPreviewDC::TPrintPreviewDC(TDC&         screen,
  64.                                  TPrintDC&    printdc,
  65.                                  const TRect& client,
  66.                                  const TRect& clip)
  67. :
  68.   TPreviewDCBase(screen, printdc),
  69.   PrnFont(0),
  70.   CurrentPreviewFont(0)
  71. {
  72.   //
  73.   // Set the initial mode & extents for the screen dc
  74.   //
  75.   ::SetMapMode(GetHDC(), MM_ANISOTROPIC);
  76.   ::SetWindowExt(GetHDC(), client.Width(), client.Height());
  77.   ::SetViewportExt(GetHDC(), client.Width(), client.Height());
  78.  
  79.   //
  80.   // Static call to virtual method, but some mapping must be done now.
  81.   //
  82.   ReScale();
  83.  
  84.   //
  85.   // Assume clip rect is in device points - DPs are same in new viewport
  86.   //
  87.   SelectClipRgn(clip);
  88.   PrnFont = (HFONT)PrnDC.GetCurrentObject(OBJ_FONT);
  89.   SyncFont();
  90. }
  91.  
  92. //
  93. //
  94. //
  95. TPrintPreviewDC::~TPrintPreviewDC()
  96. {
  97.   // cleanup screen dc
  98.   //
  99.   ::DeleteObject(::SelectObject(GetHDC(), ::GetStockObject(SYSTEM_FONT)));
  100.   delete CurrentPreviewFont;
  101. }
  102.  
  103. //
  104. // Intercept setting of the printer font, making & keeping a copy of it and
  105. // calling SyncFont if needed to recreate the preview font.
  106. //
  107. void
  108. TPrintPreviewDC::SelectObject(const TFont& newFont)
  109. {
  110.   if ((HFONT)newFont) {
  111.     LOGFONT   lf;
  112.     newFont.GetObject(lf);
  113.  
  114.     TFont*  oldPreviewF = CurrentPreviewFont;
  115.     CurrentPreviewFont = new TFont(&lf);
  116.  
  117.     PrnDC.SelectObject(*CurrentPreviewFont);
  118.     delete oldPreviewF;
  119.  
  120.     if ((HFONT)(*CurrentPreviewFont) != PrnFont) {
  121.       PrnFont = (HFONT)(*CurrentPreviewFont);
  122.       SyncFont();
  123.     }
  124.   }
  125. }
  126.  
  127. //
  128. //
  129. //
  130. void
  131. TPrintPreviewDC::SelectStockObject(int index)
  132. {
  133.   PrnDC.SelectStockObject(index);
  134.   switch (index) {
  135.     case ANSI_FIXED_FONT:
  136.     case ANSI_VAR_FONT:
  137.     case DEVICE_DEFAULT_FONT:
  138.     case OEM_FIXED_FONT:
  139.     case SYSTEM_FONT:
  140.     case SYSTEM_FIXED_FONT: {
  141.       HFONT stockFont = (HFONT)GetStockObject(index);
  142.       if (stockFont != PrnFont) {
  143.         PrnFont = stockFont;
  144.         SyncFont();
  145.       }
  146.       break;
  147.     }
  148.     default:
  149.       TPrintDC::SelectStockObject(index);
  150.   }
  151. }
  152.  
  153. //
  154. //
  155. //
  156. void
  157. TPrintPreviewDC::RestoreFont()
  158. {
  159.   PrnDC.RestoreFont();
  160.   PrnFont = (HFONT)PrnDC.GetCurrentObject(OBJ_FONT);
  161.   TPrintDC::RestoreFont();
  162.   SyncFont();
  163. }
  164.  
  165. //
  166. //
  167. //
  168. int
  169. TPrintPreviewDC::GetDeviceCaps(int index) const
  170. {
  171.   switch (index) {
  172.     case CLIPCAPS:
  173.     case RASTERCAPS:
  174.     case CURVECAPS:
  175.     case LINECAPS:
  176.     case POLYGONALCAPS:
  177.     case TEXTCAPS:      // report capabilities supported on both devices
  178.       return PrnDC.GetDeviceCaps(index) & TPrintDC::GetDeviceCaps(index);
  179.  
  180.       // otherwise, report printer caps and let GDI sort out differences
  181.     default:
  182.       return PrnDC.GetDeviceCaps(index);
  183.   }
  184. }
  185.  
  186. //
  187. //
  188. //
  189. inline int
  190. GlyphHeight(TEXTMETRIC& tm)
  191. {
  192.   return tm.tmHeight < 0
  193.             ? tm.tmHeight
  194.             : -(tm.tmHeight - tm.tmInternalLeading);
  195. }
  196.  
  197. //
  198. // SyncFont performs a simple font match attempt, with a retry option if
  199. // the GDI selected match is too different from the selected printer font.
  200. // In print preview, matching the size of the characters is more important
  201. // than matching their appearance.  In most cases, the print preview will
  202. // barely be legible anyway.  Size is most important because you don't
  203. // want character size differences to change the line breaks or page
  204. // breaks of the on-screen document from what they would be on the
  205. // printed page.  This effect is minimized in this TPrintPreviewDC object,
  206. // since info reports such as GetTextMetrics and GetTextExtent are always
  207. // reported from the printer dc using the real font.  Internal calculations
  208. // should be the same for preview as for printing, but the output accuracy
  209. // will depend upon the accuracy of font selection.
  210. //
  211. // It is also possible to take over control of the text output functions
  212. // through this DC object - the TextOut and other text methods are virtual.
  213. // You can place each character on the preview screen yourself, if you
  214. // desire more precision in character placement than GDI's font matching
  215. // can provide.  That's a lot of work, and a lot of code, and isn't
  216. // necessary to meet the needs of most applications.
  217. //
  218. // SyncFont is virtual so that you may substitute your own font matching
  219. // algorythm with more font matching heuristics.
  220. //
  221. void
  222. TPrintPreviewDC::SyncFont()
  223. {
  224.   //
  225.   // set screen font to match current printer font.
  226.   //
  227.   LOGFONT lf;
  228.   ::GetObject(PrnFont, sizeof(lf), &lf);
  229.  
  230.   TEXTMETRIC tm;
  231.   PrnDC.GetTextMetrics(tm);
  232.  
  233.   lf.lfHeight         = GlyphHeight(tm);
  234.   lf.lfWidth          = tm.tmAveCharWidth;
  235.   lf.lfWeight         = tm.tmWeight;
  236.   lf.lfItalic         = tm.tmItalic;
  237.   lf.lfUnderline      = tm.tmUnderlined;
  238.   lf.lfStrikeOut      = tm.tmStruckOut;
  239.   lf.lfCharSet        = tm.tmCharSet;
  240.   lf.lfOutPrecision   = OUT_TT_PRECIS;
  241.   lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
  242.   lf.lfQuality        = DRAFT_QUALITY;
  243.  
  244.   // Keep just the pitch (low 2 bits). Ignore the family
  245.   //
  246.   lf.lfPitchAndFamily = uint8((tm.tmPitchAndFamily & 0x0003) | FF_DONTCARE);
  247.   PrnDC.GetTextFace(sizeof(lf.lfFaceName), lf.lfFaceName);
  248.  
  249.   ::DeleteObject(::SelectObject(GetHDC(), ::CreateFontIndirect(&lf)));
  250.  
  251.   //
  252.   // if height isn't right, relax the font pitch and facename requirements
  253.   //
  254.   GetTextMetrics(tm);
  255.   if (abs(abs(lf.lfHeight) - abs(GlyphHeight(tm))) > 2) {
  256.     if (lf.lfPitchAndFamily & FF_DECORATIVE)
  257.       lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
  258.     else
  259.       lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  260.     lf.lfFaceName[0] = 0;
  261.     ::DeleteObject(::SelectObject(GetHDC(), CreateFontIndirect(&lf)));
  262.   }
  263. }
  264.  
  265. //
  266. // Rescale the preview DC by adjusting its window & viewport
  267. //
  268. // Assume the viewport extent (scrve) is set to the size of the window
  269. // client area.  All we have to do to map the addressable points of the
  270. // printer DC into the screen DC, then, is set the screen window extent
  271. // equal to the maximum addressable logical point of the printer dc.
  272. // PrnDC.DPtoLP will pull the device point through the printer's mapping
  273. // mode conversions, giving us the maximum point we should allow on the
  274. // screen dc.
  275. //
  276. void
  277. TPrintPreviewDC::ReScale()
  278. {
  279.   TSize scrve;
  280.   ::GetViewportExtEx(GetHDC(), &scrve);
  281.  
  282.   TPoint scrwe(PrnDC.GetDeviceCaps(HORZRES), PrnDC.GetDeviceCaps(VERTRES));
  283.   PrnDC.DPtoLP(&scrwe);
  284.  
  285.   ::SetMapMode(GetHDC(), MM_ANISOTROPIC);
  286.   ::SetWindowExt(GetHDC(), scrwe.x, scrwe.y);
  287.   ::SetViewportExt(GetHDC(), scrve.cx, scrve.cy);
  288.   ReOrg();
  289. }
  290.  
  291. //
  292. // Reset the DC's origin
  293. //
  294. void
  295. TPrintPreviewDC::ReOrg()
  296. {
  297.   TPoint origin = PrnDC.GetViewportOrg();
  298.   PrnDC.DPtoLP(&origin);
  299.   LPtoSDP(&origin);
  300.   ::SetViewportOrg(GetHDC(), origin.x, origin.y);
  301.  
  302.   PrnDC.GetWindowOrg(origin);
  303.   ::SetWindowOrg(GetHDC(), origin.x, origin.y);
  304. }
  305.  
  306. //
  307. //
  308. //
  309. TColor
  310. TPrintPreviewDC::SetBkColor(const TColor& color)
  311. {
  312.   TColor result = PrnDC.SetBkColor(color);
  313.   ::SetBkColor(GetHDC(), PrnDC.GetBkColor());
  314.   return result;
  315. }
  316.  
  317. //
  318. //
  319. //
  320. TColor
  321. TPrintPreviewDC::SetTextColor(const TColor& color)
  322. {
  323.   TColor result = PrnDC.SetTextColor(color);
  324.   ::SetTextColor(GetHDC(), PrnDC.GetTextColor());
  325.   return result;
  326. }
  327.  
  328. //
  329. //
  330. //
  331. int
  332. TPrintPreviewDC::SetMapMode(int mode)
  333. {
  334.   int result = PrnDC.SetMapMode(mode);
  335.   ReScale();
  336.   return result;
  337. }
  338.  
  339. //
  340. //
  341. //
  342. bool
  343. TPrintPreviewDC::SetViewportOrg(const TPoint& origin, TPoint far* oldOrg)
  344. {
  345.   bool result = PrnDC.SetViewportOrg(origin, oldOrg);
  346.   ReOrg();
  347.   return result;
  348. }
  349.  
  350. //
  351. //
  352. //
  353. bool
  354. TPrintPreviewDC::OffsetViewportOrg(const TPoint& delta, TPoint far* oldOrg)
  355. {
  356.   bool result = PrnDC.OffsetViewportOrg(delta, oldOrg);
  357.   ReOrg();
  358.   return result;
  359. }
  360.  
  361. //
  362. //
  363. //
  364. bool
  365. TPrintPreviewDC::SetViewportExt(const TSize& extent, TSize far* oldExtent)
  366. {
  367.   bool result = PrnDC.SetViewportExt(extent, oldExtent);
  368.   ReScale();
  369.   return result;
  370. }
  371.  
  372. bool
  373. TPrintPreviewDC::ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom,
  374.                                   TSize far* oldExtent)
  375. {
  376.   bool result = PrnDC.ScaleViewportExt( xNum, xDenom, yNum, yDenom, oldExtent);
  377.   ReScale();
  378.   return result;
  379. }
  380.  
  381. bool
  382. TPrintPreviewDC::SetWindowExt(const TSize& extent, TSize far* oldExtent)
  383. {
  384.   bool result = PrnDC.SetWindowExt(extent, oldExtent);
  385.   ReScale();
  386.   return result;
  387. }
  388.  
  389. //
  390. //
  391. //
  392. bool
  393. TPrintPreviewDC::ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom,
  394.                                 TSize far* oldExtent)
  395. {
  396.   bool result = PrnDC.ScaleWindowExt(xNum, xDenom, yNum, yDenom, oldExtent);
  397.   ReScale();
  398.   return result;
  399. }
  400.  
  401.  
  402. DEFINE_RESPONSE_TABLE1(TPreviewPage, TWindow)
  403.   EV_WM_SIZE,
  404. END_RESPONSE_TABLE;
  405.  
  406. IMPLEMENT_CASTABLE(TPreviewPage);
  407.  
  408. //
  409. //
  410. //
  411. TPreviewPage::TPreviewPage(TWindow* parent, TPrintout& printout,
  412.                            TPrintDC& prndc, TSize& printExtent, int pagenum)
  413. :
  414.   TWindow(parent),
  415.   Printout(printout),
  416.   PrintDC(prndc),
  417.   PrintExtent(printExtent),
  418.   PageNum(pagenum)
  419. {
  420.   Attr.Style = WS_CHILD | WS_BORDER | WS_VISIBLE;
  421.   SetBkgndColor(TColor::White);
  422. }
  423.  
  424. //
  425. //
  426. //
  427. void
  428. TPreviewPage::SetPageNumber(int newNum)
  429. {
  430.   PageNum = newNum;
  431.   if (GetHandle())
  432.     Invalidate();
  433. }
  434.  
  435. //
  436. // Using a TPrintPreviewDC, 'print' the current page (PageNum) of Printout
  437. // onto the window DC provided,
  438. //
  439. void
  440. TPreviewPage::Paint(TDC& dc, bool, TRect& clip)
  441. {
  442.   TPrintPreviewDC pdc(dc, PrintDC, GetClientRect(), clip);
  443.   Printout.SetPrintParams(&pdc, PrintExtent);
  444.  
  445.   if (Printout.HasPage(PageNum)) {
  446.     Printout.BeginPrinting();
  447.     Printout.BeginDocument(PageNum, PageNum, pfBoth);
  448.  
  449.     // Change clip rect into the shared logical coordinate space, & print
  450.     //
  451.     pdc.SDPtoLP(clip);
  452.     Printout.PrintPage(PageNum, clip, pfBoth);
  453.  
  454.     Printout.EndDocument();
  455.     Printout.EndPrinting();
  456.   }
  457.   else
  458.     dc.PatBlt(0, 0, Attr.W, Attr.H, WHITENESS);
  459. }
  460.  
  461. //
  462. // Always repaint whole window if size is changed
  463. //
  464. void
  465. TPreviewPage::EvSize(uint sizeType, TSize& size)
  466. {
  467.   Invalidate();
  468.   TWindow::EvSize(sizeType, size);
  469. }
  470.