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

APR 2000

© 2000, Cliff Bros and Alyce Watson All Rights Reserved

In this issue:

  1. Install Maker -- a review by Gary Capps
  2. More on user-defined functions
    new functions and explanations
    functions in functions, and as parameters
    adding more functions to our editor
  3. Creating bmpbuttons at runtime - many ways!
  4. Adding a bmpbutton to the open source editor
 

In future issues:


This newsletter is packed with good stuff. Some of it came about because of questions or comments from members.

This forum belongs to all of us, and suggestions, comments and submissions of articles are welcomed and desired.

Please participate!

Gary Capps has written a very thorough review of a neat, freeware installation program called Install Maker. Thanks, Gary!!

Get Install Maker here:  http://www.clickteam.com

1. INSTALL MAKER, A REVIEW BY GARY CAPPS

Install Maker is a complete installer program that offers the programmer all of the features that he needs to move large programs, with lots of attached files, back and forth between friends and co-workers. But, it also offers features that will appeal to the professional who is trying to distribute his program across the net. All of this out of a free program. That's right, free. But we all know what free means. It means you do something for me and I'll give you something free. But for the tradeoff I think that it's pretty close to being free. At the end of the install, right before the program ends, there is a window that gives the user the option to visit the website of the 'ClickTeam", the authors of the program.

The option to use or not use a wizard is what greets you when the program is loaded and running. The wizard is so easy to use that I choose to use it up until I get ready to actually build the installer file. The wizard starts by asking simply to select the directory that contains your files. You are also given the option to include any subdirectories that may be in your main directory. A handy browse button is available at all places when one is asked for files. Next you are asked to name your product and the language for your chosen install. The name that you give at this stage will be the name that appears as your install icon, not necessarily the name of your program. At this point a preview button is introduced, it allows you to see what the install is looking like at this stage. This feature is used throughout the rest of the program to allow you to see what you are actually building. You are always given the opportunity to go back and redo if you don't like what you see. Then comes the selection of .exe files to be represented by an icon that the program creates, and then adds to your start menu. You are also given the opportunity to have a shortcut to your desktop if you so choose. The .exe file usually refers to the run.exe that you have renamed to match your .tkn file (you did make that .tkn file didn't you?). Again, if you don't want to name your icons the same as your program, now is where you can make that decision. The next option in the process is the information window. This is where you input any license information, special installing instructions, or any pertinent information that you want your user to view.

You don't have to worry about amount of information, because it is presented in a window with scroll bar to access loads of information.

At this time it will be convenient to have a few graphics ready to be used in the install. Specifically if you have some sort of logo or icon that you have created for your program, then you need to have that BMP resized to be 128x280. This BMP will be used in the install program itself and is a good place to do a little promotion for yourself, your product, your web site, and your programming language... You will also need a bitmap to be used as you background wallpaper if you choose the full-window style of install. I created a BMP with a gradient fill in the colors that I thought were more in the style of my program, rather than using the included blue color that they use as the default background. The only thing to remember is that this BMP is tiled if it doesn't fit in the window, and it needs to be 16 or 256 colors, no millions of colors here. If you have a readme type document that you want to be read before exiting the installer, add it here. For ease of use try not to use an application specific file but rather use a .txt or .doc type where everyone will have access through the system notepad. These are actually all of the special items that need to be prepared specifically for the install program; everything else should be in your program directory or sub-directories.

Now you are given the option of having a full screen format with a background, or a small format with no background. The full screen is the format most people are familiar with as it presents the dialog windows inside of a full screen background. You are asked to input any text that you want to appear in the right top corner of your full screen format. I use this to input a welcome line or a title line for the program I am installing. The bitmap window is where you enter the bitmaps that you created earlier that you want for your background and your logo. Again use the browse buttons to locate these files. For convenience I stored everything in my program directory, because later you can choose not to include these files in your install, but still have them handy to use in the program. Now is when the preview button comes in handy. If you don't like what you see stop the install and correct anything that you don't like. In real life you would do a few trial installs and have all of the BMPs worked out before you do the real thing. It took a few tries until I got my background and logo bitmaps just right, as fonts and bitmaps can look different under different applications.

