                        README - TstRpt23

        Tools for printing from textfiles with multi fonts and graphics
        ---------------------------------------------------------------
                        For use with both FW and FWH

The key original files in this set are TRept23.prg, ToText.prg and Printpos.prg

   TRept23 - This reads either a textfile or a large text memvar passed to it
             to print out a report via TReport, with multi fonts and graphics
             that are coded into the text in a manner similar to HTML coding.

             Rept23.prg is the functionally still-current non-oop version
             upon which TRept23 is based. It can do everything that Trept23 
             does. Anyone who wants to see an example of how to convert a 
             procedural program to OOP may wish to compare the two versions.

   ToText  - A translator that takes output form old Clipper DOS report prg's
             in the @ SAY etc. format and converts the output into a text
             file that can be read by TRept23, including enhancing those
             reports with multi-fonts and graphics.

   Printpos - A utility to adjust the horiz and vert alignment of blocks of 
             text and graphics. Things get out of alignment if a report was
             originally designed for 300 DPI and is then printed on a
             600 or 1200 DPI printer. This enables you easily fix those
             misalignment of text problems for the printer that you're using.

   TstRpt23.prg - the demo app that makes calls to TRept23, etc.

   TstRpt23.exe - This package comes with an xHb/FWH .EXE already included, so
             you can immediately operate the TstRpt23 demo. The reports menu
             enables you to preview/print two sample reports demonstrating
             the use of multiple fonts and graphics. If text doesn't line up
             right, then use the Utilities menu to access the Printing
             Position Adjustments feature. It's dialog enables you to print
             out a testgrid to identify what adjustments to make via the
             dialog's controls.

   Buildit.bat - this will compile and link all PRG's to create a 16 bit
             FW demo executable, TstRpt23.exe . The same thing can be done
             in xHarbour - just refer to TstRpt23.lnk for the files list.


   Silvio -
     Please take a look at Projlist.prg and its companion RRGENRC.prg, which
      illustrate the logic of how R&R creates a report with header, body,
      footer, etc.  - the typical "bands" of a report.

     Projlist.prg, using rrgenrc.prg functions, creates a report in a cText
     memory variable that it sends to TRept23 for processing via TReport.

Sample report files to demonstrate TREPT23 font and graphics functions...
These report files can be read into TREPT23 and printed out:

   Samplpa1.txt - an employee performance appraisal showing use of various 
                  fonts.

   Samplpa2.txt - a summary version of the same performance appraisal using
                  graphic boxes and shading.

   Orglogo.bmp - a sample logo called up by the Samplpa2.txt report.




   Printpos.prg - a utility program module used to test and set print head
                  positioning, via app.ini settings.

   Printpos.dll & .rc - contains the dialog used by Printpos.prg - just use 
                  Borland Resource Workshop to import this resource into your 
                  app's screens .dll or .rc file. There is also Printp32.dll
                  for use with Harbour/xHarbour.

   Printest.txt - A report used by Printpos.prg to test printer alignment
                  positioning.


The versions of Report.prg and Rpreview and their companion files have some
minor modifications, as noted. TRept23 and ToText, however, should work fine
with the standard versions. Note that my version of the preview screen is
a little different as to the instructions and info on the toolbar, as
compared with the standard version.

Here are explanatory comments taken from the PRG's to make it easier for you
to print and read these explanations...

