---------------------------------------------------------
The Liberty Basic Newsletter - Issue #105 - FEB 2003
    2003, http://groups.yahoo.com/group/lbnews/
             All Rights Reserved
Individual authors retain copyrights to their works.
---------------------------------------------------------
If I have ever made any valuable discoveries, it has been 
owing more to patient attention, than to any other talent.
--Sir Isaac Newton
---------------------------------------------------------
In this issue:
	Drawn Objects - A Beginning Graphics Tutorial
	Documenting Your Code the Easy Way!
	Tipcorner - Maximizing the Usefulness of the
		    Liberty BASIC Helpfile
	BmpButton Manipulations
	Roll Your Own Prompt - by Brad Moore
	Alternative Way of Hiding and Showing Controls
		in LB3 - by Mike Bradbury
	Demos by Dennis McKinney:
		Minimize CPU Usage in Scan Loop
		API Color Dialog
	Demos by Bill Jennings
		Virtual Tabs
		Hot Keys and Mouse Clicks
	A User's Review of TheWrap by David Drake
	Using BASIC for Numerical Integration
		by Tom Nally
	LibSQL v1.4 - SQLite Database for LB
		by Richard Peeters
	Help! (... is on the way!) by Jerry Muelver


---------------------------------------------------------
Notes from the Editor

Thanks so much to Mike Bradbury for his great explanation and demo of hiding and showing controls in a window!

Thanks Dennis McKinney, for the information and demo on minimizing CPU usage in a scan loop. Great tip!  And thanks also for the API color dialog code and explanation.

Thanks to Brad Moore for the article and code on creating a custom dialog to replace the LB prompt command, adding functionality and flexibility.  This snippet will go into everyone's snippet library!

Bill Jennings has shared a demo that allows non-fixed width fonts to appear to be tabbed.  Thanks, Bill!  He also gives us a demo of hot keys and mouse clicks - a clever idea!

David Drake has given us both a comprehensive review of Joe Block's great app, TheWrap, and a humorous story.  Thanks, David!

Tom Nally has done it again! Here is another of his clear and detailed articles on using math in our programs. This one describes numerical integration and tells us how to use it in our code. Well done, Tom!  In honor of Tom's article on calculus, our featured quote is from Sir Isaac Newton, the "Father of Calculus."

Richard Peeters has taken the SQLite database functions shared by Colin McMurchie and written an explanatory article and included a demonstration program.  People have been asking for database abilities for a long time, and this method fills that need admirably.  Thanks, Richard, for the wonderful demo and explanation!

Jerry Muelver has provided a blueprint for documentation writing that is both concise and clear. Thank you, Jerry!

Please feel free to comment on the format of this issue. It is being published in two formats.  It is going out as plain text, as always.  It is also going out in html format.  This allows each article to appear on its own page, making for more clarity, easier navigation, and less scrolling. The HTML version was created with WikiWriter, by Jerry Muelver of HyText Consulting.  Jerry is a registered user of Liberty BASIC and a contributing member of our community.  Visit his site at http://hytext.com 

---------------------------------------------------------
DRAWN OBJECTS - A BEGINNING GRAPHICS TUTORIAL
     2003, Alyce Watson
    excerpt from "Mastering Liberty BASIC 3"
    http://iquizme.0catch.com/lb/lbw3/master.html

There are two kinds of graphics available in Liberty BASIC, turtle graphics, and objects.  The turtle graphics method employs a drawing pen that moves about the screen, leaving a trail if the pen is down.  Objects and turtle graphics can be drawn together, but it is more usual to see one or the other in a program.  For more about turtle graphics, see Issue #98.

For any graphics, the first important lesson is that the pen must be in the DOWN position for graphics to display on the screen.  The default is UP, so remember to issue the DOWN command to start drawing.

print #1, "down"    'put the pen down
print #1, "up"      'raise the pen, no graphics will be drawn

SIZE
By default, the drawing pen is a single pixel wide.  It can be made any size with the SIZE comand.  Remember that objects drawn with a larger-sized pen will take up more space than objects drawn with the default 1-pixel-wide pen.  To issue the size command:

print #1, "size 10"    'a pen 10 pixels wide

'using variables:
s = 10
print #1, "size ";s

Remember that variables must be placed outside of the quote marks and that blank spaces must be preserved.

FILL and CLS
The graphicbox or graphics window will be filled with color when the FILL command is issued.  This will cover any existing graphics.  FILL can be a named Liberty BASIC color, or an RGB color.  For more, see Issue #100.  To clear the screen and erase drawn objects from memory, issue a CLS command.

print #1, "cls"    'clear screen, erase drawn objects
print #1, "fill white"    'cover over drawn objects

col$="green"
print #1, "fill ";col$

print #1, "fill 10 211 156" 'fill with RGB color

r=142:g=217:b=56
print #1, "fill ";r;" ";g;" ";b


COLOR
Objects are drawn with a pen in the COLOR chosen.  The default color is black.  To change the color at any time in a program, issue a COLOR command.  Objects will be drawn in that color until another COLOR command is issued.  The color can be a named Liberty BASIC color, or an RGB color.   For more, see Issue #100.  Examples of the COLOR command:

print #1, "color red"

col$="blue"
print #1, "color ";col$

print #1, "color 100 220 30"

r=130:g=200:b=255
print #1, "color ";r;" ";g;" ";b


BACKCOLOR
Objects can be drawn as outlines, or as objects filled with a color.  Filled objects are filled with the current BACKCOLOR.  The default BACKCOLOR is white.   For more, see Issue #100.  BACKCOLOR can be a named Liberty BASIC color, or an RGB color.  It will be used to fill drawn objects until another BACKCOLOR command is issued.  Examples of the BACKCOLOR command.

print #1, "backcolor red"

col$="blue"
print #1, "backcolor ";col$

print #1, "backcolor 100 220 30"

r=130:g=200:b=255
print #1, "backcolor ";r;" ";g;" ";b


LOCATION
  The pen starts at point 0, 0.  This is the upper left corner of the graphics area.  The x values get larger as you move right and the y values get larger as you move down.  You can locate the pen using turtle graphics commands.  See Issue #98.  It is more common to locate the pen using the PLACE command when drawing objects.  This command puts the drawing pen at the x,y location given.  The pen does not draw a line from its previous position.  It is lifted and placed at the new location.  Examples:

print #1, "place 12 58"    'place pen at x=12, y=58

x=37:y=123
print #1, "place ";x;" ";y

It is possible to retrieve the current pen location with the POSXY command.  This command will assign the pen's position to the receiver variables specified.

Syntax:  print #handle, "POSXY X Y"

As it would appear in a program:

print #1, "posxy xVar yVar"

After this command, the values for the current pen position are contained in the variables xVar and yVar.


OBJECTS
There are several objects that can be drawn.  They are:

LINE
BOX
BOXFILLED
CIRCLE
CIRCLEFILLED
ELLIPSE
ELLIPSEFILLED
PIE
PIEFILLED

For all except the line, if the command contains "FILLED", the object will be a solid object, filled with the current BACKCOLOR.  It will completely cover all drawn objects beneath it.  Objects that aren't "FILLED" are drawn as outlines.  Any drawn graphics that already exist on the screen under the new object will still be visible within its borders.  Here is a small demo.  Notice how the graphics beneath the box show within its borders, while the graphics beneath the boxfilled are covered by the BACKCOLOR.

nomainwin
WindowWidth=300:WindowHeight=240
open "Test" for graphics_nsb_nf as #1
print #1, "trapclose [quit]"
print #1, "down; size 10; color blue"
print #1, "fill cyan; backcolor pink"
print #1, "line 0 100 500 100"
print #1, "color darkpink"
print #1, "place 10 10; box 180 180"
print #1, "place 200 10; boxfilled 280 180"
wait

[quit]
close #1:end


LINE
The LINE command draws a line in the current pen color and size, from the first pair of points to the second pair of points.  If the pen is UP, the pen will move, but no line will be drawn.

Syntax:  print #handle, "X1 Y1 X2 Y2"

As it would appear in a program:

print #1, "line 10 56 238 122"

x1=33:x2=287
y1=12:y2=311
print #1, "line ";x1;" ";y1;" ";x2;" ";y2


BOX, BOXFILLED
The two BOX commands draw a box from the current pen position to the x,y position given.  BOX draws an outline of a box in the current pen color and size.  BOXFILLED draws a box using the current pen size and color and fills it with the current BACKCOLOR.

Syntax:  print #handle, "BOX X Y"

As it would appear in a program:

print #1, "box 200 300"
print #1, "boxfilled 145 222"

x=87:y=225
print #1, "box ";x;" ";y

print #1, "boxfilled ";x;" ";y


CIRCLE, CIRCLEFILLED
The two CIRCLE commands draw a circle from the current pen position with the radius given.  The radius specifies the distance in pixels from the center of the circle to its outside edge.  CIRCLE draws an outline of a circle in the current pen color and size.  CIRCLEFILLED draws a circle using the current pen size and color and fills it with the current BACKCOLOR.

Syntax:  print #handle, "CIRCLE	 R"

As it would appear in a program:


print #1, "circle 50"
print #1, "circlefilled 73"

r=100
print #1, "circle ";r
print #1, "circlefilled ";r


ELLIPSE, ELLIPSEFILLED
The two ELLIPSE commands draw an ellipse centered at the current pen position with the width and height given.  ELLIPSE draws an outline of an ellipse in the current pen color and size.  ELLIPSEFILLED draws an ellipse using the current pen size and color and fills it with the current BACKCOLOR.

Syntax:  print #handle, "ELLIPSE W H"

As it would appear in a program:

print #1, "ellipse 200 300"
print #1, "ellipsefilled 145 222"


x=87:y=225
print #1, "ellipse ";x;" ";y
print #1, "ellipsefilled ";x;" ";y