The installation directory is where you stipulate what directory you want your program to install into. You can install into an existing directory or create a new directory for your install. I always use 'c:\program name', as c drive is the safest, because most everyone will have a c drive but not always d, e, f... You can also have the program load information from the registry base or from an .ini file. In the registry base option you are asked for the Root Key, Key and the Subkey. The .ini file option asks for the file name, section and entry. Again, I take the easy way and use, 'c:\', but still the option to use the registry or .ini file is still available for use. On the user side, they are presented with the option of changing to any directory and are presented with how much disk space the install will need and how much disk space is available. If the user decides not to install, now is where they can bail out if they so choose.

The uninstallation window simply asks you whether you want an Uninstaller provided for the user. I always use this, because like the end user, I believe they ought to be able to remove my program with no hassles from my side. The end page is where you put information for the "end page" this being the page where the user is given the option to view a readme type document that you have prepared beforehand. They are also given the option to launch your program when they exit the installer. The real end page though, is the advertising window that you agreed to, which gives the option to go to their web site. As I stated earlier, this is a small price to pay. If the user doesn't quit at this time the program is installed on his machine. You can choose to let the wizard build your install program at this time, but I always revert to the main program where additional options are available for the programmer.

If you check the "do not build" option on the end wizard page you will be put into the main application where you can fine tweak your install. You are given options for the following: Files, wizard texts, wizard options, uninstaller, and build. Files allow you to make changes and add options that the wizard doesn't offer. These are important features that I always use to specify the system file to place dll's, to place special fonts that I use in the font directory, not to include certain files (like that .bas and .bak program that I forgot to remove from my program directory). You can even specify files to not be removed by the uninstaller.

After you fine tweak all the settings that you feel will be necessary, you can save your .iit program for future use and then you're ready to build your install program. The program produces a fine and compact package that can be used in a professional setting as well as being used to pass around your programs to friends and colleagues.

Gary Capps:

mailto:mourndove@w...
2. USER DEFINED FUNCTIONS

We've discussed functions in previous newsletters. Please check newsletter #67 for an article by Carl Gundel on programmer- defined functions in LB2, and a beginner's tutorial on functions in general, and programmer-defined functions.

The ability to define our own functions in Liberty BASIC 2 will make the language more flexible, and it will make it very easy to share code with one another. There has been some discussion recently regarding possible new string manipulation functions that Carl might implement. We can write our own versions of string functions that are not part of the native Liberty BASIC syntax. We'll include some string functions here, and also some math functions.

Some of the following functions should be easy to understand even for beginners, while others are meant to be used by more experienced programmers.

My hope is that this newsletter will spur others to experiment with their own functions and share them with everyone. There is a page on the Community Web that will serve as a function library for LB2, so please post your own functions here and on the CoWeb!

 
http://www.libertybasic.com/CoWeb.182
********************IMPORTANT ***************************   To use these functions, we only need to know how to call them. Just as with Liberty BASIC functions, we do not need to understand HOW they work internally. We just need to know the proper way to use the functions. We can then make use of functions that have been shared by others, even if we do not quite undertand the coding methods used.   ********************IMPORTANT ***************************

 

FUNCTION LIBRARY

Attached to this newsletter, you will find a file containing the functions discussed here. The discussion here is not meant to be a tutorial on function writing, but rather an overview of the way these functions were created.

 

InsertString$

Several people requested a function that would insert one string into another. We can write our own InsertString$ function. The parameters we want to pass will be:

(original string, insertion string, position to start the insertion)

We'll try to use syntax that makes sense, yet is compact:

	newString$=InsertString$(string$,insert$,start)

Remember that as of this writing, a function must always return a value, so the value must be captured in a variable, as above, or used in a command, as in the next example.

As an example to call our new function, let's give Carl Gundel his middle initial:

print InsertString$("Carl Gundel","E. ",6)
produces:  Carl E. Gundel

Here is the function, which takes in the original string, the string to insert, and the starting position, then uses Liberty BASIC's own left$() and mid$() functions.

function InsertString$(string$,insert$,start)
    InsertString$=left$(string$,start-1)+insert$+mid$(string$,start)
    end function

Remember that when using the mid$() function, the third parameter is optional:

	mid$(string$,start[,length])

You must include the source string, and the starting position. The mid$() function will return a string that starts at the position indicated within the source string, and is the length indicated. If no length is indicated, then the string from the start position to the end is returned.

 

