---------------------------------------------------------
The Liberty Basic Newsletter - Issue #98 - JUL 2002
    2002, http://groups.yahoo.com/group/lbnews/
             All Rights Reserved
Individual authors retain copyrights to their works.
---------------------------------------------------------
"I haven't failed, I've found ten thousand ways that
don't work." 
	--Ben Franklin
---------------------------------------------------------
In this issue:

	Notes from the editor
	Spotlight - Remembering Logo
	Turtle graphics tutorial
	Scripting language tutorial 
	Scripter.bas - a simple scripting language
	Changing window icons at runtime
	A real spinner control for Liberty BASIC
	Tip Corner - Select Case
	Hocus Focus, by Brad Moore
	Illuminated Radiobuttons by Mike Bradbury
	Submissions
	Credits
---------------------------------------------------------
---------------------------------------------------------
NOTES FROM THE EDITOR

The Liberty BASIC Newsletter started as "Brosco's LB
Newsletter" in April of 1998.  At that time, Brosco wrote
the technical articles, and I served as a proofreader and 
sounding-board for his ideas.  The form of the newsletter
has changed several times over the years.  I now think we
have found the best way to handle the publication -- as a
team!  In the past, if "the publisher" was unavailable, then
the newsletter wasn't published.  That should no longer 
happen.  If one person is unavailable, the others will fill
the gaps.  We won't have any more big changeovers in
publishers.  People will join the team and others will leave
at intervals as their needs dictate, but the newsletter
itself will have continuity.

Brad Moore and Tom Nally are the newest members of the
team.  They are both terrific in every way... they are
clever coders with a knack for explaining things so that
we can all understand.  They are also both terrifically
nice, helpful people.  You needn't take my word for it --
just read Tom's incredible article on Polar Coordinates in
the May newsletter, and Brad's great June newsletter!

Email addresses for all publishing team members are at the
bottom of each newsletter.  Feel free to contact one of
us with submissions, or to volunteer to join the team.

LIBERTY BASIC WINS!
Liberty BASIC received enough votes to put it in third
place in its category in the Isidor Shareware Awards.
Congrats, Carl!

THANKS!
Special thanks to Brent Thorn for sharing the method
to change a window's icon at runtime.  Thanks also to
Brad Moore for his great article on window and control
focus.  Thanks to Mike Bradbury for his clever and
attractive illuminated radiobutton demo.

REMINDER
The lbnews Yahoo group is no longer a discussion group.  It
has gone back to its original use -- as a distribution point
for the newsletters.  Post discussions to one of the other
discussion forums, such as the official LB group, here:
http://groups.yahoo.com/group/libertybasic/

or the experienced users group here:
http://groups.yahoo.com/group/lbexp/

or the ABC archives programming forum here:
http://www.allbasiccode.com/cgi-bin/yabb/YaBB.cgi

or the D4L forum here:
http://development4life.net/board/index.php


------------
Respectfully,
Alyce Watson


---------------------------------------------------------
---------------------------------------------------------
SPOTLIGHT - REMEMBERING LOGO

http://el.www.media.mit.edu/groups/logo-foundation/logo/index.html

To learn more about Logo, visit the URL listed above.  
Logo was the original "Turtle Graphics".  It was designed to
be a simple beginning programming language that interacted
with the learner.  The turtle graphics tutorial and the
scripting language detailed in this newsletter both derive
from Logo.

Below are some interesting quotes from the website.  It is
definitely worth a visit to learn more.

INTERACTIVITY
Although there are some versions of Logo that compile, it 
is generally implemented as an interpreted language. The 
interactivity of this approach provides the user with immediate 
feedback on individual instructions, thus aiding in the debugging 
and learning process. Error messages are descriptive.  

THE TURTLE:
The most popular Logo environment has involved the Turtle, 
originally a robotic creature that moved around on the floor. 

It can be directed by typing commands at the computer. The 
command forward 100 causes the turtle to move forward in a 
straight line 100 "turtle steps". Right 45 rotates the turtle 
45 degrees clockwise while leaving it in the same place on 
the floor. Then forward 50 causes it to go forward 50 steps 
in the new direction. 

With just the two commands forward and right, the turtle can 
be moved in any path across the floor. The turtle also had a 
pen which may be lowered to the floor so that a trace is left 
of where it has traveled. With the pen down, the turtle can 
draw geometric shapes, and pictures, and designs of all sorts. 

Off the Floor and Onto the Screen 

The turtle migrated to the computer screen where it lives as 
a graphics object. Viewing the screen is like looking down on 
the mechanical turtle from above. 

The screen turtle also understands forward and right.
(read more at the website!)

---------------------------------------------------------
---------------------------------------------------------
TURTLE GRAPHICS TUTORIAL	(novice level)
	by Alyce Watson

In Liberty BASIC, we don't have a robotic turtle walking
around on the floor.  When we issue turtle graphics
commands, we see the output in a graphics window or in a
graphicbox.  We can imagine that we have a turtle that holds
a drawing pen.  If the drawing pen is down, then when the
turtle travels, he leaves a trail on the display.  If the
pen is up, the turtle travels, but no graphics are drawn.

Note that Liberty BASIC has many drawing commands that
will draw boxes, circles, etc., but we will not discuss
these in this article.  We will focus only on the turtle
graphics commands.

IMPORTANT NOTE
Drawing commands are issued inside of quote marks.  The
commands are case insensitive, which means that it doesn't
matter if you type them in all caps, all lowercase, or in
a combination.


POSITIONING THE DRAWING PEN
When a graphics window is opened, the drawing pen is located
at point 0, 0, which is the upper left corner of the drawing
area (another name for this area is the client area.)  

Graphics are measured in PIXELS, which is short for PICTURE
ELEMENTS, or dots on your screen.  Point 0, 0 is in the upper
left corner of the drawing area.  As x positions get larger,
they move to the right.  As y positions get larger, they move
down.  This might be confusing at first for those of us who
were used to drawing graphs in math where the 0, 0 point was
positioned at the LOWER left corner.  Don't worry, after a
while the computer's method of positioning will seem natural!

When we first open a graphics window or graphicbox, the
pen is up.  To draw, we must first put the pen down, like
this:

print #gr, "down"

All graphics commands will show until we issue the UP command,
like this:

print #gr, "up"

When the pen is UP, the drawing pen will move around in the
drawing area, but no graphics will be drawn.

We can locate the drawing pen in several ways.  If we want to 
center the pen in the drawing area, we can issue a HOME 
command, like this:

print #gr, "home"

We can locate the drawing pen with the GOTO command.  The
pen will move to the x, y position indicated, and it will
draw if it is down.  If the pen is up, it will move to the
position indicated, but no line will be drawn.

print #gr, "goto 100 20"

Before we continue, let's consider an important point!