PIE, PIEFILLED
The two PIE commands draw a pie section inside of an ellipse whose width and height are given.  The starting and stopping points of the ellipse are expressed in angles.  The PIE will start at the first angle and sweep clockwise to the second angle, if the second angle is positive.  It will sweep counter-clockwise to the second angle if the second angle is negative.  The figure can appear to be any section of a pie:  a thin slice, a quarter, half or three-quarters of a pie, or even an entire pie ellipse, if the two angles are equal.

Syntax:  print #handle, "PIE W H A1 A2"

As it would appear in a program:

print #1, "pie 300 200 45 125"
print #1, "piefilled 160 220 90 270"

w=150:h=200
a1=75:a2=350
print #1, "pie ";w;" ";h;" ";a1;" ";a2
print #1, "piefilled ";w;" ";h;" ";a1;" ";a2

Here is a small pie demo:

nomainwin
WindowWidth=300:WindowHeight=240
open "Test" for graphics_nsb_nf as #1
print #1, "trapclose [quit]"
print #1, "down; size 5; color darkgreen"

print #1, "fill yellow; backcolor lightgray"
print #1, "place 100 80"
print #1, "pie 120 60 45 125"
print #1, "place 200 120"
print #1, "piefilled 60 160 90 270"
wait

[quit]
close #1:end

---------------------------------------------------------
DOCUMENTING YOUR CODE THE EASY WAY!
	by Alyce Watson
 
Undocumented code is a disaster waiting to happen!  You can write the best program in the world, spending much time and effort.  You can be convinced that you will ALWAYS remember the logic and construction of this program.  Three months later, you can open up the code to add a neat feature that just popped into your head and find that you are looking at a strange, incomprehensible jumble!

COMMENTS:  THE LONG, BUT COMPREHENSIVE WAY
You can put comments in your code in two ways.  At the beginning of a comment line, you can use the REM statement, like this:

REM this is just a comment and the LB compiler will ignore it.

You can also use the apostrophe/single quote to mark the beginning of a comment.  This can be placed at the beginning of a line, or within a line, like this:

'this is a comment, just like the one above
print "hello"  'I can add a comment after a line of code!


NO COMMENTS!
If you don't like to take the time or the space to write actual comments, there are other ways to document your code.


DESCRIPTIVE NAMES
Use descriptive names for branch labels, subs, functions, arrays and variables.  It is much easier to understand your code later or for someone else to understand your code if you do this.  Which of these is easiest to understand?

MaximumNumber = 77
or
m = 77

Hmmm, there IS something to be said for brevity.  It is a lot quicker to type "m" than to type "MaximumNumber" isn't it?  There is a compromise.  Use abbreviations!  Adopt a convention of your own so that your abbreviations make sense.  You might use something like this:

maxNum = 77
or 
maxN = 77
or 
intMax = 77

There can be no spaces in names of variables, arrays, functions, subs and branch labels.  Make them easy to read by selectively capitalizing the beginnings of words.  Which of these is easier to read:

MaximumNumber
or
maximumnumber

Avoid Liberty BASIC reserved words.  Some of these will generate a syntax error when you try to compile the program.  Here is an example:

print = 77

Instead, use something like this:

printCopies = 77

