---------------------------------------------------------
The Liberty Basic Newsletter - Issue #65 - FEB 2000
       2000, Cliff Bros and Alyce Watson
             All Rights Reserved
---------------------------------------------------------
In this issue:

    Hard copy printing in Liberty BASIC
        with lbprnt01.dll

In future issues:
    Copyright and licensing considerations
    the FILES command
    Writing and using an ini file
    Writing output 'code'
    Choosing fonts
    RGB color choices
    Changing the runtime icon
    Launching the default web browser and email client
    Installers
---------------------------------------------------------
PRINTING WITH LBPRNT01.DLL

In Newsletter #63, we discussed several ways to achieve
hard copy printouts using Liberty BASIC.  We can use
Liberty BASIC's own LPRINT function for text and the graphics
PRINT function for graphicboxes and graphics windows.  We
can ask Notepad, or other default text editor to print text
for us.  We can use Dean Hodgson's excellent library, 
Deanslib.dll.  We can also "do it all" with api function
calls.

We discussed the vbprint.dll at length, and it is a great
tool.  If only it offered a few more functions...

I've had it in mind to write a printing dll for Liberty BASIC
for some time, and all of this printing discussion has prompted
me to give it a try.  The result is not perfect, but it does
offer some useful functions.

---------------------------------------------------------
LBPRNT01.DLL FOR PRINTING IN LIBERTY BASIC
    BY ALYCE WATSON
    awatson@wctc.net
     Alyce Watson, 2000
    ALL RIGHTS RESERVED

LBprnt01.dll is being released as shareware.  It is not crippled
or time limited, and it contains no nags.  The released version
is the only version there is.  Registration will be on the
honor system.  For use in commercial applications, the one-time
registration fee is $15.00.  For all other uses, the registration
fee is determined by the individual user, with a suggested value
of $1.00.  This will help defray the cost of the many ink
cartridges reams of printer paper that were consumed in writing 
and testing this.  Note that anyone who has purchased the 
CDROM, Windows Programming for Everybody with Liberty BASIC
need not register the DLL, except for commercial use.  Send 
registration fee to:
Alyce Watson
3030 Buchberger Road
Wisconsin Rapids, WI 54494     USA
---------------------------------------------------------

Thanks to these special people, who gave so unselfishly
of their time, their energy, their patience, and their
goodwill:

Carl Courtney  mailto:CarlCourt@aol.com
Eldron Gill    mailto:egill@eritter.net
Bill Jennings  mailto:bbjen@tir.com
Brian Pugh     mailto:bdpugh@hipperholme19.freeserve.co.uk
Dean Hodgson   mailto:dhodgson@nexus.edu.au

Without their help, this DLL would never have seen the
light of day.

Thank you, friends.

---------------------------------------------------------
FUNCTION LIST

PrinterDialog               PrinterInit
EndPrint                    NewPage
PrintTextLocate             PrintTextLine
PrintBlankLine              SetBottomMargin
SetTopMargin                SetLeftMargin
SetRightMargin              GetLineYPos
GetTextLineHeight           ChooseTextRGB
PointSizeFont               PrinterFont
EasyFont                    GetMaxChars
GetMaxCharsTotalWidth       GetAveCharWidth
GetMaxCharWidth             GetNumberCopies
GetDotsInchWidth            GetDotsInchHeight
GetDotsTotalWidth           GetDotsTotalHeight
PrinterNullBrush            PrinterBrush
PrinterPen                  PrintRectangle
PrintLine                   PrintRoundRectangle
PrintEllipse                PrintWindowArea
BitmapWidth                 BitmapHeight
PrintBitmap 
---------------------------------------------------------
GETTING STARTED

You must first open the DLL, of course!

Open "lbprnt01.dll" for dll as #lb

To begin a print job, you must call either PrinterInit or
PrinterDialog.  All other printing functions should be
placed after one of these calls.  When the job is ready
to be sent to the printer, you must call EndPrint.  You
may initialize the printer, print, then call EndPrint as
many times as you need within a program.  When you are
finished with all printing jobs, close the DLL:

close #lb

INITIALIZING THE PRINTER

You may use either of the following calls to initialize
the printer.  Use PrinterDialog if you want to give the
user a chance to cancel the operation, to choose the printer
to use, or to choose the number of copies to print.  The window
handle is the first parameter in the call.  It is best to use
your program window's handle for this parameter, but it may be set 
to zero.  The return from the PrinterDialog function is the
device context of the printer.

    CallDll #lb, "PrinterDialog",_  'must call this to start a document
        h as short,_                'handle of program window
        pDC as short                'nozero if successful = printer DC