ReplaceString$

Some folks have also requested a string function that would replace characters within a string with other characters. This one will have the following syntax:

	newString$=ReplaceString$(string$,replace$,start)

The first string will be the original string, the second string will be the string that should replace part of the original string, and 'start' will be the starting position within the string to replace the characters. Here is an example that will replace the word, "like" with the word, "love".

print ReplaceString$("I like LB.","love",3)
produces:  I love LB.

We'll use LB string functions within our functions, just as wedid in the previous string function example. This time, insteadof placing the new string into the original string, and thenadding the remainder of the original string to the end, we'llplace the insertion string in at the start position, and thenmove as many characters as the length of the insertion stringto the right, and take the remainder of the original string from that point to add to our new string. We'll use a local variablecalled "length" to represent the length of the insertion string.

 
function ReplaceString$(string$,replace$,start)
    length=len(replace$)
    ReplaceString$=left$(string$,start-1)+replace$+mid$(string$,start+length)
    end function

 

ReverseString$

Some other programming languages have a function that will reverse the order of characters in a string. Here is the syntax for such a function:

	reversed$=ReverseString$(string$)

Here is an example using the function:

print ReverseString$("Liberty BASIC")
produces:  CISAB ytrebiL

For this function, we will again rely on the LB mid$() function. We can place our routine into a loop that decrements one on each pass, starting with the last character in the string and putting it into the first spot in a new string, then moving to the next-to-last character, and so on until the entire string has been reversed.

function ReverseString$(string$)
    for i = len(string$) to 1 step -1
        ReverseString$=ReverseString$+mid$(string$,i,1)
    next i
    end function

 

String$

Some other languages also have a function that returns the given number of characters specified. Liberty BASIC has a function called space$() that returns the number of blank spaces specified. We can write a function that returns a string of ANY character specified, or even any group of characters.Syntax:

	repeatString$=String$(char$, total)

As we might call it:

print String$("Tom ",4)
print String$("*",15)
 

produces:

Tom Tom Tom Tom
***************

This one is easy to write. We just start a string in a for/next loop, adding the string contained in char$ as many times as is specified by "total".

function String$(char$, total)
    for i=1 to total
    String$=String$+char$
    next i
    end function

 

BinDec (Binary to Decimal)

Liberty BASIC now has functions to convert hexadecimal numbers to decimal numbers and decimal numbers to hexadecimal numbers. It is sometimes also useful to have a binary to decimal conversion. Binary numbers consist of all 0's and 1's. This is a binary number: 1001 0010 1000 1011, or it can look like this, if you choose: 1001001010001011

Syntax for the function:

	decimalnumber=BinDec(binarynumber)

Usage:

print BinDec(100)

produces: 4

The easiest way we have found to do this conversion is to convert the binary number to a string, as Thomas has done in his version of binary to decimal conversion. In a loop, he parses the string version of the binary number, getting its value with the VAL() function and adding it to the decimal number that will be returned.

function BinDec(bin)
    binary$=str$(bin)
    for i = 0 to len(binary$)-1
        g$=left$(right$(binary$,i+1),1)
        BinDec=BinDec+((2^i)*val(g$))
    next i
end function

 

DecBin (Decimal to Binary)

It is sometimes useful to be able to convert a decimal number to its binary representation. This is not as easily accomplished as the conversion in the other direction.

Syntax:
 
	binarynumber=DecBin(decimalnumber)
 

Usage:

print DecBin(8)

produces: 1000

The following method could be improved, so please post your improvements of the function! Thomas' routine evaluates the position for the binary numeral in question, then uses an algorithm to compare powers of the number to determine if the binary digit will be a "0" or a "1". He appends each digit to the beginning of a string, and when the computation is complete, he returns the value of the string with the VAL() function.

function DecBin(dec)
    dec=int(dec)
    for i=1 to 64
        x=int((2^i)+.5)
        y=int((2^(i-1))+.5)
        nm=int(dec/y)*y
        if int(nm/x)=nm/x then s$="0"+s$ else s$="1"+s$
    next i
    DecBin=val(s$)
    end function

 

Modulus or MOD

Most other languages have a MOD function. This returns the remainder when one number is divided by another. Syntax:

	modnumber=Modulus(number,divisor)

