aboutsummaryrefslogblamecommitdiffstats
path: root/apps/windoze/CBuilder5/BibleCS/PreviewForm.cpp
blob: 32e7b8ab40c3d12ff60ee2da0812438f3f42ce01 (plain) (tree)







































































































































































































































































































































                                                                                                      
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "PreviewForm.h"
//---------------------------------------------------------------------------
// include this...
#include <vcl\printers.hpp>
//---------------------------------------------------------------------------
// thanks to Scott Proper for finding several errors where the code 
// used 1400 instead of the correct 1440.
//---------------------------------------------------------------------------
// standard template library is used for to build a vector (or table) of
// page offsets
//
/*
typedef struct tagTPageOffset {
	long int Start;
	long int End;
	RECT rendRect;
	} TPageOffsets;
*/
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TPreviewForm *PreviewForm;
//---------------------------------------------------------------------------
// custom panel onto which we can draw
//
class TPreviewPanel : public TPanel
{
public:
	__fastcall virtual TPreviewPanel(Classes::TComponent* AOwner) :
		TPanel(AOwner) { };
	__fastcall virtual ~TPreviewPanel(void) { };
	__fastcall virtual void Paint(void) {
		TPanel::Paint();
		PreviewForm->DrawRichEdit();
		};
	__property Canvas;

};
//---------------------------------------------------------------------------
__fastcall TPreviewForm::TPreviewForm(TComponent* Owner)
	: TForm(Owner)
{
	PreviewPanel = new TPreviewPanel(this);
	PreviewPanel->Parent = Panel1;
	PreviewPanel->Color = clWhite;
    this->WindowState = wsMaximized;
    currPage = 0;
}
//---------------------------------------------------------------------------
__fastcall TPreviewForm::~TPreviewForm(void)
{
	if (PreviewPanel) delete PreviewPanel;
    FPageOffsets.erase(FPageOffsets.begin(), FPageOffsets.end());
}
//---------------------------------------------------------------------------
// size the panel to dimensions that approximate the page scaled
// to fit within the window.
//
void __fastcall TPreviewForm::FormResize(TObject *Sender)
{
	// get the printer dimensions.
	int wPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALWIDTH);
	int hPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALHEIGHT);

	// get the client window dimensions.
	int wClient = ClientWidth;
	int hClient = ClientHeight;

	// initially adjust width to match height
	wClient = ::MulDiv(ClientHeight, wPage, hPage);

	// if that doesn't fit, then do it the other way
	if (wClient > ClientWidth) {
		wClient = ClientWidth;
		hClient = ::MulDiv(ClientWidth, hPage, wPage);
		// center the page in the window
		PreviewPanel->Top = (ClientHeight - hClient) >> 1;	// divide by two
		}
	else	// center the page in the window
		PreviewPanel->Left = (ClientWidth - wClient) >> 1;	// divide by two

	// now set size of panel
	PreviewPanel->Width = wClient;
	PreviewPanel->Height = hClient;
}
//---------------------------------------------------------------------------
// sample code to demonstrate implementing a print preview window.  the code,
// as written, uses hard-coded two-inch margins (as above) and displays only
// the first page.  the goal of the example is to demonstrate rendering a
// a page of text, in this case the first page only, to a window.  the
// window can be resized by the user and will be rescaled to approximate
// the printed page.  to extend this into a useful class, you will need to
// add code and buttons (or other means) to move between pages.  refer to the
// printing code in the main form for code that will, with a little insight
// and effort, help you in this effort.  in particular, the printing code
// demonstrates how to build a table of offsets corresponding to the printed
// pages.
//
// here's an obvious tip:  there is a considerable amount of duplicated code,
// between the printing function in the main form and the code in the
// following routine, that the savy programmer will consolidate into useful
// subroutines.
//
void TPreviewForm::DrawRichEdit(void)
{
	//-----------------------------------------------------------------------
	// *** same as printing version ***
	//-----------------------------------------------------------------------
	float	leftMargin = StrToFloat(PrintForm->editLeft->Text),
    		rightMargin = StrToFloat(PrintForm->editRight->Text),
			topMargin = StrToFloat(PrintForm->editTop->Text),
			bottomMargin = StrToFloat(PrintForm->editBottom->Text);


	int wPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALWIDTH);
	int hPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALHEIGHT);
	int xPPI = ::GetDeviceCaps(Printer()->Handle, LOGPIXELSX);
	int yPPI = ::GetDeviceCaps(Printer()->Handle, LOGPIXELSY);
	int wTwips = ::MulDiv(wPage, 1440, xPPI);
	int hTwips = ::MulDiv(hPage, 1440, yPPI);

	RECT pageRect;
	pageRect.left = pageRect.top = 0;
	pageRect.right = wTwips;
	pageRect.bottom = hTwips;

	RECT rendRect;
	rendRect.left = rendRect.top = 0;
	rendRect.right = pageRect.right - 1440 * (leftMargin + rightMargin);
	rendRect.bottom = pageRect.bottom - 1440 * (topMargin + bottomMargin);
	TPageOffsets po;
	po.Start = 0;

	//-----------------------------------------------------------------------
	// differences from the printing version start here (although, even
	// the following has considerable similarity).
	//-----------------------------------------------------------------------

	// we will need a few DCs before it is over.  note also that this
	// function is called inside of the TPreviewPanel Paint() handler.
	HDC hdcDesktop = ::GetWindowDC(::GetDesktopWindow());
	HDC hdcCanvas = dynamic_cast<TPreviewPanel*>(PreviewPanel)->Canvas->Handle;
	HDC hdcPrinter = Printer()->Handle;

    FPageOffsets.erase(FPageOffsets.begin(), FPageOffsets.end());

	// initialize the formatting data.
	TFormatRange fr;
	fr.hdc = hdcDesktop;
	fr.hdcTarget = hdcPrinter;
	fr.chrg.cpMin = po.Start;
	fr.chrg.cpMax = -1;

	// get the size of the text in the control (use EM_GETTEXTLENEX for RE 2.0).
	int lastOffset = ::SendMessage(rtfPrint->Handle,
		WM_GETTEXTLENGTH, 0, 0);

	// clear the formatting buffer.
	::SendMessage(rtfPrint->Handle, EM_FORMATRANGE,
		(WPARAM) 0, (LPARAM) 0);

	// save the canvas DC and prepare to scale.
	SaveDC(hdcCanvas);
	::SetMapMode(hdcCanvas, MM_TEXT);			// set to device units
	::SetMapMode(hdcCanvas, MM_ANISOTROPIC);	// inherits prior mapping mode
	::SetMapMode(hdcPrinter, MM_TEXT);			// set to device units

	// set window extent to width/height of printer in printer device units.
	::SetWindowExtEx(hdcCanvas, pageRect.right, pageRect.bottom, NULL);

	// scale window extent to width/height of printer in desktop device units.
	int xDesktopPPI = ::GetDeviceCaps(hdcDesktop, LOGPIXELSX);
	int yDesktopPPI = ::GetDeviceCaps(hdcDesktop, LOGPIXELSY);
	::ScaleWindowExtEx(hdcCanvas, xDesktopPPI, 1440, yDesktopPPI, 1440, NULL);

	// set viewport to width/height of PreviewPanel in device units.
	::SetViewportExtEx(hdcCanvas, PreviewPanel->ClientWidth,
		PreviewPanel->ClientHeight, NULL);

	// now, here is one that I really do not get:  we have to reduce the
	// horizontal range a little for the text (wrap) to exactly match.
	// this may be due to two things:  (1) the font scaling that Windows
	// to make screen fonts appear about the same size at a distance as
	// the printed fonts do close up or (2) the adjustment to the rendering
	// rectangle that Rich Edit may or may not do to adjust for the non-
	// printable portion of the printed page.  although (1) strikes me as
	// perhaps more likely, the latter is easier to do and seems to work
	// in other projects.  if you figure this one out, please, please
	// let me know.  anyway, we will assume that the vertical adjustment
	// is also required.  oh, and we are working in twips.
	int xPrinterOffset = ::MulDiv(::GetDeviceCaps(hdcPrinter, PHYSICALOFFSETX),
		1440, xPPI);
	int yPrinterOffset = ::MulDiv(::GetDeviceCaps(hdcPrinter, PHYSICALOFFSETY),
		1440, yPPI);
	rendRect.left += xPrinterOffset >> 1;
	rendRect.right -= xPrinterOffset - (xPrinterOffset >> 1);
	rendRect.top += yPrinterOffset >> 1;
	rendRect.bottom -= yPrinterOffset - (yPrinterOffset >> 1);

	// adjust output origin for two inch margin.
	int xOffset = ::MulDiv(PreviewPanel->ClientWidth * leftMargin, 1440, pageRect.right);
	int yOffset = ::MulDiv(PreviewPanel->ClientHeight * topMargin, 1440, pageRect.bottom);
	::SetViewportOrgEx(hdcCanvas, xOffset, yOffset, NULL);

	// loop through data to format and build page offset table.
	do {
		// set up remaining format data.
		fr.rc = rendRect;			// RE returns something useful here...
		fr.rcPage = pageRect;
		po.Start = fr.chrg.cpMin;

		// format range with render set to false.
		fr.chrg.cpMin = ::SendMessage(rtfPrint->Handle, EM_FORMATRANGE,
			(WPARAM) 0, (LPARAM) &fr);
        // I don't know why I need to do this, but there is an apparent bug in the TRXRichEdit control
        // and it doesn't handle the last page properly if there are more than 3 pages of text.
        if(fr.chrg.cpMin == po.End)
        	fr.chrg.cpMin = lastOffset;
        po.End = fr.chrg.cpMin - 1;
		po.rendRect = fr.rc;		// and where is this documented?
        if(fr.chrg.cpMin < lastOffset)
			FPageOffsets.push_back(po);
    } while (fr.chrg.cpMin != -1 && fr.chrg.cpMin < lastOffset);

	// at this point, FPageOffsets.size() is the page count which will
	// always be at least one.  pageCount is not used here since we
	// display only the first page.
	//	int pageCount = FPageOffsets.size();


	// set the rendering device to the scaled DC and the target to null.
	fr.hdc = hdcCanvas;
	fr.hdcTarget = 0;

	// set up remaining format data.
	fr.rc = FPageOffsets[currPage].rendRect;	// documented where?
	fr.rcPage = pageRect;
	fr.chrg.cpMin = FPageOffsets[currPage].Start;
	fr.chrg.cpMax = FPageOffsets[currPage].End;

	// format range with render set to true.
	fr.chrg.cpMin = ::SendMessage(rtfPrint->Handle, EM_FORMATRANGE,
		(WPARAM) 1, (LPARAM) &fr);

	// clean up.
	::RestoreDC(hdcCanvas, -1);
	::ReleaseDC(::GetDesktopWindow(), hdcDesktop);
	::SendMessage(rtfPrint->Handle, EM_FORMATRANGE,
		(WPARAM) 0, (LPARAM) 0);
    UpdatePageNums();
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::FormShow(TObject *Sender)
{
	rtfPrint = PrintForm->rtfPrint;
    //UpdatePageNums();
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::btnFwdClick(TObject *Sender)
{
	if(currPage < (FPageOffsets.size() - 1)){
    	currPage++;
        PreviewPanel->Repaint();
        //UpdatePageNums();
    }
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::btnBackClick(TObject *Sender)
{

    if(currPage > 0){
		currPage--;
		PreviewPanel->Repaint();
        //UpdatePageNums();
    }
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::btnEndClick(TObject *Sender)
{
	if(currPage != (FPageOffsets.size() - 1)){
    	currPage = (FPageOffsets.size() - 1);
        PreviewPanel->Repaint();
        //UpdatePageNums();
    }
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::btnBeginClick(TObject *Sender)
{
	if(currPage != 0){
    	currPage = 0;
        PreviewPanel->Repaint();
        //UpdatePageNums();
    }
}
//---------------------------------------------------------------------------

void __fastcall TPreviewForm::btnCloseClick(TObject *Sender)
{
	ModalResult = mrCancel;	
}
//---------------------------------------------------------------------------


void TPreviewForm::UpdatePageNums()
{
	AnsiString strPages = "Page ";
    strPages += IntToStr(currPage + 1);
    strPages += " of ";
    strPages += IntToStr(FPageOffsets.size());
    editPages->Text = strPages;
    Caption = (AnsiString)"Print Preview " + strPages;
}

void __fastcall TPreviewForm::btnPrintClick(TObject *Sender)
{
	ModalResult = mrOk;	
}
//---------------------------------------------------------------------------