This is a fully functioning application, the purpose of which is to display the configuration lines in your ProWesS config file, and to change a setting immediately.
It contains an edline object which lets you edit the name of the ProWesS config file: Either you HIT the Edline object, in which case you can edit the name directly, or you DO the Edline object, in which case it pops up a file select window and lets you select your config file.
Once the file name is given, the file is opened, a (cursory) check is made on whether it is a ProWesS config file, and then the content of the file, i.e. the config lines, are displayed. You can now click on a line, this is then proposed for editing, and the change is made.
The program first calls the set_windows procedure, to make sure that the outline is set if we are in the SBasic interpreter and to initialise the ysize% variable, which contains the y size of the screen. Then procedure test is called.
set_windows:test : DEFine PROCedure test LOCal object_hit,hit%,lp%,none_yet$ LOCal text$(2,20),file_name$(50),option_chosen LOCAL config_options$(120,80),my_option$(81) LOCal number_of_elements%,watermark$,box_left,loose_item LOCal fname_edline,infotext,sep_obj,menu_object,fs,add_info : rem note how I use a Local string variables here, since rem the window will be gone when we leave this procedure! : rem first initialise some variables : watermark$="% configuration file for ProWesS" option_chosen=0 mem=0:hit%=0:object_hit=0 text$(1)="ProWesS Config"&CHR$(0) : rem the title, and button text text$(2)="Config file: "&CHR$(0) : rem label text none_yet$="Here, first of all, we create an outline, which contains a sleep item and a quit item. The quit item is also actioned by the ESC keypress (remember, ESC=CHR$(27)). The outline has a text in the title, which is nicer than just the name of the program (since that will always be 'SBasic' in the interpreter)."&CHR$(0) file_name$=none_yet$ : REMark name of the config file : rem now create all of the objects needed at first : outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_SLEEP'),PW('OUTLINE_SLEEP_TEXT'),text$(1), PW('OUTLINE_QUIT'),PW('OUTLINE_QUIT_KEYPRESS'),27, PW('OUTLINE_TITLE_TEXT'),text$(1)) : rem use chr$(27) = ESC as keypress for the quit item : ylines=PWquery(outl,PW('DEFAULT_FONTSIZE')) ylines=INT(ylines/65536)+6 ylines=INT((ysize%-80)/ylines) : infotext=PWcreate(outl,PW('TYPE_LABEL'),PW('LABEL_TEXT'),text$(2)) : fname_edline=PWcreate(outl,PW('TYPE_EDLINE'), PW('EDLINE_MAXLENGTH'),50, PW('EDLINE_SET'),file_name$, PW('EDLINE_ACTION_AFTER'),HIT_ROUTINE, PW('EDLINE_KEYPRESS'),CODE('c'), PW('EDLINE_ACTION_DO'),DO_ROUTINE) : sep_obj=PWcreate(outl,PW('TYPE_SEPARATOR')) : menu_object=PWcreate(outl,PW('TYPE_MENU'), PW('MENU_ITEMWIDTH_PIX'),480, PW('MENU_VISIBLE_LINES'),ylines, PW('MENU_ACTION_SELECT'),DO_ROUTINE, PW('MENU_UNIQUE')) : fs= PWcreate(outl,PW('TYPE_FILESELECT')) : box_left=PWquery(outl,PW('OUTLINE_BOX_LEFT') ) loose_item=PWcreate(box_left,PW('TYPE_LOOSE_ITEM'), PW('LOOSE_TEXT_COPY'),"Save", PW('LOOSE_ACTION_HIT'),HIT_ROUTINE, PW('LOOSE_KEYPRESS'),CODE('s')) : rem now the main loop : REPeat lp% mem=PWactivate(outl,mem,object_hit,add_info,hit%) IF NOT mem:EXIT lp% : rem prog is finished SELect ON object_hit : rem let's see what was hit =fname_edline : rem object hit= filename editor SELect ON hit% : rem HIT or DO? =0 file_name$=get_from_edline$ (fname_edline,0) =1 file_name$=select_file$ PWchange fname_edline,PW('EDLINE_SET'),file_name$ END SELect load_the_file =menu_object : rem object hit was menu get_choice : rem get the string to configure IF LEN(my_option$)>1 popup_window : rem popup win with this string set_option : rem do the configuration END IF PWchange menu_object,PW('MENU_STATUS_CURRENT'), PW('STATUS_AVAILABLE') =loose_item save_the_file END SELect END REPeat lp% : PWremove outl : rem this also removes all objects owned by this one END DEFine test : rem -----------------------------------------------------------------
Please note that, for the sake of clarity, I have split up the parameters for the function over several lines. Unless you have the Basic Linker, you cannot do that, and should always have the parameters for the function on the same line.
We then create a label and an edline object. The edline object will contain the name of the file to edit. We set the maximum length of this object to 50 character, since a filename cannot be longer than that anyway, and set the text in the object to file_name$, which, for the time being, is still "no file yet".
After this, we set the ACTION_AFTER
to HIT_ROUTINE, and the
ACTION_DO
to DO_ROUTINE. This is quite important, since it
will allow us to distinguish between a hit and a do on the object. If the
object is hit, then you can edit the name, and after you finished editing
the name, HIT_ROUTINE will be called, which then returns to SBasic, showing
that the object was "hit". If you "DO" the object, you cannot edit the
name, since DO_ROUTINE will be called instead. This also returns to SBasic,
showing that the object was "done".
We then create a separator (a nice line) and a menu object. The width
(440 pixels) and the heigth of the menu object are also set. The heigth has
been calculated by dividing the screen y size by the fontsize of the
default font. This is an attempt to make sure that the window always fits
the screen whilst displaying a maximum amount of information for those
having a larger screen. The size of the default font is obtained with the
DEFAULT_FONTSIZE
query tag which returns a number that must be
divided by 65536 to obtain the fontsize. The menu object is not (yet)
filled in, so it is just empty. Notice the MENU_UNIQUE
tag.
After this, we create a fileselect object which we will need later. and, last but not least, we set up the loose item with which to save the file. We put this in the empty box to the left of the title, so we first of all get the object which is the container to the left of the title, with the PWquery. Then we put the loose item into that container by making the container the owner of the loose item.
The keypress for the item will be 's', so we use CODE('s')
as keypress parameter.
Then we set up the main loop of the program. Notice how mem was set to 0 first. As usual, the main loop activates the object. This will await all of your actions and return with mem set to 0 if you quit the program (or break the window down with PWbreak), else mem will be <>0. If you quit the program, we leave the loop, remove the object, and the program just stops.
Else, we determine what object was hit or done, with the SELect. If the object actioned was the filename edline object, we further determine whether it has been hit or done. If it has been hit then the filename was edited first, so we just get this filename from the object. If this object was "done", then we call the select_file$ function, which opens the fileselect window. We will come to that in a moment. After that, we call the load_the_file procedure, which does as its name suggests...
You will also note that most variables are LOCal variables, apart from outl and mem, of course. These variables are all visible in all other procedures/functions called by the test procedure but will not interfere with any variables used in function that might call test - useful if you would want to incorporate this into one of your programs... (How's this for scope of variables? Eat your heart out, 'C'!).
Now we can examine the procedures or functions called:
rem ------------------------------------------------------------------- rem the following 2 functions get the filename, they are called rem by a hit or a do on the edline object rem ------------------------------------------------------------------- : DEFine FuNction get_from_edline$ (object,strip_chr0%) rem this gets the text from the edline object and returns it rem if strip_chr0% is set, the CHR$(0) at the end of the string is rem stripped off rem the max length of the string is 80 characters LOCal my_string$(81) PWchange object,PW('EDLINE_GET'),80,my_string$ : rem get str frm edline IF strip_chr0% MKLEN my_string$ : rem set new length w/o chr$(0) ELSE MKLEN0 my_string$ : rem set new length keep chr$(0) END IF RETurn my_string$ : rem and return the string END DEFine get_from_edline$ : DEFine FuNction select_file$ rem this activates the fileselect object and rem gets the string (composed of dirname + filename) from rem the fileselect object LOCal f_name$ PWchange fs,PW('FILESELECT_ACTIVATE') : rem activate fileselect window f_name$=PWquery(fs,PW('FILESELECT_DIRECTORY')) f_name$=f_name$&PWquery(fs,PW('FILESELECT_FILENAME')) return f_name$&chr$(0) END DEFine select_file$ :The get_from_edline$ function gets the text from the edline object, using the PWchange command. For various reasons one doesn't use the PWquery function for this, which would have been more logical. Notice how I use a local one-dimensional array set to the maximum length of a filename to get this string. Once I have got the string, I make it the correct length for SBasic, either stripping off the CHR$(0) at the end or not, depending on the strip_chr$% parameter to the function. The string is then returned to the caller. This function is used directly from the main loop if the edline object was hit, since in that case the string had been edited in that object first.
The select_file$ function is called from the main loop when the edline object was "done". First of all, it activates the fileselect object which is set up in the procedure test. This activation is achieved, curiously enough, with a PWchange, and not an PWactivate as one would expect... The fileselect object is displayed, and will come back if you select a file (with DO) or quit. Then we query the fileselect object about the directory of the file, and the filename (which does not contain the name of the directory).
When you query a fileselect object for the directory and the filename, it returns a string directly, which is one of the few exceptions to the PWquery function which normally returns a value.
Please note that, if we had set up the fileselect object in such a way that it allows multiple filenames to be selected, the object returned (for the filenames) would have be a menu object (i.e. a value), not a string. One can then query the menu object for the files.
rem -------------------------------------------------------------- rem the following procedure displays a small 'please wait' window & opens rem the file, reads in the options and changes the menu object rem ------------------------------------------------------------------- : DEFine PROCedure load_the_file REMark this displays the 'please wait' window REMark and loads the file LOCal lp%,a%,a$,f$,wait$,loop%,dummy,dummy% LOCal lf_info LOCal lf_out,lf_mem : wait$="Reading file - please wait"&CHR$(0) lf_mem=0:dummy=0:dummy%=0:number_of_elements%=0 : REMark now create the objects : lf_outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('SYSTEM_ACTION_INIT'),INIT_ROUTINE) : lf_info=PWcreate(lf_outl,PW('TYPE_INFOSTRING'), PW('INFOSTRING_TEXT'),wait$) : REMark now the main 'loop' REPeat loop% lf_mem=PWactivate(lf_outl,lf_mem,dummy,dummy,dummy%) IF NOT lf_mem:EXIT loop% : REMark quits after PWbreak f$=file_name$(1 TO LEN(file_name$)-1) : REMark strip off chr$(0) a%=FOP_IN(f$) : REMark open file IF a%<0 err_window a%,"" PWbreak lf_outl NEXT loop% endif INPUT#a%,a$ IF a$<>watermark$ CLOSE#a% : REMark make a small check err_window 0,'This is not a ProWesS config file' PWbreak lf_outl : REMark oops... NEXT loop% END IF REPeat lp% IF EOF(#a%):EXIT lp% INPUT#a%;a$ config_options$(number_of_elements%)=a$&CHR$(0) number_of_elements%=number_of_elements%+ 1 END REPeat lp% CLOSE#a% PWbreak lf_outl PWchange menu_object,PW('MENU_CLEAR') : REM get rid of old items PWchange menu_object,PW('MENU_ADD_ARRAY'), number_of_elements%, DIMN(config_options$,2)+2, config_options$ END REPeat loop% PWremove lf_outl END DEFine load_the_file : REMark -------------------------------------------------------------------We now come to the procedure load_the_file. here, I want to display a small window that says 'reading file, please wait', and then reads in the configuration lines of the file, makes the menu, closes the small window and returns to the main loop.
I won't comment on the part that concerns the actual loading of the file, and putting the lines of the file into an array, except to say that this routine expects the line "% configuration file for ProWesS" to be the very first line in the file, else it doesn't believe that this is a ProWesS configuration file. Then, and also if there if a file error, it calls the err_window procedure, which we will comment later.
The load_the_file procedure is interesting since it uses the
SYSTEM_ACTION_INIT
tag. This is a tag which is followed by a
routine, in our case INIT_ROUTINE (we could actually have used any other of
the xxxx_ROUTINEs in this example). This routine is called as soon as the
window is drawn by the Pwactivate keyword. In our case, INIT_ROUTINE is
called which does a (fake...) exit to SBasic. So, as soon as the window is
drawn, control is passed back to SBasic, which is just what we want, since
we don't want to wait for the user to hit a key, we only want to display
the window whilst working.
This function doesn't need the normal object, add_info and hit_or_do% parameters in the PWactivate call since we don't care about the object returned etc.. So we just use some dummy variables instead.
This way, we come back after the PWactivate call, and then read the file etc... Once this is finished, we use the PWbreak command. This tells the system to remove the window from the screen at the next PWactivate call, and come back to SBasic with lf_mem set to 0, as if the user had pressed "quit".
Then we set the content of the menu, after having cleared it to make sure
that nothing remains of a possible earlier file. The MENU_ADD_ARRAY
tag needs three parameters: the size of the array (number of
elements and maximum length of an element), and the array itself. I use
number_of_elements% to set the number of elements. I could have used
DIMN(config_options$,1)+1
since that gives the number of
elements in the array, but it will cause the menu object to display several
empty lines at the end, since the config_options$ array is probably not
filled in entirely.
After this, we come to the end of the loop, i.e. we go back to the beginning, into PWactivate and then come back from this immediately since we had used PWbreak. We then leave the loop, and the procedure. The menu object is automatically redrawn, and shows the configuration options.
You will notice that I have made the outline and the memory pointer (lf_outl and lf_mem) into LOCal variables. I ONLY DID THAT ONCE I HAD THOROUGHLY DEBUGGED THIS PART OF THE PROGRAM. Always remember to let the variables for the outline and the memory pointer accessible.
Now the configuration options are displayed, and you can hit one of them.
The PWactiavte call in the procedure test will then come back, showing that
the object hit was menu_object. This then calls, one after the other, the
procedures get_choice, popup_window and set_option. The latter two are only
called when the option chosen was not an empty line - see the line IF
len(my_option$)>1
rem ------------------------------------------------------------------- rem the following procedure gets the choice hit in the menu rem ------------------------------------------------------------------- : DEFine PROCedure get_choice rem get the choice hit in the menu LOCal address, a% option_chosen=0 address=PWquery(menu_object,PW('MENU_SELECTED_FIRST')) IF NOT address:RETurn : rem oops! my_option$=MKSTRING$(address)&CHR$(0) : rem get the string option_chosen=arrsrch(config_options$,my_option$,0,0) END DEFine get_choice : rem -------------------------------------------------------------------
This first asks the menu object what is the first item selected in the
menu. This must always be the item just selected, since I have made sure
that only one item can be selected at a time (the MENU_UNIQUE
tag when creating it). With this tag, the menu object does not return a
number, but a pointer to an address where the string concerning this option
lies. We use MKSTRING$ to make this address into the string my_option$ and
we also find this string in the array using the arrsrch function (which I
won't explain here, it should be obvious) so that we know which element in
the array we are talking about.
rem ------------------------------------------------------------------- rem the following proc pops up the window where the string can be edited rem ------------------------------------------------------------------- : DEFine PROCedure popup_window rem this pops up the window in which the string can be edited LOCal dummy,dummy%,lp%,string$ local cfg_edline local pop_outl,pop_mem : string$='Please edit this string...'&CHR$(0) pop_mem= 0 : pop_outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_TITLE_TEXT'),string$ ) : cfg_edline=PWcreate(pop_outl,PW('TYPE_DIRECT_EDLINE'), PW('EDLINE_MAXLENGTH'),80, PW('EDLINE_SET'),my_option$, PW('EDLINE_ACTION_AFTER'),HIT_ROUTINE) : rem now the main 'loop' : REPeat lp% pop_mem=PWactivate(pop_outl,pop_mem,dummy,dummy,dummy%) IF pop_mem=0:EXIT lp% my_option$=get_from_edline$(cfg_edline,0) PWbreak pop_outl : rem show we don't want the window anymore END REPeat lp% PWremove pop_outl : rem get rid of this window END DEFine popup_window : rem -------------------------------------------------------------------Now we have chosen our option to configure, we pop up (or pull down) a small window which contains an edline where you can configure the option. string. Once this is done, we come back to SBasic because of the
EDLINE_ACTION_AFTER
tag and get the string from the edline via
the get_from_edline$ function. We then break down the window and leave
after removing this object.
It now only remains to set the option:
rem ------------------------------------------------------------------- rem the following procedure sets the configuration choice rem ------------------------------------------------------------------- : DEFine PROCedure set_option rem this does the actual configuration with PWconfig LOCal string$,p$ p$="prowess" string$=my_option$ : rem this is necessary, pwconfig changes the string! PWconfig p$,string$ config_options$(option_chosen)=my_option$ END DEFine set_option :
This uses PWconfig to set the option. Notice how I copy this to a local variable first, since ProWesS changes the string passed to it via the configuration thing. I then update the string in my array, and reset the status of the item hit to available.
If there is an error loading the file, we call the procedure err_window:
: REMark ---------------------------------------------------------------- REMark the following procedure pops up an error window REMark ---------------------------------------------------------------- : DEFine PROCedure err_window (error%,error_string$) REMark this makes the error string if that isn't set, REMark and sets it in the infostring item LOCal dummy,dummy%,lp%,string$(1,40) LOCal err_outl,err_mem : string$(0)='Attention, error:'&CHR$(0) IF error% string$(1)=ERRSTR$(error%) : REMark make error string ELSE string$(1)=error_string$&CHR$(0) END IF pop_mem= 0 : err_outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_TITLE_TEXT'),string$, PW('OUTLINE_QUIT'),PW('OUTLINE_QUIT_KEYPRESS'),27) : info1=PWcreate(err_outl, PW('TYPE_INFOSTRING'), PW('INFOSTRING_TEXT'),file_name$) info1=PWcreate(err_outl, PW('TYPE_INFOSTRING'), PW('INFOSTRING_TEXT'),string$(1)) : REMark now the main 'loop' : REPeat lp% err_mem=PWactivate(err_outl,err_mem,dummy,dummy%) IF err_mem=0:EXIT lp% END REPeat lp% PWremove err_outl : REMark get rid of this window END DEFine err_window : REMark ------------------- :As you can see, this is nothing special, we make the window on the fly and draw it with PWactivate. Since the only thing the user can do is hit QUIT, there is no need for a SELect within the loop. The error message, if it is a file error, is made with the ERRSTR$ function.
There is also the procedure save_the_file which is modelled on the procedure load_the_file, so there is no need to print it here in full again.
Finally, there is also the source code for the ProWesS Config program. This is closely modeled on this example, but with enough differences to make it interesting to look at!