/***************************************************************************/ /* TQuickPrint version 1.01 */ /* ----------------------------------------------------------------------- */ /* What is it: Ever needed to print some text quickly but was tired of */ /* ----------- the lot of work it requires to use TPrinter? */ /* On top of that it takes a lot of code to make your prints */ /* look good and look good with different printer resolutions. */ /* */ /* TQuickPrint is the answer for those "problems". */ /* */ /* */ /* How to install it: Go to the "Component" Menuitem and select "Install */ /* ------------------ Component...". Click the "Browse" button next to the */ /* "Unit file name:". Choose "QuickPrint.cpp". */ /* Choose the apporpriate package to install TQuickPrint*/ /* in to, from the "Package file name" combobox */ /* (normally: dclusr35.bpk or dclusr40.bpk) */ /* TQuickPrint will register it self in the "System" */ /* palette. */ /* */ /* How to use it: Just drop it on to the Form you're working with and work */ /* -------------- on. */ /* */ /* What does it cost: Nothing. It's free of charge for any usage! :-) */ /* ------------------ */ /* */ /* Which version of C++ Builder is it tested with: 3 and 4. Should work */ /* ----------------------------------------------- with version 1 too. */ /* */ /* Disclaimer: */ /* ----------- */ /* TQuickPrint is provided "AS IS" without warranty of any */ /* kind, either expressed or implied, including but not limited */ /* to the implied warranties of merchantability and fitness */ /* for a particular purpose. In no event shall Cramon Utilites */ /* be liable for any damages whatsoever including direct, indirect, */ /* incidental, consequential, loss of business profits or */ /* special damages, even if Cramon Utilities has been advised */ /* of the possibility of such damages. */ /* You may use TQuickPrint free of charge in any application you make */ /* be it freeware, shareware or commercial. If you change the sourcecode */ /* of TQuickPrint you must include this text and clearly state which parts */ /* are changed by you and that this is not the original version. */ /* If you would like your changes in the "official" version please send */ /* the updated source file(s) to me and I'll update my sourcecode (you'll */ /* ofcourse get credit for all changes you've made to TQuickPrint). */ /* */ /* Author..: Jeppe Cramon */ /* Company.: Cramon Utilities */ /* WWW.....: http://www.cramon.dk */ /* E-mail..: jeppe@cramon.dk */ /* (C) Copyright 1999 Cramon Utilities */ /* */ /* ----------------------------------------------------------------------- */ /* Date Comment Programmer */ /* 05/30-1999 Created the first version (1.00) Jeppe Cramon */ /* 06/05-1999 Version (1.01) Jeppe Cramon */ /* Fixed the Convertion functions so they */ /* work properly (caused by casting problems). */ /* Fixed all Printing routines so the */ /* Margins now are correct (I hope) ;) */ /* Changed the consts in the header, to */ /* avoid problems when compiling together */ /* with THintBox. */ /***************************************************************************/ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "quickprint.h" #include #pragma package(smart_init) //--------------------------------------------------------------------------- // Consts const int iDefaultDPI = 300; // Default resolution const int iAlignLeft = 0; // Align Left const int iAlignCenter = 1; // Align Center const int iAlignRight = 2; // Align Right //--------------------------------------------------------------------------- // ValidCtrCheck is used to assure that the components created do not have // any pure virtual functions. // static inline void ValidCtrCheck(TQuickPrint *) { new TQuickPrint(NULL); } //--------------------------------------------------------------------------- __fastcall TQuickPrint::TQuickPrint(TComponent* Owner) : TComponent(Owner) { // Set default values for properties bWordWrap = true; fMeasureUnit = Millimeters; fLineSpacing = SingleSpace; PrintPageNo = false; uiLines = 0; uiPageNumber = 0; // Margins MarginLeft = 0.0; MarginRight = 0.0; MarginTop = 0.0; MarginBottom = 0.0; // Allocate vars fLines = new TStringList(); TextList = new TStringList(); AlignList = new TList(); } //--------------------------------------------------------------------------- namespace Quickprint { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TQuickPrint)}; RegisterComponents("System", classes, 0); } } //--------------------------------------------------------------------------- // Destructor __fastcall TQuickPrint::~TQuickPrint() { // Clean up if (Lines) { Lines->Clear(); delete Lines; } if (TextList) { TextList->Clear(); delete TextList; } if (AlignList) { AlignList->Clear(); delete AlignList; } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetWordWrap(bool Value) { if (!Printer()->Printing) { if (Value != bWordWrap) { bWordWrap = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetMeasureUnit(TMeasureUnit Value) { if (!Printer()->Printing) { if (fMeasureUnit != Value) { fMeasureUnit = Value; // Translate the Margins to the new Unit if (fMeasureUnit == Millimeters) { // Convert from Inches to millimeters MarginTop *= 25.4; MarginBottom *= 25.4; MarginLeft *= 25.4; MarginRight *= 25.4; } else { // Convert from millimeters to inches MarginTop /= 25.4; MarginBottom /= 25.4; MarginLeft /= 25.4; MarginRight /= 25.4; } } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetLineSpacing(TLineSpacing Value) { if (!Printer()->Printing) { if (fLineSpacing != Value) { fLineSpacing = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetLines(Classes::TStrings* Value) { if (!Printer()->Printing) { fLines->Assign(Value); } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetMarginTop(float Value) { if (!Printer()->Printing) { if (fMarginTop != Value) { fMarginTop = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetMarginBottom(float Value) { if (!Printer()->Printing) { if (fMarginBottom != Value) { fMarginBottom = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetMarginLeft(float Value) { if (!Printer()->Printing) { if (fMarginLeft != Value) { fMarginLeft = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetMarginRight(float Value) { if (!Printer()->Printing) { if (fMarginRight != Value) { fMarginRight = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetPrintTitle(AnsiString Value) { if (!Printer()->Printing) { if (asPrintTitle != Value) { asPrintTitle = Value; } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetPrintPageNo(bool Value) { if (!Printer()->Printing) { if (bPrintPageNo != Value) { bPrintPageNo = Value; } } } //--------------------------------------------------------------------------- Printers::TPrinterOrientation __fastcall TQuickPrint::GetOrientation(void) { try { return Printer()->Orientation; } catch(...) { return poPortrait; } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetOrientation(Printers::TPrinterOrientation Value) { if (!Printer()->Printing) { if (Printer()->Orientation != Value) { try { Printer()->Orientation = Value; } catch(...) {} } } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::SetFont(Graphics::TFont* Value) { if (!Printer()->Printing) { try { Printer()->Canvas->Font->Assign(Value); Printer()->Canvas->Font->Size = Value->Size; } catch(...) {} } } //--------------------------------------------------------------------------- TFont* __fastcall TQuickPrint::GetFont() { return Printer()->Canvas->Font; } //--------------------------------------------------------------------------- bool __fastcall TQuickPrint::GetPrinting() { return Printer()->Printing; } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPageHeight() { return PhysicalPageHeight-PhysicalOffsetY-MarginTop-MarginBottom; } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPageWidth() { return PhysicalPageWidth-PhysicalOffsetX-MarginLeft-MarginRight; } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPhysicalPageHeight() { return PixelsToMeasureUnitVert( GetDeviceCaps(Printer()->Handle, PHYSICALHEIGHT) ); } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPhysicalPageWidth() { return PixelsToMeasureUnitHorz( GetDeviceCaps(Printer()->Handle, PHYSICALWIDTH) ); } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPhysicalOffsetX() { return PixelsToMeasureUnitHorz( GetDeviceCaps(Printer()->Handle, PHYSICALOFFSETX) ); } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::GetPhysicalOffsetY() { return PixelsToMeasureUnitVert( GetDeviceCaps(Printer()->Handle, PHYSICALOFFSETY) ); } //--------------------------------------------------------------------------- Graphics::TCanvas* __fastcall TQuickPrint::GetCanvas() { return Printer()->Canvas; } //--------------------------------------------------------------------------- // Helper functions //--------------------------------------------------------------------------- float __fastcall TQuickPrint::PixelsToMeasureUnitHorz(unsigned int Pixels) { // Local variable float fTmp; try { // GetDeviceCaps returns pixels per inch fTmp = (float)Pixels/GetDeviceCaps(Printer()->Handle, LOGPIXELSX); } catch(...) { // Set a value measured from our default resolution (300) fTmp = (float)Pixels/iDefaultDPI; } if (MeasureUnit == Millimeters) // Convert from inches to mm's return fTmp*25.4; else return fTmp; } //--------------------------------------------------------------------------- float __fastcall TQuickPrint::PixelsToMeasureUnitVert(unsigned int Pixels) { // Local variable float fTmp; try { // GetDeviceCaps returns pixels per inch fTmp = (float)Pixels/GetDeviceCaps(Printer()->Handle, LOGPIXELSY); } catch(...) { // Set a value measured from our default resolution (300) fTmp = (float)Pixels/iDefaultDPI; } if (MeasureUnit == Millimeters) // Convert from inches to mm's return fTmp*25.4; else return fTmp; } //--------------------------------------------------------------------------- unsigned int __fastcall TQuickPrint::MeasureUnitToPixelsHorz(float Measure) { // Local variable float fTmp; try { // GetDeviceCaps returns pixels per inch fTmp = (float)Measure * GetDeviceCaps(Printer()->Handle, LOGPIXELSX); } catch(...) { // Set a value measured from our default resolution (300) fTmp = (float)Measure * iDefaultDPI; } if (MeasureUnit == Millimeters) // Convert from inches to mm's return (int)fTmp/25.4; else return (int)fTmp; } //--------------------------------------------------------------------------- unsigned int __fastcall TQuickPrint::MeasureUnitToPixelsVert(float Measure) { // Local variable float fTmp; try { // GetDeviceCaps returns pixels per inch fTmp = (float)Measure * GetDeviceCaps(Printer()->Handle, LOGPIXELSY); } catch(...) { // Set a value measured from our default resolution (300) fTmp = (float)Measure * iDefaultDPI; } if (MeasureUnit == Millimeters) // Convert from inches to mm's return (int)fTmp/25.4; else return (int)fTmp; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void __fastcall TQuickPrint::PrintLines() { // Jump out if there's nothing to print if (fLines->Count == 0) return; // Parse ParseLines(); for (int iLoop = 0; iLoop < TextList->Count; iLoop++) { PrintLine( TextList->Strings[iLoop], iLoop ); } // end for } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::PrintLine(AnsiString asText, int iAlignListIndex) { // Check if we're using WordWrap when printing if (bWordWrap) { // Using WordWrap int iPos1 = 1, iPos2 = 1, iLastSpace = 0 ; AnsiString asTmp; TSize size = TextExtentEx(asText); // Skip the line if it's empty /* if (asText == "") return; else*/ if (uiX+size.cx > MeasureUnitToPixelsHorz(PageWidth)) { do { iPos2++; asTmp = asText.SubString(iPos1, iPos2-iPos1); //size = Canvas->TextExtent(asTmp); size = TextExtentEx(asTmp); if (asTmp[asTmp.Length()] == ' ') iLastSpace = iPos2-1; if (uiX+size.cx > MeasureUnitToPixelsHorz(PageWidth)) { // Check if the iLastSpace is zero (otherwise no text at all would be written) if (iLastSpace==0) iLastSpace = iPos2-1; // Make sure it doesn't extend the frames bottom if (uiY+size.cy >= MeasureUnitToPixelsVert(PageHeight+MarginTop)) NewPage(); // Write string to the canvas // TextOutEx(uiX, uiY, asText.SubString(iPos1, iLastSpace-iPos1)); size = TextExtentEx(asText.SubString(iPos1, iLastSpace-iPos1)); switch((int)AlignList->Items[ iAlignListIndex ]) { case iAlignLeft : TextOutEx(uiX, uiY, asText.SubString(iPos1, iLastSpace-iPos1)); break; case iAlignCenter : TextOutEx((MeasureUnitToPixelsHorz(PageWidth+PhysicalOffsetX/2)-size.cx)/2, uiY, asText.SubString(iPos1, iLastSpace-iPos1)); break; case iAlignRight : TextOutEx(MeasureUnitToPixelsHorz(PageWidth+PhysicalOffsetX)-size.cx, uiY, asText.SubString(iPos1, iLastSpace-iPos1)); break; } // end switch iPos2 = iLastSpace+1; iLastSpace = 0; iPos1 = iPos2; } // end if } while(iPos2 <= asText.Length()); } else { iPos1 = 1; iPos2 = asText.Length(); } // end if // Write the rest of the string (or the entire string, incase there was no WordWrapping required) // Make sure we don't extend the bottom of the box if (uiY+size.cy >= MeasureUnitToPixelsVert(PageHeight+MarginTop)) NewPage(); switch((int)AlignList->Items[ iAlignListIndex ]) { case iAlignLeft : TextOutEx(uiX, uiY, asText.SubString(iPos1, iPos2-iPos1+1)); break; case iAlignCenter : TextOutEx((MeasureUnitToPixelsHorz(PageWidth+PhysicalOffsetX/2)-size.cx)/2, uiY, asText.SubString(iPos1, iPos2-iPos1+1)); break; case iAlignRight : TextOutEx(MeasureUnitToPixelsHorz(PageWidth+PhysicalOffsetX)-size.cx, uiY, asText.SubString(iPos1, iPos2-iPos1+1)); break; } // end switch /* if (AlignList->Items[ iLoop ] ) { //Canvas->TextOut(Rect.Left + (Rect.Right-Rect.Left-size.cx)/2-4, Rect.Top+size.cy*iLineNo, asText.SubString(iPos1, iPos2-iPos1+1)); TextOutEx(Rect.Left + (Rect.Right-Rect.Left-size.cx)/2-4, Rect.Top+size.cy*iLineNo, asText.SubString(iPos1, iPos2-iPos1+1)); } else TextOutEx(Rect.Left, Rect.Top+size.cy*iLineNo, asText.SubString(iPos1, iPos2-iPos1+1)); //Canvas->TextOut(Rect.Left, Rect.Top+size.cy*iLineNo, asText.SubString(iPos1, iPos2-iPos1+1)); */ } else { // Not using WordWrap TSize size = TextExtentEx(asText); // Make sure we don't extend the bottom of the box if (uiY+size.cy >= MeasureUnitToPixelsVert(PageHeight+MarginTop)) NewPage(); switch((int)AlignList->Items[ iAlignListIndex ]) { case iAlignLeft : TextOutEx(uiX, uiY, asText); break; case iAlignCenter : TextOutEx((MeasureUnitToPixelsVert(PageWidth+PhysicalOffsetX/2)-size.cx)/2, uiY, asText); break; case iAlignRight : TextOutEx(MeasureUnitToPixelsVert(PageWidth+PhysicalOffsetX)-size.cx, uiY, asText); break; } // end switch } } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::BeginDoc() { try { // Set the title of the print job Printer()->Title = PrintTitle; // Tell the printer that we're starting a new print job Printer()->BeginDoc(); } catch(...) { throw("Unable to Start new Print Job"); } // Check if OnBeginDoc is assigned. If it is then fire an event. if ( fOnBeginDoc ) fOnBeginDoc(this); // Init // uiX = 0; uiY = MeasureUnitToPixelsVert( MarginTop ); uiLines = 0; uiPageNumber = 0; // Start a new page NewPage(); } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::EndDoc() { try { Printer()->EndDoc(); } catch(...) { throw("Unable to Finish Print Job"); } // Check if OnEndDoc is assigned. If it is then fire an event. if (fOnEndDoc) fOnEndDoc(this); } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::AbortDoc() { try { Printer()->Abort(); } catch(...) { throw("Unable to Abort Print Job"); } // Check if OnAbortDoc is assigned. If it is then fire an event. if (fOnAbortDoc) fOnAbortDoc(this); } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::NewPage() { try { // If this is the very first page, don't set the new page on the printer if (uiPageNumber != 0) Printer()->NewPage(); } catch(...) { throw("Unable to Set New Page"); } // Update uiPageNumber++; // Check if we should print the page number if (PrintPageNo) { // Currently the page number is printed centered below the bottommargin TSize size = Printer()->Canvas->TextExtent( IntToStr(uiPageNumber) ); Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz((PhysicalPageWidth/2-PhysicalOffsetX))-size.cx/2, MeasureUnitToPixelsVert(PhysicalPageHeight-PhysicalOffsetY)-2*size.cy, IntToStr(uiPageNumber)); } // Init all vars used uiX = 0, uiY = MeasureUnitToPixelsVert(MarginTop-PhysicalOffsetY); uiLines = 0; // Check if OnNewPage is assigned. If it is then fire an event. if (fOnNewPage) fOnNewPage(this); } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::Print(float fX, float fY, AnsiString asText) { // Init TextList->Clear(); AlignList->Clear(); // Parse ParseLine(asText); // Set start point uiX = MeasureUnitToPixelsHorz(fX); uiY = MeasureUnitToPixelsVert(fY)+MeasureUnitToPixelsVert(MarginTop-PhysicalOffsetY); // Print for (int iLoop = 0; iLoop < TextList->Count; iLoop++) { PrintLine( TextList->Strings[iLoop], iLoop ); } // end for } //--------------------------------------------------------------------------- // HTML Align tag Parse the contents of Lines. We assume that Lines is not empty! void __fastcall TQuickPrint::ParseLines() { // Init AlignList->Clear(); TextList->Clear(); // Parse the contents of Lines for (int iLoop=0; iLoop < Lines->Count; iLoop++) { ParseLine( Lines->Strings[ iLoop ] ); } // end for } //--------------------------------------------------------------------------- // HTML Align tag Parse contents of asText // NOTE: This might not be the best and most efficient parser, but it does what // it should well ;) void __fastcall TQuickPrint::ParseLine(AnsiString asText) { // Local variables int iLastPos = 1; int iEndPos; int iStartPos; int iAlign = iAlignLeft; int iEndOfTagAlign = iAlignLeft; // Used to set the proper align while(1) { // Start parsing the line // Check if it contains a HTML tag // Find the start of the tag SEARCH_AGAIN: if (asText == "") { TextList->Add(asText); AlignList->Add((void*)iAlign); return; } iStartPos = FindNext(asText,"<", iLastPos); if (iStartPos == 0) { // It didn't contain a start of tag TextList->Add(asText); AlignList->Add((void*)iAlign); return; } // Check if it an end of tag (contains ">" without the (")) iEndPos = FindNext(asText,">", iLastPos); if (iEndPos == 0) { TextList->Add(asText); AlignList->Add((void*)iAlign); return; } else if (iEndPos < iStartPos) { iLastPos = iEndPos+1; goto SEARCH_AGAIN; } AnsiString asTmp = asText.SubString(iStartPos+1, iEndPos-iStartPos-1).UpperCase(); if ( asTmp == "CENTER") { if (iStartPos != 1) { // We're starting on a new line, so move the start of the string to a line for it self asTmp = asText.SubString(1, iStartPos-1); AlignList->Add((void*)iAlign); iEndOfTagAlign = iAlignCenter; TextList->Add(asText.SubString(1, iStartPos-1)); } else { iEndOfTagAlign = iAlignCenter; } iLastPos = 1; asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos).TrimLeft(); iAlign = iAlignCenter; } else if (asTmp == "BR") { TextList->Add(asText.SubString(1, iStartPos-1)); AlignList->Add((void*)iAlign); asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos).TrimLeft(); iLastPos = 1; } else if (asTmp == "RIGHT") { if (iStartPos != 1) { // We're starting on a new line, so move the start of the string to a line for it self asTmp = asText.SubString(1, iStartPos-1); AlignList->Add((void*)iAlign); iEndOfTagAlign = iAlignRight; TextList->Add(asText.SubString(1, iStartPos-1)); } else { iEndOfTagAlign = iAlignRight; } iLastPos = 1; asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos).TrimLeft(); iAlign = iAlignRight; } else if ( asTmp == "/CENTER") { TextList->Add( asText.SubString(1, iStartPos-1)); AlignList->Add((void*)iEndOfTagAlign); asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos).TrimLeft(); iLastPos = 1; iAlign = iAlignLeft; if (asText == "") return; } else if ( asTmp == "/RIGHT") { TextList->Add( asText.SubString(1, iStartPos-1)); AlignList->Add((void*)iEndOfTagAlign); asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos).TrimLeft(); iLastPos = 1; iAlign = iAlignLeft; if (asText == "") return; } else iLastPos = iStartPos+1; } // end while(1) } //--------------------------------------------------------------------------- // Check to see if the line only contains tags (meaning it's empty if all tags are removed) bool __fastcall TQuickPrint::OnlyContainsTags(AnsiString asText) { // Local variables bool bTagsFound = false; int iLastPos = 1; int iEndPos; int iStartPos; while(1) { // Start parsing the line // Check if it contains a HTML tag // Find the start of the tag SEARCH_AGAIN: if (asText == "") { return bTagsFound; } // First char didn't contain a start of tag, therefore the line contains other things // then tags if (asText[1] != '<') return false; iStartPos = FindNext(asText,"<", iLastPos); if (iStartPos == 0) { return false; } // Check if it an end of tag (contains ">" without the (")) iEndPos = FindNext(asText,">", iLastPos); if (iEndPos == 0) { return false; } else if (iEndPos < iStartPos) { iLastPos = iEndPos+1; goto SEARCH_AGAIN; } AnsiString asTmp = asText.SubString(iStartPos+1, iEndPos-iStartPos-1).UpperCase(); if ( asTmp == "B") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "I") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "U") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "STRIKE") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "/B") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "/I") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "/U") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else if ( asTmp == "/STRIKE") { // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; bTagsFound = true; } else { // Unsupported tag asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } } // end while(1) } //--------------------------------------------------------------------------- // Helper function (maybe not the fastest way to do it, but it works ;) // I don't get why AnsiString doesn't have a function like this! int __fastcall TQuickPrint::FindNext(AnsiString asText, AnsiString asFind, int iOldIndex) { // Remember AnsiString is not 0 based ;) AnsiString asTmp; int iIndex = iOldIndex; while(iIndex <= asText.Length()) { asTmp = asText.SubString(iIndex, asFind.Length()); if (asTmp == asFind) return iIndex; else iIndex++; } return 0; } //--------------------------------------------------------------------------- // HTML printing helper function TSize __fastcall TQuickPrint::TextExtentEx(AnsiString asTestText) { // Local variables TSize tmpSize; TFontStyles style = Printer()->Canvas->Font->Style; AnsiString asText = asTestText; int iLastPos = 1; int iEndPos; int iStartPos; /* --- Init --- */ tmpSize.cx = 0; tmpSize.cy = 0; while(1) { // Start parsing the line // Check if it contains a HTML tag // Find the start of the tag SEARCH_AGAIN: if (asText == "") { // Reset style Printer()->Canvas->Font->Style = style; return tmpSize; } iStartPos = FindNext(asText,"<", iLastPos); if (iStartPos == 0) { // It didn't contain a start of tag TSize size = Printer()->Canvas->TextExtent(asText); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Reset style Printer()->Canvas->Font->Style = style; return tmpSize; } // Check if it an end of tag (contains ">" without the (")) iEndPos = FindNext(asText,">", iLastPos); if (iEndPos == 0) { // It didn't contain an end of tag TSize size = Printer()->Canvas->TextExtent(asText); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Reset style Printer()->Canvas->Font->Style = style; return tmpSize; } else if (iEndPos < iStartPos) { iLastPos = iEndPos+1; goto SEARCH_AGAIN; } AnsiString asTmp = asText.SubString(iStartPos+1, iEndPos-iStartPos-1).UpperCase(); if ( asTmp == "B") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsBold; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "I") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsItalic; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "U") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsUnderline; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "STRIKE") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsStrikeOut; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/B") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsBold; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/I") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsItalic; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/U") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsUnderline; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/STRIKE") { // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)); tmpSize.cx += size.cx; // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsStrikeOut; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else { // Unsupported tag // Get extents of current text TSize size = Printer()->Canvas->TextExtent(asText.SubString(1, iEndPos)); tmpSize.cx += size.cx; asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); // Check if we need to update cy if (size.cy > tmpSize.cy) tmpSize.cy = size.cy; iLastPos = 1; } } // end while(1) } //--------------------------------------------------------------------------- void __fastcall TQuickPrint::TextOutEx(int X, int Y, const AnsiString asTextOut) { // Local variables AnsiString asText = asTextOut; TSize tmpSize; tmpSize.cx = 0; int iLastPos = 1; int iEndPos; int iStartPos; // Set linespacing vars float fLineSpace; if (LineSpacing == HalfSpace) fLineSpace = 0.5; else if (LineSpacing == SingleSpace) fLineSpace = 1.0; else if (LineSpacing == SingleAndAHalf) fLineSpace = 1.5; else if (LineSpacing == DoubleSpace) fLineSpace = 2.0; iLineHeight = Printer()->Canvas->TextHeight(asTextOut); while(1) { // Start parsing the line // Check if it contains a HTML tag // Find the start of the tag SEARCH_AGAIN: if (asText == "") { if (!OnlyContainsTags(asTextOut)) { // Update the vars uiY += iLineHeight*fLineSpace; uiX = 0; uiLines++; // Fire event? if (fOnNewLine) fOnNewLine(this); } return; } iStartPos = FindNext(asText,"<", iLastPos); if (iStartPos == 0) { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText); // Update the vars uiY += iLineHeight*fLineSpace; uiX = 0; uiLines++; // Fire event? if (fOnNewLine) fOnNewLine(this); return; } // Check if it an end of tag (contains ">" without the (")) iEndPos = FindNext(asText,">", iLastPos); if (iEndPos == 0) { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText); break; } else if (iEndPos < iStartPos) { iLastPos = iEndPos+1; goto SEARCH_AGAIN; } AnsiString asTmp = asText.SubString(iStartPos+1, iEndPos-iStartPos-1).UpperCase(); if ( asTmp == "B") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsBold; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "I") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsItalic; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "U") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsUnderline; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "STRIKE") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style << fsStrikeOut; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/B") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsBold; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/I") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsItalic; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/U") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsUnderline; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else if ( asTmp == "/STRIKE") { Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iStartPos-1)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iStartPos-1)).cx; // Set new font Printer()->Canvas->Font->Style = Printer()->Canvas->Font->Style >> fsStrikeOut; // Skip the <..> part asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } else { // Unsupported tag Printer()->Canvas->TextOut(MeasureUnitToPixelsHorz(MarginLeft-PhysicalOffsetX)+tmpSize.cx+X, Y, asText.SubString(1, iEndPos)); tmpSize.cx += Printer()->Canvas->TextExtent(asText.SubString(1, iEndPos)).cx; asText = asText.SubString(iEndPos+1, asText.Length()-iEndPos); iLastPos = 1; } } // end while(1) // Update uiX and uiY uiX += tmpSize.cx; uiY += iLineHeight*fLineSpace; // Fire event? if (fOnNewLine) fOnNewLine(this); } //---------------------------------------------------------------------------