Usage:

print Modulus(11,4)

produces: 3

Why does it produce 3 for an answer? If you divide 11 by 4, the quotient is 2, with a remainder of 3. (4 * 2) + 3 = 11

Here it is. Pretty easy, eh?

function Modulus(number, divisor)
    Modulus=(number)-(int(number/divisor)*divisor)
    end function

 

MakeRGB

For API calls, we may need a long integer color value to represent the red/green/blue color intensity of a color. Liberty BASIC uses named colors, such as white, red, darkcyan, etc. It can also use a graphics color command to achieve an RGB custom color. API calls require that the red/green/blue values be passed as a single long integer. We do this by multiplying the blue value by 256*256, the green value by 256, and then adding the two results to the red value. Here is is as a function:

Syntax:

 
	longcolorvalue=MakeRGB(red,green,blue)
 

Usage:

 
print MakeRGB(100,200,30)
 

produces: 2017380

Have a look at the function below. It contains error trapping to prevent the possibility of values below 0 or above 255 from being used in the function. This is up to the individual programmer, but error trapping should be done either within the function, or as part of the code before the function is called.

 
function MakeRGB(red,green,blue)
    if red<0 then red=0
    if red>255 then red=255
    if green<0 then green=0
    if green>255 then green=255
    if blue<0 then blue=0
    if blue>255 then blue=255
    MakeRGB=(blue*256*256)+(green*256)+red
    end function

 

GetRed

We might also have a need to retrieve the individual RGB values from a long integer color value. For instance, we can get the color of any pixel in a window with the GDI function to GetPixel. It returns a long integer color value. To use this with LB's color command, we need to separate the colors into red, green and blue. Remember LB uses RGB like this:

with variables:

red=100 : green=231 : blue=52
print #graphics, "color ";red;" ";green;" ";blue

or with hard-coded values:

print #graphics, "color 100 231 52"

To 'get' the red componant of an RGB long integer color value, we use the formula to create a long value from separate RGB values, backwards! We will send in the long integer color value, and ask our function to return just the red componant.

Here is the function:

print GetRed(9471354)
function GetRed(color)
    blue=int(color/(256*256))
    green=int((color-blue*256*256)/256)
    GetRed=color-blue*256*256-green*256
    end function

 

GetGreen

Of course, we'll want the green value also, so here it is:

print GetGreen(9471354)
function GetGreen(color)
    blue=int(color/(256*256))
    GetGreen=int((color-blue*256*256)/256)
    end function

 

GetBlue

And now for the blue. Notice that we must do the most manipulating to retrieve the red value, and the least to retrieve the blue value.

 
print GetBlue(9471354)
function GetBlue(color)
    GetBlue=int(color/(256*256))
    end function

 

HiWord and LoWord

 

A double-word, or dword value consists of two word values, a hiword and a loword value. Sometimes an api function will return a dword, and we need to separate the hiword value from the loword value for use. If we wanted to make a dword value from two word values, we would multiply the value that is to be the high word by (256*256), which is also 256^2 (256 squared). Then we would add the hiword to the loword:

 
dwordvalue = hiword*(256*256) + loword
 
To separate the hiword and loword from a dword value, we do
the process in reverse:
 
 
print HiWord(99471354)
function HiWord(dword)
    HiWord=int(dword/(256*256))
    end function
 
print LoWord(99471354)
function LoWord(dword)
    hiword=int(dword/(256*256))
    LoWord=dword-(hiword*256*256)
    end function

 

HiByte and LoByte

Just as a dword is made up of two word values, a word value consists of two byte values. To make a word value from two byte values, we multiply the value that is to be the high byte by 256, then add it to the lowbyte value:

 
wordvalue = hibyte*256 + lobyte
 
To separate the HiByte and LoByte from a word value, we reverse
the process:
 
print HiByte(4*256+5)
function HiByte(word)
    HiByte=int(word/256)
    end function
 
print LoByte(4*256+5)
function LoByte(word)
    hibyte=int(word/256)
    LoByte=word-(hibyte*256)
    end function

 

HOW ABOUT??

Perhaps somebody would like to write a MakeWord or MakeDword function and share it? How about some other useful math functions???


NEW FUNCTIONS FOR OPEN SOURCE EDITOR