PrinterInit does not give the user a chance to cancel the operation,
or to choose number of copies or printer.  It also requires the
window handle as the first parameter and it returns the printer
device context.  In this case, it will be the user's default printer.

    CallDll #lb, "PrinterInit",_    'init with no print dialog
        h as short,_                'window handle
        pDC as short                'nonzero if successful = printer DC

You cannot print anything if the initialization call fails, so be sure
to trap that possiblity in your code.  If pDC = 0, then you do not need
to call EndPrint.  Here is one way:
 
    IF pDC = 0 THEN
        notice "Print job cancelled!"
        goto [loop]
    END IF

When all items to be printed have been added to the document, then
call EndPrint to send the job to the printer.  The EndPrint call will 
release the DC of the printer and eject the final printed page.
After issuing this call, you will need to initialize the printer 
again for a new print job. 

    CallDll #lb, "EndPrint",_   'ends document, ejects final page
        h as short,_            'window handle
        r as short              'nonzero if successful

If you have initialized with PrinterDialog, you can retrieve
the number of copies requested by the user with the GetNumberCopies
function.  You cannot get other information, such as page selections
if the user chooses to print only part of the job, or print quality.
This function does not retrieve the number of pages in each job, but
the number of printouts requested by the user.

    CallDll #lb, "GetNumberCopies",_ 'only works with PrinterDialog call
        h as short,_                 'window handle
        numbercopies as short        'number of copies chosen by user

IMPORTANT NOTICE
PrinterDialog and PrinterInit both return the device context of
the printer, and call StartDoc and StartPage.  If you are familiar
with printer function calls to GDI.DLL, you may place your
own calls in amongst calls to the lbprnt01.dll.  Calling
EndPrint calls EndPage and EndDoc and releases the printer DC.

---------------------------------------------------------
CREATE FONTS

All text will be printed using the font Courier New - 10pt, unless
you choose to create a font of your own.  You do not need to create
a font, but you may do so.  There are three ways to create a font
with this dll.  The easiest way requires only the name of the font
face desired, and the fontheight in hundredths of an inch.  A
fontheight of 25, for instance, would result in a font that is one
quarter of an inch high = 25/100 inch.  Note that the height includes 
the blank space between lines, which is called the "External Leading"
space.  The actual font will be slightly smaller than the height you
specify.  This simple font creation function is called EasyFont.

In Liberty BASIC, when we specify font names, we must replace any blanks
in the name with an underscore character.  "Courier New" becomes
"Courier_New" in Liberty BASIC syntax.  DON'T DO THAT HERE!! Please 
leave blank spaces blank for these font creation functions.  You must 
terminate the string containing the font name with a null character,
which is chr$(0)  Here is the correct syntax for specifying a font
name and height in this dll:

    pfontname$="Courier New" + chr$(0)  'must be null terminated 
    height=24                           'in hundredths of inch

The call to EasyFont requires the window handle, height parameter as 
short, and the fontname parameter as a pointer.  The function
returns the handle of the created font.  If the return is 0, the 
function was unable to create a font.

    CallDll #lb, "EasyFont",_           'easy create font
        h as short,_                    'window handle
        height as short,_               'height in hundedths of inch
        pfontname$ as ptr,_             'null terminated, no LB underscores
        hfont as short                  'returns handle of font


You can create a font with additional attributes, with a call to
PrinterFont.  It has a few more parameters; bold, italic, underline,
and strikeout.  If any of these parameters is set to 1, that attribute 
will be set.  They can be used in any combination, so a font can be
both bold and underlined, for instance.  If an attribute's parameter is
set to 0, that attribute will not be used in the font.  The other 
parameters are exactly the same as for the EasyFont call:

    pfontname$="Courier New" + chr$(0)  'must be null terminated 
                                        'no underscores between words
    height=30                           'in hundredths of inch
    bold=0                              'do not make it bold
    italic=1                            'make it italic
    underline=1                         'make it underlined
    strikeout=0                         'do not make it strikeout

    CallDll #lb, "PrinterFont",_        'create a font with many attributes
        h as short,_                    'window handle
        height as short,_               'height in hundredths of inch
        bold as short,_                 '0=normal  1=bold
        italic as short,_               '0=normal  1=italic
        underline as short,_            '0=normal  1=underline
        strikeout as short,_            '0=normal  1=strikeout
        pfontname$ as ptr,_             'null terminated, no LB underscores
        hfont as short                  'returns handle of font


For the purists, there is another font creation function that allows you
to create fonts in point sizes, rather than in hundredths of an inch.  There 
are approximately 72 points in an inch.  When you use a word processor such
as WordPad, the fonts are sized in points.  All parameters are the same as
in the call to PrinterFont, except that the size attribute for the call,
PointSizeFont is in points instead of hundredths of an inch:

    CallDll #lb, "PointSizeFont",_      'create a font with many attributes
        h as short,_                    'window handle
        height as short,_               'height in points - 72 pts per inch
        bold as short,_                 '0=normal  1=bold
        italic as short,_               '0=normal  1=italic
        underline as short,_            '0=normal  1=underline
        strikeout as short,_            '0=normal  1=strikeout
        pfontname$ as ptr,_             'null terminated, no LB underscores
        hfont as short                  'returns handle of font