/*------------------------------------------------------------------------------
  TREPT23.PRG (OOP version) and REPT.PRG (prior procedural version)
  -  by Roger Seiler: roger@leadersoft.com     Mar. 12, 2005

  Non-oop version. Originally written in 1995. Many enhancements since then.

  This PRG is for both 16 bit FW and 32 bit FWH

  Printing .TXT files or cText memvar passed from report creation .prg.
     Also includes specifying font by field and underlaying of boxes, shadows,
     lines, and bitmaps. See explanatory note at bottom of this file.

   Adapt this program to print text file output from other report generators
   that create Clipper DOS code such as Bandit, R&R Code Generator, or if just 
   directly coded in Clipper.  To "instantly" convert to FiveWin any such  
   pre-existing Clipper DOS reports, just re-program the lead-in screen 
   prompts in FiveWin. Then tack on the Clipper DOS procedural code that 
   actually creates the report - BUT be sure to have the report output to 
   disk as a .TXT file. Then use this .PRG to get FiveWin to print the .TXT 
   file or report text memvar passed as a parameter.

   A full explanation of the special codes for fonts and graphics is at the
   bottom of this file. Also info on how to access this from program.

   To aid in the conversion of hard coded Clipper reports to create output
   that can be printed with Trept23, use ToText.prg accompanying this prg.

   IMPORTANT: Make sure that PREVIEW.DLL (from \fivewin\samples\report or
   from \fivewin\dll subdir) has been copied into your application
   subdirectory so that the Report Engine can have access to the dialog
   resources it needs when running in your application.  This .dll must be
   distributed with your ap.  Otherwise you'll get an error: CAN'T CREATE
   DIALOG etc. With FWH, use PREV32.DLL for 32 bits.


Explanation of special codes for font assignment by field and also codes
for printing boxes, lines, shades and bitmaps.

FONTS

You can specify up to 6 different fonts to be used in a report. Pass them
to REPT23() in an array, aFonts, in the following layout:

aFonts := {;
          {"TIMES NEW ROMAN", 0,-11, ""},;
          {"TIMES NEW ROMAN", 0,-11, "BOLD"},;
          {"TIMES NEW ROMAN", 0,-11, "ITALIC"},;
          {"", 0,0, ""},;
          {"ARIAL", 0,-14, "BOLD"},;
          {"ARIAL", 0,-24, "BOLD"};
          }

          Each array element has the font name, the width ("0"), the height
          (always a negative "points" number, and whether the font is
          standard (""), "BOLD" or "ITALIC". If the specs are blank, then
          the default Courier 0,-12 font is used, as specified in REPT23.

The call to REPT23 is as follows:   (calling TRept23 is similar)

    lPrnstat := Rept23(cFile,cText,aFonts,aSpool,lPreview)

    Relevant Parameters:
      cFile  ...   If printing a report stored in a text file, 
                   the name of the file.
      cText  ...   If printing from a report created in a text string memory
                   variable, the name of that string memvar.
      aFonts ...   The array with the fonts used in the report, as above. 
      aSpool ...   If using in 16 bit FW app, and if report's memvar will
                   exceed 64k, then due to 64k memvar limit, pass in an array
                   with names of sequential text files, each containing a
                   sequential portion of the report.
      lPreview ... Whether output shall go to on-screen preview tool, RPreview.
      nMargin ...  Number of pixels from left edge of paper to force position
                   of printing, overriding regular left margin. (For graphics.)

In the cText or cFile text sent to REPT23, the indication of font codes is
done in a way similar to HTML program code, in that the font codes are 
contained within < > symbols. Example: <f1> which means to use the first font
in the fonts array. The font code must be placed in front of the field
of text to which it applies. The space taken by the font code does not count
as part of the text length of the line, so if your line length is set at
70 characters, and you have a line with 69 characters plus a 3 character font
code at the beginning, it just counts as a 69 character line as far as margins
and printed line length are concerned.

Using the fonts specified in the array above, you could specify fonts
for various fields as shown in this example of text to be printed:

   <f2>My Favorite Poem... <f3 s4>by Anonymous Artist

   <f1>Mary had a little lamb
            whose fleece were white as snow.

            <f3 p450>To be continued...

In the text above, <f2> means that "My Favorite Poem..." will be printed in 
Times Roman Bold, 11 point type.  Next, <f3 s4> says that "by Anonymous Artist" 
will be printed in Times Roman Italic, also 11 point, and that the print head
is to move 4 extra spaces to the right before printing this field after
printing the previous field. This is to allow a way of adding compensating 
spaces when converting from Courier same-space characters (in which the
report may have been designed) to a proportional space type style like
Times Roman. So if converting to a proportional space font (which bunches up
blank spaces into much less space than same-space typewriter style Courier
font) causes there to be less space between two fields of text than you want, 
then use the spaces code "s" and the number of spaces you want added. Just 
insert this code right after the fint code within the same pointed brackets
as shown above.

"Mary had a little lamb" will be printed in Times Roman Standard font, 
11 point size, and so will the next line.  A font stays in effect for all
following text until a new font code appears.

The last line, "To be continued..." is printed in Times Roman Italic, 11 point,
as specified by <f3.  The p450> means that the printhead is to jump to the
right 450 pixels and then start printing this field of text at that point. This
"P" function is more precise than the "s" function for positioning the
beginning of printing at a specific place on the line. BUT, there is a
problem - the "p" code assumes that the printer is set at 300 DPI. Many 
printers are set at a higher DPI, like 1200 DPI on some laser printers. In
that case, telling the printhead to start printing at 450 pixels will cause
printing to start at about 1/4 the distance that it would print if 300 DPI
was used. The solution is a multiplier code, pulled from the application's
.INI file that tells what the "p" number should be multiplied by in order
to get the correct position on the printer being used.  So if 1200 DPI is
used, the multiplier would be 4.  Near the top of the SayMemo() function,
the .INI file is queried to get the nMultPoint factor, which is the multiplier
to compensate for a greater DPI.

GRAPHICS CODES - Boxes, Lines, Shades and Bitmaps

This is the really fun part! Changing fonts appropriately from one section
of text to another can greatly improve the look of your report. In addition,
adding boxes, shades, lines and bitmaps can really dress it up nicely. Codes
for doing this use the same kind of < > delimeters as the font codes, and they 
are placed right after the font code at the beginning of the field to which
the code applies, as shown in the example below.

An important concept to remember, is that before printing a page, the program
first lays out all the graphics for a line in a memory buffer, and then lays
down the text on top of the graphics.  That is why we have to specify the
graphic element used with a text field BEFORE we write the text of the field,
just as we have to specify the font for the field before printing it.

An interesting problem is how to deal with placing a box around variable length
text fields - like text coming from variable length memo fields. The graphic
codes for the box, with its dimensions, must be specified BEFORE printing the
field, yet we won't know where the bottom line of the box should be until
we finish printing the text, which may extend several lines down the page. 
This problem is solved by placing a <e> code ("extension") at the beginning of
each line of text from the variable field. When the program sees this <e> code,
it updates the nBottom dimension of the last box defined prior to this
<e> code.  It keeps updating the nBot dimension as each line is printed,
until the last line is laid down, and then that update becomes the final
nBot dimension that determines the bottom of the box.  The same principle
applies to the printing of vertical lines, except that an <h> code ("height")
is used to trigger the updating of the nBot dimension of the line.

However, if a variable length area that is to be boxed or have a vertical line
continues from the bottom of one page to the top of the next, then weird
things will happen unless the box and/or line is ended at the bottom of the
first page and then restarted at the top of the next page. This is
accomplished by using two static variables, lV := .t. and cGraphics := "<box &
line specs>". When the EndP() procedure is called in the report program to
check if the end of the page has been reached, if it finds a new page is to be
started, and if both lBoxes and lV are true, then <e><h> codes are inserted
at the end of the line just printed in order to make the printer end the
box and line at the bottom of the first page for the variable area. Then the
HeadP() procedure, which prints the header at the top of the next page,
refers to the lV and cGraphics variables to insert the box and line specs
at the beginning of the first line of text of the new page, in order to
restart the box and/or line for the variable area as it continues on
the new page.

Before we look at the sample below, one more critical item: you must place
a <t> code somewhere on the first line of text of your report to let REPT23
know that you are using graphic codes in this report. If it doesn't see this
<t> code, then REPT23 won't do the necessary setup step needed for printing
graphics. However, if it does see this code, then it executes the BoxSpecs()
setup function. This function, executed at the beginning of REPT23, scans the
entire text of the report for graphics codes, and then loads them into a
multi-dimension array for the program's reference during printing. Each row
of the array is keyed by page and line number so that the program can find
the graphic specs that apply to each line as it prints each line.  As each
line is printed, BoxWork() is executed to take care of implementing the
graphics, with reference to the aBoxSpecs array created by the BoxSpecs()
function.

There are 7 graphic codes:
   b  ... print a box
   c  ... print a box filled in with a shading
   s  ... print a shaded area without a box outline
   l  ... print a line
   e  ... extend the bottom of box
   h  ... (height) extend the bottom of a vertical line
   g  ... (graphic) print a bitmap

The syntax for a graphic code is as follows:

   <cGraphicCode nTop,nLft,nBot,nRt,nLinewidth,cBitmapName>
   
nTop, nLft, nBot and nRt are positional parameters that are measured
in inches. nLft and nRt are measured horizontally from the left edge of page, 
and nTop and nBot are measured vertically from the bottom edge of the line - 
where an underline character would be in the line.

During processing, the program automatically calculates the vertical position
from the top edge of the page for each nTop and nBot parameter by adding in
the top page margin plus the distance down from the top of the page based
on what line we are in and the assumption that we are using 6 vertical lines
to the inch.

Here is an example of using the graphic codes:

   <t><g -.27,.83,0,1.3,1,,orglogo.bmp>

   <f2><b -.2,.93,0,7.2,1,,>My Favorite Poem... <f3 s4>by Anonymous Artist

   <f1>Mary had a little lamb
            whose fleece were white as snow.

            <f3 p450>To be continued...

*/

