Liberty Basic is develeopped by Carl Gundel Original Newsletter compiled by Alyce Watson and Brosco Translation to HTML: Raymond Roumeas
In future issues:
- A new way to use the filedialog
- Playing wavs
- Using ascii characters in commands
- the FILES command
- writing and using an ini file
- writing output 'code'
Since Carl Gundel has made the alpha for Liberty BASIC version 2.0 available to us, we need to take care about version checking in our programs. Really, we should have been doing this all along, because new versions of LB provided functions not available in previous versions, so often programs would not run in older versions of LB.
The open source editor will not work properly in LB v2.0. The way that the fonts are sized has changed, probably permanently, so font commands will not be backwards compatible.
According to Carl: "The font sizing is based on point size. LB v1.x uses pixels. I'm not sure what to do with that, but I'll do my best to make it compatible. Backwards compatibility is important to me, but I may need to make some compromises."
In our editor, this means that the font size we have chosen that makes small button captions in v1.42, makes much larger characters and the captions no longer fit on the buttons when used in v2.0. The new font sizing is actually better in keeping with the way fonts are sized in other Windows applications, such as word processors.
In versions up to v1.42, we needed to list a graphicbox command first before we listed other controls in our window setup. If a graphicbox was listed after a button, but in the same location, the graphicbox would obscure the button.
This is not true in v2.0, AND listing the graphicbox first makes the button unusable! For v2.0 programs we MAY need to make a change, and list the graphicbox after the other controls. (Remember, everything is subject to change in version 2.0 -- it is still in its alpha stage!)
Version$ contains the version of Liberty BASIC being run.
print Version$ would produce: 1.42
If we want to insure that Version$ is ONLY 1.42:
if Version$="1.42" then {BASIC code}
Version$ is a string variable. To evaluate it, you may need to use the val() function, as in this example:
if val(Version$) < 2 then {BASIC code}
We'll try to remember to do a version check in our programs from now on. I suspect we will devote a newsletter to updating programs to be v2.0 compliant, when v2.0 goes into beta release. Here's the version check. If the version of LB is greater than 1.42, the program execution is aborted:
'** this program will not work in LBv2.0! if val(Version$)>1.42 then notice "This program will not work in LBv2.0!" end end if
The first section of a bitmap file contains information about the bitmap. Try opening a bitmap file in Notepad. The first two caracters will be "BM". This will be followed by a bunch of characters; some of them will be recognizable, some will be odd-looking, and many will be unprintable.
These characters are evaluated according to their ascii values. Try this little routine, being sure the path and filename are valid on your system. It reads the ascii values of the first 29 characters of a bmp file and prints them in the main window.
open "c:\lb142w\bmp\copy.bmp" for input as #b b$=input$(#b, 29) close #b for i=1 to len(b$) print asc(mid$(b$,i,1)) next i
You will get a list that begins like this:
66 77 242 1 0 0 0 0 0 0 118 0 0 0 40 0 0 0 25 0 0 0 25 0 0 0 1 0 4
Look at the first two characters. 66 is the ascii value for "B" and 77 is the one for "M". We can read part of this file (the first 29 bytes will be enough) to retrieve information about this bitmap.
The width of the bitmap is contained in characters 19 & 20. Together, they form a "word" value that can be interpreted by Windows programs. We can make sense of this by evaluating the ascii values for characters 19 & 20 in the proper way.
Character 20 will be the "hibyte" when used by api calls. A "word" value consists of a "hibyte" and a "lowbyte". The hibyte portion of a "word" is evaluated by multiplying it by 256. Character 19 will be the "lobyte" part of the "word" value. The two values are added together to get a value for the bitmap width. Pseudo code:
asc(char 19) + {asc(char 20) * 256} = width
In our sample, above, the values are
char 19 = 25 char 20 = 0 25 + (0*256) = 25
Our little bitmap has a width of 25 pixels. If instead,
char 19 = 10 char 20 = 2
then the bitmap width would be:
10 + (2*256) = 522
Height is evaluated in exactly the same way, but using characters 23 and 24, in pseudo code: asc(char23) + {asc(char 24) * 256} = height
In our sample above:
char 23 = 25 char 24 = 0 bitmap height = 25 + (0*256) = 25
In our editor, we will add a bitmap previewer tool. When the user chooses a bitmap file, we'll read the header to determine information about the bitmap. Here is the routine we'll use to get the bitmap dimensions. We'll open the file and read in the first 29 bytes. To get a value for character 19, we'll use the mid$() function, reading the header string, pic$ at char 19, for a length of 1:
asc(mid$(pic$,19,1))
We'll get a value for characters, 20, 23 and 24 in the same way. Here it is:
[openbmp] filedialog "Open Bitmap","*.bmp", picFile$ open picFile$ for input as #pic pic$=input$(#pic,29) close #pic bmpwidth = asc(mid$(pic$,19,1)) + (asc(mid$(pic$,20,1)) * 256) bmpheight = asc(mid$(pic$,23,1)) + (asc(mid$(pic$,24,1)) * 256)
We have an even more important bit of information to check, though. Since LB v1.42 and below can load bitmaps that have 256 or fewer colors, we will have a program crash if we try to load 16,000,000 color bitmaps. We can find out how many colors are in the bitmap format by checking the color depth from the file header, as we did for the width and height. The color depth will be contained in character 29, so we can get its value like this:
picDepth=asc(right$(pic$,1))
In our earlier sample, this value is 4. To determine the number of colors in a bitmap from its depth, we take 2 to a power of picDepth:
picColors=2^picDepth
In our sample
picColors = 2 ^ 4 = 16
Our bitmap is in 16-color format. Liberty BASIC 1.42 can load bitmaps that have 256 or fewer colors. The color depth that corresponds to 256 colors is 8. In our bitmap previewer, if the depth is greater than 8, that means that there are more than 256 colors in the bitmap, and Liberty BASIC cannot load it. If that is the case, we'll give the user the chance to load it and view it in PaintBrush. To run PaintBrush with a bitmap loaded:
run "pbrush "+picFile$
The complete code for the bitmap previewer is at the end of this newsletter. The complete code for the updated Open Source Editor is attached to the newsletter, since it is getting to be quite lengthy. Here is a routine that traps bitmaps that are formatted to more than 256 colors:
if picColors > 256 thenmessage$="The chosen bitmap has more than 256 colors, "+_ "so Liberty BASIC cannot load it. Would you like to "+_ "view it with Paintbrush?" confirm message$;answer$ if answer$="yes" thenrun "pbrush "+picFile$ picFile$=""end ifend if
If we find that the bitmap can be loaded in Liberty BASIC, then we load and display it. We will want to set a flag if we have loaded a bitmap, so we can call UNLOADBMP and free the memory consumed by the previous bitmap. Let's call the flag bmploaded, and set it to 1 when we have loaded a bmp:
bmploaded=1
If a bmp was loaded previously, let's unload it, then load the bmp that was chosen (picFile$) as "tempPicture".
if bmploaded=1 then unloadbmp "tempPicture" loadbmp "tempPicture", picFile$
Since we know the bitmap width and height, we can center it within our graphicbox. Our graphicbox has been created with a width of 410 and a height of 200:
graphicbox #bit.box1, 20,100,410,200
To get the x location to draw the bmp centered, let's check the difference between the width of the graphicbox and the width of the bitmap. Since we want equal parts of the graphicbox to show on both sides of our bmp to center it, we'll divide the difference by 2. We'll do the same thing with the height values for the bmp and the graphicbox to determine the proper y location for the upper left corner of the bmp. Then we'll DRAWBMP at that X, Y location. Remember that variables must be placed outside of quote marks in commands:
xbmp=int((410-bmpwidth)/2) ybmp=int((200-bmpheight)/2) print #bit.box1, "cls" print #bit.box1, "drawbmp tempPicture ";xbmp;" ";ybmp print #bit.box1, "flush" goto [loop]
Notice that we first cleared the screen with CLS. This accomplished two things. It freed the memory from any previous FLUSH commands, and it removed any previous bitmaps from the graphicbox display, so that only the current bitmap will show. Then, we issue a FLUSH command, so that the bitmap will be redrawn if the window is obscured and restored.
We'll set up our bitmap previewer code by listing some new variables to use in the bmp routines, and by adding a Bitmap Preview item to the Tools Menu.
'picFile$ filename for opened bitmap 'pic$ string to hold bitmap file header 'savebmpfile$ name to save bmp AS 'picDepth color depth of bitmap 'picCols number of colors in bitmap 'bmpwidth width of bitmap 'bmpheight height of bitmap 'xbmp x location to draw bitmap in graphibox 'ybmp y location to draw bitmap in graphibox 'bmploaded flag to set when a bitmap is loaded 'message$ string variable to hold notice and confirm messages menu #1, "&Tools",_ "&Branch Labels",[branchlabels],_ "Bit&map Preview",[bmp]
When the routine is called, we'll open a window that contains a graphicbox to display the bitmap, some buttons for user interaction, and a textbox to display the bitmap name, and another textbox to display the bitmap dimensions.
[bmp] '** BITMAP PREVIEWER WindowWidth=451:WindowHeight=350 button #bit.open, "Open", [openbmp], UL,350,5,80,26 button #bit.save, "Save As",[savebmp], UL,350,35,80,26 button #bit.exit, "Exit", [closebit], UL,350,65,80,26 textbox #bit.t1, 20,35,300,26 textbox #bit.t2, 20,65,300,26 statictext #bit.s, "Bitmap File:",20,5,150,20 open "Bitmap Preview" for dialog_modal as #bit print #bit, "trapclose [closebit]"
We are using the ctl3d.dll (see Newsletter #61) to make our dialog windows look better, so let's go the extra distance and issue font commands to our controls to make them look a bit better.
print #bit.t1, "!font Times_New_Roman 0 16" print #bit.t2, "!font Times_New_Roman 0 16" print #bit.save, "!font Times_New_Roman 0 16" print #bit.open, "!font Times_New_Roman 0 16" print #bit.exit, "!font Times_New_Roman 0 16" print #bit.s, "!font Times_New_Roman 0 16"
When we close our bitmap previewer, we should free the memory used, by issuing CLS and by unloading the current bitmap. We also need to set the flag that indicates a bitmap is loaded back to 0, since the user may want to call on the bitmap previewer again.
[closebit] print #bit.box1, "cls" close #bit if bmploaded=1 then unloadbmp "tempPicture" bmploaded=0 goto [loop]
Did you notice that we included a button called SAVE AS?
button #bit.save, "Save As",[savebmp], UL,350,35,80,26
We can copy any type of file, by opening it for INPUT, reading it into a string variable, then closing the file. We then open a file with a different name for OUTPUT and write the string to that file. Voila, we have copied and moved a file!
open picFile$ for input as #pfpic$=input$(#pf, lof(#pf))close #pf
filedialog "Save As..","*.bmp",savebmpfile$ if savebmpfile$="" then [loop]
In the routine above, we've opened picFile$ for INPUT, and read the contents into the string variable pic$. Then we've closed the file. Next, we get a name from the user to save the file AS. If the user doesn't specify a name, we abort the procedure and goto [loop]
If there is a valid name for the saved file, we open it for OUTPUT, write the string pic$ to the file, then close it.
open savebmpfile$ for output as #bpfprint #bpf, pic$close #bpf
'** NEW ** [bmp] '** BITMAP PREVIEWER WindowWidth=451:WindowHeight=350 button #bit.open, "Open", [openbmp], UL,350,5,80,26 button #bit.save, "Save As",[savebmp], UL,350,35,80,26 button #bit.exit, "Exit", [closebit], UL,350,65,80,26 textbox #bit.t1, 20,35,300,26 textbox #bit.t2, 20,65,300,26 graphicbox #bit.box1, 20,100,410,200 statictext #bit.s, "Bitmap File:",20,5,150,20 open "Bitmap Preview" for dialog_modal as #bit print #bit, "trapclose [closebit]" print #bit.t1, "!font Times_New_Roman 0 16" print #bit.t2, "!font Times_New_Roman 0 16" print #bit.save, "!font Times_New_Roman 0 16" print #bit.open, "!font Times_New_Roman 0 16" print #bit.exit, "!font Times_New_Roman 0 16" print #bit.s, "!font Times_New_Roman 0 16" goto [loop] [closebit] print #bit.box1, "cls" close #bit if bmploaded=1 then unloadbmp "tempPicture" bmploaded=0 goto [loop] [savebmp] if picFile$="" then notice "It is not possible to SAVE. No Bitmap has been chosen." goto [loop] end if open picFile$ for input as #pf pic$=input$(#pf, lof(#pf)) close #pf filedialog "Save As..","*.bmp",savebmpfile$ if savebmpfile$="" then [loop] cursor hourglass open savebmpfile$ for output as #bpf print #bpf, pic$ close #bpf cursor normal notice "Bitmap saved as "+savebmpfile$ goto [loop] [openbmp] filedialog "Open Bitmap","*.bmp", picFile$ if picFile$ = "" then [loop] print #bit.t1, picFile$ open picFile$ for input as #pic pic$=input$(#pic,29) close #pic picDepth=asc(right$(pic$,1)) picColors=2^picDepth bmpwidth = asc(mid$(pic$,19,1)) + (asc(mid$(pic$,20,1)) * 256) bmpheight = asc(mid$(pic$,23,1)) + (asc(mid$(pic$,24,1)) * 256) if picColors > 256 then print #bit.t2, "" print #bit.t1, "" print #bit.box1, "cls" message$="The chosen bitmap has more than 256 colors, "+_ "so Liberty BASIC cannot load it. Would you like to "+_ "view it with Paintbrush?" confirm message$;answer$ if answer$="yes" then run "pbrush "+picFile$ picFile$="" goto [closebit] else picFile$="" goto [loop] end if end if if bmploaded=1 then unloadbmp "tempPicture" loadbmp "tempPicture", picFile$ bmploaded=1 print #bit.t2, "Width: ";bmpwidth;" Height: ";bmpheight;"" xbmp=int((410-bmpwidth)/2) ybmp=int((200-bmpheight)/2) print #bit.box1, "cls" print #bit.box1, "drawbmp tempPicture ";xbmp;" ";ybmp print #bit.box1, "flush" goto [loop]
Newsletter compiled and edited by: Brosco and Alyce. Comments, requests or corrections: Hit 'REPLY' now! mailto:brosc-@orac.net.au or mailto:awatso-@wctc.net