SET TEXT COLOR

You may choose an RGB color for text printing.  It requires a struct
containing the color information.  Color values are for red, green,
and blue, and each should be between 0 and 255.  0 means none of a
color, so rgb of 0,0,0 results in black.  255 is total saturation of
a color, so rgb of 255,255,255 is white.  If you wanted pure red, you
would set that value to 255, and the others to 0.  Here's an example:

    struct col,_                'holds info for text color
        red as short,_          'red value = 0-255
        green as short,_        'green value = 0-255
        blue as short           'blue value = 0-255

        col.red.struct = 255       '0-255
        col.green.struct = 0       '0-255
        col.blue.struct = 0        '0-255

    CallDll #lb, "ChooseTextRGB",_
        h as short,_             'handle of window
        col as struct,_          'struct of color info
        r as long                'nonzero if successful

If the user does not have a color printer, text will be printed
in black, no matter what color you set.  This would be true
of a dot matrix printer, for instance.
---------------------------------------------------------
PRINTING TEXT

There are two functions that print text in this dll.  Both
will print one line of text in the default font, or in the
most recently created font, and in the color from 
ChooseTextRGB, if that function has been called.  It is not 
necessary to create a font or to set a text color.  In that 
case, defaults will be used.


**************************************************
********IMPORTANT NOTE ABOUT TEXT PRINTING********
**************************************************

There are two ways to print a line of text with this DLL.
Using PrintTextLocate allows the programmer complete control
over text location on the printed page.  Starting new pages
is the responsibility of the programmer.

Using PrintTextLine lets the DLL print one line after another
at the proper line spacing.  The DLL controls the location
of text on the printed page, starting new pages when needed.

Although these functions may both be used in the same print
job, it is best to use one or the other, and not both, to
preclude the possibility of one function overwriting text that
has been placed on the page by the other function.

**************************************************
********IMPORTANT NOTE ABOUT TEXT PRINTING********
**************************************************
 

PrintTextLocate
The first text print function allows the programmer complete
freedom over text location on the page.  X location and Y
location are set in hundredths of an inch.  Setting xloc to
200 would cause the start of the text to be two inches from
the left margin.  Keep in mind that most printers allow a
printable width of about eight inches, and a printable height 
of about ten and a half inches.  Some newer printers will allow 
nearly the full 8 1/2 inch width and 11 inch height.

You must use a null terminator on each line of text, as you
did for the fontname discussed earlier:

    text$="Some words."+chr$(0)

You also need to determine the length of the text line to
print.  Do NOT include the null terminator in this length,
so if you have added chr$(0) before determining the length,
remember to subtract 1.

    length=len(text$)-1
    xloc=100:yloc=200
    CallDll #lb, "PrintTextLocate",_    'print one line of text
        h as short,_                    'window handle
        text$ as ptr,_                  'text string to print
        xloc as short,_                 'x location in hundredths of inch
        yloc as short,_                 'y location in hundredths of inch
        length as short,_               'length of text string
        r as short                      'nonzero if successful


You can determine the maximum number of characters that will
fit across the width of the printer page, in the current
font, with a call to GetMaxCharsTotalWidth.  This will tell
you how many characters will fit in a line of text if it
begins at the very left edge of the paper, and continues all
of the way to the right edge.  You can use this value to
determine the maximum length of a line to print with
PrintTextLocate:

    CallDll #lb, "GetMaxCharsTotalWidth",_ 'total characters from edge to edge
        h as short,_                       'window handle
        totalmax as short                  'total number of chars that will fit,
                                           'if text starts at left edge


PrintTextLine
Using the previous function to print text requires the programmer
to keep track of the location of all text on the page.  You
can eliminate this need by calling PrintTextLine.  Calls to
this function will print a line of text in the current font and
color, and  within the current margins.  Each subsequent call will 
advance the Y cursor the proper amount for the font size in use.  
It doesn't matter if you change fonts for each line, the next line 
will print at the proper distance from the previously printed line.
The parameters are similar to the PrintTextLocate call, but no
X and Y location are needed:

    text$="Some words."+chr$(0)
    length=len(text$)-1
    CallDll #lb, "PrintTextLine",_  'prints line, moves down automatically each line
        h as short,_                'window handle
        text$ as ptr,_              'text string to print
        length as short,_           'length of text string
        r as short                  'nonzero if successful