Liberty BASIC function names actually include the opening bracket.  The name hWnd is not the full name of that function.  It is hWnd(.  For this reason, you can get away with using variable names like hWnd.  It is best to avoid doing this, however, to avoid confusion.  In the past, I've used a dot within the names of some branch labels and variables.  After learning some other programming languages, I've avoided using dots in Liberty BASIC names, because dots are used in a particular way in some other languages.  They are also used in LB to separate window handles from extensions given to controls, as in

statictext #win.stext, "Hello", 8, 19, 100, 26

Here are some names.  Which would you understand instantly?

[openFile]
[openafileandreadintotexteditor]
[blahblah]
[wow]

a$()
person$()
address$()

Function wowthisisalongfunctionname()
Function ParseText$()

Sub dy1

Sub PlayMidi


WHITE SPACE

White space includes both blank lines and indents.

BLANK LINES
Some people take great pleasure in compressing code as much as possible.  They don't want to include any blank lines, and often string short lines together by connecting them with colons, like this:

print "Hello" : x = 15 : y = 459 : print "World"

Sometimes, putting lines together can be fine, and even helpful.  Setting x and y variables on the same line works fine and is short enough to read and understand:

x = 2 : y = 7

Stringing many and varied commands together is just plain confusing, as in that longer line above.

Blank lines are especially helpful to separate code routines visually.  Use them in between branch labels, gosubs, functions and subs.  Here are two examples.  The top example requires less space, but the bottom example is much easier to understand.

''''''''''''''''''''''''''''''''''''''''''
[printIt]
open "afile.txt" for output as #f
print #f, "Hello World"
close #f:wait
[openFile]
filedialog "Open","*.*",file$
if file$="" then wait:notice "You chose ";file
wait
[quit] close #main:end
''''''''''''''''''''''''''''''''''''''''''

[printIt]
open "afile.txt" for output as #f
print #f, "Hello World"
close #f
wait

[openFile]
filedialog "Open","*.*",file$
if file$="" then wait
notice "You chose ";file
wait

[quit] 
close #main:end
'''''''''''''''''''''''''''''''''''''''''

INDENTS
Indents are the white spaces at the start of lines.  You can set your own style for these.  Here is the way I like to do it.

For regular code routines, I like to put the branch label, function name, or sub name all the way to the left.  I then indent every other line within the routine through the END SUB, END FUNCTION or WAIT statement.  The code above then looks like this:

[printIt]
    open "afile.txt" for output as #f
    print #f, "Hello World"
    close #f
    wait

[openFile]
    filedialog "Open","*.*",file$
    if file$="" then wait
    notice "You chose ";file
    wait

[quit] 
    close #main:end

That style makes it very easy to see where routines begin and end.

Indents are also extremely useful when creating nested statements.  Each level of nesting gets another indent.  Look at the two examples below and see which is easier to read.  Note also that this style makes it easier to see where you might be missing a NEXT statement.

for i = 1 to 5
for j = 1 to 10 step 2
if i = j then
print "Equal"
end if
next
next

'''

for i = 1 to 5
    for j = 1 to 10 step 2
        if i = j then
            print "Equal"
        end if
    next
next

The use of descriptive naming, along with the judicious use of white space, makes self-documenting code.  There will still be spots that need some additional documentation in the form of comments, but reading and understanding the code will be much easier with these techniques!

---------------------------------------------------------
TIPCORNER
	Maximizing the Usefulness of the
	    Liberty BASIC Helpfile
	by Alyce Watson

When you need help with your Liberty BASIC programming, the first place to go is the Liberty BASIC helpfile.  The helpfile actually consists of two files - Liberty3.hlp and Liberty3.cnt.  The main file is Liberty3.hlp.  The Liberty3.cnt file is a listing of the contents in the helpfile.  It enables the "contents" feature of the helpfile to be used.  See CONTENTS below for more on this feature.  If you lose the Liberty3.cnt file, the helpfile will still be accessible, but it won't be as easy to navigate.  If you corrupt the Liberty3.cnt file, it may be difficult to use the helpfile, so do not attempt to edit this file!

CONTENTS
Choosing the "contents" tab in the helpfile pops up a small window with a listing of topics in the helpfile.  These are arranged in categories.  Each category is marked by the purple book icon.  Click on a category to expand the listing.  Under each category, there is a list of topics.  Each topic is marked with a question mark icon.  Clicking on a topic name will cause the large help window to display that topic.

INDEX
If you click on the "index" tab, the small window will pop up with the index feature displayed.  In the top textbox, type the word you hope to find.  If it is a topic or keyword in the helpfile, it will appear highlighted in the list below the textbox.  Hit ENTER or click the "display" button to cause that topic to display in the help windows.  If the word you have typed doesn't exist as a keyword, then you will get an error message.  If this happens, choose the "find" tab.
 
FIND
The first time you choose to "find" a word in the helpfile, you will get a dialog to build the word list for the "find" feature.  Once the list is built, the helpfile can find all topics that display a word, even if it is not a designated keyword.  You will be asked if you want to minimize database size, maximize search capabilities, or customize search capabilities.  Choose the option you prefer. You can choose to rebuild the word list at any time by clicking on the "rebuild" button.

After you have built the word list, you may type a word into the textbox of the "find" dialog.  The second box will give you a list of possible matching words to help you narrow your search.  Click on one of these, and a list of topics is displayed in the third box.  Click on one to choose it and hit ENTER, or click the "display" button to view the topic in the large help window.

If you want to customize the way you search, click the "options" button in the "find" dialog.  You will be presented with a group of options.  Choose the ones that meet your needs and close the options dialog.

NAVIGATION
The large help window has buttons at the top to help you navigate.  You can scroll through topics by clicking the forward and backward arrow buttons.  You can also view the last topic you displayed by clicking the "back" button.

OPTIONS
You can choose the font size for text display if you'd like - small, medium, or large.  You can also choose to keep the helpfile on top so that you can read it while working in the Liberty BASIC editor.  You may choose to print a topic.  You may also copy a topic to the clipboard so that you can paste it into a texteditor, or into the Liberty BASIC editor.  If no text is highlighted when "copy" is chosen from the "edit" menu, then the entire topic will be copied to the clipboard.  If there is highlighted text, then only that text will be copied to the clipboard.

BOOKMARK
If you find that you return to a topic many times, you might want to bookmark it so that it is easy to find in the future.  Choose the "bookmark" menu, then "define", and the current topic will be added to the list of bookmarks.  The list of bookmarked topics appears under the "bookmark" menu.  Click on a topic from the list to display it.
 
ANNOTATE
You can add your own text to the helpfile!  This is useful when you want to add your own helpful hints or code samples.  It is also useful if you find an error in the helpfile.  If a topic has been annotated, there will be a paper clip icon at the top of the topic text.  Click on this to see or edit your annotation.

TUTORIALS
Even if you already know a lot about Liberty BASIC programming, you might want to work though the tutorial section of the helpfile - or at least scan it!  There are a lot of goodies in the tutorials that will make your programming easier and more fun.

COMMAND REFERENCE
Most of us can't remember the exact syntax for ALL of the commands.  "Hmm, does this require a comma or a semi-colon?  Does that need an exclamation point in front?  And what is that command for listboxes... does it end in a quesion mark?"  Find answers quickly in the alphabetical command reference.  When something doesn't seem to be working, look it up!  If you've given that textbox a "!cls" command and it doesn't clear, check the helpfile.  The textbox has a very limited set of commands, and it is common for LB programmers to forget and try to send texteditor commands such as "!cls" to a textbox.  The alphabetical command reference gives you quick access to the entire Liberty BASIC command set.

SAMPLES
In addition to the helpfile, Liberty BASIC ships with many small, sample programs.  Some of these contain helpful routines that showcase some of the features of Liberty BASIC or offer programming shortcuts.  Take some time to load, run and study them!

---------------------------------------------------------
BMPBUTTON MANIPULATIONS
	by Alyce Watson

Liberty BASIC allows a program to include buttons with pictures on them.  If you don't mind moving into the realm of API manuiplations, Mike Bradbury has published some terrific articles in Issue #102 and Issue #103 that feature a method of placing images on various controls.

Bmpbuttons work a little differently than regular buttons.  Instead of a caption, we must specify a filename for the bitmap that will appear on the button.  This filename can have a relative path.  If we run a program in the Liberty BASIC directory, it can find the bmps in the bmp directory if we specify the path like this:

bmpbutton #1.b, "bmp\copy.bmp",[hi],UL,10,10

The bmpbutton command also requires the name of the branch label that will be the event handler for the button, the corner to which placement will be relative, and the x and y placement coordinates.  We can't specify a width and height as we can with regular push buttons, because Liberty BASIC checks the size of the bitmap and makes the button that same size.

Bmpbuttons accept a limited command set.


SETTING FOCUS TO A BMPBUTTON
Commands sent to a bmpbutton should not begin with a "!" character like commands sent to a regular button.  We cannot change the text on a bmpbutton, because there IS no text on a bmpbutton.  We can cause a bmpbutton to receive the input focus so that any keypresses will be directed to the bmpbutton.  Here is the syntax:

print #handle.ext, "setfocus"


CHANGING THE BITMAP ON THE BUTTON
We can set the bitmap of the control to be the named bitmap that has been loaded previously with the LOADBMP command (not the filename of the bitmap). 

loadbmp "bitmapname", "filename.bmp"
print #handle.ext, "bitmap bitmapname"

If the new bitmap is not the same dimensions as the original bitmap, it won't look right, because the bmpbutton will not automatically change size to match the new bitmap.  You can find the dimensions of a bitmap by loading it into MS Paint and checking its attributes.  You can also find the dimensions of a loaded bitmap at runtime.  Check Issue #100 for an explanation.


MOVING AND RESIZING A BMPBUTTON
You can reposition the bmpbutton within the window that contains it.  Use the "locate" command.  This command requires the new x and y coordinates for the bmpbutton, plus the width and height desired.  You must issue a "refresh" command to the window to cause it to update the display to show the new location of the button.  To use the "locate" command, you must know the desired dimensions of the bmpbutton.  See Issue #100 for a way to discover bitmap dimensions at runtime.  Here is the syntax:

print #handle.ext, "locate x y width height"
print #handle, "refresh"

Remember that values inside the quotes are hard-coded.  To use variables, place them outside of the quote marks and preserve the blank spaces inside the quote marks.

print #handle.ext, "locate 12 45 25 25"
or
x=12 : y=45 : width=25 : height=25
print #handle.ext, "locate ";x;" ";y;" ";width;" ";height


The "locate" command gives us the ability to specify a width and height for our bmpbuttons, so we are not limited to accepting the size given them by Liberty BASIC.  We can change the look of our buttons this way, making them smaller if the window is resized by the user to be very small, for instance.  We can also use the "bitmap" command to place a new image on the button, and then use the "locate" command to change the size of the button to match the size of the new bitmap.


DEMO
Here is a small demo that illustrates some of the possibilities of using the "bitmap" and "locate" commands with bmpbuttons.

'run this code from within your Liberty BASIC directory
'so that the bmps can be found by the program
nomainwin
WindowWidth=600:WindowHeight=400
bmpbutton #1.b, "bmp\copy.bmp",[hi],UL,10,10
button #1.move, "Move Button",[moveButton],UL,10,80,140,24
button #1.new, "New Bitmap",[new],UL,10,120,140,24
open "Move Bmpbutton" for window as #1
#1 "trapclose [quit]"
wait

[quit]
'if bmp was loaded, unload it
if pianoLoaded then unloadbmp "piano"
close #1:end

[moveButton]
'move bmpbutton to new coords

if not(pianoLoaded) then
'actual size of copy bmp is
'25x25, and we will preserve that:
#1.b "locate 200 10 25 25"
else
'if piano bmp is in use, use
'these dimensions:
#1.b, "locate 200 10 300 50"
end if

#1 "refresh"
wait


[new]
'change bmp and reposition
loadbmp "piano","bmp\piano.bmp"
pianoLoaded=1   'flag that bmp was loaded
'actual size of piano.bmp is 600x100
'but we will make it 300x50 here:
#1.b "bitmap piano"
#1.b "locate 50 10 300 50"
#1 "refresh"
wait

[hi]
notice "Hi"
wait

---------------------------------------------------------
Roll Your Own Prompt
by Brad Moore  article is copyright 2003

I am a long time user of Liberty Basic, dating back to the version 1.31 or earlier.  Through out all this time there have been a lot of things I have heard people ask Carl to add or fix or enhance.  One of the more popular has been the PROMPT function.  Here it what the help file says about the Prompt function:

PROMPT string; responseVar$

Description:

The PROMPT statement opens a dialog box, displays string, and waits for the user to type a response and press 'Return' (or press the OK or Cancel button).  The entered information is placed in responseVar$.  If Cancel is pressed, then a string of zero length is returned.  If responseVar is set to some string value before PROMPT is executed, then that value will become the 'default' or suggested response.  This means that when the dialog is opened, the contents of responseVar$ will already be entered as a response for the user, who then has the option to either type over that 'default' response, or to press 'Return' and accept it.

The prompt function has received a lot of attention be cause it seems to lack some of the functionality and design finesse of its two cousins the NOTICE function and the CONFIRM function.  Both the NOTICE and the CONFIRM function allow multiple lines of text to be displayed, where the PROMPT function only supports one line of text.  Additionally the NOTICE function allows the programmer to apply a custom title to the titlebar of the NOTICE dialog window.

An additional problem has also crept into the equation  when using a PROMPT it is not possible to set a timer, call the PROMPT function and then allow the timer to force a return from the PROMPT function.  The call to the PROMPT function appears to shut the timer down.  This prevents the user from making a PROMPT function that automatically times out and then selects a default value should the user have not entered something of their own.  A desirable feature sometimes.

I have often suggest that the programmer who is dissatisfied with the features of the PROMPT function should simply write their own custom PROMPT function, but few seem to be interested in doing this.  So I have taken the several most common complaints and compiled them into a list of features for a modular PROMPT replacement function.  The function needs to support the following:

	All the general features of the standard LB PROMPT function
	A programmable title for the titlebar that will display a default if not provided
	The ability to display multiple lines
	The ability to automatically time out and close the window after a specified period
	Encapsulated into a reusable function

Part way through programming an interesting discussion on the Liberty Basic Group List grabbed my attention.  It centered around a pitfall that one can easily get them selves into when they encapsulate a window with controls into a function or sub program that is called from another program.  The problem is a bit complex, but I wanted to talk about it, as it is important to understand so one can understand how and why the function works.  The real issue is a problem of scope.  If I cause a program to stop and wait in a function of sub program (even using a scan command) and it gets an event that the user has triggered by pressing a button, for example, the branch label to which the event is associated will not be visible to the program from with in the function or sub program and there will be an error.  That is because LB specifies branch labels as local to the area of code where they occur.  If the label [quit] is in the main part of the program, but I am in the sub program called SMILE then I can not see the branch label [quit]  it just does not exist.
This is important to recognize (and I initially failed to recognize this) because my custom function had a dialog window with controls and a WAIT statement to wait for the user to press the controls.  But what if the user moved my dialog window out of the way and press a control on the window that spawned my dialog window  ERROR!  The answer was to open the dialog as a modal window.  The modal dialog window will disable the controls on all other windows associated with that program and only allow the current window to have focus.  LBs implementation of modal is simply program wide and not system wide (there is a windows intrinsic to do that too), so other programs continue to operate.

So having conquered that the rest was fairly straight forward.  I have commented the program function fairly well, so I will let the function speak for itself.  Just a couple last words.  I have released the function and the demo program into the public domain.  You may do with them as you wish.  The article (the parts that preceded the code) is not released into the public domain.  If you use or alter my function it is not necessary to credit me.  As a public domain source it is yours.  I hope people will use it and change it and grow it.  Have fun...

'----------------------------------------------------------------------------
'Demo the "Roll Your Own Prompt" by Brad Moore
'The function and demo written in Jan 2003
'Both the function and the demo are released to the 
'public domain as of Jan 2003.  Please use them for
'good everywhere.
'
'Written in Liberty Basic - ver 3.x - using Liberty Workshop
'For more information about Liberty Basic please visit the
'website http://www.libertybasic.com


[InitColors]
    ForegroundColor$ = "Black"
    BackgroundColor$ = "Buttonface"
    TexteditorColor$ = "White"
    TextboxColor$    = "White"
    ComboboxColor$   = "White"
    ListboxColor$    = "White"

[WindowSetup]
    NoMainWin
    WindowWidth = 490 : WindowHeight = 112
    UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
    UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

[ControlSetup]
Button      #main.gi, "Get Input",[gi],UL, 245, 45, 105, 25
Button      #main.quit, "Quit",[quit],UL, 365, 45, 105, 25
Textbox     #main.tbox, 15, 10, 455, 24

Open "Demo Window" For Dialog As #main

    Print #main, "trapclose [quit]"
    Print #main, "font ms_sans_serif 10"

[loop]
    Wait

[quit]
    Close #main : End

[gi]
    'This is where I get ready to call my new prompt function.
    'Set Message$ to the prompt string with carriage returns separating
    'lines to be displayed.
    Message$ = "Please enter your name:" + Chr$(13) + _
               "Please enter Last Name First" + _
               Chr$(13) + "Then First Name and Middle Initial"
    'call the fucntion, No title, the message we built above, 3 lines
    'and 10 seconds to timeout.
    promptme$ = GetInput$("", Message$, 3, 10)
    'display the return value in the demo window textbox
    #main.tbox promptme$
    GoTo [loop]


'----------------------------------------------------------------------------
'   Functions, Sub Programs and Data 


Function GetInput$(Title$, Message$, lines, Time)
'-------------------------------------------------------------------
'This function replaces the standard LB PROMPT function with a
'generic, multi-purpose prompt function that returns the user
'input as a string.  It allows multiple lines of prompt text and 
'supports a timed response where the dialog window will close if the
'user has not responded in so many seconds.
'-------------------------------------------------------------------
'By Brad Moore - released to public domain 1/1/2003
'-------------------------------------------------------------------
'Parms:
'Title$ = The title to display on window titlebar
'Message$ = a string containing 1 to 20 lines of text used to prompt
'           the user - separate lines of text with embedded chr$(13)
'lines = The actual number of lines passed (this aids in formatting the 
'        window size and control placement)
'Time = the number of seconds you want to wait before the dialog box
'       times out and closes.  The value 0 (zero) will leave it open
'       an infinite period of time.
'-------------------------------------------------------------------

'Set some defaults if they were not supplied
If Title$ = "" Then Title$ = "User Value Required"
If lines <= 0 Then lines = 1
If lines > 20 Then lines = 20
promptme$ = ""

'Define the dialog box parameters
WindowWidth = 543
WindowHeight = 134 + (lines * 22)
UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

'setup the controls for the window
Statictext  #promptme.static1, Message$, 15, 15, 490, (20 * lines)
If Time > 0 Then
  seconds$ = "Seconds: " + Str$(Time)
  Statictext  #promptme.st2, seconds$, 15, 65 + (20 * lines), 169, 25
End If
Button      #promptme.ok, "OK",[ok.promptme],UL, 265, 65 + (20 * lines), 105, 25
Button      #promptme.cancel, "Cancel",[cancel.promptme],UL, 400, 65 + (20 * lines), 105, 25
Textbox     #promptme.textbox1, 15, 25 + (20 * lines), 490, 25

'open the window
Open Title$ For Dialog_modal As #promptme

'set a trap for close and set the global font
Print #promptme, "trapclose [quit.promptme]"
Print #promptme, "font ms_sans_serif 10"

'If a timed response was desired - turn the timer on
If Time > 0 Then
    counter = Time
    Timer 1000, [update]
End If

'Wait here for a user event
Wait

'Process user events
[ok.promptme]
    'stop the timer
    Timer 0
    'get the contents of the input textbox to be returned
    Print #promptme.textbox1, "!contents? promptme$";
    GoTo [quit.promptme]

[cancel.promptme]
    'stop the timer and set the return string to null
    Timer 0
    promptme$ = ""
    GoTo [quit.promptme]

[update]
     'decrement our second countdown counter
     counter = counter - 1
     'display the new remaining time on the dialog window
     Print #promptme.st2, "Seconds: " + Str$(counter)
     'if there are no more seconds them set then stop the timer
     'set the return string to null and prepare to exit.
     If counter = 0 Then
         Timer 0
         promptme$ = ""
         GoTo [quit.promptme]
     End If
     'if we still have time then just wait here for the next event
     Wait

[quit.promptme]
    'stop the timer, close the prompt window and set the 
    'function return to the value of promptme$
    Timer 0
    Close #promptme
    GetInput$ = promptme$

End Function

---------------------------------------------------------
Alternative way of hiding and showing controls in LB3.
	by Mike Bradbury, mike@karemi.fsnet.co.uk

Submitted for the Feb 2003 LB Newsletter.

Liberty BASIC has a 'locate' command, e.g. print #handle.ext, "locate x y width height" which is used to position/reposition a control within a window or even ouside a window if the control is to be hidden.

Sometimes applications have a group of controls which all need to be hidden at the same time and redisplayed when required to be used. To hide a number of controls and then re-display them, requires a locate command for each control, with the appropriate x, y, width and height parameters. Rather than hide/show each control,
it is easier and faster to group the controls together in an area of window which can hidden.
This can be achieved by a single call to user32.dll to resize the window to a height (or width) which will cause the controls to be hidden and later restored to the original size to show the controls again.
In this example, allowance is made for the user having dragged the window around the screen. Before resizing the window, its current x/y co-ords are obtained and used in the 'MoveWindow' message.
Click the Allow Hide checkbox to enable the Hide button. Then click the Hide button and the window will be resized to hide the controls in the bottom panel of the window. The Hide button then becomes a Show button, which when clicked restores the window height bringing twelve of the controls back into view but because the window was narrowed as well and not restored in width, the thirteenth control remains out of view.

Notice also that closing of the window is prevented until the Close button is visible, when the window can be closed either with the Close button or the system menu/buttons in the titlebar.

Button #m1.b3 is drawn with a height of 3 pixels and width of WindowWidth and then disabled, to simulate a divisor bar across the window, below which the controls are grouped. This gives the impression that the controls are positioned on a sliding panel which slides in or out as the window is resized.



'~~~~~~~ Code follows ~~~~~~~~~
if left$(Version$,1)<>"3" then
            notice "Sorry, LB version 3 only."
            end
end if

    '~~~~~~~~~~~~~~~~~~~~~~~ display ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dw=DisplayWidth: dh=DisplayHeight
    WindowWidth=427: WindowHeight=400
    UpperLeftX=Int((dw-WindowWidth)/2)
    UpperLeftY=Int((dh-WindowHeight)/2)
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

NewHeight=316 'height of window when controls are to be hidden
NewWidth=326  'width of window when controls are to be hidden
'struct for the window rectangle params
struct Rect,_
x1 as long, y1 as long,_
x2 as long, y2 as long
'
allowHide=0
show=1
CR$=chr$(13)
'
nomainwin
button #m1.b1, "Hide", [hide.show], UL,20,20
button #m1.b2, "Close", [quit], UL,20,330
button #m1.b3, "", [], UL,0,290,WindowWidth,3   'button used as graphic
button #m1.b4, "1", [null], UL,90,307,20,20
button #m1.b5, "2", [null], UL,110,307,20,20
button #m1.b4, "3", [null], UL,130,307,20,20
button #m1.b5, "4", [null], UL,150,307,20,20
button #m1.b4, "5", [null], UL,170,307,20,20
button #m1.b4, "6", [null], UL,190,307,20,20
button #m1.b5, "7", [null], UL,210,307,20,20
button #m1.b4, "8", [null], UL,230,307,20,20
button #m1.b5, "9", [null], UL,250,307,20,20
button #m1.b4, "0", [null], UL,270,307,20,20
statictext #m1.st1, "", 20,50,200,200
checkbox #m1.cb1, "Allow hide",[test],[test],330,330,75,25
textbox #m1.tb1, 90,330,200,25
open "Hiding controls" for window_nf  as #m1
hm1=hwnd(#m1)
disable=0: enable=1 'declared var
hCb3=hwnd(#m1.b3)                'get handle of button used as a graphic
call enableControl hCb3, disable 'disable button used as a graphic
#m1, "trapclose [quit]"          'only when close button is visible
#m1, "font arial 9"
#m1.tb1, "Click checkbox"
#m1.st1, "Group controls which need to be hidden into an area of the window ";_
         "which can be hidden by reducing the window size.";CR$;CR$;_
         "No need to relocate each control outside/inside the window, having to ";_
         "ensure the correct x/y locations and control sizes!";CR$;CR$;_
         "Allowance is made for the user possibly moving the window."
wait
'
[null]
wait
'
[test]
allowHide=1-allowHide
if allowHide then print #m1.tb1, "Click Hide button" else print #m1.tb1, "Click checkbox"
wait
'
[quit]  'only if close button is visible
if not(show) then
    wait
    else
    close #m1
    end
end if
'
[hide.show] 'resize window to hide or show controls
if not(allowHide) then beep:wait
show=hideShow(hm1,show,NewWidth,WindowHeight,NewHeight)
wait
'
sub enableControl hControl, state
calldll #user32, "EnableWindow", hControl as long,state as long,result as void
end sub

function hideShow(h,show,wWidth,wHeight,NewHeight)
'get window co-ords
calldll #user32, "GetWindowRect", h as long, Rect as struct, r as void
        winWidth = Rect.x2.struct - Rect.x1.struct
        winHeight = Rect.y2.struct - Rect.y1.struct
        topX = Rect.x1.struct : topY = Rect.y1.struct

'decide window height
show=1-show
if show then
        height=wHeight   'window height for panel shown
        #m1.b1, "Hide"
        else
        height=NewHeight            'window height for panel hidden
        #m1.b1, "Show"
end if
hideShow=show
'resize window
calldll #user32, "MoveWindow", h as long, topX as long, topY as long,_
        wWidth as long, height as long, 1 as long, result as void
end function
'~~~~~~~ End of Code ~~~~~~~~~

File show_hide_controls.lba is included in MBradbury.zip


Mike Bradbury.

---------------------------------------------------------
DEMOS BY DENNIS McKINNEY
---------------------------------------------------------
MINIMIZE CPU USAGE IN SCAN LOOP
	by Dennis McKinney

It recently came to my attention that some LB programmers were avoiding scan loops because they use 100% of the processor. Scan loops are necessary if you use WM_Liberty.dll or almost anything else that uses LB callbacks. Although the 100% usage is true there's a simple way to cure this. An api call to Sleep is all that's needed. The following two programs were tested on a PII 400 that had 27 tasks running in the background along with Liberty BASIC. As the pictures show (see 100%.bmp and 1%.bmp) the program without the Sleep call used 100% of the processor while the program with the sleep call used only 1%. That 1% included all of the other running tasks too.

'-------- 100%
nomainwin
open "Use all of that cpu" for window as #1
#1 "trapclose [quit]"

[loop]
    scan
goto [loop]

[quit]
    close #1: end

'-------- 1%
nomainwin
open "Minimun cpu uasage" for window as #1
#1 "trapclose [quit]"

[loop]
    scan
    'sleep for 50 milliseconds
    calldll #kernel32,"Sleep",50 as ulong,r as void
goto [loop]

[quit]
    close #1: end

---------------------------------------------------------
API COLOR DIALOG
	by Dennis McKinney

Liberty BASIC has a perfectly good color dialog built right in. If you need
to have something different though, like a color dialog that pops up fully opened, then
you need to do a little work and use the common control color dialog. At first it
seems like this would be a stright-forward api call but there is a catch or two.
The first catch is this dialog does not like LB structures! The dialog will open
and display the color you want but when you move the slider or crosshair to select
a color it causes LB to crash. A fix for this is to allocate a little memory and copy 
the LB structure into it, then the dialog can manipulate this memory all
it wants to without affecting your program. When the dialog ends the info can be
collected and used. The second catch is getting the dialog to open up in the center
of the screen. From my own observations the dialog opens with it's upper left
corner at the upper left corner of the client area of it's owner window. So from that
observation a centering trick evolved. A window_popup of 0 width and height can be used
as the dialog's owner and positioned where the dialog's upper left corner should be.
The size 450 x 325 for the color dialog is an estimate.


nomainwin

'this struct is just used for padding
'in this snippet.
struct custClr,_
    x as char[64]

struct cc,_ 'CHOOSECOLOR
    lStructSize as ulong,_
    hwndOwner as ulong ,_
    hInstance as ulong,_
    rgbResult as ulong,_
    lpCustColors as struct,_
    Flags as ulong,_
    lCustData as ulong,_
    lpfnHook as ulong,_
    lpTemplateName$ as ptr

    WindowWidth = 0
    WindowHeight = 0
    UpperLeftX = Int((DisplayWidth - 450) / 2)
    UpperLeftY = Int((DisplayHeight - 325) / 2)
    open " " for window_popup as #hWndDlgOwner
    hWndDlgOwner = hwnd(#hWndDlgOwner)

    ccSize = len(cc.struct)
    cc.lStructSize.struct = ccSize
    cc.hwndOwner.struct = hWndDlgOwner
    cc.lpCustColors.struct = custClr.struct
    'set the initial color for the dialog to open with.
    cc.rgbResult.struct = 14483455 'RGB(255 255 220)
    cc.Flags.struct = 1 or 2  'CC_FULLOPEN or CC_RGBINIT

    'Allocate memory for a CHOOSECOLOR structure and copy the cc.struct to it.
    CallDll #kernel32, "GlobalAlloc", _GMEM_FIXED as long, ccSize as ulong, hMem as long
    CallDll #kernel32, "GlobalLock", hMem as long, pMem as long
    CallDll #kernel32,"RtlMoveMemory", pMem as long, cc as struct, _
        ccSize as long, ret as void

    'make the call with the memory pointer as the argument for the structure.
    calldll #comdlg32, "ChooseColorA", pMem as long, ret as boolean

    'The choosecolor dialog has returned the selected color in
    'the structure located in memory. To get these values and use them
    'just point the cc.struct to the memory location pMem.
    cc.struct = pMem

    ret = cc.rgbResult.struct
    notice strRGB$(ret)

    close #hWndDlgOwner

    'always free the allocated memory.
    CallDll #kernel32, "GlobalFree", hMem as ulong, ret as long
end

function strRGB$(intColor)
    Blue = int(intColor / (256*256))
    Green = int((intColor  - Blue *256*256) / 256)
    Red = int(intColor - Blue*256*256 - Green*256)
    strRGB$ = str$(Red)+" "+str$(Green)+" "+str$(Blue)
end function

---------------------------------------------------------
DEMOS BY BILL JENNINGS
---------------------------------------------------------
VIRTUAL TABS
	by Bill Jennings

Here's a way to make data in a non-fixed font (like Arial) look like it's
tabbed.  The right-justified sample uses LB3's 'stringwidth' command (many
thanks, Carl).  That command also works great for centering a string.  I
suppose one could even line up decimal points of a column of numbers, by
making a left and right string out of each one.


'------------- start of demo -----------------
'   tabArial.bas  --  virtual tabbing with
'   non-fixed fonts in LB3.
'   Demo by Bill Jennings, Jan 2003.


      nomainwin
    WindowWidth=500 : WindowHeight=480
    graphicbox #w1.g1,1,1,500,480
    open "" for window as #w1
      print #w1, "trapclose [quit]"
      gosub [getData]
      print #w1.g1,"font Arial 0 18"
      gosub [display]
    WAIT


[display]  '*** in 3 columns
    print #w1.g1, "down"
    for border=1 to 4
      x=150*(border-1)+10
      print #w1.g1, "line ";x;" 28 ";x;" 414"
    next border
    print #w1.g1, "place 182 20"
    print #w1.g1, "\- Left justified -"
    print #w1.g1, "place 178 230"
    print #w1.g1, "\- Right justified -"


    '*** left-justified
    for col=1 to 3
      for row=1 to 9
        nData=(col-1)*9+row
        x=150*(col-1)+20
        print #w1.g1, "place ";x;" ";20*(row-1)+40
        print #w1.g1, "\";a$(nData)
      next row
    next col


    '*** right-justified
    'Uses "stringwidth" command.
    for col=1 to 3
      for row=1 to 9
        nData=(col-1)*9+row : b$=a$(nData)
        print #w1.g1, "stringwidth? b$ width"
        x=150*(col-1)+150-width
        print #w1.g1, "place ";x;" ";20*(row-1)+250
        print #w1.g1, "\";a$(nData)
      next row
    next col
  RETURN


[getData]  '*** make 27 strings
    DIM a$(27)
    for d=1 to 27
      nChrs=int(rnd(1)*6)+3
      a$(d)="data "
      for h=1 to nChrs
        nAsc=int(rnd(1)*74)+48
        if nAsc=92 then nAsc=45
        a$(d)=a$(d)+chr$(nAsc)
      next h
    next d
  RETURN


[quit]
    close #w1 : END
'------------- end of code -----------------

---------------------------------------------------------
HOT KEYS AND MOUSE CLICKS
	by Bill Jennings

This demo will:
        1.  cheer the hearts of hotkey lovers.
        2.  show a way to code buttons for hotkeys OR mouseclicks.
        3.  enable a listbox for hotkey selection.  Just show a number in front of
each array item, and the user can input that number followed by the enter
key.  No mouse required, but that could work too.

'   hotClicks.bas -- demo of hotkeys in combination and mouseclicks,
'     simultaneously enabled.  Jan 2003, Bill Jennings
'     Thanks to Doyle and Alyce for clarifying the 'setfocus' command.

    nomainwin
    UpperLeftX=40 : UpperLeftY=80
    WindowWidth=640 : WindowHeight=300

    b1$="Alt-X will hotkey this EXIT button"
    b2$="Input a multi-digit number"

    button #w1.b1,b1$,[quit],UL,20,40
    button #w1.b2,b2$,[number],UL,20,108
    statictext #w1.st1,"",40,160,600,160

    statictext #w1.st2,"",320,150,300,30
    graphicbox #w1.g1,0,0,0,0

    open "" for window_popup as #w1
      print #w1, "trapclose [quit]"
      print #w1, "font Arial 0 22"

    print #w1.g1, "when characterInput [key]"
    print #w1.g1, "setfocus"

      '*** buffer$ is used in [scanLoop]:
    buffer$ = space$(256) + chr$(0)

[scanLoop]  '*** Scan sets focus back to the window
      ' for mouse clicks after pressing a hot key.
  SCAN
      '*** Check for Alt-X keys combination:
    calldll #user32, "GetKeyboardState",_
      buffer$ as ptr, result as void
    Alt$=mid$(buffer$,19)
      '*** 19 is the VK code decimal value + 1.
    if asc(Alt$)>127 then Alt=1  '*** Alt key pressed
    X$=mid$(buffer$,89)
    if asc(X$)>127 then X=1  '*** X key pressed
    if Alt and X then [quit]

      '*** 1 ms delay to save processor cycles:
    calldll #kernel32,"Sleep",1 as ulong,r as void
  goto [scanLoop]

[quit]
    close #w1
  END

[key]
    Alt=0 : X=0  '*** reset
    key$ = Inkey$
    ndx=asc(right$(key$,1))
    if number then gosub [numberPressed]
  goto [scanLoop]

[number]
    decimal=0
    print #w1.st1, ""
    print #w1.g1,"locate 300 106 300 30"
    print #w1, "refresh"
    print #w1.g1, "cls"
    prompt "maximum number "; mxNum$
    if mxNum$="" then [scanLoop]
    mxNum=val(mxNum$)
    tx1$="Max number= "+mxNum$+chr$(13)+chr$(13)+_
      "Start pressing keys."+chr$(13)+_
      "The number will stop building when you press enter"+_
      chr$(13)+"or when you exceed the maximum number."
    print #w1.st1, tx1$
    print #w1.g1, "setfocus"  'reset for key input.
    number=1
  goto [scanLoop]

[numberPressed]
    ok=0
    if ndx=46 and not(decimal) then_
      decimal=1 : ok=1  '*** decimal point
    if ndx>47 and ndx<58 then ok=1 '*** a number
    if ok then
      num$=num$+chr$(ndx)
      if val(num$)>mxNum then_
        num$=left$(num$,len(num$)-1) : done=1
      print #w1.st2, num$
    end if
    if ndx=13 or done then  '*** Enter key
      print #w1.st2, ""
    print #w1.g1,"place 10 18"
      print #w1.g1, "down;\the number is ";num$ 
      num$="" : done=0 : number=0
    end if
  RETURN

---------------------------------------------------------
A Users Review of theWrap
- David Drake, ddrake@foundrysearch.com

Our story begins in the Year or our Lord 803

And the cry went out from Liberty BASIC users across the Land; yea, across the world, even: We desire that our programming creations would look like programs created by other languages.  We want a single executable instead of numerous dlls and token files.  And Carl the Creator replied, I shall not encumber mine favorite creation with the stuff of frivolity.  Besides, you dont really need it, do you?

The cries continued unheeded.  The teeming masses of Lbers wept bitterly.

Then a knight in recently polished armour, known only by the moniker TronDoc, perambulated into the virtual town.  TronDoc heard the peoples cries and said, I shall slay this evil dragon with a third-party workaround, the Holy Executable Creator!  The people were having tea at the time and failed to hear his brave declaration, so the knight stalked out of the town in a huff.

That night, the knight sat down before his trusted PC.  He began the slow, arduous process of forging link by link the Holy Executable Creator.  He worried that people might shorten the name to HECTor or some such nonsense, so he called the holy artifact theWrap.  The anvil upon which he smythed theWrap into existence was called iBasic, an insignificant language that DID compile programs into single executables.  TronDoc toiled for 1,061 days to finish theWrap, and when he was done, he wrote a detailed help file and decided to sell it for one dollar, which was equivalent to the average persons lifetime wages.

TronDoc buffed his armour (it had oxidized during his quest for the Holy Executable Creator) and walked back to town (he had traded his white stallion for a copy of iBasic) where he loudly declared: Hear ye! Hear ye, o fair programmers of LB Land!  Today, your joy is restored!  I bring to you the ability to turn your folder full of Liberty BASIC runtime DLLs and associated resource files into single executables! I give you (long, dramatic pause) theWrap!

The cicadas quietly chirped and a flock of pigeons flew dramatically overhead (making TronDoc quietly curse them for adding at least an hour to tonights armour-polishing time).  The people of LB Land stood in the streets.  They stared at Knight TronDoc with a single thought in their minds: Huh?  So the brave knight stomped out in frustration.  At the edge of town he took off his silver-and-white-splotched armour, dug a hole about three feet deep, and within it he buried the armour and Holy Executable Creator for all time.  He placed a triangular piece of flagstone over the spot to hide the evidence of his work.  Serves those thankless idiots right,  he said to no one in particular.  Im going into real estate.  TheWrap was buried forever.

Or so he thought

Fast forward 1,200 years to 2002.

Joe was puttering about in his garden one evening, wondering where on earth he was going to dig the footing for his new water fountain.  Not really the technical sort, he had already tried to place the fountain in several spots in the yard, only to have it come crashing down on his petunias or bayberry bushes.  His neighbor, Alyce, suggested that he pour a concrete footing to give it a bit of stability.

He found the perfect spot.  Have to move this triangular bit of flagstone, though, he thought.  Two hours and four band-aids later, Joe sat inside of a three-foot hole holding a small tarnished chest.  Hello, whats this? he said.  After much effort he finally broke the rusty hairpin out of the locking mechanism and opened the box to reveal a CD labeled theWrap.  Joe had never been particularly careful about installing programs on his PC, so he dashed in and popped in the CD to see what would happen.

After reading the help file (Joe happened to be one of the worlds experts in Medieval programming languages), he knew he had something special.  Joe wanted to be true to the desires of Knight TronDoc.  So he adopted the online name TronDoc, updated the help file into modern English, and made theWrap available to Liberty BASIC programmers at its original price of $1.

Now the review:

TheWrap is an impressive tool that help Liberty BASIC programmers create single executables from their LB runtimes and resource files.  

How it works:

TheWrap takes a set of source files in a directory and its subdirectories and places them in a single file with an EXE extension.  When the user runs the single EXE, the files are extracted to the local directory, used, and then are deleted when the user closes the program.  Files created by your internal program are not deleted.

What you do:

1.      Place all of your runtime files into a single project directory.
2.      Place you resource files (wavs, bitmaps, data, etc.) into that same directory or a subdirectory in that folder.
3.      Start TheWrap.  Each step of creating the final executable is placed on a single window.  After one step in the process is complete, the next button it highlighted.
4.      Select the project directory.
5.      Give your single executable a name.  This name MUST be different from what you call the LB runtime EXE.
6.      Select the icon for your single executable.  The icon MUST be 32 x 32 pixels, 16 colors and 766 bytes.
7.      Select the internal executable you want to run upon unwrapping.  For us, this is the Liberty BASIC runtime EXE.
8.      If your program requires some kind of argument or data file, select this next.
9.      Click on WrapIT and theWrap creates a single executable on theWraps directory.

Now you can test your creation.  DO NOT test it in the project directory!  Testing it in the project directory will delete your source files.

Other information:

In my test, theWrap took resource files that occupied 3.49MB and created a single executable that was 3.76MB.  In addition, the zipped resource files occupied 1.69MB while the the zipped theWrap executable was 1.90MB.

TheWrap unpacked and executed the resource files with no noticeable delay.  The program also closed instantly.  If I have the folder open that contains the wrapped executable, I see the files as they are unwrapped and they are available to the user to be copied or viewed as long as the program is open.

Final thoughts:

TheWrap is a great tool for making your programs look and feel more professional.  If you dont really need tight security and dont mind a little weight being added to your final program, the theWrap is for you!  Go ahead and register the thing, too  Its only $1 (or the foreign equivalent).

You may download the demo version of theWrap for free at Joe Blocks (aka TronDoc) web site.  The demo version limits you to wrapping 25 files, but it is otherwise fully functional.  The registered version wraps up to 200 files (more that most of us will ever need).

Get theWrap and some examples of Liberty BASIC wrapped projects here:


http://trondoc.ezwebtech.com/theWRAP/

---------------------------------------------------------
Using BASIC for Numerical Integration
by Tom Nally
Steelweaver52@aol.com

(Editors note:  please see the html version of this newsletter for a beautifully formatted article.  To read it as text, here, please refer to the attached jpg images that are referenced.)

(WikiWriter, USA) One of the fun things that we learn during the first course in calculus is to find the area under a curve. By "area under a curve", we mean the enclosed area bounded by the following:

a function, f(x), on the top; 
the x-axis on the bottom; 
a real number, "A", creating a boundary on the left; and 
another real number, "B", creating a boundary on the right. 
Figure 01 on the right shows the area under the curve between A and B shaded in light blue.

In this article, I'm going to discuss a procedure for finding the area under a curve using a Liberty BASIC computer program that features "numerical integration". This procedure is called "numerical integration" because it peforms the integration (that is, calculates the area under the curve) without strictly relying on calculus. Rather, the procedure performs this duty by slicing the area up into hundreds of thin "elements", finding the area of each element, then adding them all together.

Before we get to that, however, we are going to find the area under a curve using traditional calculus. We are doing that for two reasons:

We want to demonstrate what traditional calculus looks like, so you can see how it differs from numerical integration; and 
We want to develop an answer to a calculus problem using traditional calculus as a way of checking the answer that we get using numerical integration. 
If you haven't had a calculus course, the traditional calculus might not make much sense to you. Don't worry about that. Understanding traditional calculus is not a prerequisite for understanding numerical integration. So, just humor us for a few minutes, and we'll get to the LB program shortly.

Finding an Area using Traditional Calculus
Before we can find the area under a curve, we have to start by identifying a function. What is a "function", anyway? If I recall correctly, a function is a relationship between a set of x values and a set of y values such that each x value has one and only one y value. Any single y value can be associated with more than one x value, but the reverse cannot be true. That's how it was defined for me, anyway.

In this traditional calculus example, we will use the following function:


Here is what that same function looks like when graphed:

Let's find the area under this curve between x = 2 and x =8.

The first step in finding the area under a function in calculus is to find the "indefinite integral" of the function. The indefinite integral of a function is another function which is found by applying the rules of integration to the first function. For instance, the indefinite integral of (a*x^b) with respect to the variable "x" is (a/(b+1))*(x^(b+1)). 

For the function in which we are interested, the indefinite integral is shown in Figure 04, below, using calculus notation:


To find the area, or "definite integral" of the function, we have to evaluate the indefinite integral between our two limits, x = 2 and x =8. Figure 05 shows what that process usually looks like using calculus notation:


The result of our integration using traditional calculus is Area = 27.9. With that out of the way, we will find the area using numerical integration, and come up with the same answer. OK, it might not be exactly the same, but it will be so close that the difference will probably be insignicant.

Finding the Area by Numerical Integration
First, let's establish the concept around which we are going to build our Liberty Basic program.

 If you look at Figure 06 to the right, you will see the same function that was shown in Figure 01. In this one, however, a particular "element" of the area under the function is highlighted. Look at that highlighted element closely for a few moments. It resembles a shape with which we are quite familiar: the trapezoid. Of course, it is probably not a true trapezoid, because the function, f(x), is curved at the top of the element. However, as xa and xb get closer and closer together, the function between f(xa) and f(xb) becomes nearly a straight line! This collection of observations is the key to finding the area of this trapezoidal element, as well as the key to finding the area under the function.

So, what is the area of this trapezoidal element? That question was treated extensively in December in the Yahoo LibertyBasic news group during the discussion of the area inside of a polygon. On several occasions, I offered that the area of the trapezoid was as follows:

TrapArea = (xb - xa)*f(xa) + (1/2)*(xb - xa)*(f(xb) - f(xa)) 

While that is correct, this formula has a simpler form that we will use here forward:

TrapArea = (xb - xa)*(f(xa) + f(xb))/2

If you look at this second formula, it's easy to see why that's the area of the trapezoid. (xb - xa) is the base of the trapezoid. Then, (f(xa)+f(xb))/2 is the average of the heights of the two sides of the trapezoid. Essentially, then, we are multiplying the base of the trapezoid by the average height between the left and right sides. Pretty straight-forward if you axe me (as we say in New Orleans).

Finding the area under our curve, then, involves slicing the shaded area into many small trapezoidal elements, and using the formula above to find the area of each one. When all the areas of the trapezoids are added together, then the result will be the area under the curve.

Friends, arithmetic such as this is child's play for our computers running Liberty BASIC.

The Numerical Integration Program
Before we get into all of the slicing and dicing of the shaded area, the first thing that we will do is define a Liberty BASIC function to hold our mathematical function. This will help make the program a little more modular: if we want to change mathematical functions, all we have to do is alter the contents of the Liberty BASIC function.

Let's make our Liberty BASIC function look like the code shown below. (Even though I'm discussing this function first, it will actually appear at the end of the code.)

function f(x)
  
    f = 0.15*x^2 - 0.6*x + 3.45

end function

Let's get right into the display of the code, with comments included.

''''''''''''''''''''''''''''''''
'Liberty BASIC program to find
'the area under a curve.
'
'by Tom Nally
'Released as Open Source
'
'''''''''''''''''''''''''''''''''
'
'Note that the function, f(x), is defined
'within a Liberty BASIC function statement
'at the end of the program.
'
'First, dimension an area to hold the
'individual areas of each trapezoid

Dim TrapArea(10000)

'Establish the left and right boundaries
'for the area under the curve.
'
A = 2
B = 8

'We will cut our area into 1000 
'extremely thin elements, each of
'which will have the same width.
'we will call this width "dx".

NumElements = 1000

dx = (B - A) / NumElements

'Setup is complete.  Time to find
'the area of each trapezoid.  We will'
'use a for...next loop for this 
'operation.

for i = 0 to (NumElements - 1)
   xa  = A + i*dx
   xb  = xa + dx
   fxa = f(xa)
   fxb = f(xb)
   TrapArea(i) = (xb - xa)*(fxa + fxb)/2
next i

'The areas of all the trapezoidal elements
'have now been found.  Now we will sum
'them all together in a second loop.

TotalArea = 0

for i = 0 to (NumElements - 1)
    TotalArea = TotalArea + TrapArea(i)
next i

print "TotalArea = "; TotalArea

End

''''''''''''''''''''''''''''''''''
function f(x)
  
    f = 0.15*x^2 - 0.6*x + 3.45

    'If you want to find the are
    'under a different function
    'just change the definition
    'above!

end function

If you copy this code into Liberty BASIC and run it, a single line of output will be produced:

TotalArea = 27.9000054

While this is not exactly the same result as we saw when we found the area under the curve using traditional calculus, you have to admit that it is pretty close to the exact result of 27.9.

Three Final Notes About Numerical Integration and the LB Program
(1) You may slice the area under the curve into as many or as few elements as you wish by assigning different values to the variable NumElements. The more elements used, the more accurate the integration will be. Be aware, however, that high levels of accuracy may not be more useful than lesser levels of accuracy. Even dividing the area up into 10 elements (rather than 1000) produces an Area of 27.954, compared to the true area of 27.9.

(2) Finding areas by integration, whether by traditional calculus or by numerical integration, can sometimes produce values less than zero. Negative areas might occur when (a) all or part of the function lies below the X-axis, or (b) we integrate from the right-hand boundary to the left-hand boundary, instead of vice versa. This is not a flaw in the methods. This is the way it is supposed to work.

(3) Look again at the differential element highlighted in Fig 06. Yes, it's shaped like a trapezoid. But, as xb gets closer and closer to xa, the difference between f(xa) and f(xb) gets very small compared to either f(xb) or f(xa). Because f(xa) and f(xb) become nearly identical, the element might also be characterized as a tall, slender rectangle rather than a trapezoid. If that's the case, then the area of the element in the BASIC program can be written like this

TrapArea(i) = (xb - xa)*(fxa)

instead of the way shown above:

TrapArea(i) = (xb - xa)*(fxa + fxb)/2

If you make that change in the BASIC program you will get these results...

TotalArea = 27.8838054

Compare this to the true value of 27.9. For some problems, this may be more than enough accuracy. The TrapArea formula which you select will depend on the tradeoffs you wish to make between accuracy and computing time.
---------------------------------------------------------
LibSQL  v1.1 - SQLITE DATABASE FOR LB
	by Richard Peeters

(editor's note:  See the attached libsq4.bas for a demonstration of the method. The SQLite.DLL is included in the archive with this newsletter.)

Introduction

SQLite is a public domain C library that implements an  SQL database engine. Programs that link with the SQLite library can have SQL database access without running a separate RDBMS process. SQLite is not a client library used to connect to a big database server. SQLite is the server. The SQLite library reads and writes directly to and from the database files on disk.

All information is written to disk as strings. This means that in a CREATE TABLE statement you do not have to give the kind of data you will be putting in the fields.  Another thing is that SQLite uses records of variable length. So no need to give fieldlengths.  All tables (datafiles) and indexes in a database are all in 1 physical file on disk.

This is a first version (v1.1) of a Liberty Basic userinterface to test the SQLite DLL and to learn SQL. Colin McMurchie wrote the API  functions to access the DLL  and provided us with a program to test them. I used some of his functions as a base for LibSQL.

For the SQL syntax understood by SQLite see the SQLite website:

http://www.hwaci.com/sw/sqlite/lang.html

For the time being LibSQL only supports part of SQLite (see below).  On the other hand I added some (I hope) useful functions.  This is not a SQL course. There are many sources of information available on the subject in written form and on the internet. If there is enough interest in the subject I can eventually create a tutorial for a future newsletter.

How to get started

1. Create a folder to contain the program, the DLL and your (future) database(s).
2. Download the SQLite documentation from the above mentioned website.
2. CopySQLite.dll v2.7.5 to the created folder.
3. Copy LibSQL to the created folder.
4. Run LibSQL.
5. Create a database (database -> new) or open an existing one.
    Do not give an extension  default is .dbs
    If you try to create a database that already exists, the existing one is opened.

The program opens 2 texteditorwindows. The upper one is used to enter commands and queries. You can enter commands on one line or on different lines. When you click execute everything is concatenated in one line.

Ex: Select * from test
       is the same as
      
        Select
        *
        from test		

Every string has to be enclosed in single quotes. Numbers may be but it is optional.

Ex: Select * from test where name=lennon	
	
You can save LibSQL commands with the file -> save option and recall them with file -> open.
To save time commands can be copied and pasted.

The lower texteditor will display the results and the program messages.

6. Create a table.
7. Do some SELECT queries.
8. Try things out
9. Give feedback
 
LibSQL v1.1  - Supported functions

All syntax starting with . is an added feature. This means that the program does at least some processing before (eventually) calling the DLL.  All syntax without a leading . is a straightforward SQLite call.  In the following all LibSQL syntax is shown in UPPER Case, although lowercase is permitted in all commands.


CREATE TABLE tablename (field1,field2,,fieldx)
    Ex: CREATE TABLE test (Name,firstname,age)

CREATE INDEX indexname ON tablename (field)
    Ex:CREATE INDEX textindex ON test (name)

DROP TABLE tablename
    Ex: DROP TABLE test

DROP INDEX indexname
    Ex: DROP INDEX testindex

DELETE FROM tablename
    deletes complete table

DELETE FROM tablename WHERE condition
    Ex: DELETE FROM test WHERE name=peeters

INSERT and .INSERT
INSERT follows the SQL syntax -  .INSERT allow to drop the ,'s and the ()'s.

    Ex: INSERT INTO test VALUES
        ('peeters',
        'richard',
        30)

    Ex: .INSERT INTO test
        peeters
        richard
        30
 
UPDATE tablename SET
    fieldname=value
    WHERE condition

    Ex: update test
        SET name='tanson'
        WHERE age=30


SELECT * FROM tablename
    Ex: SELECT * FROM test
    Ex: SELECT * FROM sqlite_master
.MODE
sets the way the result from a Select query is displayed.

.MODE LINE: every field of the returned records is displayed one after the other seperated by |.
.MODE LIST: every field is on a line of its own
.MODE COL: all fields are lined up every 15 positions - fields longer then 15 are truncated.
.mod PRINT: same as col but result to the printer.
.MODE FILE: result is output to a comma separated textfile.


Future plans

- A report writer module For SQLite
- Importing of ASCII Files 
- Interactive record insertion
- A function library to embed SQLite in Liberty Basic
- Any suggestions are welcome

Richard Peeters  jan. 2003
r.peeters@pandora.be
---------------------------------------------------------
HELP (... IS ON THE WAY!)
	by Jerry Muelver, jerry@hytext.com

**************
Editor's note: 

Jerry Muelver is a programmer, an internet consultant, and an educational specialist. His article here gives us a logical and concise blueprint for documentation writing. The methods outlined are good for any kind of documentation, but are especially aimed at helping us document our programs with user guides/help files.

I got to know Jerry because I started using an authoring tool of his called WikiWriter. I've been searching out authoring tools for a few years now. I've found that most are either complicated to learn, are focused on providing glitz rather than delivering information, are overpriced, or are all of the above. WikiWriter gave me an easy way to format information - both text and images - so that it is easy to read and easy to navigate. The newsletter has contained articles on other help authoring tools, and I thought I'd do one on WikiWriter as well. Then I thought, how much better it would be if I could persuade Jerry himself to write an article! He has graciously answered my request, but rather than provide a simple description of WikiWriter, he has given us an excellent article on writing documentation, with a description of WikiWriter at the end.

	--Alyce Watson
**************

Help! (... is on the way!)
by Jerry Muelver, HyText Consulting


A quick way to access Help files for your LB app is to point the user's Web browser to an HTML file with a RUN statement. (That is to say, it's quick if you are adept at writing HTML files. See Note 1) 

Once you've got a productive, effective method for producing HTML (see Note 1), the hard work begins. How do you know what to put into a Help file, and how do you know it will actually help?

From your own experience with computer applications, you already know that a Help file's main sections are typically:

	* Table of contents 
	* Overview, description of what the program is designed to do. 
	* Controls, detailed list and description of each menu item, control button, and entry field in the program 
	* Functions, how to make the program work to accomplish its intended tasks 
	* Errors and recovery, how know what's broken, and how to fix it 
	* Index 

People who have done this sort of work before already have a good idea how to go about building Help files. Let's ignore those folks, and lay out the simplest way possible for complete beginners to build Help files. The basic assumption is that we'll create a Help system in HTML (to take advantage of Web-style built-in display features), and that those of us who do not automatically write error-free HTML markup in our sleep will use an HTML or Help file editor of some sort (see Note 1). I'll explain what to do with the tools, rather than how the tools work, because (1) I don't know which authoring tool you have chosen, and (2) those who choose WikiWriter will be productive in ten minutes or so, anyway.

Table of Contents
The process of writing Help files is iterative. You start small, and keep building and refining as you go until the job is done. The basic approach is to create a label for something, then describe the something you just labeled. 

Begin with a Table of Contents (TOC). The minimum TOC will simply point to the main sections. Build a list of links for those sections like this to get started:

	* Overview 
	* Menus and Controls 
	* Functions 
	* Troubleshooting 
	* Index 

Now your TOC is done, at least for now. You can always add more links when you have more sections, sub-sections, and topic pages to play with.

Overview
On your overview page, start with just three paragraphs, each describing one of the following, in four sentences or less:

	* What the program does 
	* What is special about this program compared to the competition 
	* Who developed the program, and how to contact the developer 

If you keep this section short, people will actually read it.

Menus and Controls
We all know your program is designed with a completely intuitive interface which really needs no explanation. But just in case your program winds up in the US Congress some day, you should probably explain the obvious anyway.

Menus are easy to document. Just build a list in outline fashion that shows your menu structure:

	File 
		New 
		Open 
		Quit 
	Edit 
		Copy 

Now add an explanatory phrase after each menu command. Keep it short and sweet. Make the explanation read more like a ToolTip than a magazine article. Avoid lecturing: "This option, when dropped down from the menu bar and selected by the user, will activate the Operating System's file selection browser in 'Open' mode, enabling...." 

Your users want information, not Victorian Romance, so try it like this:

	File 
		New - Create new file 
		Open - Find and open existing file 
		Quit - End program 
	Edit 
		Copy - Copy selected text to memory 

Do the same for controls. Use their button text or names if they are labeled. For graphics controls, take the time do do screen captures, or re-use the button graphics in your list so your user knows exactly what you're talking about. Group related controls together in sublists.

Functions
You might call this section Actions, or Tasks, or Features, if you like. Now that you've described the menus and controls, you are free to refer to them in a series of condensed instructions on their use. But, how do you explain how use the program's features without sounding like a geek out of water? You use "TWIT" -- The Whispered Instruction Technique.

To use TWIT, imagine you have a clueless user sitting at the keyboard, all set to trash your program by doing the Wrong Thing at the Wrong Time. Your job is to prevent disaster by whispering instructions into the user's ear just before Something Awful happens. You can't grab the mouse, or poke at keys, or pull the power cord plug out of the wall. You can only whisper instructions, and jot them down for your Help file as you whisper.


Start with a list (familiar, comfortable refrain, isn't it?) of the jobs you want TWIT to do. Your list should cover the range of actions your program supports. If some of the actions are large-scale ("Build House"), use sublists to break them down for TWIT ("Build House > Clear land, dig basement, pour foundation, set footers, assemble wall frames..."). Two basic formats are the narrative:

	* Open a file - Select File > Open. Use the file browser to find a file. Double-click on the file name to open the file, or single-click on the name to select the file and then click on Open. 
and the sequence (or "recipe"):

	* Move text 
		1. Select the text with the mouse click-and-drag. 
		2. Release the mouse button. 
		3. Move the mouse cursor into the area of the selected text. 
		4. Click-and-hold the right mouse-button. 
		5. Holding the button down, move the cursor to drag the text to the new location. 
		6. When the text is positioned where you want want it, release the mouse button. 
		7.To undo the move, in case it didn't work the way you wanted, press Control-Z (press and hold Control while you press and release Z). 

I usually build the outline of jobs as a list of links, and apply TWIT to each job on a separate page. It's easier to scan a list of jobs and pick out the specific one you need than it is to find it by scrolling though long, dense text like this article.

Troubleshooting
Name this section whatever you wish, as long as the users can identify this as the place to go if something unexpected happens. I once had a client who banned "troubleshooting" from our dictionary of authorized technical terms because that term could give someone the idea that people could have trouble with the product. That was about the time I came up with "TWIT".

This section holds your error messages and explanations, typical user-caused glitches and recoveries, and problem diagnostic procedures. Once again, use lists to organize your material, and keep it short and to-the-point.

Index
Indexing is a special art, and not for timid to attempt. With a properly detailed TOC and readable lists for controls and functions, you can get by without an index. But for really large, complex programs and systems, an index is essential. Get experts to help on this effort, unless you have tools that can make indexing easy to do (see Note 1).

Packaging
One way to package your Help system is to deliver it as a bunch of HTML files. If you put your application in a Zip file, just add the HTML files and any supporting graphics files to your application's main directory. Hook your app's Help button up to a RUN call to the first file in your set. This works even if the user has some browser other than MS Internet Explorer.

Another way is to compile all the Help files into a single MHT-format file, and point your Help button to that file with a RUN command to trigger the user's Internet Explorer. Only MSIE reads MHT format smoothly. See Note 1.

You can go the whole 9 yards and compile your system into Windows HtmlHelp, with the proper tools. That process is easier to do than it is to explain, once you've acquired the tools and some mildly frustrating experience, so I won't cover it here.

What to do next
Since you started simply, and organized tightly, it's not difficult to enhance and expand your Help system with such goodies as Tutorials, Tips and Tricks, Templates, or whatever else your user base demands. Don't get seduced into a bunch of tricky layouts and magic secondary pop-up windows and tooltip glitz. If you need those things, you're already working for a big-big company with lots of resources and money to waste, which means it's probably a good idea to out-source the Help file production to someone who already knows all the tricks and secrets of tech writing, so you can concentrate on programming. 

For an example of how a Help system can be simple and direct, and still do the job, take a look at http://hytext.com/iwiki/ which is the posted HTML version of the Help files for WikiWriter, generated by WikiWriter (see Note 1).

********
Note 1: If you're not a wonderful HTML coder (or if you are, and you really want to fly!), take a look at WikiWriter. It produces HTML files from your simple tag-marked text files. WikiWriter will also compile your entire directory full of Help files into a single MSIE-compatible MHT file, graphics and everything, so you only have one file to distribute.

Help files aren't the only thing you can do with the WikiWriter authoring system. You can run it on a trial basis for 45 days to experiment with PIM applications, free-form textbase stuff, web site design, project and program specification and wire-frame design, and all the other writing jobs that settle on the shoulders of programmers.

See what the WikiWriter way of working means for your programming and your program users by checking it out at http://hytext.com/ww. WikiWriter can do for your writing what Liberty Basic has done for your programming.

********
Note 2: The rumor that Microsoft is using WikiWriter internally for project documentation on the .NET product line is, as yet, unverified, and must be regarded as possibly untrue.

---------------------------------------------------------
---------------------------------------------------------
SUBMISSIONS

The Liberty BASIC Newsletter encourages all LB programmers
to submit articles for publication.  Everyone has something
valuable to say, from beginners to veteran LBers.  Consider
sharing a code routine, with explanation.  Perhaps you can
review a favorite LB website, or program, or coding tool?
Why not submit a list of questions that have been nagging
at you?  How about sharing your favorite algorithm?

---------------------------------------------------------
---------------------------------------------------------
    Comments, requests, submissions or corrections: 
Simply reply to this message, or contact a member of the team!

			The Team:
	Alyce Watson: alycewatson@charter.net
	Brad Moore: brad.moore@weyerhaeuser.com
	Tom Nally:  SteelWeaver52@aol.com
	Carl Gundel: carlg@libertybasic.com
	Bill Jennings: bbjen@bigfoot.com
---------------------------------------------------------
---------------------------------------------------------
---------------------------------------------------------