USING VARIABLES IN DRAWING COMMANDS
In the example above, the value for x is 100, and the value
for y is 20.  These are "hard coded" values.  This means that the
actual values appear in the command.  It may at times be
necessary to give a command when values are variables.
This is easy, but it requires you to remember that values
that are variables must be located OUTSIDE of the quote marks,
and that BLANK SPACES MUST BE PRESERVED.

Correct usage:
x=100 : y = 20
print #gr, "goto ";x;" ";y

In the above example, Liberty BASIC sees this:
print #gr, "goto 100 20"


Incorrect usages:
x = 100 : y = 20
print #gr, "goto x y"     'variables are not outside of quotes!
print #gr, "goto";x;y     'no blank spaces!

In the above examples, Liberty BASIC sees this:
print #gr, "goto x y"
print #gr, "goto10020"


There is yet another way to locate the drawing pen in Liberty
BASIC turtle graphics.  The pen will move the desired distance
in the current direction when a GO command is issued, like this:

print #gr, "go 10"

or

d=10
print #gr, "go ";d

If the pen is DOWN, a line will be drawn from the current pen
position in the current direction, and it will be the length
specified.  If the pen is UP, the pen will move to the new
position, but no line will be drawn.

We may also locate the pen in the desired x, y position with
the PLACE command, which moves the pen to the position indicated
without drawing.  This isn't really a part of turtle graphics,
even though it is a part of Liberty BASIC graphics, so we won't
use it here.

We can also move the drawing pen with a SET X Y command.  This
command draws a point in the x, y location given.

print #gr, "set 100 20"
or
x = 100 : y = 20
print #gr, "set ";x;" ";y

SETTING AND CHANGING DIRECTION
In the GO command that was mentioned earlier, we stated that
the pen would travel the distance indicated in the CURRENT
DIRECTION.  When a graphicbox or graphics window is first 
opened, the direction is NORTH.  We can return the direction
to the default NORTH direction whenever we want by issuing
a NORTH command:

print #gr, "north"

The direction of travel can be changed with a TURN A command.
A will be the number of degrees in the angle used to turn
the pen direction.  An angle of 180 will reverse the direction.
An angle of 90 will cause the pen to begin traveling at a right
angle to the current direction.  When a TURN command is issued,
the pen does not move.  It turns while staying at the same
x, y location.

If the angle specified is positive, the direction will change in
a clockwise direction.  If it is negative, the change will be in
a counter-clockwise direction.

print #gr, "turn 90"
or
a = 90
print #gr, "turn ";a

There are 360 degrees in a circle.  You can specify an angle that
is greater than 360 degrees.  In that case, the drawing direction
will make a full rotation for each multiple of 360 degrees, and
the remainder is the actual angle of change.  For example, if
you specify an angle of 450, the first 360 degrees will simply
place the drawing pen so that it is heading in the exact same
direction as it was before the command, and then it will turn
90 degrees.  450 - 360 = 90.  This means that specifying an
angle of 450 has exactly the same result as specifying an angle
of 90.

If you want the pen to travel towards the "east" or towards the
right side of the window, then issue a NORTH command, followed
by a TURN 90 command, like this:

print #gr, "north"
print #gr, "turn 90"

CHAINING COMMANDS
The example above could be written on a single line, like this:

print #gr, "north; turn 90"

Graphics commands can be placed on a single line within a pair of
double quote marks if they are separated by a semi-colon, as
above.  If graphics text is used, no commands can be added after
a semi-colon, but we are not discussing graphics text in this article,
so we don't need to worry about this now.

SIZE AND COLOR
The drawing pen is one pixel wide by default.  We can make the pen as
wide as we would like by issuing a SIZE command, like this:

print #gr, "size 5"
or
s = 5
print #gr, "size ";s

We can draw in the color of our choice as well.  Liberty BASIC allows
us to choose from 16 named colors, or to make an RGB color choice.
The RGB choice will be discussed in a future graphics tutorial. 
 
The 16 named colors are:
white
black
lightgray (same as palegray)
darkgray
red
darkred
green
darkgreen
blue
darkblue
yellow
brown
cyan
darkcyan
pink
darkpink

Issue a COLOR command like this:

print #gr, "color green"
or
color$ = "green"
print #gr "color ";color$

The colornames are case insensitive, so RED, Red, and red are
all acceptable.


LOOPING
Because we can use variables in our turtle graphics commands,
we can achieve some very fancy graphics in very few lines of
code.  Look at the following tiny program.  It uses a loop to
draw the graphics, and the counter variable for the loop
determines the distance the pen travels in each step.

nomainwin
WindowWidth=400 : WindowHeight=400
open "Test" for graphics_nsb as #gr
print #gr, "down; home; color red; size 2"

for d = 1 to 30
    print #gr, "turn 60; go ";d
next d

wait


Do you see that we have used the counter variable, d, as
the distance variable as well?  And because it is a variable,
we've placed it outside of the quote marks.  We've hard-coded
the turning angle of 60 degrees, so it is placed inside of the
quote marks.

Let's examine the steps and see what Liberty BASIC "sees" 
when it executes the program.