If you need to advance the text printing location down the page more than
one line's height, then make a call to PrintBlankLine.  This call can
be made as many times as needed to create the space desired.

    CallDll #lb, "PrintBlankLine",_ 'move cursor down page the height of one line
        h as short,_                'window handle
        r as void                   'no return

When calling PrintTextLine and PrintBlankLine, you do not need
to concern yourself with the location of the bottom of the page.
When the bottom of the page is reached, the page will automatically 
be ejected, and a new page will begin.  This takes the current margins
into account for all four sides of the page.

If you do need to know the location of the Y cursor, which is the Y
location to print the NEXT line with PrintTextLine, you may use
the function GetLineYPos, which returns the location of the Y cursor
in hundredths of an inch.

    CallDll #lb, "GetLineYPos",_    'cursor position for PrintTextLine
        h as short,_                'window handle
        linepos as short            'position of y cursor in hundredths

Remember that the Y cursor is only used by PrintTextLine.  In 
PrintTextLocate, the programmer has complete control over the
location of the text on the page.  If you are not careful, a call
to PrintTextLocate could overwrite lines printed with PrintTextLine.
Calling GetLineYPos will help you determine the lower extent of text
printed with PrintTextLine.

You may retrieve the current line height, as determined by the current
font, with GetTextLineHeight.  This function retrieves the height of
a font, including the space between the previous line of text, and the
top of the font, which is called the External Leading space.  This
line height value is used by the DLL in PrintTextLine to determine 
the y position of each succeeding line of text.  You may retrieve this
value for use in PrintTextLocate, for proper line spacing when you locate
text on the page.  The line height is returned in hundredths of an inch.

    CallDll #lb, "GetTextLineHeight",_  'height for lines in current font
        h as short,_                    'window handle
        lineheight as short             'height in hundredths of text line


Notice that for both PrintTextLocate and PrintTextLine, only one
line of text at a time may be printed.  For PrintTextLine, you
can make a call to GetMaxChars to determine the maximum number
of characters that can be printed across the width of the page,
considering the current page margins:

    CallDll #lb, "GetMaxChars",_    'max for PrintTextLine, current margins
        h as short,_                'window handle
        maxchar as short            'total number of characters that will fit
                                    'in a line within current page margins

You may eject a page and start a new page yourself whenever you
would like, by calling NewPage:

    CallDll #lb, "NewPage",_    'ejects page, starts new one
        h as short,_            'window handle
        r as short              'nonzero if sucessful

You may retrieve the values for the maximum possible width
of a character in the current font, and the value for
the average width of a character, with the following two
functions.  Maximum width and average width will be the same,
or very close to the same for a fixed width font.  They might
vary greatly for a variable width font.  In a fixed width font,
all characters occupy the same space, as on an old-fashioned
typewriter.  In a variable width font, large characters, such as
an upper case letter "M" will take much more space than small
characters such as a lower case "i", a comma, a space, etc.

    CallDll #lb, "GetMaxCharWidth",_    'maximum width of char in current font
        h as short,_                    'window handle
        maxwidth as short               'max char width in printer dots


    CallDll #lb, "GetAveCharWidth",_    'average width of char in current font
        h as short,_                    'window handle
        avewidth as short               'ave char width in printer dots

---------------------------------------------------------
MARGINS for PrintTextLine

Margins are only significant when using the PrintTextLine
function.  The default margins are one inch on all sides.
If you are using PrintTextLocate, you are not restricted,
and you may print right up to all edges of the paper.  You
may change the margins that will be used by PrintTextLine
with the following four functions that allow you to change
only the margins desired.  Remember, the default margins
are all one inch, and needn't be changed unless you desire
to do so.  Margins are set in hundredths of an inch.
Choosing a margin of 50 would result in a half inch
margin:  50/100 = one half inch.

        top=100     'top margin in hundredths of inch
    CallDll #lb, "SetTopMargin",_
        h as short,_    'window handle
        top as short,_  'top margin in hundredths of inch
        r as short      'nonzero if successful

        right=80    'right margin in hundredths of inch
    CallDll #lb, "SetRightMargin",_ 'OPTIONAL
        h as short,_         'window handle
        right as short,_     'right margin in hundredths of inch
        r as short           'nonzero if successful

        bottom=100  'bottom margin in hundredths of inch
    CallDll #lb, "SetBottomMargin",_
        h as short,_          'window handle
        bottom as short,_     'bottom margin in hundredths of inch
        r as short            'nonzero if successful

        left=150    'left margin in hundredths of inch
    CallDll #lb, "SetLeftMargin",_
        h as short,_     'window handle
        left as short,_  'left margin in hundredths of inch
        r as short       'nonzero if successful

---------------------------------------------------------
PRINTER INFORMATION