*---------------------------------------------------------------------

* ToText.PRG - for use with both 16 bit FW and 32 bit FWH

/*
  By Roger Seiler - first written in 12/96; many revisions since then.

  This is a tool for converting old Clipper DOS reports into Windows
  reports that are printed via TRept23 and TReport.

  ( Also includes MemWrap() function for selecting one word-wrapped line 
  at a time for printing. This and GetText() and GetText2() are called
  from outside - not called from proc ToText(). )

  The main concept here is that a report is constructed inside a cText 
  filewide static, line by line. Each new line of text is constructed
  field by field into cNewLine.  When finished building a line in cNewLine,
  then cNewLine is added to the end of cText, and then the next new line
  is started.  When the report is finished being assembled, then the calling 
  proc makes a call to the GetText() function here to retrieve cText and then 
  sends it on to Rept23() for printing.

  The text sent to this proc in "cLine" uses the standard Clipper 
  "@ nRow, nCol SAY text" format, so we use AT() to find the "@" symbol, 
  the "," and the "SAY" word in order to find nRow, nCol and the text that
  we need to work with here.  In addition, if the text element comes from a 
  memvar instead of being passed as a quoted string, i.e. "some text", then
  it gets passed as a parameter in place of the dummy cMemvar. But if a quoted
  string is used for the text in the "@ nRow, nCol SAY text" statement,
  then the empty dummy cMemvar is passed.

  Note that this proc currently assumes that cText will not build up to
  over 64K.  If it does, then whoops, you've got a GPF (Go Pray Faithfully).

*/

