GEM Bindings for GFA Basic
I have tested most of the routines here as completely as I could and have found no bugs. However, I make no guarantees to the programmer that they are 100% error free. Since I'm just poking things into the GEM control arrays, chances are if there are any bugs it's due to a typo and can be quite easily fixed. Please contact me if you make any changes or find bugs. GEM is very powerful, and can be dangerous as well. Giving GEM a bad parameter can send your program off into memory never never land, never to return. With C, this just causes the frustration of resetting and recompiling...with GFA however, it is easy to go long stretches without saving, only to watch it waste away in a second when you rub GEM the wrong way. So...save your work often. I hope you find these routines useful and fun, as I think they take a lot of pain out of GEM programming.
If you're so inclined, you can send lots of money to:
Paul Chinn
4995 Fern Place
Rohnert Park Ca. 94928
or lots of praise to Compuserve ID, 76157,55
Direct complaints to Atari corp.
GEM Bindings for GFA Basic. 1987 Paul Chinn
Release 1
As most people are well aware, GFA basic is perhaps the most powerful basic ever created. Not only that, but its performance rivals that of many compiled languages such as C or Pascal. Graphics, sound, I/O, GFA does everything...well maybe not _everything_. GFA's weakest part, in my opinion, is its use of GEM. As implemented GFA is great for beginning GEM programmers. What could be easier than OPENW 1 to pop open a window? Well, with the simplicity you lose much of the power of GEM. Under GFA only four windows can be opened, and GFA maintains tight control over them, redirecting output to only the open window. Use of resource files is limited to just menus and these are limited to text only. As I mentioned, as is GFA's GEM is fine for beginners but is probably missing close to 90% of GEM functions, functions that are very desirable for advanced programming. Fortunately, the programmers of GFA left their product amazingly open ended with hooks to all sorts of neat internal ST stuff...like GEM.
I've taken advantage of these hooks, and created the set of subroutines you have here. Now, right at your fingertips are all the GEM AES calls(except for appl_read, appl_write, and the play and record functions which are rarely used). I've adopted the 'C' format for these calls, so GFA programmers can take advantage of the numerous tutorials about GEM in C. Also, I myself, am a C programmer. I have found GFA invaluable for testing out ideas and program mock-ups and now with these utilities, a GEM program can be translated virtually verbatim from basic to C(or vice versa). Not only that, but I can test out the AES and GEM in real time, from GFA's direct mode...something not previously possible. The rest of this doc file will explain the use of these routines. It is not intended as a tutorial on GEM but will outline each of the calls, and give some explanations for overcoming some of the dissimilarities between basic and C.
Using the routines:
To use the routines you have to include the following routines in each program:
fill_gcont()
fill_gint()
gem()
crack_add()
vs_clip()
Gem(),fill_gcont(), and fill_gint() are used by the routines and you need not worry about their use. The other 2 will be explained later. All these routines are at the end of the listing.
The rest of the routines are the actual GEM calls and you may include all of them in your program or only the ones you need. I suggest that when you use my routines you don't mix in the GFA counterpart. So if you use wind_open, keep away from GFA's openw.
The calls for the most part, follow their C counterparts exactly.
So the following call in C:
handle=wind_create(11,20,20,100,100);
would look like:
@wind_create(11,20,20,100,100)
in GFA. As you can see, the transition is an easy one. There are a few exceptions however.
Crossing the C to BASIC bridge:
Once difference between Basic and C is that unlike C, basic cannot return values from subroutines. I solved this by creating the global variable ret. So after a call, ret will contain the value normally returned by the C counterpart. In the above example, ret would equal handle.
Another difference concerns passing variables. In C the following is perfectly valid:
rsrc_load("Dummy.rsc");
In GFA, however, you will get an error because all my GEM routines take integers as parameters and unlike C, GFA does not convert types.(Note: in GFA integers are 4 bytes while in C they are only 2...this will not usually be a problem). The solution is again simple:
a$="DUMMY.RSC"
@rsrc_load(varptr(a$))
is the working basic equivalent.
Finally, if the C call is something like:
do_it(&x,&y,j);
the GFA call would be
@do_it(*x,*y,j)
The & in C and the * in basic tell the function to pass the _address_ of the variable so that its value may be changed by the function. If this concept seems radically new to you, I suggest you brush up on variables and pointers before continuing.
There are some other differences that affect individual functions but they are minor and will be explained when needed.
And now the routines:
For explanation of the routines and their variables I suggest the abacus GEM book or Tim Oren's excellent series of tutorials on Compuserve. The variable names shown here are the names used in the actual routines and because of the way GFA handles local and global variables you _MUST NOT_ use the same names for variables when calling my routines.
vs_clip(cx%,cy%,ch%,cw%,toggle%)
this call sets the clipping rectangle. You specify the corner x and y and the width and height. Clipping is turned on when toggle% is 1 and off when toggle% is 0. Turn off clipping only when you can be sure you won't write over the wrong part of the screen. This command must be used so that you don't draw over other windows or open ACCs.
*****AES initializing routines
Sets up your application.(I believe GFA takes care of this so they probably aren't needed)
@appl_init
@graf_handle(*hwchar%,*hhchar%,*hwbox%,*hhbox%)
*****AES window management
@wind_get(ghandle%,gfield%,*gw1%,*gw2%,*gw3%,*gw4%)
@wind_create(crkind%,crwx%,crwy%,crww%,crwh%)
@wind_open(ohandle%,owx%,owy%,oww%,owh%)
@wind_close(clhandle%)
@wind_delete(dhandle%)
@wind_set(shandle%,sfield%,sw1%,sw2%,sw3%,sw4%)
****>now's a good time to introduce the routine crack_add(). If you
use wind_set to set the address of the text in the name or info
lines of a window, you need to pass the lo and hi words in sw1% and
sw2%. This is how you do it:
title$="My Window Title"
title_add=varptr(title$)
@crack_add(title_add)'crack_add returns 2 global variables:
hi% & lo%
@wind_set(shandle%,2,lo%,hi%,0,0)
@wind_find(fmx%,fmy%)
@wind_update(ubegend%)
@wind_calc(ctype%,ckind%,cinx%,ciny%,cinw%,cinh%,*coutx%,*couty%,
*coutw%,*couth%)
*****AES event handlers
@evnt_keybd
@evnt_button(bclicks%,bmask%,bstate%,*bmx%,*bmy%,*bbutton%,*bkstate%)
@evnt_mouse(moflags%,mox%,moy%,mowidth%,moheight%,*momx%,*momy,
*mobutton%,*mokstate)
@evnt_timer(tlocount%,thicount%)
@evnt_mesag(mgpbuff%)
*****>buffer% has to be the address of a 16 byte buffer here's a how
I like to do it:
buffer$="0123456789abcdef"
buffer%=varptr(buffer$)
@evnt_mesag(buffer%)
Then you can read the buffer like this:
val1%=dpeek(buffer%+offset)'offset must be a multiple of 2
@evnt_multi(mflags%,mbclicks%,mbmask%,mbstate%,mm1flags%,mm1x%,
mm1y%,mm1width%,mm1height%,mm2flags%,mm2x%,mm2y%,
mm2width%,mm2height%,mmgpbuff%,mtlocount%,mthicount%,
*mmox%,*mmoy%,*mmobutton%,*mmokstate%,*mkreturn,
*mbreturn%)'what a beast!!!!
*****File Selection Manager
@fsel_input(iinpath%,iinsel%,*iexbutton%)
****AES Object manager
@objc_draw(dtree%,drstartob%,drdepth%,drxclip%,dryclip%,drwclip%,
drhclip%)
@objc_find(ftree%,fstartob%,fdepth%,fmx%,fmy%)
@objc_offset(oftree%,ofobject%,*ofxoff%,*ofyoff%)
@objc_edit(edtree%,edobject%,edchar%,edidx%,edkind%,*ednewidx%)
@objc_change(ctree%,cobject%,cresvd%,cxclip%,cyclip%,cwclip%,
chclip%,cnewstate%,credraw%)
*****Dialog box manager
@rsrc_load(lpfname%)
@rsrc_free
@rsrc_gaddr(gtype%,gindex%,*gaddr%)
@rsrc_saddr(stype%,sindex%,saddr%)
@form_do(do_tree%,dostartob%)
@form_dial(diflag%,dilittx%,dilitty%,dilittw%,dilitth%,dix%,diy%,
diw%,dih%)
@form_center(ctree%,*cx%,*cy%,*cw%,*ch%)
@form_alert(adefbttn%,astring%)
@form_error(enum%)
*****AES drop down menu manager
@menu_bar(btree%,bshow%)
@menu_icheck(ctree%,citem%,ccheck%)
@menu_enable(etree%,eitem%,eenable%)
@menu_tnormal(ntree%,ntittle%,nnormal%)
@menu_text(ttree%,titem%,ttext%)
@menu_register(rapid%,rpstring%)
*****AES graphic library
@graf_rubberbox(rx%,ry%,rminwidth%,rminheight%,*rlastwidth%,
*rlastheight%)
@graf_dragbox(dwidth%,dheight%,dstartx%,dstarty%,dboundx%,dboundy%,
dboundw%,dboundh%,*dfinishx%,*dfinishy%)
@grav_movebox(mwidth%,mheight%,msourcex%,msourcey%,mdestx%,mdesty%)
@graf_growbox(gstx%,gsty%,gstwidth%,gstheight%,gfinx%,ginfy%,
gfinwidth%,gfinheight%)
@graf_shrinkbox(sfinx%,sfiny%,sfinwidth%,sfinheight%,sstx%,ssty%,
sstwidth%,sstheight%)
@graf_watchbox(wptree%,wobject%,winstate%,woutstate%)
@graf_slidebox(slptree%,slparent%,slobject%,slvh%)
@graf_mouse(monumber%,mofaddr%)
@graf_mkstate(*mkmx%,*mkmy%,*mkmstate%,*mkkstate%)