There are four functions in the DLL that will tell you
information about the printer resolution.  GetDotsInchWidth
will tell you how many printer dots are in one inch of
page width.  My printer has 300 dots per inch.  My previous
printer had 360 dots per inch width.  My old dot matrix
printer has only 75 dots per inch width.  You may also
find out the dots per inch height with a call to
GetDotsInchHeight.  Why do we need both?  Aren't they the
same?  No!  On some printers there are more dots in one
direction than in the other.

    CallDll #lb, "GetDotsInchWidth",_
        h as short,_    'window handle
        dpix as short   'dots per inch in width

    CallDll #lb, "GetDotsInchHeight",_
        h as short,_    'window handle
        dpiy as short   'dots per inch in height

The other measurements of printer resolution in the dll are
for total dots per width and height of the paper.  In
general, the total dots per width will be equal to the
dots per inch width multiplied by 8 -- the number of inches
that may be printed by most printers.  My printer has
300 dots per inch width, and 2400 total dots per page width.
In the same way, the total dots in the height will be equal
to the number of dots per inch in height multiplied by 10 1/2.
Here are the calls to get total dots:

    CallDll #lb, "GetDotsTotalWidth",_
        h as short,_       'window handle
        dotswide as short  'total dots in width

    CallDll #lb, "GetDotsTotalHeight",_
        h as short,_       'window handle
        dotshigh as short  'total dots in height

If you want to know the width of a page in printable inches,
then divide the Total Dots Width by the Dots per Inch Width.

    inchesWide=dotswide/dpix

The same is true for height in inches:
    
    inchesHigh=dotshigh/dpiy

---------------------------------------------------------
GRAPHICS

LINE
There are four graphics entities that can be printed with
the dll.  The first is PrintLine.  The parameters x1 and y1
specify the starting point of the line, in hundredths of an
inch, on the printed page.  The parameters x2 and y2 specify
the ending points of the line.  You may draw as many lines
as you would like.

    CallDll #lb, "PrintLine",_
        h as short,_        'window handle
        x1 as short,_       'x origin in hundredths of inch
        y1 as short,_       'y origin in hundredths of inch
        x2 as short,_       'x end    in hundredths of inch
        y2 as short,_       'y end    in hundredths of inch
        r as short          'nonzero if successful


RECTANGLE
Printing a rectangle is quite similar to printing a line.  The
parameters x1 and y1 specify the coordinates for the starting
corner of the rectangle -- usually the upper left corner is used.
The parameters x2 and y2 specify the coordinates for the corner
opposite the starting corner.  If the upper left corner was determined
by the x1, y1 parameters, then the x2, y2 parameters would specify
the coordinates for the lower right corner of the rectangle.  All
coordinates are in hundredths of an inch locations on the printed
page.

    CallDll #lb, "PrintRectangle",_ 'measure in hundredths of inch
        h as short,_        'window handle
        x1 as short,_       'x origin corner
        y1 as short,_       'y origin corner
        x2 as short,_       'x end opposite corner
        y2 as short,_       'y end oppposite corner
        r as short          'nonzero if successful


ELLIPSE
The call to print an ellipse is very similar to the PrintRectangle call.  
This is because the parameters also specify a rectangular shape, in
just the same way as they did in the PrintRectangle call.  This
rectangle will not be visible, but it will be the bounding rectangle
for the ellipse.  The ellipse will be drawn so that its edges intersect
the bounding rectangle on all four sides.

    CallDll #lb, "PrintEllipse",_  'measure in hundredths of inch
        h as short,_        'window handle
        x1 as short,_       'x origin corner - bounding rectangle
        y1 as short,_       'y origin corner - bounding rectangle
        x2 as short,_       'x end opposite corner - bounding rectangle
        y2 as short,_       'y end oppposite corner - bounding rectangle
        r as short          'nonzero if successful


ROUND RECTANGLE
The call to PrintRoundRectangle is indentical to the PrintRectangle call
except that it contains two more parameters.  The x3 parameter specifies
the width of a small ellipse that will be used to round the corners of
the rectangle.  The y3 parameter specifies the height of the small
ellipse that will be used to round the corners.  The larger these
numbers in relation to the size of the Round Rectangle, the more rounded
the corners will be.  A small relative size of the x3 and y3 parameters
will create sharper curves on the corners of the round rectangle.

    CallDll #lb, "PrintRoundRectangle",_  'measure in hundredths of inch
        h as short,_        'window handle
        x1 as short,_       'x origin corner
        y1 as short,_       'y origin corner
        x2 as short,_       'x end opposite corner
        y2 as short,_       'y end oppposite corner
        x3 as short,_       'corner ellipse width
        y3 as short,_       'corner ellipse height
        r as short          'nonzero if successful

---------------------------------------------------------
COLOR IN GRAPHICS