/* Sample report code that calls ToText() to assemble the report as a
   text memvar and then saves that memvar to disk as a text file which
   will be read and printed by TRept23. Alternatively, the text memvar can
   just be passed directly to TRept23():New() as the second parameter leaving 
   the first parameter empty.

// A code excerpt from a typical report...

// Max Page length = 55
IF(nRow < 55,nRow++,nRow := 1)

   // Report header...
IF nRow = 1
   nPage++
   cMemvar := "" // <--- This dummy memvar should be made local

// Just take the old Clipper report code of the @...SAY type, for example:
//     @ 5, 10 SAY "Whatever"  
// and convert it into parameters of the ToText() function call, 
// as for example...

// ToText('@ 5, 10 SAY "Whatever" ', cMemvar)
// Note above the use of single quotes and the dummy parameter cMemvar.

// But where the SAY is a memvar or the result of some function, then replace
// the dummy cMemvar with the real memvar or functional expression, as shown
// below. Also below, note how font and printhead positions are inserted into
// the code for use later by TRept23...

   ToText('@ nRow,   1 SAY DTOC(DATE())', "<f1>"+DTOC(DATE()))
   ToText('@ nRow,  11 SAY TIME()', TIME())    // Passing result of a function.
   ToText('@ nRow,  26 SAY "<f1 p850>Responses Tabulation"', cMemvar)
   ToText('@ nRow,  54 SAY "<f1 p1560>SurCalc4   "', cMemvar)
   ToText('@ nRow,  64 SAY "Page No."', cMemvar)
   ToText('@ nRow,  73 SAY LTRIM(STR(nPage))', LTRIM(STR(nPage)))
   nRow++
   cSurvey := PADC(ALLTRIM(cSurvname),50)
   cSurvey := "<f2 p650>"+cSurvey
   ToText('@ nRow,  11 SAY cSurvey', cSurvey)  // Passing a real memvar here.
   nRow++
   ToText('@ nRow,   1 SAY REPLICATE("_",75)', "<f4>"+REPLICATE("_",75))
   nRow++
   nRow++
ENDIF

   // Print totals triggered by lL4...
IF nRow > 4
    // If start of question is past 55 lines, then push it to next page...
  IF (nRow + nAns + 1) > 55
     nRow := 1
     nPage++
     Header(nPage,cSurvName)
  ENDIF

  cLevel4 := STR(nLevel4,6,2)
  IF SUBSTR(cLevel4,6,1) == "0"
     cLevel4 := SUBSTR(cLevel4,1,5)+" "
     IF SUBSTR(cLevel4,5,1) == "0"
        cLevel4 := SUBSTR(cLevel4,1,3)+"   "
     ENDIF
  ENDIF
  cLevel4 := ALLTRIM(cLevel4)

  IF Itemtyp == "Q"
   ToText('@ nRow,   2 SAY "<f2>Q"', cMemvar)
   ToText('@ nRow,  4 SAY cLevel4+":"', cLevel4+":")
  ENDIF

     // Print the first line of the memo...
  cQ1 := MemWrap(cQtn,9,nLnEnd,@nTxtLen,nRow)  // MemWrap() in ToText.prg
  cQ1 := "<f1>"+cQ1
  ToText('@ nRow,  10 SAY Q1', cQ1)
  nRow++

     // Print all subsequent lines of the memo...
     // (nCnt is a safety factor to prevent endless loop)
  DO WHILE nTxtLen > 0 .AND. nCnt < 25
     cQ2 := MemWrap("",10,nLnEnd,@nTxtLen,nRow)
     cQ2 := "<f1>"+cQ2

     ToText('@ nRow,  10 SAY Q2', cQ2)
     IF(nRow < 55,nRow++,nRow := 1)
     nCnt++
       // Report header...
     IF nRow = 1
        nPage++
        Header(nPage,cSurvName)
     ENDIF
     SysRefresh()
     CursorWait()
  ENDDO
  nCnt := 0

  nRow++


// And so on through the body of the report.

// Then...

// save cText to disk
cText := GetText()  // Retreive cText from ToText.prg, where it is filew static
MEMOWRIT("MyReport.txt", cText)


oRept23 := TRept23():New("MyReport.txt","",,,.t.)  // Now print the report.
oRept23:Activate()
oRept23 := nil


*/