We can convert some more of our routines in the open source editor to functions. Here are two really useful ones. The first one will take a full path and filename, such as would be returned by a filedialog, and it will return the filename with no drive/directory information.

 
    function SeparateFile$(f$)
        fileindex=len(f$)
        filelength=len(f$)
          while mid$(f$, fileindex,1)<>"\"
            fileindex=fileindex-1
          wend
        SeparateFile$=right$(f$,filelength-fileindex)
        end function

And here is the equivalent function that will return just the drive and directory information from a filename:

 
    function SeparatePath$(f$)
        fileindex=len(f$)
        filelength=len(f$)
          while mid$(f$, fileindex,1)<>"\"
            fileindex=fileindex-1
          wend
        SeparatePath$=left$(f$,fileindex)
        end function
 

The previous two functions make it really easy to test for a file's existence with the FILES statement.

function FileExist(fPath$,fFile$)
files fPath$,fFile$,info$(
FileExist=val(info$(0,0))
end function
 

Here is the way we call these functions in our file/open routine in the open source editor. We place the filename into the variable, file$. We then get the filename alone and place it into the variable, shortFile$, and the path information alone and place that into the variable, filePath$.

    filedialog "Open file..",filePath$+"*.bas",file$ 
 
    shortFile$=SeparateFile$(file$)
    filePath$=SeparatePath$(file$)

With that information, we can easily use our FileExist function to see if the requested file exists, and if it doesn't (that means the return from the FileExist function is less than 1) then we do not attempt to open the file:

    if FileExist(filePath$,shortFile$)<1 then
        notice "Error"+chr$(13)+"File does not exist."
        goto [loop]
    end if
 

 

USING FUNCTIONS WITH FUNCTIONS

Earlier, we made our own InsertString$ function that used LB functions left$() and mid$() within it. We can also use functions as parameters to send to other functions. We called the InsertString$ function like this:

print InsertString$("Carl Gundel","E. ",6)

We could also have called it like this:

print InsertString$(upper$("Carl Gundel"),"E.",6)

Notice that the upper$() function is actually used as a parameter in our InsertString$ function? The result of the call would be:

CARL E. GUNDEL

In addition to using Liberty BASIC functions as parameters in our functions, we can use OUR OWN functions as parameters in functions. The FileExist function could have been called without setting the filename and pathname into variables first, by using the SeparatePath$() and SeparateFile$() functions as parameters passed to our FileExist() function. Here it is:

 
    if FileExist(SeparatePath$(file$),SeparateFile$(file$))<1 then
        notice "Error"+chr$(13)+"File does not exist."
        goto [loop]
    end if

Just as we can use Liberty BASIC functions within our own functions, we can call other functions of our own within our functions.


REQUEST

Do you think we can also use OUR OWN functions as parameters in Liberty BASIC functions? I am often asked how I know all the things about Liberty BASIC that I know. Here is the anwer:

I ask questions, then try it out myself. This function information is an example of that. I assume that you may, indeed, use your own functions within Liberty BASIC functions, but I have purposely not tried it out, in hopes that some others will become inquisitive and perhaps think of some new questions to ask that I haven't thought of.

Can we use LOWER$(SeparateFile$(file$))

Try it and see, and report back to us!

How about an example of two programmer defined functions, one of which calls the other? Or perhaps two functions that call one another? How about an example of recursion in programmer- defined functions? Inquiring minds want to know, and there are far better brains out there than mine!


3. BMPBUTTONS AT RUNTIME -- LB VERSION 2 ONLY!

We recently had a question from a member who wanted to know if new text could be placed upon a bmbutton at runtime. It seemed that for his needs, simply having a set of bmpbutton bitmaps loaded and waiting would not suit his purposes.

Remember that we can change the bitmap that appears on a button during program execution with the command:

 
    loadbmp "newbmp", "New.bmp"
    print #1.bmpbtn, "bitmap newbmp"
 

To place text onto a bmpbutton at runtime, will require that we create a new bitmap at runtime, save it with BMPSAVE, load it with LOADBMP and then issue a bitmap command to the bmpbutton.

There are at least two ways to create a bmpbutton at runtime. The first way is to load a blank button template, then draw it into a graphicbox, and print the desired text upon it. The other way is to draw the new button completely with graphics commands in a graphicbox. With either drawing method, we then save it as a file, load it, and issue a bitmap command to the bmpbutton in question. Here are the steps:

1. Draw the desired button image in a graphicbox.

2. GetBmp, x, y, width, height of the button image desired.

3. BMPSAVE the bitmap named in the GetBmp command to a file.

4. LOADBMP the bitmap file that we newly created.

5. Issue a "bitmap " command to the bmpbutton.

Here it is, in code, using a blank button template called "empty.bmp" #1.g is the handle of a graphicbox. #1.b is the handle of the bmpbuton. The entire code for this program is contained in the attached file, "bmpbuts.bas".

 
'draw the new bitmap, using a template bitmap and text commands:
    loadbmp "empty","empty.bmp"
    print #1.g, "down;color cyan;place 22 22"
    print #1.g, "drawbmp empty 0 0"
    print #1.g, "font arial 16"
    print #1.g, "|Close"
    print #1.g, "getbmp closebmp 0 0 100 30;flush"
    BMPSAVE "closebmp","close.bmp"
    loadbmp "closebmp","close.bmp"
 
'place the new image on the bitmap button:
    print #1.b, "bitmap closebmp"
 

The file "bmpbuts2.bas" is very similar, but it asks for user input to determine the text to place upon the button template to make a new image for the bmpbutton. That new text is contained in the variable, text$. The code to draw this image follows:

 
'draw the new bitmap, with user input for bmpbutton text:
    loadbmp "empty","empty.bmp"
    print #1.g, "down;color cyan;place 12 22"
    print #1.g, "drawbmp empty 0 0"
    print #1.g, "font arial 16"
    print #1.g, "|";text$
    print #1.g, "getbmp closebmp 0 0 100 30;flush"
    BMPSAVE "closebmp","close.bmp"
    loadbmp "closebmp","close.bmp"
 
'place the new image on the bitmap button:
    print #1.b, "bitmap closebmp"
 

"Bmpbuts3.bas" is similar. It uses a graphics window, whose handle is #g, to draw the bitmap entirely with graphics commands, save it, etc. BEFORE the program window opens. In this way, the newly created bitmap is the original image to appear on the bmpbutton.

 
'draw the new bitmap entirely with graphics commands:
    print #g, "down;fill darkred"
    print #g, "size 2;backcolor darkred"
    print #g, "color black;line 99 1 99 28"
    print #g, "line 3 29 99 29"
    print #g, "color red"
    print #g, "line 1 1 99 1"
    print #g, "line 1 1 1 29"
    print #g, "place 18 22"
    print #g, "font arial 16"
    print #g, "|Button"
    print #g, "getbmp newbmp 0 0 100 30;flush"
    BMPSAVE "newbmp","new.bmp"
 
'make a bmpbutton with this new bitmap, and open a window:
    bmpbutton #1.b, "new.bmp",[open],UL,10,100
    open "Bmpbuttons at Runtime" for window as #1
 

There are two other demos included here. "Bmpbuts4.bas" uses sprite routines to draw an image for the bmpbuttons and "Bmpbuts5.bas" shows a way to include only one bitmap file with a program, and to make separate bitmap files for bmpbuttons at runtime. This one works pretty much as the previous examples, so I won't include more explanation here. It takes a large bitmap that includes some of the bmputtons from the LB2 editor, and makes separate bmpbuttons in a window.

"Bmpbuts4.bas" is the demo that uses sprite routines. Why would one go to all of that trouble? Have a look at the attached bitmap, toolbar.bmp. I have set my system color scheme to one called "maple". You can see that the toolbar itself is the maple color, while the buttons are gray. This shows up in plenty of applications, but there are also many programs that color the button background to the system colors, then draw the image on IT. Unfortunately, you cannot just draw an image on top of another without obscuring all that is underneath, so if your image has an irregular shape, it will obscure a rectangular area on the screen below it. To place an image on the screen so that the screen background shows all around the image, use masks and sprites. A sprite is simply the desired image, placed against a black background.

The mask is an identically shaped image, which is black in every pixel of the desired image, and white everywhere else.

For a sample image sprite with mask, look at the attached runbtn.bmp. It is a copy of the run button from the LB2 editor, but as a sprite and mask. Have a look at wowmaple.bmp. It is the result on my system of drawing the mask and sprite to make the bmpbutton.

This method does not use LB's Drawbmp command, but uses the GDI function, BitBlt. The mask is placed upon the screen using the raster operation SRCAND, which combines pixels on the screen with the mask bitmap by using the Boolean AND operator. The sprite is then put onto the screen using the dwROP SRCPAINT, which combines pixels on the screen with the sprite bitmap using the Boolean OR operator.

We can capture the results of these operations into a really nice- looking bitmap for our bmpbutton, using GetBmp and BmpSave, as we did in earlier examples.

 

IMPORTANT NOTE ABOUT COLORS

LB2 now colors windows with the DEFAULT system colors of the user unless you override this with a BackgroundColor$ command.

Graphicboxes are now filled with this default color, but graphics windows are not. Use a graphicbox for this sprite/mask bmpbutton technique, and you will automatically have the correct background color for your button. Please look at "Bmpbuts4.bas", which illustrates this method.


4. ADDING A BMPBUTTON AT RUNTIME TO OUR EDITOR

 

We can make a bitmap button at runtime by opening a special window to create and save our button. Since we are avoiding extra files in this editor, we'll draw the button with graphics commands, and after we've saved it to a file, we'll close the drawing window and open the program window.

[makebmpbutton]
    WindowWidth=btnwide+40:WindowHeight=btnhigh+60
'** NEW ** note that a graphicbox will automatically be
'          filled with default or programmer-set
'          BackgroundColor$! (not true of graphics window)
    graphicbox #b.g, 0,0,200,100
    open "BmpButton" for window_nf as #b
    print #b, "trapclose [closeb]"
 
    print #b.g, "font arial 0 12 bold"
    print #b.g, "down;color red ; place 5 10"
    print #b.g, "|Quit"
    print #b.g, "color 230 230 230"
    print #b.g, "line 0 0 29 0;line 0 0 0 14"
    print #b.g, "color darkgray"
    print #b.g, "line 28 1 28 14;line 1 13 28 13"
    print #b.g, "color 45 45 45"
    print #b.g, "line 29 1 29 15;line 1 14 29 14"
    print #b.g, "getbmp quitbutton 0 0 30 15"
    BMPSAVE "quitbutton","qbutton.bmp"
[closeb]
    WindowWidth=600:WindowHeight=480
    close #b:return
 

Remember that the graphicbox will be filled automatically with the BackgroundColor$, which is the system default color, or the BackgroundColor$ chosen by the programmer. We'll let that be the background color for the button, making the foreground color red and writing the text "Quit" on the button. We'll also draw some borders to give a 3D-look.

The look of your bmpbutton is up to you, so experiment to get a look that pleases you.

After the window is closed and the new bitmap is saved to file, we had better check that the file was created successfully before we try to add our RED "Quit" button to our editor. We can use our new FileExist() function! The bitmap file will be in the DefaultDir$ and will be called "qbutton.bmp"

 
 
    if FileExist(DefaultDir$,"\qbutton.bmp")<1 then
        notice "Error"+chr$(13)+"Unable to create bmpbutton!"
        end
    end if
 

The program will abort if the bitmap file is not found. If everything is okay, we can use the new bitmap for a bmpbutton"

 
    bmpbutton #1.quit, "qbutton.bmp",[quit],UL,504,btnY
 
 

We should also remember to add a tooltip for new button:

    struct toolinfo17, cbSize as word, uFlags as word,_
        hwnd as word, uId as word, x as word, y as word,_
        w as word, h as word, _
        hInst as word, lpstrText$ as ptr
 
    toolinfo17.cbSize.struct = 22
    toolinfo17.uFlags.struct = TTF.IDISHWND or TTF.SUBCLASS
    toolinfo17.hwnd.struct = h
    toolinfo17.uId.struct = hwnd(#1.quit)
    toolinfo17.hInst.struct = hInstance
    toolinfo17.lpstrText$.struct = "Close Program."
    calldll #user, "SendMessage", hwndTT as word, TTM.ADDTOOL as word, _
    0 as word, toolinfo17 as struct, re as long
 

As always, the full code for the open source editor is attached to this newsletter. Please consider sending in your own version of the editor, or any functions that you have written and are willing to share.


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