"Chip G." wrote: > > At 22:08 -0400 06/01/02, Ken Shmidheiser wrote: > >Nevertheless, there is something elegant to letting the toolbox do > >the math for you: > > > >dim as rect r > >setrect( r , 20, 50, 400, 300 ) > >window 1, "test window 1", @r > >offsetrect( r, 50, 50 ) > >window 2, "test window 2", @r > >offsetrect( r, 50, 50 ) > >window 3, "test window 3", @r > >insetrect( r, 50, 50 ) > >window 4, "test window 4", @r > >offsetrect( r, 50, 50 ) > >window 5, "test window 3", @r > > > >do > >handleevents > >until fn button > > Here is another example of why I'd like a shell. Without a shell all > I can do is study this example. With a shell I could drop this code > in an appropriate location and run it to see what it does. This is > mainly an issue with my being a novice with this language (although > I've studied BASIC before, it's been so long that it is effectively a > new language to me, especially with all the GUI elements). > I would recommend to use the project manager to build a reusable shell, otherwise you would end up building various little shells mainly for demo purpose, like those posted in the list. I personally have no shell to offer (I always build from scratch because the samples here are short), however I would amend Ken's work since I think that it is easier to remove things than to add them. First, I would include all the event types that the dialog handler can handle (it would be useful to add a few comments in white characters so that BB can't see them ;-)). Here is a more complete list: select case ( evnt ) '~window events case _wndClick case _wndClose case _wndRefresh case _wndActivate case _wndZoomin case _wndZoomOut case _wndResized '~System events case _evDiskInsert '~button events case _btnClick '~contextual menu events case _cntxtMenuClick '~edit fields events case _efClick case _efReturn case _efTab case _efShiftTab case _efClear case _efLeftArrow case _efRightArrow case _efUpArrow case _efDownArrow case _efSelected case _efClick case _pfClick '~keystroke events case _evKey '~cursor events case _cursOverBtn case _cursOverEF case _cursOverNothing, _cursEvent '~process events case _MFEvent case _FBQuitEvent '~preview events case _preview select id case _preMenuClick case _preWndGrow case _wndMoved case _wndSized case _efChanged case _preEfClick case _preWndZoomIn case _preWndZoomOut case _wndDocWillMove end select '~programmer events case _userDialog end select I would also build a raw event handler in a similar manner. A raw event handler lets you handle the event before the runtime deals with it. If you don't want the runtime to do its usual work once you have handled the event, just set the what field to 0. clear local fn doEvent dim evnt as ^EventRecord dim handled as boolean evnt = event select evnt.what case _keyDwnEvt case _nullevt case _mbutdwnevt case _mbutupevt case _keydwnevt select ( evnt.message and _charCodeMask ) end select case _keyupevt case _autokeyevt case _updatevt case _diskinsertevt case _activateevt case _osevt case _khighlevelevent case _highlevelevtbit end select if handled then evnt.what = 0 end fn the above handler needs more work in order to decipher the event. You will probably notice that the constants used by FB differ from the Apple constants. Don't ask me, I don't know why. If you are used to deciphering the events with other languages such as C or Pascal, it is the place where you can use the same techniques, I think. Frankly, it is better to let the runtime do the hard work for you, since the deciphering routines are built-in and will be included in your final application anyway. This handler is sometimes very useful on special occasions. I've been told that it is not a good idea to use the gFBQuit global variable. Again, I don't know precisely the reason for this, let's say it's a private global for the runtime. So, it is better to use your own flag to end the application. You should replace all gFBQuit with something like gAppMustQuit or anything you like (declared as a boolean global variable). I would also create a function for the initialization where I would set all the possible vectors clear local fn initialize dim err as OSErr /* set here the initial values for the global variables for example: gIsRunningOnX = ( system( _sysVers ) => 1000 ) if something may fail return an error */ on dialog fn doDialog on menu fn doMenu on event fn doEvent on mouse fn doMouse on edit fn doEdit on break fn doBreak on finderinfo fn doFinderInfo on overflows fn doOverFlow on stop fn doStop on timer(1) fn doTimer kill appleevent _kRequiredEventClass, _kAEOpenDocuments on appleevent ( _kRequiredEventClass, _kAEOpenDocuments ) fn doAEReadFile end fn = err It is likely that you won't need all of them, but there are all there in case and besides you can rem out or delete the unneeded statements. Of course you would have to create the empty functions. Don't forget to set the gAppMustQuit variable to _zTrue during development in your doBreak and doStop functions, so that you can exit gracefully in certain situations. You might wish to plug in draft functions that handle the opening of files specifically with the finderInfo and Appleevent vectors because they both use global runtime variables not always easy to remember: clear local fn doFinderInfo dim info as FInfo long if gFBFndrInfoCount gFBFndrInfoCount-- long if fn FSpGetFInfo( gFBInfoSpec( gFBFndrInfoCount ), info ) = _noErr select gFBInfoAction%( gFBFndrInfoCount ) case _finderInfoOpen : fn OpenFile( gFBInfoSpec( gFBFndrInfoCount ), info.fdType ) case _finderInfoPrint : fn PrintFile( gFBInfoSpec( gFBFndrInfoCount ), info.fdType ) end select end if end if end fn clear local fn doAEReadFile dim as int i dim as long @ count, actualSize, keyWord, type dim as AEDesc AE dim as FSSpec f dim as FInfo info long if fn AEGetParamDesc( gFBAEEvent, _keyDirectObject, _typeAEList, AE ) = _noErr long if fn AECountItems( AE, count ) = _noErr for i = 1 to count long if fn AEGetNthPtr( AE, i, _typeFSS, keyWord, type, @f, sizeof(FSSpec), actualSize ) = _noErr long if fn FSpGetFInfo( f, info ) = _noErr fn OpenFile( f, info.fdType ) end if end if next end if i = fn AEDisposeDesc( AE ) end if end fn I would also add a kind of template to remind me how I can deal with contextual menus (this is not what I would call straight forward). Here is a little example that can be added to Ken's shell. In that function I remap the user selection to an FB menu event so that the handling is done in the regular menu handler. To see this working, control click onto the text that reads "Click around to see things work", but before: 1 - Add the following line in your dialog handler: case _cntxtMenuClick : fn HandleContextualMenu 2 - Append the following line to your doMenu function (1000 is an arbitrary menuID) case 1000 : edit$(1) = "Contextual menu selected, item " + str$( itemID ) 3 - Plug the HandleContextualMenu function, near the top of the program: local fn HandleContextualMenu dim evnt as .EventRecord dim teH as ..TERec dim menuH as handle dim where as point dim @ selectionType as unsigned long dim choice as long;0,menuID as int, itemID as Int evnt = event where = evnt.where GlobalToLocal( where ) teH = tehandle( 3 ) long if teH long if fn PtInRect( where, teH..viewRect ) menuH = fn NewMenu( 1000, "" ) long if menuH InsertMenu( menuH, -1 ) AppendMenu( menuH, "item 1" ) AppendMenu( menuH, "item 2" ) AppendMenu( menuH, "item 3" ) LocalToGlobal( where ) long if fn ContextualMenuSelect( menuH, where, _nil, _kCMHelpItemNoHelp, "", #_nil, selectionType, menuID, itemID ) = _noErr long if selectionType evnt.where = choice evnt.what = _FBMenuEvent fn FBDoMacEvent( evnt ) end if end if DisposeMenu( menuH ) end if end if end if end fn I hope it won't confuse the matter. -- Cheers, Alain