Liberty Basic is develeopped by Carl Gundel
Original Newsletter compiled by Alyce Watson and Brosco
Translation to HTML: Raymond Roumeas

The Liberty Basic Newsletter - Issue #73 - MAY 2000

© 2000, Side by Side Software

http://alyce.50megs.com/sss/

All Rights Reserved


In this issue:

  1. A new kind of subroutine in LB2
  2. CALL sub and the API
  3. Fun with the caret

In future issues:


1 - A New SubRoutine Function for LB2!

Liberty BASIC has always had the ability to use GOSUBS. The subroutine was activated by calling it like this:

GOSUB [branchLabel]
 

The program would continue execution at [branchLabel], performing all actions in the code until it reached a RETURN command, when it would return to the line following the GOSUB command and continue from there. A subroutine might look like this:

[branchLabel]
	Print "I am a subroutine."
	RETURN

This GOSUB is a really handy tool, but it has some limitations. If we wanted to print a different text each time in this example, we would need to be careful of our variable use. Here is what we'd do:

message$="I love Liberty BASIC."
GOSUB [branchLabel]
 
...
...
...
 
[branchLabel]
	Print message$
	RETURN

We would need to remember that the string variable to print is named message$, and we would have to set up the proper value for message$ each time we wanted to activate the subroutine.

In LB2, Carl Gundel offered us a way to pass a parameter such as message$ directly into the routine, by allowing the use of FUNCTIONS. See newsletters #67 & #70 for more explanation of functions. The syntax for functions is:

function FunctionName(parameter1,parameter2...)
    {basic code routine}
    FunctionName = (value)
  end function

Our message print routine could be done with a function. It would look like this:

function PrintMessage(message$)
	print message$
	PrintMessage=1
	end function

To call it, we need to set its value equal to a variable, or use it in a print statement, like this:

z = PrintMessage("Hello World!")

The z doesn't really do anything, but functions always return a value, so it must be there. (See the previous newsletters for a more thorough explanation!)

Ah, if only we could have a handy routine like this that would accept parameters, but which did not return a value! Now we can! This one is a CALL sub subroutine.

The syntax is different from that of a function. No brackets are needed. Declare the sub with the word "sub", then state the name and the first parameter. If there are additional parameters, separate them each with a comma. On subsequent lines, place the code to perform the actions that are needed. End the routine with "end sub". Here is the syntax:

    sub subname var1, var2$
        'some code here
    end sub

To call a subroutine, the CALL statement is used.

    call subname expr1, expr2$
 

Let's use a CALL sub to use our message printing routine. Here is the CALL sub routine itself:

sub PrintMessage message$
    print message$
    end sub

When we want to call it in the program:

text$="Hello World!"
call PrintMessage text$

OR

call PrintMessage "Hello World!"

Note that you can use either literals or variables as the parameters in the CALL sub's calling statement.

SUMMARY

If you need to call a routine multiple times in a program, use one of the following:

 

 

  1. The GOSUB/RETURN. Use this when you need the same routine more than once in a program, and you do not need to pass parameters (set variables) to use it.
  2. The FUNCTION. Use this when you need the same routine more than once in a program, and you must pass parameters to be used in the routine. Use a FUNCTION if the routine must return a value!
  3. The CALL sub. Use this when you need the same routine more than once in a program, and you must pass parameters to be used in the routine. Use a CALL sub when you do not want to have a value returned from the routine.


2 - CALL SUB AND THE API

It will be very easy to use API calls if they are placed into FUNCTIONS and CALL subs. Here is a CALL sub that will maximize the window whose handle is passed as a parameter:

 
sub MaximizeWindow winHandle
    open "user" for dll as #subuser
    CallDll #subuser, "ShowWindow",_
        winHandle as short,_
        _SW_SHOWMAXIMIZED as short,_
        result as ushort
        close #subuser
    end sub
 

To call it:

