- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
389 lines
11 KiB
C++
389 lines
11 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Definition of print preview classes
|
|
//----------------------------------------------------------------------------
|
|
#include <owl/owlpch.h>
|
|
#include <owl/preview.h>
|
|
#include <owl/printer.h>
|
|
#include <owl/gdiobjec.h>
|
|
#include <owl/dc.h>
|
|
#include <owl/printdia.h>
|
|
#include <math.h>
|
|
|
|
//
|
|
// Some inlines to provide platform independence since we drop directly to API
|
|
// calls to implement some of TPrintPreviewDC.
|
|
//
|
|
#if defined(BI_PLAT_WIN32)
|
|
inline bool SetWindowExt(HDC hdc, int w, int h) {return ::SetWindowExtEx(hdc, w, h, 0);}
|
|
inline bool SetWindowOrg(HDC hdc, int w, int h) {return ::SetWindowOrgEx(hdc, w, h, 0);}
|
|
inline bool SetViewportExt(HDC hdc, int w, int h) {return ::SetViewportExtEx(hdc, w, h, 0);}
|
|
inline bool SetViewportOrg(HDC hdc, int x, int y) {return ::SetViewportOrgEx(hdc, x, y, 0);}
|
|
#endif
|
|
|
|
TPrintPreviewDC::TPrintPreviewDC(TDC& screen,
|
|
TPrintDC& printdc,
|
|
const TRect& client,
|
|
const TRect& clip)
|
|
:
|
|
TPrintDC(screen),
|
|
PrnDC(printdc),
|
|
PrnFont(0),
|
|
CurrentPreviewFont(0)
|
|
{
|
|
//
|
|
// Set the initial mode & extents for the screen dc
|
|
//
|
|
::SetMapMode(GetHDC(), MM_ANISOTROPIC);
|
|
::SetWindowExt(GetHDC(), client.Width(), client.Height());
|
|
::SetViewportExt(GetHDC(), client.Width(), client.Height());
|
|
|
|
//
|
|
// Static call to virtual method, but some mapping must be done now.
|
|
//
|
|
ReScale();
|
|
|
|
//
|
|
// Assume clip rect is in device points - DPs are same in new viewport
|
|
//
|
|
SelectClipRgn(clip);
|
|
PrnFont = (HFONT)PrnDC.GetCurrentObject(OBJ_FONT);
|
|
SyncFont();
|
|
}
|
|
|
|
TPrintPreviewDC::~TPrintPreviewDC()
|
|
{
|
|
// cleanup screen dc
|
|
//
|
|
::DeleteObject(::SelectObject(GetHDC(), ::GetStockObject(SYSTEM_FONT)));
|
|
delete CurrentPreviewFont;
|
|
}
|
|
|
|
HDC
|
|
TPrintPreviewDC::GetAttributeHDC() const
|
|
{
|
|
return PrnDC;
|
|
}
|
|
|
|
//
|
|
// Intercept setting of the printer font, making & keeping a copy of it and
|
|
// calling SyncFont if needed to recreate the preview font.
|
|
//
|
|
void
|
|
TPrintPreviewDC::SelectObject(const TFont& newFont)
|
|
{
|
|
if ((HFONT)newFont) {
|
|
LOGFONT lf;
|
|
newFont.GetObject(lf);
|
|
|
|
TFont* oldPreviewF = CurrentPreviewFont;
|
|
CurrentPreviewFont = new TFont(&lf);
|
|
|
|
PrnDC.SelectObject(*CurrentPreviewFont);
|
|
delete oldPreviewF;
|
|
|
|
if ((HFONT)(*CurrentPreviewFont) != PrnFont) {
|
|
PrnFont = (HFONT)(*CurrentPreviewFont);
|
|
SyncFont();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TPrintPreviewDC::SelectStockObject(int index)
|
|
{
|
|
PrnDC.SelectStockObject(index);
|
|
switch (index) {
|
|
case ANSI_FIXED_FONT:
|
|
case ANSI_VAR_FONT:
|
|
case DEVICE_DEFAULT_FONT:
|
|
case OEM_FIXED_FONT:
|
|
case SYSTEM_FONT:
|
|
case SYSTEM_FIXED_FONT: {
|
|
HFONT stockFont = (HFONT)GetStockObject(index);
|
|
if (stockFont != PrnFont) {
|
|
PrnFont = stockFont;
|
|
SyncFont();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
TPrintDC::SelectStockObject(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
TPrintPreviewDC::RestoreFont()
|
|
{
|
|
PrnDC.RestoreFont();
|
|
PrnFont = (HFONT)PrnDC.GetCurrentObject(OBJ_FONT);
|
|
TPrintDC::RestoreFont();
|
|
SyncFont();
|
|
}
|
|
|
|
int
|
|
TPrintPreviewDC::GetDeviceCaps(int index) const
|
|
{
|
|
switch (index) {
|
|
case CLIPCAPS:
|
|
case RASTERCAPS:
|
|
case CURVECAPS:
|
|
case LINECAPS:
|
|
case POLYGONALCAPS:
|
|
case TEXTCAPS: // report capabilities supported on both devices
|
|
return PrnDC.GetDeviceCaps(index) & TPrintDC::GetDeviceCaps(index);
|
|
|
|
// otherwise, report printer caps and let GDI sort out differences
|
|
default:
|
|
return PrnDC.GetDeviceCaps(index);
|
|
}
|
|
}
|
|
|
|
inline int
|
|
GlyphHeight(TEXTMETRIC& tm)
|
|
{
|
|
return tm.tmHeight < 0
|
|
? tm.tmHeight
|
|
: -(tm.tmHeight - tm.tmInternalLeading);
|
|
}
|
|
|
|
//
|
|
// SyncFont performs a simple font match attempt, with a retry option if
|
|
// the GDI selected match is too different from the selected printer font.
|
|
// In print preview, matching the size of the characters is more important
|
|
// than matching their appearance. In most cases, the print preview will
|
|
// barely be legible anyway. Size is most important because you don't
|
|
// want character size differences to change the line breaks or page
|
|
// breaks of the on-screen document from what they would be on the
|
|
// printed page. This effect is minimized in this TPrintPreviewDC object,
|
|
// since info reports such as GetTextMetrics and GetTextExtent are always
|
|
// reported from the printer dc using the real font. Internal calculations
|
|
// should be the same for preview as for printing, but the output accuracy
|
|
// will depend upon the accuracy of font selection.
|
|
//
|
|
// It is also possible to take over control of the text output functions
|
|
// through this DC object - the TextOut and other text methods are virtual.
|
|
// You can place each character on the preview screen yourself, if you
|
|
// desire more precision in character placement than GDI's font matching
|
|
// can provide. That's a lot of work, and a lot of code, and isn't
|
|
// necessary to meet the needs of most applications.
|
|
//
|
|
// SyncFont is virtual so that you may substitute your own font matching
|
|
// algorythm with more font matching heuristics.
|
|
//
|
|
void
|
|
TPrintPreviewDC::SyncFont()
|
|
{
|
|
//
|
|
// set screen font to match current printer font.
|
|
//
|
|
LOGFONT lf;
|
|
::GetObject(PrnFont, sizeof(lf), &lf);
|
|
|
|
TEXTMETRIC tm;
|
|
PrnDC.GetTextMetrics(tm);
|
|
|
|
lf.lfHeight = GlyphHeight(tm);
|
|
lf.lfWidth = tm.tmAveCharWidth;
|
|
lf.lfWeight = tm.tmWeight;
|
|
lf.lfItalic = tm.tmItalic;
|
|
lf.lfUnderline = tm.tmUnderlined;
|
|
lf.lfStrikeOut = tm.tmStruckOut;
|
|
lf.lfCharSet = tm.tmCharSet;
|
|
lf.lfOutPrecision = OUT_TT_PRECIS;
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lf.lfQuality = DRAFT_QUALITY;
|
|
|
|
// Keep just the pitch (low 2 bits). Ignore the family
|
|
//
|
|
lf.lfPitchAndFamily = uint8((tm.tmPitchAndFamily & 0x0003) | FF_DONTCARE);
|
|
PrnDC.GetTextFace(sizeof(lf.lfFaceName), lf.lfFaceName);
|
|
|
|
::DeleteObject(::SelectObject(GetHDC(), ::CreateFontIndirect(&lf)));
|
|
|
|
//
|
|
// if height isn't right, relax the font pitch and facename requirements
|
|
//
|
|
GetTextMetrics(tm);
|
|
if (abs(abs(lf.lfHeight) - abs(GlyphHeight(tm))) > 2) {
|
|
if (lf.lfPitchAndFamily & FF_DECORATIVE)
|
|
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
|
|
else
|
|
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
|
lf.lfFaceName[0] = 0;
|
|
::DeleteObject(::SelectObject(GetHDC(), CreateFontIndirect(&lf)));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rescale the preview DC by adjusting its window & viewport
|
|
//
|
|
// Assume the viewport extent (scrve) is set to the size of the window
|
|
// client area. All we have to do to map the addressable points of the
|
|
// printer DC into the screen DC, then, is set the screen window extent
|
|
// equal to the maximum addressable logical point of the printer dc.
|
|
// PrnDC.DPtoLP will pull the device point through the printer's mapping
|
|
// mode conversions, giving us the maximum point we should allow on the
|
|
// screen dc.
|
|
//
|
|
void
|
|
TPrintPreviewDC::ReScale()
|
|
{
|
|
TSize scrve;
|
|
::GetViewportExtEx(GetHDC(), &scrve);
|
|
|
|
TPoint scrwe(PrnDC.GetDeviceCaps(HORZRES), PrnDC.GetDeviceCaps(VERTRES));
|
|
PrnDC.DPtoLP(&scrwe);
|
|
|
|
::SetMapMode(GetHDC(), MM_ANISOTROPIC);
|
|
::SetWindowExt(GetHDC(), scrwe.x, scrwe.y);
|
|
::SetViewportExt(GetHDC(), scrve.cx, scrve.cy);
|
|
ReOrg();
|
|
}
|
|
|
|
//
|
|
// Reset the DC's origin
|
|
//
|
|
void
|
|
TPrintPreviewDC::ReOrg()
|
|
{
|
|
TPoint origin = PrnDC.GetViewportOrg();
|
|
PrnDC.DPtoLP(&origin);
|
|
LPtoSDP(&origin);
|
|
::SetViewportOrg(GetHDC(), origin.x, origin.y);
|
|
|
|
PrnDC.GetWindowOrg(origin);
|
|
::SetWindowOrg(GetHDC(), origin.x, origin.y);
|
|
}
|
|
|
|
TColor
|
|
TPrintPreviewDC::SetBkColor(TColor color)
|
|
{
|
|
TColor result = PrnDC.SetBkColor(color);
|
|
::SetBkColor(GetHDC(), PrnDC.GetBkColor());
|
|
return result;
|
|
}
|
|
|
|
TColor
|
|
TPrintPreviewDC::SetTextColor(TColor color)
|
|
{
|
|
TColor result = PrnDC.SetTextColor(color);
|
|
::SetTextColor(GetHDC(), PrnDC.GetTextColor());
|
|
return result;
|
|
}
|
|
|
|
int
|
|
TPrintPreviewDC::SetMapMode(int mode)
|
|
{
|
|
int result = PrnDC.SetMapMode(mode);
|
|
ReScale();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::SetViewportOrg(const TPoint& origin, TPoint far* oldOrg)
|
|
{
|
|
bool result = PrnDC.SetViewportOrg(origin, oldOrg);
|
|
ReOrg();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::OffsetViewportOrg(const TPoint& delta, TPoint far* oldOrg)
|
|
{
|
|
bool result = PrnDC.OffsetViewportOrg(delta, oldOrg);
|
|
ReOrg();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::SetViewportExt(const TSize& extent, TSize far* oldExtent)
|
|
{
|
|
bool result = PrnDC.SetViewportExt(extent, oldExtent);
|
|
ReScale();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom,
|
|
TSize far* oldExtent)
|
|
{
|
|
bool result = PrnDC.ScaleViewportExt( xNum, xDenom, yNum, yDenom, oldExtent);
|
|
ReScale();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::SetWindowExt(const TSize& extent, TSize far* oldExtent)
|
|
{
|
|
bool result = PrnDC.SetWindowExt(extent, oldExtent);
|
|
ReScale();
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
TPrintPreviewDC::ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom,
|
|
TSize far* oldExtent)
|
|
{
|
|
bool result = PrnDC.ScaleWindowExt(xNum, xDenom, yNum, yDenom, oldExtent);
|
|
ReScale();
|
|
return result;
|
|
}
|
|
|
|
|
|
DEFINE_RESPONSE_TABLE1(TPreviewPage, TWindow)
|
|
EV_WM_SIZE,
|
|
END_RESPONSE_TABLE;
|
|
|
|
IMPLEMENT_CASTABLE(TPreviewPage);
|
|
|
|
TPreviewPage::TPreviewPage(TWindow* parent, TPrintout& printout,
|
|
TPrintDC& prndc, TSize& printExtent, int pagenum)
|
|
: TWindow(parent),
|
|
Printout(printout),
|
|
PrintDC(prndc),
|
|
PrintExtent(printExtent),
|
|
PageNum(pagenum)
|
|
{
|
|
Attr.Style = WS_CHILD | WS_BORDER | WS_VISIBLE;
|
|
SetBkgndColor(TColor::White);
|
|
}
|
|
|
|
//
|
|
// Using a TPrintPreviewDC, 'print' the current page (PageNum) of Printout
|
|
// onto the window DC provided,
|
|
//
|
|
void
|
|
TPreviewPage::Paint(TDC& dc, bool, TRect& clip)
|
|
{
|
|
TPrintPreviewDC pdc(dc, PrintDC, GetClientRect(), clip);
|
|
Printout.SetPrintParams(&pdc, PrintExtent);
|
|
|
|
if (Printout.HasPage(PageNum)) {
|
|
Printout.BeginPrinting();
|
|
Printout.BeginDocument(PageNum, PageNum, pfBoth);
|
|
|
|
// Change clip rect into the shared logical coordinate space, & print
|
|
//
|
|
pdc.SDPtoLP(clip);
|
|
Printout.PrintPage(PageNum, clip, pfBoth);
|
|
|
|
Printout.EndDocument();
|
|
Printout.EndPrinting();
|
|
}
|
|
else
|
|
dc.PatBlt(0, 0, Attr.W, Attr.H, WHITENESS);
|
|
}
|
|
|
|
//
|
|
// Always repaint whole window if size is changed
|
|
//
|
|
void
|
|
TPreviewPage::EvSize(uint sizeType, TSize& size)
|
|
{
|
|
Invalidate();
|
|
TWindow::EvSize(sizeType, size);
|
|
}
|