Liberty Basic is develeopped by Carl Gundel Original Newsletter compiled by Alyce Watson and Brosco Translation to HTML: Raymond Roumeas
- Writing output 'code'
- Launching the default web browser and email client
- Timing and benchmarking
- Do it with math?
- Wow, comboboxes!
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:
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?
' '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
---------------------------------------------------------
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.
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.
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.
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.
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.
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.
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.
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.
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.
'************************************************ '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