// globals
var cpMin, PixH, PixW: longint;
ViewScale: double;
dc: THandle;
fr: TFormatRange;
ox, oy, w, h: LongInt;
MorePages: boolean;
PageMap: widestring;
PgCnt, PgSum: integer;
function XPixToTwips(px: integer): integer;
var
dc: THandle;
begin
dc:= GetDC(HWND_DESKTOP);
Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSX));
ReleaseDC(HWND_DESKTOP, dc);
end;
function YPixToTwips(px: integer): integer;
var
dc: THandle;
begin
dc:= GetDC(HWND_DESKTOP);
Result:= Round(1440*px/GetDeviceCaps(dc, LOGPIXELSY));
ReleaseDC(HWND_DESKTOP, dc);
end;
procedure TCmdForm.SetupViewPage(BegPos, EndPos: longint);
begin
// clear the image canvas
TextArea.Canvas.Brush.Color:= clWindow;
TextArea.Canvas.FillRect(0, 0, TextArea.Canvas.ClipRect.Right, TextArea.Canvas.ClipRect.Bottom);
TextArea.Canvas.MoveTo(0, 0);
// set the printing metrics
dc:= TextArea.Canvas.Handle;
ox:= 0; //GetDeviceCaps(dc, PHYSICALOFFSETX);
oy:= 0; //GetDeviceCaps(dc, PHYSICALOFFSETY);
w:= XPixToTwips(Round(PixW * ViewScale)); //GetDeviceCaps(dc, PHYSICALWIDTH);
h:= YPixToTwips(Round(PixH * ViewScale)); //GetDeviceCaps(dc, PHYSICALHEIGHT);
FillChar(fr, SizeOf(TFormatRange), 0);
fr.hdc:= dc; // fr._hdc:= dc; **on some systems**
fr.hdcTarget:= dc;
fr.rc.Left:= ox;
fr.rc.Right:= ox+w;
fr.rc.Top:= oy;
fr.rc.Bottom:= oy+h;
fr.chrg.cpMin:= BegPos; // set to 0 for start of document
fr.chrg.cpMax:= EndPos; // set to -1 for end of document
// get document content
SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
SendMessage(PageMemo.Handle, EM_HIDESELECTION, 1, 0); // hide selection
SendMessage(PageMemo.Handle, EM_SETSEL, BegPos, EndPos); // select to end of document
SendMessage(PageMemo.Handle, EM_EXGETSEL, 0, LParam(@fr.chrg)); // copy selection
SendMessage(PageMemo.Handle, EM_SETSEL, 0, 0); // reset to no selection
SendMessage(PageMemo.Handle, EM_HIDESELECTION, 0, 0); // show selection
end;
procedure TCmdForm.CountPages;
var x,p: longint;
begin
// get total page count
SetupViewPage(0, -1);
cpMin:= 0; PgSum:= 0; p:= 0; MorePages:= true; PageMap:= '';
while (fr.chrg.cpMin<=fr.chrg.cpMax) and (MorePages) do // track through document
begin
SetupViewPage(cpMin, -1);
p:= p + 1;
PageMap:= '#'+IntToStr(p)+':'+IntToStr(cpMin)+','+PageMap;
cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
fr.chrg.cpMin:= cpMin;
PgSum:= PgSum + 1;
if (fr.chrg.cpMin=fr.chrg.cpMax)
then MorePages:= false;
end;
PageMap:= '*'+IntToStr(p)+':'+IntToStr(cpMin)+','+PageMap; // end + 1
for x:=1 to PgSum do ViewPageList.Items.Add(IntToStr(x));
end;
procedure TCmdForm.ConfigureView;
var
PgWide, PgHigh, PgLft, PgRht, PgTop, PgBtm, InchW, InchH: double;
begin
// define paper size... these 6 can be global for paper size and display
PgWide:= 8.5; PgHigh:= 11.0; // US Letter Size
PgLft:= 1.0; PgRht:= 1.0;
PgTop:= 1.0; PgBtm:= 1.0;
// setup the PaperArea metrics
PaperArea.top:= 0; // 0 or 40 fits my layout
PaperArea.height:= Round(PgHigh * Screen.PixelsPerInch / ViewScale);
PaperArea.width:= Round(PgWide * Screen.PixelsPerInch / ViewScale);
PaperArea.left:= Round((PageMemo.width - PaperArea.width) / 2); // centering view page
if PaperArea.left<0 then PaperArea.left:= 0;
// setup the TextArea metrics
InchH:= PgHigh - PgTop - PgBtm;
InchW:= PgWide - PgLft - PgRht;
PixH:= Round(InchH * Screen.PixelsPerInch / ViewScale);
PixW:= Round(InchW * Screen.PixelsPerInch / ViewScale);
// setup the TextArea position
TextArea.Top:= Round((Screen.PixelsPerInch * PgTop) / ViewScale);
TextArea.height:= PixH;
TextArea.width:= PixW;
TextArea.left:= Round((Screen.PixelsPerInch * PgLft) / ViewScale);
TextArea.Picture.Bitmap.SetSize(Round(PixW * ViewScale), Round(PixH * ViewScale));
end;
procedure TCmdForm.GetPageMap;
var PgSel,GetStr: string;
x,s: integer;
begin
PgSel:= IntToStr(PgCnt);
GetStr:= '#'+PgSel+':';
x:= pos(GetStr,PageMap);
s:= length(PageMap);
if x>0 then
begin
GetStr:= copy(PageMap,x,s-x+1);
x:= pos(':',GetStr);
delete(GetStr,1,x);
x:= pos(',',GetStr);
GetStr:= copy(GetStr,1,x-1);
cpMin:= StrToInt(GetStr);
end;
end;
procedure TCmdForm.btnViewPagesClick(Sender: TObject);
begin
PaperArea.visible:= true;
ScrollView.visible:= true;
SetupViewPage(0, -1);
PostFirstPage;
end;
procedure TCmdForm.btnViewZoomClick(Sender: TObject);
begin
if ViewScale>1.5 // zoom toggle between full and half
then ViewScale:= 1.0
else ViewScale:= 2.0;
ConfigureView;
NavPanel.left:= Round((PaperArea.width - NavPanel.width) / 2);
end;
procedure TCmdForm.btnViewBegClick(Sender: TObject);
var PgSel,GetStr: string;
x,s: integer;
begin
PgCnt:= 1;
GetPageMap;
PostNewPage;
end;
procedure TCmdForm.btnViewEndClick(Sender: TObject);
var PgSel,GetStr: string;
x,s: integer;
begin
PgCnt:= PgSum;
GetPageMap;
PostNewPage;
end;
procedure TCmdForm.btnViewPrtClick(Sender: TObject);
begin
// no built
end;
procedure TCmdForm.btnViewBckClick(Sender: TObject);
var PgSel,GetStr: string;
x,s: integer;
begin
PgCnt:= PgCnt - 1;
if PgCnt<1 then PgCnt:= 1;
GetPageMap;
PostNewPage;
end;
procedure TCmdForm.btnViewNxtClick(Sender: TObject);
begin
PgCnt:= PgCnt + 1;
if PgCnt>PgSum then PgCnt:= PgSum;
GetPageMap;
PostNewPage;
end;
procedure TCmdForm.btnViewQuitClick(Sender: TObject);
begin
// clean up
SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
if MorePages
then EndDoc(fr.hdc) // close EM_FORMATRANGE
else AbortDoc(fr.hdc);
TextArea.Picture.Bitmap.Canvas.Changed; // reset image event
PaperArea.visible:= false;
ScrollView.visible:= false;
end;
procedure TCmdForm.ViewPageListEditingDone(Sender: TObject);
begin
ViewPageListSelect(self)
end;
procedure TCmdForm.ViewPageListSelect(Sender: TObject);
var PgSel,GetStr: string;
x,s,p: integer;
begin
PgSel:= ViewPageList.Text;
PgCnt:= StrToInt(PgSel);
GetPageMap;
PostNewPage;
end;
procedure TCmdForm.PostNewPage;
var PgStr: string;
begin
SetupViewPage(cpMin, -1);
cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
fr.chrg.cpMin:= cpMin;
PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
PgStr:= PgStr+IntToStr(PgSum);
PageMonitor.caption:= PgStr;
end;
procedure TCmdForm.PostFirstPage;
var
PgStr: string;
begin
ViewScale:= 2.0; // display size: 10.5=double, 1.0=full, 2.0=half
ConfigureView;
CountPages;
MorePages:= true;
cpMin:= 0;
SetupViewPage(cpMin, -1);
cpMin:= SendMessage(PageMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@fr));
SendMessage(PageMemo.Handle, EM_FORMATRANGE, 0, 0); // clear EM_FORMATRANGE
fr.chrg.cpMin:= cpMin; // set to start of next page
PgCnt:= 1;
PgStr:= 'Page '+IntToStr(PgCnt)+' of ';
PgStr:= PgStr+IntToStr(PgSum);
PageMonitor.caption:= PgStr;
ViewPageList.Text:= '1';
end;