PRINTER PEN
Objects are drawn with black lines unless changed by programmer.  The
drawing pen can be altered in width, style and color, by calling the
PrinterPen function.  You may set the color for any pen style.  As
in the ChooseTextRGB function, the values for red, green, and blue may
be between 0-255, with 0, 0, 0 being black.  You may set the size of
the pen for the pen style _PS_SOLID.  This size will be in logical
units, which in this case are printer dots.  You may call the function
GetDotsInchWidth to determine the best number of dots for the pen size,
if this is important in your graphics.  For instance, with a dots per 
inch of 300, a size of 75 would give a one quarter inch thick pen.

You may set the style of the pen also.  All styles other than a solid
pen default to size 1.  Here are the possible styles:

    '0 = _PS_SOLID       PS = PEN STYLE
    '1 = _PS_DASH
    '2 = _PS_DOT;
    '3 = _PS_DASHDOT
    '4 = _PS_DASHDOTDOT
    '> 4 THEN default is _PS_SOLID

'NOTE if style > 0 then size reverts to 1 pixel

The PrinterPen function returns the handle of the created pen,
if successful.

    CallDll #lb, "PrinterPen",_ 'shapes outlined with pen
        h as short,_        'window handle
        size as short,_     'size in dots
        style as short,_    'pen style
        pred as short,_     'red value 0-255
        pgreen as short,_   'green 0-255
        pblue as short,_    'blue 0-255
        hPen as short       'returns handle of pen


PRINTER BRUSH
Objects are filled with hollow brush unless changed by programmer.        
Unless you specify a brush, your drawn objects will just be
outlines.  You must again specify the rgb color values for the
brush, just as for the PrinterPen and ChooseTextRGB functions.
You must also choose a brush style.  To fill shapes with a solid
color, choose a style value of 6.  The other style patterns are
as follows:

    '0 = _HS_HORIZONTAL    HS = HATCH STYLE
    '1 = _HS_VERTICAL
    '2 = _HS_FDIAGONAL
    '3 = _HS_BDIAGONAL
    '4 = _HS_CROSS
    '5 = _HS_DIAGCROSS
    '6 will give a solid fill = no pattern

The PrinterBrush function returns the handle of the created brush,
if successful.

    CallDll #lb, "PrinterBrush",_ 'fills graphics entities
        h as short,_        'window handle
        style as short,_    '6=solid, 0-5 are hatch styles
        pred as short,_     'red value 0-255
        pgreen as short,_   'green 0-255
        pblue as short,_    'blue 0-255
        hBrush as short     'returns handle of brush

If you have created a PrinterBrush, then have a need to
return to a hollow brush to draw outline figures only,
then call PrinterNullBrush.

The PrinterNullBrush function returns the handle of the created 
brush, if successful.

    CallDll #lb, "PrinterNullBrush",_  'allows you to return to default hollow figure
        h as short,_    'window handle
        hBrush as short 'returns handle of brush
---------------------------------------------------------
SCREEN PRINT

*************** WARNING ************************
IN TESTS, THIS FUNCTION SOMETIMES RESULTED IN
A GRAYSCALE PRINTOUT, RATHER THAN A COLOR PRINTOUT.
WHEN IT PRINTS IN COLOR, IT MAY NOT APPEAR THE
SAME AS THE SCREEN DISPLAY VERSION.
*************** WARNING ************************

As we've discussed in a previous newsletter, the graphics
printing capabilities of Liberty BASIC have some limitations.
The PrintWindowArea function will allow some graphics printing
flexibility.  The first parameter required is the window's
handle.  YOU MUST USE THE HANDLE OF THE GRAPHICS WINDOW OR
GRAPHICBOX  - you may not use 0 for this parameter in this
function.  After the window handle parameter, there are four 
parameters that specify the location and size of the screen 
image to capture.  You need not take the entire image.  The xorg 
and yorg are the coordinates of the upper left corner of the 
desired area, in PIXELS!  Remember that pixels are the logical 
units of the display, so the measurements for the screen are in 
pixels.  The width and height parameters tell the function how much 
of the screen to copy to the printer, in pixels.  If you wanted to 
capture the image from x = 10, y = 33, and take an area that is 
100 pixels by 227 pixels:

    xorg=10
    yorg=33
    width=100
    height= 227

The next four parameters are the ones that tell the printer where
to locate the screen image on the page, and how large to make it.  
These values are all given in hundredths of an inch.  The params,
pxorg and pyorg will define the location of the upper left corner
of the screen image on the printed page, in hundredths of an inch.
If you wanted the image to begin 2 1/2 inches from the left side
of the page, you would have pxorg = 250.