On the first iteration (that's a fancy word for step) LB sees
this:

print #gr, "turn 60; go 1"

It turns 60 degrees clockwise and travels a distance of 1 pixel
in that direction.

On the second iteration, LB "sees" this:

print #gr, "turn 60; go 2"

It now turns another 60 degrees clockwise and travels two pixels
in that direction.  Liberty BASIC repeats this procedure, 
incrementing the counter variable by one each time, until the
counter variable reaches 30.

We can achieve a different figure by changing the step increment
from the default value of 1.  Let's change it to 2, like this:

nomainwin
WindowWidth=400 : WindowHeight=400
open "Test" for graphics_nsb as #gr
print #gr, "down; home; color red; size 2"

for d = 1 to 30 step 2
    print #gr, "turn 60; go ";d
next d

wait

Here is a more complicated example.  We can make both the angle and
the distance dependent on the value of the counter variable.

nomainwin
WindowWidth=400 : WindowHeight=400
open "Test" for graphics_nsb as #gr
print #gr, "down; home; color red; size 2"

for d = 1 to 30
    print #gr, "turn " ;d+40; " ; go ";d
next d

wait


In the example above, the value of the angle will be equal to the 
counter variable plus 40.


For an impressive display of turtle graphics in Liberty BASIC,
look at the mandala.bas program that comes in the Liberty
BASIC distribution.

TURTLE GRAPHICS COMMANDS:
print #gr, "up"       'lift the pen - don't draw
print #gr, "down"     'lower the pen - begin drawing
print #gr, "go D"     'go D pixels in the current direction
print #gr, "home"     'center the pen
print #gr, "north"    'set direction to North - 270 degrees
print #gr, "turn A"   'turn angle A degrees 
print #gr, "goto X Y" 'go to point XY, drawing if the pen is down
print #gr, "set"      'draw one point at current pen position
print #gr, "set X Y"  'draw one point at location XY
print #gr, "color colorname"  'set the color to be colorname
print #gr, "size n"   'set the pen size to be n

---------------------------------------------------------
---------------------------------------------------------
SCRIPTING LANGUAGE TUTORIAL   (intermediate level)
	by Alyce Watson

What is a scripting language?  It is a language that allows
users to write a script -- often in the form of a plain text
file -- and it interprets the commands in the script and
performs actions according to the commands.  Many installation
programs read scripts.  The installer might be called "setup.exe"
and the script might be "setup.lst", for example.

We can write scripting languages in Liberty BASIC.  We can
create a program that will read a script and proceed according
to the instructions contained in the script.  Some people have
written successful scripting languages using Liberty BASIC.
Brandon Watts wrote one called Panther, and Philip Richmond
wrote a very popular game creation scripting language called
Creative Adventure Toolkit.

Creative Adventure Toolkit is available at Phil's Liberty
BASIC Adventure Page:  
http://www.richmond62.freeserve.co.uk/index.htm

The Wattsware Website appears to be offline.  You can
download Panther at Download.com, here:
http://download.com.com/3000-2069-5404551.html?tag=lst-0-5

A scripting language needs three things.  It requires a way
for users to write scripts.  Scripts may often be written in
Notepad, since they are likely to be simple text files.  We
can provide a utility to help users write scripts.  We can
keep it very simple and basic, or we can get very fancy.

A scripting language also needs an interpreter.  The
interpreter is the heart of the language.  It must read the
commands written by the user in his script and translate them
to commands that can be recognized by Liberty BASIC.

A scripting language must also have a way to implement the
commands from the script after it has translated them to
Liberty BASIC syntax.

We've provided a program that contains all three of these
needed functions.  It is very simple, and it is called
"scripter.bas".

The program contains a texteditor where users will write
their scripts.  The scripts can even be saved and loaded
again at a later time.

It also contains a parser to translate the script commands
into Liberty BASIC commands.

We've based this scripting language on turtle graphics, 
similar to Logo.  The window contains a graphicbox to
implement the scripted drawing commands. 

Because the program uses a feature that was added in Liberty
BASIC v3.01, you must have LB 301 to run it.  It is a good
idea to do a version check in a case like this:

If Val(Version$)<3.01 Then
    Notice "You must have at least LB3.01 to run this program."
    End
End If


It is always a good idea to initialize all variables that will
be used in a program, and document their uses:

    ForegroundColor$ = "Black"
    BackgroundColor$ = "Buttonface"
    dsteps           = 0    'number of drawing steps
    cstep            = 0    'current drawing step
    Dim steps$(20)          'array to hold drawing script info
    crlf$=Chr$(13)+Chr$(10) 'carriage return/line feed

The Scripter window will contain some menus and buttons:

    WindowWidth = 606 : WindowHeight = 480
    UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
    UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

[ControlSetup]
Menu        #1, "&File", "&Open", [open], "&Save", [save],_
                "E&xit", [quit]
Menu        #1, "Edit"  'position automatic Edit menu in second spot
Menu        #1, "&Run", "R&un",[runit]
Menu        #1, "&Help", "&Instructions", [help], "&Commands",_
                [commands], "&About",[about]
Button      #1.open, "Open",[open],UL,10,6,80,24
Button      #1.run, "Run",[runit],UL,92,6,80,24
Statictext  #1.s, "", 210,4,200,30
Statictext  #1.pen, "Pen is down!",411,4,200,30

It will also contain a graphicbox to implement the drawing
commands and a texteditor for users to write the script.

Graphicbox  #1.g, 200,38,400,400
Texteditor  #1.t, 0,38,198,400

Always issue a TRAPCLOSE command, and be sure that the
closing routine closes all open files and windows and
ends the program with an END command:

[quit]
    Timer 0
    Close #1 : End


The program will allow the user to save and open scripts
in the texteditor.  See the program code for details on
these operations.  We'll focus here on the heart of the
program, which is interpreting and implementing the
actual script.

We must set up the commands that will be recognized by our
simple scripting language.  We'll stick to a few turtle
graphics commands, and add some functionality for the user:

[commands]
center     = center the pen
north      = turn north
west       = turn west 
south      = turn south 
east       = turn east
turn a     = turn number of degrees in a
moveto x y = goto point indicated
move n     = go distance of n in current direction
up         = pen up, move without drawing
down       = pen down, draw while moving

If you look at the command list, you will see that some
commands are identical to LB graphics commands.  "North" is
one such command.  Some others are standing in for LB
graphics commands.  "Move" is the same as the LB command
"Go".  There are also some commands that do not have an
equivalent LB command, like "east".  It will be up to our
interpreter to read these commands and to translate them
into Liberty BASIC commands.

When the user has loaded or typed a script into the texteditor,
he can click a button or use a menu to run his script.  The
first thing the Scripter program will do is clear the drawing
area for the start of the new script graphics.

    #1.g "cls; fill Darkblue; color cyan ; size 2"
    #1.g "north; home"

Next, we'll retrieve the number of lines in the script by 
issuing a "!lines" command to the texteditor:

    #1.t "!lines dsteps"    'get number of lines in texteditor

We COULD simply read the script from the texteditor, a line at
a time, implementing the commands as we go along.  This might 
cause an uneven performance, halting for each step while the 
interpreter routine does its job.  To make for a smoother 
graphics display, we'll interpret the commands and store the 
resulting LB syntax commands in an array, which we can then 
loop through to display the graphics at a nice, steady speed.  

We'll need enough array elements to contain all of the lines 
of the script, so we'll REDIM the array to be the same size
as the number of lines contained in the texteditor:

    ReDim steps$(dsteps)    'redim array to number of lines

Now we can fill the array with the scripted commands, in
preparation for their translation into LB commands:

    'fill array with drawing commands
    For i = 1 to dsteps
        #1.t "!line ";i;" txt$"
        'trap blank lines:
        If Len(txt$)=0 Then txt$="move 0"
        steps$(i)=txt$
    Next

Did you notice the line:

    If Len(txt$)=0 then txt$="move 0"

We've included that to trap any possible errors that a 
blank line might cause in our interpreter.


We've now filled the string array with the lines of text
from the texteditor.  It is time to translate the steps to 
LB syntax.  To do this, we will parse the text in the 
commands.  We've written a parsing function, which will 
return 0 if there were no problems, but otherwise it will
return a positive number that indicates the line number 
where a problem is encountered.

    okay = Parse(dsteps)    'the heart of the scripter program

    If okay>0 Then  'there was an error
        Notice "An error occured on line ";okay
        Wait
    End If

We'll discuss the parsing routine in detail shortly, but for now,
notice that we've stopped the program from executing and given
the user a message telling him where to find his error, if an
error occurs.

If there is no error, we'll clear the screen again to make
extra sure that no drawing remnants remain, then set the
counter for the steps to be 0, and start the timer that will
draw one step each time it is activated:

        'everything is okay, start the drawing process
        cursor hourglass    'to show user something is happening
        #1.g "cls; fill Darkblue; color cyan ; size 2"
        #1.g "north; home"
        cstep=0
        Timer 500, [draw]


The timer routine increments the counter, and draws the current
step by accessing the array item that matches the counter value.

    cstep=cstep+1   'increment drawing step number

    'draw the current step
    #1.g " " + steps$(cstep) + " "

To draw the current step, we've simply printed it to the
graphicbox as a string.  LB3 allows us to omit the word "print".
We could also write the command above as follows.  Either is
correct.  We've chosen to use the shorthand version that
omits the word "print".

    'another way to send the drawing command:
    print #1.g, " " + steps$(cstep) + " "

The drawing step has now taken place in the drawing area, and
we'll scroll the code window to remain in sync with the drawing
step.  This isn't necessary, but it is a nice way to give the
user feedback about what is happening.

    'scroll the code window in sync with current drawing step
    #1.t "!origin ";cstep;" 1";

The following step is also not necessary, but it gives the
user another bit of feedback while his script is running.
We use a statictext command to display the current script
command:

    'get current script command, write to statictext
    #1.t "!line ";cstep;" txt$"
    #1.s txt$

Did you notice that we've used two different ways to add strings
together?  Adding strings together to form one larger string is
called "concatenation".  Liberty BASIC allows us to do this with
a plus sign "+" or with a semi colon.  To use the "+" operator
to concatenate strings, make sure than any numbers are converted
to strings first.  The following two commands are equivalent.

    #1.t "!origin ";cstep;" 1";
    #1.t "!origin " + str$(cstep) + " 1"

If the drawing pen is up, it may look like nothing is happening
in the drawing area.  Let's alert the user by letting him know
when the pen changes to UP or to DOWN by placing that information
into a statictext control:

    'let user know if pen is up or down
    t$=Lower$(Word$(txt$,1))
    If Lower$(t$)="down" Then Print #1.pen, "Pen is DOWN!"
    If Lower$(t$)="up" Then Print #1.pen, "Pen is UP!"


The last part of the drawing routine evaluates the current step
number against the total number of steps to discover when all
drawing steps have been accomplished.  When the script is finished
running, the timer is turned off and the code window is scrolled
back to the top:

    If (cstep>=dsteps) Then  'last step was reached
        Timer 0              'turn timer off
        cursor normal   'to show user drawing is done
        #1.g "color red; circlefilled 4"
        #1.g "flush"
        #1.t "!origin 1 1"  'reset code window to top line
    End If
    Wait


The heart of the Scripter program is the parser.  It reads the
script commands one by one and evaluates them.  If it understands
the command, it can translate it into LB syntax.  If it does
not understand the command, it will halt the parsing process
at the current step and return the line number of the errant
script line to the calling function.   The parser uses the
Select Case command.  If you are not familiar with Select
Case, then see the Tip Corner section of this newsletter.

The following description deals with the parser in this 
scripter.bas program.  Every scripting program will have different 
needs, so I've tried to show a simple method to evaluate text 
input and use it to cause something to happen in Liberty BASIC.


In the parsing routine, we will loop through the array of script
commands, evaluating them one at a time.

  For i = 1 to num

      s$=Lower$(steps$(i))            'entire command line
      c$=Lower$(Word$(steps$(i),1))   'command is first word
      Select Case c$  'use script command to determine needed
                      'Liberty BASIC drawing command

First, we extract the current step into a variable, called
s$.  Then we check the first word$() in s$ to extract the
command part of the script line to the variable c$.  We'll
put this first word$() into a variable c$.  This is the 
variable we will evaluate in our Select Case routine.

The first command we check for is "center":

        Case "center"   'equivalent to LB home command
            steps$(i)="home"

If we find a match, then we translate this to the LB "home"
command and replace the array element with "home".

We then check for "north".  This has an exact equivalent to
an LB drawing command, so we simply write it back into the array:

            Case "north"    'equivalent to LB north command
                steps$(i)="north"

The next command we check for is "south".  There is no equivalent
command in LB, but we can implement this ourselves by setting the
direction to "north" then turning 180 degrees:

            Case "south"    'south=north+180
                steps$(i)="north; turn 180"

Again, there is no LB "east" command, so we implement it by
setting the direction to "north", then turning 90 degrees:

            Case "east"     'east=north+90
                steps$(i)="north; turn 90"

"West" is implemented by setting the direction to "north" and
turning 270 degrees:

            Case "west"     'west=north+270
                steps$(i)="north; turn 270"

Since "turn" has an exact equivalent in LB, we simply write it
back to the array, but in this case we need to do more parsing to
discover the angle used in the "turn" command.  We'll retrieve the
second word$() in the command string.  It would be easy to place
this directly into our angle string variable, a$, but what would
happen if the user had written a command:

    turn hello

"Hello" is not a numeric value and we wouldn't want to try to use
it in an LB command that required a number.  We'll instead get
the numeric value of the second word$() with the VAL() function.
If the second word$() isn't a number, then VAL() will return
0.  Once we have the value, we convert it to a string so that
we can write the string back into our array:

            Case "turn" 'equivalent to LB turn command
                'check for value, in case second word has
                'no numeric equivalent - it will then be 0
                a=Val(Word$(s$,2))
                a$=Str$(a)
                steps$(i)="turn ";a$

"Moveto" is not a Liberty BASIC command, but we are using it as
an exact equivalent of "goto".  "Goto" requires two parameters:
an X and a Y location are needed.  We'll get these in a similar
fashion to getting the angle for "turn", only this time we need
to get a value for both the second and third words in the user's
command string.  The second word$() will be the X value and the
third word$() will be the Y value:

            Case "moveto"  'goto point indicated
                         'trap x,y values that are larger
                         'than drawing area
                x=Val(Word$(s$,2))
                If x>396 Then x=396
                x$=Str$(x)

                y=Val(Word$(s$,3))
                If y>396 Then y=396
                y$=Str$(y)

                steps$(i)="goto "+x$+" "+y$

If you look at the routine above, you'll see that we tried to
do some more error-trapping.  We know that our drawing area is
contained within a box that is 400x400 pixels, so we've checked
for values greater than the visible area of the graphicbox and
changed the value if it is greater than that to keep the
drawing visible.


"Move" is not a Liberty BASIC command, but it has a direct 
equivalent in "go".  As in the two above examples, we also need
to check for a numeric value in the command string to see the
desired distance to travel:

            Case "move" 'travel set distance in current direction
                d=Val(Word$(s$,2))
                'not perfect, but trap distances outside
                'of drawing area:
                #1.g "posxy x y"
                if x+d>396 then d=396-x
                if y+d>396 then d=396-y

                d$=Str$(d)
                steps$(i)="go "+d$


The last two scripter.bas commands for are "up" and "down" 
which are also Liberty BASIC commands and they can be
written back into the array just as they are:

            Case "down" 'equivalent to LB down command
                #1.g "down"

            Case "up"   'equivalent to LB up command
                #1.g "up"


Remember, we called the return from this parsing function "okay" 
and if it is greater than 0, it indicates the line number of the 
problem, but if it is 0, then everything worked properly and it 
is okay to start drawing.  The error handler is in the 
"Case Else" case:

    Case Else   'script command not understood by parser
        result=i    'return line number of error
        'scroll to error line:
        #1.t "!origin ";i;" 1 ";    'row, column
        #1.t "!select 1 ";i         'column, row
        exit for    'error, exit for/next loop

If an error is encountered, then "result" is set to the value
of the current line, or "i".  The code window is scrolled to
that line to make it easy for the user to see where he made his
mistake.  Since an error was encountered, there is no need to
continue parsing the commands, so an "exit for" command is issued
which causes execution to jump out of the parsing loop and to
return the line number with the error to the calling function.

    Parse=result 'return the result
    End Function


Please try scripter.bas to see the program in action.  Why not
enlarge upon the sample program, or go in a different direction
and write a scripting language of your own?
---------------------------------------------------------
---------------------------------------------------------
SCRIPTER.BAS

Please see the zip file attached to this newsletter for a
copy of scripter.bas.

---------------------------------------------------------
---------------------------------------------------------
CHANGING WINDOW ICONS AT RUNTIME (intermediate level)

It is possible to have a different icon in each window of
a program.  We can use the Liberty BASIC icon editor to
create an icon and to include it in the runtime engine so
that it becomes the icon for each window in a program.  It
is sometimes interesting or useful to have individual icons
for the different windows in a program, and this can be 
achieved quite easily.

To do this, include all icons required in the program's 
distribution.  When needed, the icons must first be loaded
from disk with a function call from user32.dll called
LoadImageA.  Here it is, with all arguments documented:

IconFile$ = "guy.ico"
CallDLL #user32, "LoadImageA", _
    _NULL As long, _            'instance handle, can be null (=0)
    IconFile$ As ptr, _         'file name
    _IMAGE_ICON As long, _      'type
    16 As long, _               'width
    16 As long, _               'height
    _LR_LOADFROMFILE As long, _ 'flags
    hIcon As long               'returns icon handle


The function returns a handle to the icon that is now loaded
into memory.  A call to SendMessageA with the windows message
_WM_SETICON, the handle of the window and the handle of the
loaded icon will cause the icon to appear as the window's icon:

'Set the icon.
CallDLL #user32, "SendMessageA", _
    hWnd As long, _        'window handle
    _WM_SETICON As long, _ 'message to set icon
    _ICON_SMALL As long, _ '_ICON_SMALL/_ICON_BIG
    hIcon As long, _       'icon handle
    hOldIcon As long       'returns handle to old icon

Whenever we load images, we must destroy them or unload them
before ending the program to free the memory that they
consumed.  There is a special function for this called
DestroyIcon.

CallDLL #user32, "DestroyIcon", _
    hIcon As long, _ 'icon handle
    result As long

For a working example, see ICON.BAS - adapted from an example by 
Brent Thorn, used by permission.  Thanks, Brent!

Please see the zip file attached to this newsletter for a
copy of icon.bas and the two icon files it uses.
---------------------------------------------------------
---------------------------------------------------------
A REAL SPINNER CONTROL FOR LIBERTY BASIC (advanced level)
	by Alyce Watson

A spinner, or updown control is a textbox with two small
arrow buttons attached to one side.  When a user presses the
buttons, either by clicking on them with the mouse, or by
pressing the up and down arrow keys on the keyboard, the value
displayed in the textbox is incremented or decremented.

Pressing a regular push button only activates a routine once.
To activate it again, the button must be released, then pressed
again.  This is not true of the arrow buttons on spinner
controls.  As long as the button is depressed, the value
displayed in the textbox continues to change - it is 
incremented if the up arrow is being pressed, and decremented
if the down arrow is being pressed.

Although it may sound as if this control would be complicated
to create with API calls, and to use, it is actually quite
simple.  It does require a knowledge of the Windows API as used
in Liberty BASIC, however, and that basic knowledge is assumed
for this article.

Please note that this is for LB3 only.  It is a good idea to include
version checks in our programs to insure that the correct version
of LB is used to run them:

if val(Version$)<3 then
    notice "Requires LB3."
    end
end if

The function to create it is part of the common controls 32-bit DLL
-- comctl32.dll.  It is first necessary to initialize the DLL for use:

    calldll #comctl32, "InitCommonControls",re as void

The function is called "CreateUpDownControl".  It requires several 
arguments.  You  must include the handle of the parent window, 
which is obtained with LB's HWND() function.  It also requires the 
Instance Handle of the window, which is obtained with the 
GetWindowLongA function, using the _GWL_HINSTANCE flag.

    hwndParent = hwnd(#1)

    'get parent instance handle:
    CallDLL #user32, "GetWindowLongA",_
    hwndParent As long,_    'window handle
    _GWL_HINSTANCE As long,_'want instance handle
    hInstance As long       'returns instance handle of window



The function arguments also include x, y, width and height values,
which can all be set to 0, because our example gives the updown
control a buddy textbox, and the control will be located and
sized according to the buddy control.  We'll need the handle
of the buddy textbox as well:

    textbox #1.t, 50,40,60,26
    '''''
    hText=hwnd(#1.t)

The function also allows us to set the upper limit value for
the spinner as well as the lower limit.  It also allows us to
set the initial value to be displayed.  The function returns a
handle to the spinner (updown) control:

    x=0:y=0:wide=0:high=0:upr=100:lwr=0:pos=50
    calldll #comctl32, "CreateUpDownControl",_
        dwStyle as ulong,_      'style
        x as long,_             'x placement
        y as long,_             'y placement
        wide as long,_          'width
        high as long,_          'height
        hwndParent as long,_    'parent handle
        id as long,_            'an ID number
        hInstance as long,_     'parent instance handle
        hText as long,_         'buddy control - a textbox handle
        upr as long,_           'upper limit
        lwr as long,_           'lower limit
        pos as long,_           'initial value
        hSpinner as long        'handle of control


We haven't yet addressed an essential argument for the function.
This is the style argument.  All controls created by API must have
a minimum style flag that includes the _WS_CHILD and _WS_VISIBLE 
window styles, so that the control is a child of the program window,
and so that it is visible.  It is also good to include the _WS_BORDER
style so that the control has a nice appearance.

    dwStyle = _WS_CHILD or _WS_VISIBLE or _WS_BORDER 

There are other style bits that must be set for an updown spinner
control.
  
       UDS.SETBUDDYINT or UDS.ALIGNRIGHT or UDS.ARROWKEYS

Our demo uses the ones above.  The UDS.SETBUDDYINT causes the buddy
textbox to display the value continuously and automatically when the
spinner is activated.  The UDS.ALIGNRIGHT bit places the spinner on the
right edge of the buddy textbox.  The UDS.ARROWKEYS makes the spinner
respond when the user presses the keyboard arrow keys.

Here are all of the possible UDS styles, along with their values
and descriptions:


UDS.SETBUDDYINT = hexdec("2")   
Causes the up-down control to set the text of the buddy window
(using the WM_SETTEXT message) when the position changes. The text
consists of the position formatted as a decimal or hexadecimal string.

UDS.NOTHOUSANDS = hexdec("80")  
Does not insert a thousands separator between every three decimal digits.

UDS.HOTTRACK = hexdec("100")    
Causes the control to exhibit "hot tracking" behavior. That is,
it highlights the UP ARROW and DOWN ARROW on the control as the
pointer passes over them. This style requires Microsoft Windows 98
or Windows 2000. If the system is running Windows 95 or Windows NT 4.0,
the flag is ignored. To check whether hot tracking is enabled, call
SystemParametersInfo.

UDS.HORZ = hexdec("40")         
Causes the up-down control's arrows to point left and right instead of
up and down.

UDS.AUTOBUDDY = hexdec("10")    
Automatically selects the previous window in the z-order as the
up-down control's buddy window.

UDS.ARROWKEYS = hexdec("20")   
Causes the up-down control to increment and decrement
the position when the UP ARROW and DOWN ARROW keys are pressed.

UDS.ALIGNRIGHT = hexdec("4")    
Positions the up-down control next to the right edge
of the buddy window. The width of the buddy window is
decreased to accommodate the width of the up-down control.

UDS.ALIGNLEFT = hexdec("8")     
Positions the up-down control next to the left edge
of the buddy window. The buddy window is moved to the right,
and its width is decreased to accommodate the width of the up-down control.

UDS.WRAP = hexdec("1")          
Causes the position to "wrap" if it is incremented or decremented beyond the
ending or beginning of the range.


The style bits as set in our demo:

    dwStyle = _WS_CHILD or _WS_VISIBLE or _WS_BORDER _
         or UDS.SETBUDDYINT or UDS.ALIGNRIGHT _
         or UDS.ARROWKEYS

When the program finishes, free the memory used by the control
by destroying it with a call to DestroyWindow"

[quit]
    calldll #user32, "DestroyWindow",_
    hSpinner as long, re as long
    close #1:end

To discover the value chosen by the user, simply check the contents
of the buddy textbox:

    #1.t "!contents? txt$"
    notice "Percent is ";txt$

Although it takes a few function calls to create the control,
once it is created, it is very simple to get the buddy
textbox contents with the Liberty BASIC "!contents? txt$"
command to discover the value.  If necessary, use the
VAL() function to get a numeric value

answer = VAL(txt$)

Please see the attached file, updownspinner.bas for the
complete demo program.


---------------------------------------------------------
---------------------------------------------------------
TIP CORNER - SELECT CASE   (novice level)
	by Alyce Watson

Select Case was used by the parsing routine in the scripting
language tutorial:

Select Case c$  
    Case "center"   'equivalent to LB home command
    Case "north"    'equivalent to LB north command
    Case "south"    'south=north+180
    Case "east"     'east=north+90
    Case "west"     'west=north+270
    Case "turn"     'equivalent to LB turn command
    Case "moveto"   'goto point indicated
    Case "move"     'travel set distance in current direction
    Case "down"     'equivalent to LB down command
    Case "up"       'equivalent to LB up command
    Case Else       'script command not understood by parser
End Select

The following primer on Select Case is from the ebook,
Mastering Liberty BASIC 3, available here:
http://iquizme.0catch.com/lb/lbw3/master.html

***********
Select Case from Mastering Liberty BASIC 3 
(All Rights Reserved)

A program can evaluate a set of conditions with the 
IF...THEN...ELSE construction.  If the set of conditions 
evaluates to TRUE, the code after THEN is executed.  If 
there is an ELSE, then it is executed if the set of conditions 
evaluates to FALSE.  To evaluate a complex set of conditions 
with IF...THEN...ELSE requires numerous similar statements.  
This can quickly get cumbersome and difficult to modify and debug.

Liberty BASIC 3 brings a new construction for evaluating and 
acting on sets of conditions, called SELECT CASE.  The syntax 
for Select Case is:

SELECT CASE var
    CASE x
        'basic code
        'goes here
    CASE y
        'basic code
        'goes here
    CASE z
        'basic code
        'goes here
    CASE else
        'basic code
        'goes here
    END SELECT

The first line in a select case statement is "select case" 
followed by the named variable or the expression that will be 
selected.  On subsequent lines, there are "case" statements, 
specifying the conditions to evaluate for the selected variable, 
with code after the "case" statement that is to be executed if 
that particular case evaluates to TRUE.  The "select case" routine 
must end with the words "end select".

There is no limit to the number of conditions that can be used for
evaluation.  The program can also specify a routine to perform if 
none of the conditions is met by using the "case else" designation.  

Here is a trivial example.  The variable selected is called "num" 
so the statement reads "select case num".  If the value of "num" 
equals "1" then the program will print "one", as determined by 
the "case 1" statement and the code which follows it.  The same 
is true for "case 2" and "case 3".  If the value of "num" is not 
specified in one of the case statements, then the code which 
follows "case else" is executed.

num = 3

select case num
    case 1
        print "one"
    case 2
        print "two"
    case 3
        print "three"
    case else
        print "other number"
    end select

The example above results in output in the mainwindow of:

three

The example above had a single variable in the "select case" 
statement.  It is also permissable to use an expression in the 
"select case" statement.  In the following example, (num * a) 
is to be evaluated.


num = 3
a = 2

select case num * a
    case 1
        print "one"
    case 2
        print "two"
    case 3
        print "three"
    case else
        print "other number"
    end select

The example above results in output in the mainwindow of:

other number

STRINGS
SELECT CASE also works for string variables.

animal$ = "cat"

select case animal$
    case "dog"
        print "woof"
    case "cat"
        print "meow"
    case "bird"
        print "tweet"
    case else
        print "other animal"
    end select

The example above results in output in the mainwindow of:

meow

MULTIPLE CONDITIONS
IF...THEN...ELSE can evaluate multiple condions at once, 
and this is also true for SELECT CASE.  For simple expressions, 
separate the expressions with commas.  In the example below, 
there is a case for num to equal either 1, 2, or 3.

num = 3

select case num

    case 1,2,3
        print "less than four"
    case 4
        print "four"
    case 5
        print "five"
    case else
        print "other number"
    end select

The printout for the example above is

less than four

Notice that once a CASE is met, later CASE statements are ignored 
and program execution continues at the line after the END SELECT 
statement.  In the following example, even though all three cases 
are met, only the first one is used.  Once the first CASE statement 
is met, program execution jumps out of the SELECT CASE... 
END SELECT routine.

num = 3

select case num
    case 1,2,3
        print "less than four"
    case 2,3,4
        print "more than one"
    case 1,3,5
        print "odd number"
    end select
print "All done."

The printout for the example above is

less than four
All done.

MULTIPLE EXPRESSIONS
There is a way to evaluate multiple conditions that contain 
boolean expressions.  It can be done by using SELECT CASE 
without an expression.  Omitting the expression in the select 
case statement causes the conditions to be evaluated in their 
entirety.  To omit the expression, type "select case" with no 
words following it on the line of code.

value = 109
print "value = "; value
print
select case
    case value < 10 or (value > 100 and value < 110)
        print "value < 10 or (value > 100 and value < 110)"
    case value > 200 and value < 210
        print "(value > 200 and value < 210)"
    case value = 110 or value = 112
        print "value = 110 or value = 112"
end select

MULTIPLE STRINGS
String variables can also be evaluated for multiple conditions 
in a single CASE statement by separating them with commas, just 
as it is done for numeric expressions.  This is a trivial 
example to show multiple string CASE evaluations:

var$="hello"

select case var$
    case "howdy"
        print "Howdy to you, too."
    case "hi","hello"
        print "Good day."
    case else
        print "See you later."
end select

EXITING SELECT CASE
The code to be executed for any of the specified cases may be 
placed directly after the CASE statement.  It is also correct 
to have a "goto [branchLabel" following a CASE statement.  The 
code may also include a GOSUB, a SUB or a FUNCTION.  If the program 
is not sent to another location to continue execution, then the 
code after the END CASE statement will be carried out once any 
specified code within the CASE statements is executed.

animal$ = "bird"

select case animal$
    case "dog"
        call Woof
    case "cat"
        goto [cat]
    case "bird"
        print DoTweet$()
    case else
        print "other animal"
    end select

'other basic code goes here
wait

[cat]
    print "meow"
    wait

sub Woof
    print "woof"
    end sub

function DoTweet$()
    DoTweet$ = "tweet"
    end function

---------------------------------------------------------
---------------------------------------------------------
HOCUS FOCUS  (advanced level)
	By Brad Moore

I have always thought that Liberty Basic, 
although quite powerful, was missing a few 
key commands and/or events.  One of the 
events that I wished was present, and whose 
absence has troubled me more than once - is 
the "Lost Focus" event.  The purpose of the 
lost focus event is to trigger a call to a 
specific label from which to execute code, 
whenever a specified window or control either 
gains focus or loses focus.  

If you have played around with Visual Basic 
before, you may recognize this event.  It is 
sometimes used in that environment to detect 
when a textbox that had focus (and presumably 
some sort of input) has subsequently lost 
focus.  This is useful to perform validation 
of the text entered into the field.  Likewise, 
determining when a form (or window) has lost 
focus could prove useful for many reasons.  
For instance it could trigger a repaint event, 
or possibly initiate a routine that could 
automatically store data, which a user has 
been working on should the program lose focus.  
The possibilities abound.

But the lack of the "Lost Focus" event in 
Liberty Basic is not the liability it would 
seem, as the language allows us to improvise 
easily.  Access to the windows API is one of 
our greatest assets when "impossible" 
situations arise that demand a response.  So, 
having asked for this functionality several 
times (and Carl has given it consideration) - 
I decided that maybe there was already a 
method that I could employ to achieve the 
results I was seeking. 

I turned to Dave Appleman's book titled Win32 
API for Visual Basic.  I like this book a lot, 
because the examples are clear and easy to 
read for someone accustomed to Basic.  After a 
bit of searching I ran across the very API call 
I was hoping to find.  It was the simple little 
"GetFocus" call, which is part of the User32.DLL.  
The Liberty Basic syntax to call this API looks 
like this:

CallDLL #user32, "GetFocus", handle As long

Very simple.  Issue the command and in a split 
second you are returned the handle of the window 
that has the focus.  In fact if you were to use 
the Liberty Basic command hWnd(#main) and 
compare the value it returns with the value 
returned from the "GetFocus" API call (presuming 
that the main window has focus) then you would 
observe that the two values would be identical!  

But how could I turn this one simple command 
into a tool that I could use to determine what 
window had focus and take appropriate action 
depending on the results?

The answer lay in the fairly new Liberty Basic 
command: TIMER.  (Timer was added to the Liberty 
Basic language with the version 2 release.)  
The HELP file says the following about the timer 
command:

TIMER milliseconds, [branchLabel]

Description: This commands manages a Windows 
timer.  This is useful for controlling the rate 
of software execution (games or animation perhaps), 
or for creating a program or program feature 
which activates periodically (a clock perhaps, or 
an email client which checks for new messages).  
Deactivate the timer with a time value of 0, and 
no branch label.  There is only one timer.  The 
elapsed time value and/or branch label to execute 
can be changed at any time by issuing a new TIMER 
command.  There are 1000 milliseconds in one second.  
A value of 1000 causes the timer to fire every one 
second.  A value of 500 causes the timer to fire 
every half second, and so on.

Usage:

    'set a timer to fire in 3 seconds
    timer 3000, [itHappened]
    'wait here
    wait

[itHappened]
    'deactivate the timer
    timer 0
    confirm "It happened!  Do it again?"; answer
    if answer then
        'reactivate the timer
        timer 3000, [itHappened]
        wait
    end if
 end


To make the timer command work for us in 
determining who has focus is a matter of 
following a few simple steps.

1) Determine what handle you are trapping for 
   (say the handle of the main window) and save 
   that value.
2) Initiate a timer and point it at an event 
   handler.
3) In the event handler compare the value of 
   the window that currently has focus to the 
   value saved in step 1
4) If the value has changed - take action.

If the timer were set to 50 or 100 milliseconds, 
each interval the system would check to see "who" 
had focus and compare it with "who" we thought 
should have focus.  In step four, should the values 
be different, we will have triggered a "Lost Focus" 
event and we can take appropriate action.

Having established the process, a word about 
windows and controls would be in order before we 
continue.  In WINDOWS (the operating system) 
nomenclature a window is the form on which controls 
are placed, but it is also each and every control 
as well.  In fact they are a lot like child windows 
of the form (e.g. window) on which they are placed.  
The API call "GetFocus" returns the value of both 
windows and controls (which are placed on the 
windows - since, as I explained, they are really 
windows as well).

This means that your main window may not have 
actually lost focus even though the value returned 
by the API function "GetFocus" has changed.  This 
is because the user may have changed the focus to 
one of the controls on the window.  So when writing 
code to test for lost focus of the form (e.g. 
window), we must account for all the controls that 
are on the form as well, since they too have a 
valid reason to receive focus.

The second implication of this fact is that you 
can also trap for the event when focus moves from 
one control to another control.  Do this by 
obtaining the handle value for a control on the 
form, such as a textbox, for instance using the 
following command:

handle = hWnd(#main.textbox1)

Once you have that value you would be able to 
trap the moment when the focus was both gained and 
lost for that control by following steps two 
through four.  The uses of such event traps are 
many - only your imagination is the limit.

So, let me put it all together in a little 
demonstration program.  This program, called 
HocusFocus.bas is attached as a zip file, as 
well as being annotated here in this article.

First the program header information.  If you 
write programs which you share, please allow me 
to take just a second and encourage you to always 
include a few lines of comment about your code.  
It should state the name of your program, what 
your program does, who wrote the program and for 
which version of what language you have written 
it.  Also include a version number or date of last 
revision (this helps the rest of us out in case 
more than one version of the code is floating 
around).  Don't forget to mention the copyright 
status and what criteria need to be met to use 
your work.  For this simple demo the following is 
included:

'   HocusFocus.bas
'   by Brad Moore - copyright 2002
'   Last revision 6/17/2002
'-----------------------------------------------
'   Inclusion within other works is permitted
'   without requirement of credit or permission.
'   All rights are retained by author.
'-----------------------------------------------
'   This is written for Liberty Basic v3.x
'   To learn more about Liberty Basic please
'   visit the website http://www.libertybasic.com


With this out of the way, I begin by following 
standard practices of setting up a simple window 
with a couple controls on it.  If you need help 
understanding this section please refer to the 
Liberty Basic Help System. 

'Initalize the settings for the window
    ForegroundColor$ = "Black"
    BackgroundColor$ = "Buttonface"
    TexteditorColor$ = "White"
    TextboxColor$    = "White"
    NoMainWin
    WindowWidth = 393 : WindowHeight = 210
    UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
    UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

'setup the controls
Statictext  #main.st1, "", 80, 20, 130, 25
Statictext  #main.st2, "", 55, 54, 155, 25
Statictext  #main.st3, "", 20, 88, 195, 25
Button      #main.quit, "",[quit],UL, 220, 125, 140, 35
Textbox     #main.tbx1, 220, 15, 137, 24
Textbox     #main.tbx2, 220, 50, 137, 24
Textbox     #main.tbx3, 220, 85, 137, 24

Open "Hocus Focus" For Window As #main

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


I have chosen to write the static text out to 
the window after the window is created.  You 
don't have to do this, I do it to keep my code 
line short and readable without line wraps.

'I assigned text to labels to avoid line wrap above
    #main.st1 "Handle of this window"
    #main.st2 "Last window to have focus"
    #main.st3 "What window/control has focus?"
    #main.quit "I am done" 

Now I get the handles of all the controls on the 
window and the handle of the window, too.  I will 
use these later to determine where the focus is 
during program execution.

'Enumerate the open windows/controls in the lb form
    hmain = hWnd(#main)
    tb1main = hWnd(#main.tbx1) 
    tb2main = hWnd(#main.tbx2)
    tb3main = hWnd(#main.tbx3)
    btnmain = hWnd(#main.quit)

Now, knowing these values, I plug a couple of the 
fields with the handle values.

'Intialize values for the textboxes
    #main.tbx1 Str$(hmain)
    #main.tbx2 Str$(hmain)
    #main.tbx3 "Main Window"

Now I initiate the time control and point it to 
my event handler each iteration the timer fires.  
Timers can be confusing - the thing to remember 
is that they are simply a control mechanism that 
causes the program pointer (an imaginary pointer 
that keeps track of what line of code to 
execute next) to be redirected to a specific 
label to begin executing code, and it causes 
this redirection on a regular basis which is 
determined by the time interval you specify.  A 
second important thing to remember about timers 
is that although they are driven by the PC's 
system clock, they are not precise to the 
millisecond.  This means that just because you 
specify 100 milliseconds, you may not realize 
the exact resolution in timing.  It will not 
run faster, but may run slower.  This is because 
the timer is limited by the other functions 
that Windows is performing elsewhere.  Odds are 
good Liberty Basic will not receive Windows 
attention at the exact moment that your timer 
should fire, resulting in a latency effect.  
You timer will fire every 110 milliseconds 
instead of every 100 milliseconds.  That is 
the way windows is.  Enough of the technical 
stuff - if the concept of timers is still a 
bit unclear please experiment with some of the 
examples in the help file.  Information on the 
timer command is available in several places 
there.  In the case of the code below, I am 
simply causing program execution to go to the 
label [events] every 50 milliseconds.

'set the timer to 50 milliseconds    
    Timer 50, [events]

Finally we wait.

'Wait for events
    Wait


There are only two events which are handled 
in the remaining code.  The first simply handles 
the close event, closing the main window and 
halting program execution.  


'Process the events
[quit]
    Close #main
    End


The last event is the one that does the work of 
the demo.  The first thing that is done each time 
this code is executed is the dll call to the 
"GetFocus" function which returns the handle of 
the window or control that has focus.  That 
handle value is updated in the textbox #main.tbx2.

[events]
    'Find out who has the focus currently
    CallDLL #user32, "GetFocus", handle As long
    'Display the value
    #main.tbx2 Str$(handle)


Next the value returned is evaluated in a select - 
case statement against each of the known good 
handles for the window and its controls.  If the 
focus is found to be any of the know values then 
the third textbox is updated with a text string 
literal which tells the user what window or control 
has the focus.  If none of the known windows or 
controls has focus, then we declare that focus 
has been lost by the application and an external 
window currently has the focus.

    'Evaluate the result of call    
    Select Case handle
       Case hmain
          #main.tbx3 "Main Window"
       Case tb1main
          #main.tbx3 "Textbox 1 Control"
       Case tb2main
          #main.tbx3 "Textbox 2 Control"
       Case tb3main
          #main.tbx3 "Textbox 3 Control"
       Case btnmain
          #main.tbx3 "Quit Button Control"
       Case Else
         #main.tbx3 "External Window"
    End Select

Finally, after all is said and done we wait until 
the timer fires again.

    Wait


I hope it all made sense.  Maybe someday you will 
find a need where this can be integrated into a 
project you are working on.  Until then, thanks 
for staying with me.
---------------------------------------------------------
---------------------------------------------------------
ILLUMINATED RADIOBUTTONS
	by Mike Bradbury	mike@karemi.fsnet.co.uk

Plastic Surgery for radiobuttons (or How to make bitmap 
radiobuttons to improve your application user interface) 
	by Mike Bradbury.

Requires LibertyBASIC v3 and tested with Win98SE in 16 bit colour.

Using bitmap buttons instead of standard windows buttons makes 
the user interface more interesting and functional. This demo 
uses two bitmap images to display a button in the off and on states, 
the on state indicated by an 'illuminated' green bar at the centre 
of the button. The window also contains a bitmap button labelled 
On/Off. When this button is in the off state, all other buttons are 
locked in the off state and when this button is on, the other buttons 
become active and a label for the buttons is displayed. Also for the 
purposes of this example, when a button is clicked, the previously 
active button is reset to off, the buttons behaving like radiobuttons.
For a personal style, replace the bitmaps with your own design, using 
a painting package like MSPaint or PaintShop Pro etc., making the 
bitmaps 63x25 pixels in size.

Remember to click the On/Off button first, else you will not see 
the illuminated effect!

See illumButtons.bas in the attached zip file for the demo!

---------------------------------------------------------
---------------------------------------------------------
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
---------------------------------------------------------
---------------------------------------------------------