hWin=hwnd(#1)
call MaximizeWindow hWin

Using this method, we can set up a library of API calls, and use them by making one simple CALL sub statement, instead of making the complicated call each time. Of course, to use API calls that are to return a value, we can do the same type of thing with a FUNCTION library.

Using CALL sub libraries and FUNCTION libraries, we can reduce the time it takes us to write code, and we can easily share these with others, so we all benefit.

Here is a very small program that uses several CALL sub functions. Please post more examples here! Perhaps someone will start a CALL sub library page on the CoWeb?


SAMPLE CALL SUB PROGRAM

'
'the following CALL subs are used:
'call SetWindowText WindowHandle, Title$
'call MaximizeWindow WindowHandle
'call WavPlay wavfile$, playmode$
'call PrintMessage text$
 
 
button #1.w, "Play a Wav",[wav],UL,10,10
Open "test" for window as #1
print #1, "trapclose [quit]"
handle=hwnd(#1)
call SetWindowText handle, "New Title!"
call MaximizeWindow handle
call PrintMessage "Hello World!"
 
[loop]
input a$
 
[wav]
filedialog "Choose wav","*.wav",wavfile$
call WavPlay wavfile$, "async"
goto [loop]
 
[quit]
close #1:end
 
sub SetWindowText winHandle, caption$
    open "user" for dll as #subuser
    CallDll #subuser, "SetWindowText",_
        winHandle as short,_
        caption$ as ptr,_
        result as void
        close #subuser
    end sub
 
sub MaximizeWindow winHandle
    open "user" for dll as #subuser
    CallDll #subuser, "ShowWindow",_
        winHandle as short,_
        _SW_SHOWMAXIMIZED as short,_
        result as ushort
        close #subuser
    end sub
 
sub WavPlay file$,mode$
    playwave file$,mode$
    end sub
 
sub PrintMessage message$
    print message$
    end sub
 
 
---------------------------------------------------------

3 - FUN WITH THE CARET

The caret is the flasing text cursor. People sometimes refer to this as the CURSOR, but the mouse pointer is called the CURSOR. It is possible to create a custom text cursor. This can be a line or block, or even a bitmap! There are two sample programs here to demonstrate. One creates a block caret, the other creates a bitmap caret. If an LB window loses the input focus, the caret reverts to the normal flashing line.

CreateCaret is used to create the custom caret, and it must then be displayed with a call to ShowCaret. Use DestroyCaret when closing the window. Complete explanations follow. These are largely copied from reference material, with changes to Liberty BASIC syntax. Remember to try out the sample programs.

The final section contains the routine to add a created caret to the open source editor.

Comments and additions are welcome.


CREATE CARET

 
CallDll #user, "CreateCaret",_
hText as short,_      'texteditor handle
hbitmap as short,_    'bitmap handle, or 0, or 1
nWidth as short,_     'width of caret
nHeight as short,_    'height of caret
result as void        'no return

The CreateCaret function creates a new shape for the system caret and assigns ownership of the caret to the given window. The caret shape can be a line, block, or bitmap.

"hText" identifies the window that owns the new caret. "hbitmap" identifies the bitmap that defines the caret shape. If this parameter is NULL (0), the caret is solid; if the parameter is 1, the caret is gray. "nWidth" specifies the width of the caret in pixels. If this parameter is NULL (0), the width is set to the system-defined window-border width. "nHeight" specifies the height of the caret, in pixels. If this parameter is NULL

(0), the height is set to the system-defined window-border height. This function does not return a value.

If the hbitmap parameter contains a bitmap handle, the nWidth and nHeight parameters are ignored; the bitmap defines its own width and height. Get the bitmap handle by loading a bitmap with Liberty BASIC's LOADBMP function, then getting its handle with the HBMP() function. If hbitmap is NULL (0) or 1, nWidth and nHeight give the caret's width and height, in pixels.

The CreateCaret function automatically destroys the previous caret shape, if any, regardless of which window owns the caret. Once created, the caret is initially hidden. To show the caret, use the ShowCaret function. The system caret is a shared resource. A window should create a caret only when it has the input focus or is active. It should destroy the caret when it closes.


SHOW CARET

 
CallDll #user, "ShowCaret",_
hText as short,_    'texteditor handle
result as void      'no return

The ShowCaret function shows the caret on the screen at the caret's current position. Once shown, the caret begins flashing automatically. "hText" identifies the window that owns the caret. This function does not return a value.

The ShowCaret function shows the caret only if it has a current shape and has not been hidden two or more times consecutively. If the given window does not own the caret, the caret is not shown.

Hiding the caret is cumulative. If the HideCaret function has been called five times consecutively, ShowCaret must be called five times to show the caret. The caret is a shared resource. A window should show the caret only when it has the input focus or is active.


HIDE CARET

 
CallDll #user, "HideCaret",_
hText as short,_    'texteditor handle
result as void      'no return

The HideCaret function hides the caret by removing it from the screen. Although the caret is no longer visible, it can be displayed again by using the ShowCaret function. Hiding the caret does not destroy its current shape.

"hText" identifies the window that owns the caret. This function does not return a value.

The HideCaret function hides the caret only if the given window owns the caret. Hiding is cumulative. If HideCaret has been called five times in a row, ShowCaret must be called five times before the caret will be shown.


SET CARET POSITION

 
CallDLL #user, "SetCaretPos",_
x AS short,_        'x location
y AS short,_        'y location
result AS void      'no return
 

The SetCaretPos function moves the caret only if it is owned by the window. SetCaretPos moves the caret whether or not the caret is hidden. The caret is a shared resource. A window should not move the caret if it does not own the caret.


GET CARET POSITION

 
STRUCT point, x as short, y as short
 
CallDll #user, "GetCaretPos"_
point as struct,_    'structure to receive information
result as void       'no return
 
CaretX = point.x.struct
CaretY = point.y.struct

The GetCaretPos function retrieves the current position of the caret. This function does not return a value. The caret position is always given in the client coordinates of the window that contains the caret.


GET CARET BLINK TIME

 
CallDll #user, "GetCaretBlinkTime",_
blinks as short      'milliseconds in each blink

The GetCaretBlinkTime function retrieves the caret blink rate. The blink rate is the elapsed time, in milliseconds, between flashes of the caret. The return value specifies the blink rate, in milliseconds, if the function is successful.


SET CARET BLINK TIME

 
CallDll #user, "SetCaretBlinkTime",_
setblink as short,_    'milliseconds in each blink
result as void         'no return

The SetCaretBlinkTime function sets the caret blink rate. The blink rate is the elapsed time, in milliseconds, between caret flashes. This function does not return a value. The caret flashes on or off every "setblink" milliseconds. One complete flash (off-on) takes twice "setblink" milliseconds. The caret is a shared resource. A window should set the caret blink rate only if it owns the caret. It should restore the previous rate before it loses the input focus or becomes inactive.


DESTROY CARET

 
CallDLL #user, "DestroyCaret",r as void

The DestroyCaret function destroys the current caret shape, frees the caret from the window that currently owns it, and removes the caret from the screen if it is visible. The DestroyCaret function checks the ownership of the caret and destroys the caret only if a window in the current task owns it. If the caret shape was previously a bitmap, DestroyCaret does not free the bitmap. This function does not return a value. The caret is a shared resource. If a window has created a caret shape, it should destroy that shape upon closing.


SAMPLE PROGRAMS:

'************************************************
'create a caret of width and height desired --
'complete sample program
 
texteditor #main.t, 0,0,200,200
open "Big Caret" for window as #main
 
print #main, "trapclose [quit]"
hText=hwnd(#main.t)
 
    open "User" for dll as #user
 
    CallDll #user, "CreateCaret",_
        hText as short,_    'text editor handle
        0 as short,_        'bitmap handle, not used
        10 as short,_       'width
        20 as short,_       'height
        r as void           'no return
 
    CallDLL #user, "SetCaretPos",_
        1 AS short,_        'x location
        1 AS short,_        'y location
        r AS void
 
    CallDll #user, "ShowCaret",_
        hText as short,_    'text editor handle
        r as void           'no return
 
    CallDll #user, "GetCaretBlinkTime", blinktime as ushort
 
    setblink = 2*blinktime  'make blink twice as slow
    CallDll #user, "SetCaretBlinkTime",_
        setblink as short,_    'milliseconds in each blink
        result as void         'no return
 
    print #main.t, "Blink time is now  "
    print #main.t, str$(setblink)
    print #main.t, "milliseconds";
 
 
[loop]
input aVar$
 
[quit]
    CallDll #user, "SetCaretBlinkTime",_
        blinktime as short,_   'restore original blink time
        result as void         'no return
 
    CallDLL #user, "DestroyCaret",r as void
    close #user:close #main:end
 
 
 
nomainwin
'************************************************
'create a caret from a bitmap -- complete sample program
texteditor #main.t, 0,0,200,200
open "Smiling Caret" for window as #main
 
print #main, "trapclose [quit]"
hText=hwnd(#main.t)
 
    open "User" for dll as #user
 
    loadbmp "smile","smile.bmp"
    hsmile=hbmp("smile")
    CallDll #user, "CreateCaret",_
        hText as short,_    'text editor handle
        hsmile as short,_   'bitmap handle, if used
        0 as short,_        'not used
        0 as short,_        'not used
        r as void           'no return
    unloadbmp("smile")
 
    CallDLL #user, "SetCaretPos",_
        1 AS short,_        'x location
        1 AS short,_        'y location
        r AS void
 
    CallDll #user, "ShowCaret",_
        hText as short,_    'text editor handle
        r as void           'no return
 
 
[loop]
input aVar$
 
[quit]
    CallDLL #user, "DestroyCaret",r as void
    close #user:close #main:end
 
 
 
nomainwin
'************************************************
A NEW CARET FOR THE OPEN SOURCE EDITOR
 
Here is the addition of a created caret to the open source editor.
[create.caret]
    CallDll #user, "CreateCaret",_
        hText as short,_    'text editor handle
        0 as short,_        'bitmap handle, if used
        10 as short,_       'pixel width of new caret
        12 as short,_       'pixel height of new caret
        r as void           'no return
 
    CallDLL #user, "SetCaretPos",_
        1 AS short,_        'x location
        1 AS short,_        'y location
        r AS void
 
    CallDll #user, "ShowCaret",_
        hText as short,_    'text editor handle
        r as void           'no return
    return
 
[quit]'add this to the quit routine!
    CallDLL #user, "DestroyCaret",r as void
 
 
Side by Side Software offers a Book for Liberty BASIC, which is available in electronic form on a CDROM. For details: http://alyce.50megs.com/sss/cd.htm
Comments, requests or corrections: Hit 'REPLY' now! Dean Hodgson -- mailto:Hodgson.Dean@saugov.sa.gov.au Alyce Watson -- mailto:awatson@wctc.net