The next two parameters tell the printer how wide and high you
want to make the image -- again in hundredths of an inch.  If
you wanted the image to be four inches wide, then pwidth = 400.

    CallDll #lb, "PrintWindowArea",_
        h as short,_        'valid window handle NOT = 0 !
        xorg as short,_     'starting x pixel for print
        yorg as short,_     'starting y pixel for print
        width as short,_    'pixel width from screen
        height as short,_   'pixel height from screen
        pxorg as short,_    'x loc on page in hundredths of inch
        pyorg as short,_    'y loc on page in hundredths of inch
        pwidth as short,_   'width of image on page in hundredths of inch
        pheight as short,_  'height of image on page in hundredths of inch
        r as short          'nonzero if successful

There have been some reports that this function results in a
grayscale printout on some systems.  Please take this into
consideration when using this function.
---------------------------------------------------------
BITMAP PRINT

You may print a hard copy of any bitmap that is loaded
into memory.  The bitmap may be loaded with Liberty BASIC's
LOADBMP function, or it may be an image loaded from a third-
party DLL.  You must have the handle of the bitmap to pass
into the call.  If the image was loaded with an add-on DLL,
you will likely get the handle of the bitmap as the return from
the loading function.  In Liberty BASIC, we get the handle
of a bitmap with the HBMP function.  The syntax would be:

    loadbmp "party","party.bmp"
    hbitmap = hbmp("party")

After the window handle and the bitmap handle, you must specify
the coordinates for the location and size to print the bitmap
on the paper.  These values are in hundredths of an inch.
The point x1, y1 will determine the upper left corner for
bitmap placement on the page, in hundredths of an inch.  If
you wanted to print the bitmap 3 1/4 inches from the top, then
y1 = 325.

You must also set a width and height to print the bitmap, in
hundredths of an inch.  If you want the bitmap to be 4 inches
wide, then pwidth = 400.  The function returns nonzero if 
successful.

    CallDll #lb, "PrintBitmap",_
        h as short,_        'window handle
        hbitmap as short,_  'bitmap handle
        x1 as short,_       'org x on page in hundredths
        y1 as short,_       'org y on page in hundredths
        pwidth as short,_   'hundredths of inch wide to print
        pheight as short,_  'hundredths of inch high to print
        r as short          'nonzero if successful


To aid in sizing and proportion when printing a bitmap, there
are functions that return the bitmap's dimensions.  You may
use these for scaling/sizing purposes.  To retrieve the
width of a loaded bitmap, pass the handle of the bitmap into
the function BitmapWidth, and the function returns the width
of the bitmap in pixels.  The BitmapHeight function will
return the height of the bitmap in pixels.  You can use these
values to set the width and height of the printed copy of the
bitmap.  If you multiply the bitmap width and bitmap height
by the same factor, then the proportions will remain the
same.  It is not necessary to keep the proportions the same,
so you may use different scaling factors if you wish.

    CallDll #lb, "BitmapWidth",_
        h as short,_        'window handle
        hbitmap as short,_  'bitmap handle
        bmpwidth as short   'bitmap width

    CallDll #lb, "BitmapHeight",_
        h as short,_        'window handle
        hbitmap as short,_  'bitmap handle
        bmpheight as short  'bitmap height

If you wanted the bitmap to be twice as large (in hundredths
of an inch) on the printed page as its width on the screen,
then you would set the width and height like so:

    pwidth  = 2 * bmpwidth
    pheight = 2 * bmpheight

If you wanted the bitmap to be out of proportion, you might
have something like this:
    pwidth  = 3 * bmpwidth
    pheight = int(2.3 * bmpheight)

Note that you should use the INT function if there is a chance
of a fractional value, because Liberty BASIC will crash
if you try to use a fraction as a parameter in an api call.
---------------------------------------------------------
DEMOS

There are several demonstration programs included with this
newsletter that use many of the functions in the dll.
There are demos using the following line-wrap routine.

There is also a great demo by Bill Jennings, with a better
line-wrap routine, so thanks AGAIN, Bill!

It would be very, very nice if people would post code that
uses this DLL, so that others can benefit, and so that the
author of the DLL knows if this tool has been useful.

---------------------------------------------------------
LINE WRAP

This DLL will print one line of text.  It will not automatically
wrap lines that are too long to fit on the width of the page.

Please consider whether the VBprint.dll we discussed in an
earlier newsletter would be better for your needs, if your 
program needs to print large blocks of text easily.

The function GetMaxCharsTotalWidth will tell you the approximate
number of characters that will fit on a line, if the line is
to begin at the left printable edge of the page, and continue
to the right printable edge.  You can use this value to 
determine the length to make lines to insure that they will not
be truncated when using PrintTextLocate.  This formula uses the
average character width to calculate the maximum number of 
characters, so it will only be approximate.

The function GetMaxChars will tell you the approximate number
of characters that will fit on a line using PrintTextLine
with the current margins.  You can use this value to determine
the length to make lines, so that they will not be truncated.
This formula also uses the average character width to calculate
the maximum number of characters, so it will only be
approximate.

If you would like to send a large block of text to the printer,
without concerning yourself with line-wrapping, the following
subroutine is provided for your convenience.  You will need
to place the text string into a variable called TextBlock$
and then call GOSUB [print.text.block].  Be sure to paste
the routine below, unchanged, into your code.  The beginning
and end of the routine are clearly marked.  The block of
text can be obtained from an opened file, like this:

  open "readme.txt" for input as #rm
    TextBlock$ = input$(#rm, lof(#rm))
  close #rm
    gosub [print.text.block]

The contents of a text editor may be retrieved and printed
using this subroutine, like this:

    print #1.texted, "!contents?";
    input #1.texted, TextBlock$
    gosub [print.text.block]

You may also hard-code the text into your program like this:

    TextBlock$="Here is some text to print.  It can be as long as you like."
    gosub [print.text.block]

SUBROUTINE FOR PRINTING WITH LINE-WRAP FOLLOWS:
---------------------------------------------------------
'-----------------------------------------------
'-----------------------------------------------
'          BEGIN LINE-WRAP ROUTINE
'       DO NOT CHANGE THE CODE BELOW!
'
'       LBPRNT01.DLL MUST BE OPENED
'               AS #lb
'
'       PRINTER MUST BE INITIALIZED WITH
'             PrinterDialog
'                 OR
'              PrinterInit
'
'       SEND IN A BLOCK OF TEXT IN
'       A STRING CALLED TextBlock$
'       CALL GOSUB [print.text.block]
'-----------------------------------------------
'-----------------------------------------------

[print.text.block]
    gosub [get.max.chars.in.line] 'returns max.char
    gosub [print.wrap]            'wraps and places in temp file tf.tmp

    Open "tf.tmp" for input as #5
    While eof(#5)=0
        Line input #5, temp.line$  'send one line of text to printer

[fix.tab.stops]'removes chr$(9) and replaces with blank spaces
        if instr(temp.line$,chr$(9))>0 then
             blank=instr(temp.line$,chr$(9))
             temp.line$=left$(temp.line$,blank-1)+space$(4)+Mid$(temp.line$,blank+1)
        if instr(temp.line$,chr$(9))>0 then goto [fix.tab.stops]
        end if

        line.length=len(temp.line$)
        temp.line$=temp.line$+chr$(0)

        gosub [print.text.line.from.block]
    wend
    close #5
    kill "tf.tmp"
    return


[print.text.line.from.block]
    CallDll #lb, "PrintTextLine",_
        h as short,_                'window handle
        temp.line$ as ptr,_         'text string to print
        line.length as short,_      'length of text string
        r as short                  'nonzero if successful
    RETURN



[get.max.chars.in.line]
    CallDll #lb, "GetMaxChars",_
        h as short,_         'window handle
        max.char as short    'returns maximum chars in line
    RETURN


[print.wrap]  'word wrap for printing based on max.char formula
        newL$=""
        CrLf$=chr$(13)
    ist = 1
    while ist < len(TextBlock$)
        nst = instr(TextBlock$, CrLf$, ist)
        if nst = 0 then
            line$ = mid$(TextBlock$, ist)
            ist = len(TextBlock$)
        else
            line$ = mid$(TextBlock$, ist, nst-ist)
            ist = nst + 2
            if line$ = "" then newL$ = newL$ + CrLf$
            end if
        while line$ <> ""
            if len(line$) <= max.char then
                newL$ = newL$ + line$ + CrLf$
                line$ = ""
              else
                if instr(line$, " ") < 1 then
                    newL$ = newL$ + left$(line$, max.char) + CrLf$
                    line$ = mid$(line$, max.char+1)
                  else
                    char$ = ""
                    index = max.char + 1
                    while char$ <> " "
                        char$ = mid$(line$, index, 1)
                        index = index - 1
                    wend
                    newL$ = newL$ + left$(line$, index+1) + CrLf$
                    line$ = mid$(line$, index+2)
                end if
            end if
        wend
    wend
        open "tf.tmp" for output as #5
            print #5, newL$
            close #5
        cursor normal
return

'-----------------------------------------------
'-----------------------------------------------
'          END LINE-WRAP ROUTINE
'       DO NOT CHANGE THE CODE ABOVE!
'-----------------------------------------------
'-----------------------------------------------

---------------------------------------------------------
Brosco and Alyce have written a Book for Liberty BASIC,
which is available in electronic form on a CDROM.
For details:  http://alyce.50megs.com/sss/cd.htm
---------------------------------------------------------
Newsletter compiled and edited by: Brosco and Alyce.
Comments, requests or corrections: Hit 'REPLY' now!
mailto:brosco@orac.net.au or mailto:awatson@wctc.net
---------------------------------------------------------
