The program starts innocuously enough with a call to the set_windows procedure, and then it just does a loop calling the test procedures according to your choice.
set_windows REPeat lp% choice=set_menu SELect ON choice =-1: EXIT lp% = 0: test1 = 1: test2 = 2: test3 = 3: test4 END SELect END REPeat lp% :The set_windows procedure, which you could use in every program using the ProWesS SBasic Interface, makes sure that the outline of the window is set if we are not in a "compiled" program:
: DEFine PROCedure set_windows LOCal not_compiled,upper%,xo%,yo%,xs%,ys%,ysize_0% not_compiled=IS_OPEN(#0) : REMark window#0 open? IF not_compiled xs%=0:ys%=0:xo%=0:yo%=0 PWscrsize#0,xs%,ys%,xo%,yo% upper%=28:ysize_0%=50 PWoutln#0,xs%,ys%-upper%,xo%,upper%+yo% WINDOW#0,xs%,ysize_0%,xo%,ys%-ysize_0% WINDOW#1,xs% DIV 2,ys%-upper%-ysize_0%,xo%+(xs% DIV 2),yo%+upper% WINDOW#2,xs% DIV 2,ys%-upper%-ysize_0%,xo%,yo%+upper% BORDER#1,1,255:BORDER#2,1,255 PAPER#1,2:PAPER#2,7 INK#1,7:INK#2,2 CLS#0:CLS#1:CLS#2 END IF END DEFine set_windows :As you can see, this checks whether window #0 is open. If it is, the outline of that is set. You will notice that this code will work in programs running under the interpreter (whether they have been EXEC'ed, or loaded and run) and under QLiberator.
Now we come to the first test procedure, which is a very simple program. It sets up a small window containing two items and two info objects. You can hit or do the items. Hitting or doing the second item has no result, whereas hitting or doing the first item changes the text in the two info objects, to show how often the item was hit:
: DEFine PROCedure test1 LOCal object, hit%,hits,dos,times$,mhit$,mdo$ LOCal loop%,add_info : : REMark first initialise some variables mhit$="You have hit the item ":times$=" times":hits=0 mem=0:object=0:hit%=0 mdo$="You have done the item ":dos=0 : : REMark now make some strings, note the CHR$(0) at the end! : my_hit$=mhit$& hits×$&CHR$(0) my_do$=mdo$&dos×$&CHR$(0) : REMark now create the outline object : outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_QUIT'), PW('OUTLINE_SLEEP')) : REMark now create the item objects : item1=PWcreate(outl,PW('TYPE_LOOSE_ITEM'), PW('LOOSE_TEXT_COPY'),"Hit or Do me", PW('LOOSE_ACTION_DO'),DO_ROUTINE, PW('LOOSE_ACTION_HIT'),HIT_ROUTINE) item2=PWcreate(outl,PW('TYPE_LOOSE_ITEM'), PW('LOOSE_TEXT_COPY'),"Hitting or Doing me will do nothing", PW('LOOSE_ACTION_DO'),DO_ROUTINE, PW('LOOSE_ACTION_HIT'),HIT_ROUTINE) : REMark now we create two infostring objects : info1=PWcreate(outl,PW('TYPE_INFOSTRING'), PW('INFOSTRING_TEXT'),my_hit$) info2=PWcreate(outl,PW('TYPE_INFOSTRING'), PW('INFOSTRING_TEXT'),my_do$) : REMark the main loop : REPeat loop% mem=PWactivate(outl,mem,object,add_info,hit%) IF NOT mem:EXIT loop% SELect ON object =item1 SELect ON hit% =0:hits=hits+1 my_hit$=mhit$&hits×$&CHR$(0) PWchange info1,PW('INFOSTRING_TEXT'),my_hit$ =1:dos=dos+1 my_do$=mdo$&dos×$&CHR$(0) PWchange info2,PW('INFOSTRING_TEXT'),my_do$ END SELect END SELect END REPeat loop% : PWremove outl END DEFine test :After having initialised some variables, we create the outline of the window. The window is supposed to have a quit item, and a sleep item.
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.
Once the outline is set up, we create two loose items with some text in them. Notice how the tag used to put the text in the items is a "_COPY" tag, so that we can give direct strings as parameters (see the strings part of this manual if this isn't clear). For item1 we also indicate routines to call when the item is "hit" (HIT_ROUTINE) or "done" (DO_ROUTINE). These don't exist for the other item, which is why hitting or doing it will have no effect.
After this, we set up two infostring items. They will contain the text which says how many times you have hit or done item1. For the first infostring, I have set AUTOSIZE to 0 (i.e. False - by default it is True, i.e. 1). As you can see, this makes a difference: when the text in the first item is changed (after a hit), the window is not redrawn, since AUTOSIZE is not set. If the text in the second item is changed, the window is redrawn. This is because the length of the text might have changed and it might have become much longer. This means that the text might no longer fit in the object. If it doesn't, then, IF AUTOSIZE IS TRUE, the object containing the string is made larger, and then, of course the window MUST also be made larger - and redrawn. This is why the window is also redrawn if AUTOSIZE is TRUE...
These few lines are enough to set up the window! Once this is done, we can actually have it do something, like drawing it on the screen. So, we come to the main loop of the program. All ProWesS programs will have such a loop (or something similar). We first call the PWactivate function which draws the window on the screen and waits for your actions. At the first call, mem is 0, which is as it should be. Later on, it is automatically maintained by the system. Of course, mem is also returned by the PWactivate call. The PWactivate call comes back whenever you actioned QUIT, or the first item. It won't come back for the second item, since we haven't given this item a hit or do routine.
When the PWactivate call comes back, we first check whether mem is 0 or not. If it is, we should quit the loop since mem will only be 0 if the User indicated that he wants to leave the window. In that case, we leave the loop, remove the object with PWremove (which also removes all the other objects owned by it i.e. all other objects!), and the procedure is finished.
If mem is not 0, we should check which object was hit. Here we know that this object was necessarily item1, so we actually don't really need to check this. On the other hand, we check whether the object item1 was hit or done. The parameter hit% to the PWactivate function will reflect that: a DO_ROUTINE will set this to 1, whereas a HIT_ROUTINE will set it to 0.
So, according to whether item1 was hit or done, we change the text in info1 or info2. The text is changed with the PWchange command, and the info object is automatically redrawn. For the object info2 this also automatically redraws the entire window, since AUTOSIZE was left on.
Now we can go on the the second test example. This will set up a an applic type but doesn't do anything useful...:
DEFine PROCedure test2 LOCal xmax,ymax,object_hit,hit% LOCal item1,canvas LOCal text$(2,20) LOCal lp% : REMark note how I use a Local string variable here, the REMark window will be gone when we leave this procedure! : xmax=10:ymax=10 text$(1)="Sleep item text"&CHR$(0) : REMark note the chr$(0) mem=0:hit%=0:object_hit=0 : outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_SLEEP_TEXT'),text$(1), PW('OUTLINE_QUIT'),PW('OUTLINE_QUIT_KEYPRESS'),27) REMark use chr$(27) = ESC as keypress for the quit item : item1=PWcreate(outl,PW('TYPE_LOOSE_ITEM'), PW('LOOSE_TEXT_COPY'),"Direct string", PW('LOOSE_ACTION_DO'),DO_ROUTINE, PW('LOOSE_ACTION_HIT'),HIT_ROUTINE) : canvas=PWcreate(outl,PW('TYPE_APPLIC'), PW('APPLIC_CANVAS_LIST'), PW('CANVAS_SIZE_PIX'),100,40, PW('CANVAS_ACTION_REDRAW'),HIT_ROUTINE, 0, PW('APPLIC_SCROLLBAR_Y'), PW('APPLIC_YSCROLL_LIST'), PW('SCROLL_MINDIST'),20, PW('SCROLL_MAXDIST'),-20, PW('SCROLL_MAXIMUM'),ymax, 0, PW('APPLIC_SCROLLBAR_X'), PW('APPLIC_XSCROLL_LIST'), PW('SCROLL_MINDIST'),20, PW('SCROLL_MAXDIST'),-20, PW('SCROLL_MAXIMUM')xmax, 0) : REMark now the loop which doesn't do anything other than REMark draw the window and wait for you to hit quit : REPeat lp% mem=PWactivate(outl,mem,object_hit,object_hit,hit%) IF NOT mem:EXIT lp% END REPeat lp% : PWremove outl : REMark this also removes all the objects END DEFine test2 :This again sets up an outline with sleep and quit items, but the sleep item this time has a text associated with it. This text is displayed in the button when the program is put to sleep as a button.
The quit item can now be actioned by the 'ESC' keypress - pressing ESC is the same as indicating the quit item.
Then we come to the long applic type definition. This has a lot of parameters, but they are not difficult to understand. Please note that, here again, 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.
The interesting thing to note here are the "_LIST" tags. They are nothing else than tags with lots and lots of parameters (which are also tags) - as you can see. They actually show that what follows is a list of tags, which must always be terminated with a '0'. This is why there are three different 0s - they terminate the three different lists.
The normal PWactivate loop doesn't do anything else than wait for you to quit the program. Since we don't care about the object_hit, I also use this variable for the add_info parameter.
The third test goes a bit further and shows you an aspect of the dynamic creation possibilities of ProWesS: it displays a menu with an edline. You can edit the text in the edline. When you indicate the DO item in the window, it will add a new loose item to the window. The text of this new item is set to the text contained in the edline:
: DEFine PROCedure test3 LOCal my_array$(1,51),hit% LOCal object_hit,quit_object LOCal lp%,add_info : mem=0:hit%=0:object_hit=0 outl=0:item1=0:CLS my_array$(1)="Type text here"&CHR$(0) : REMark now create the outline outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_SLEEP'), PW('OUTLINE_QUIT'),PW('OUTLINE_QUIT_KEYPRESS'),27, PW('OUTLINE_ACTION_DO'),HIT_ROUTINE) : REMark make the edline object edline_object=PWcreate(outl,PW('TYPE_EDLINE'), PW('EDLINE_SET'),my_array$(1), PW('EDLINE_MAXLENGTH'),50, PW('EDLINE_ACTION_AFTER'),HIT_ROUTINE) : do_object=PWquery(outl,PW('OUTLINE_OBJECT_DO') ) : REPeat lp% mem=PWactivate(outl,mem,object_hit,add_info,hit%) IF NOT mem:EXIT lp% SELect ON object_hit =do_object new_item=PWcreate(outl,PW('TYPE_LOOSE_ITEM'), PW('LOOSE_TEXT'),my_array$(1), PW('POSITION_BELOW'),edline_object) =edline_object PWchange edline_object,PW('EDLINE_GET'),50,my_array$(1) a%=CHR$(0) INSTR my_array$(1) IF a%:my_array$(1)=my_array$(1,1 TO a%) END SELect END REPeat lp% END DEFine test3 :Here again, we set up an outline with Quit and Sleep items. We also create a DO item at the same time. This is a kind of implicit object which the outline can create for you, just like the quit and the sleep items.Then we set up an edline object. This allows us to edit a string when indicated.
After that, we query the outline to get the DO object, so that we can later SELect on it and know that the DO object was indicated. The DO object's routine (HIT_ROUTINE) will be called whenever you DO within the window, other than on an item, of course.
Having thus set up the window, we activate it within the now familiar loop. The edline object, as usual, allows us to change the text by editing it. Whenever you DO the window, you create a new loose item. Please note that this does not necessarily mean that you have to put the pointer over the DO item: for example, bring the pointer over the title (which should be SBasic). Hit ENTER or the right mouse buton (i.e. you generate a DO event). A new item is created! So a DO item will catch a DO event whenever the pointer is in the window. However, it doesn't get the DO event if the pointer is over another item - you can now test this...
As you can see, the new items are POSITIONed_BELOW the edline, and each new item thus pushes down the earlier ones, since for each one we indicate that it is to be positioned below the edline.
This example was included mainly to draw your attention to two quirks of ProWesS. First of all, you will have noticed that the new item is created as soon as you have hit ENTER to show that you have finished the edited text. This is due to the fact that the ENTER is, of course, also a DO, so ProWesS thinks that you "did" the window, even though you were in the edline! You should be aware of this. There is a way of getting around that: (i) only inidcate the edline with a HIT, not ENTER - you thus don't egnerate a DO when going into the edline, (ii) quit the edline by hitting CTRL J, which is ENTER, but not a DO. Thus you have not generated any DO for the DO object to catch...
Second, you will notice that all of the items get the same text, which
corresponds to the one last edited. This is due to the fact that, when
setting up the loose items, we have used
...PW('LOOSE_TEXT'),my_array$(1)...
So all of the items have the
same text, and, since the window is redrawn when a new loose item object is
added, they are drawn with the same text. You can get around this either by
using a different variable for each item, or by using
PW('LOOSE_TEXT_COPY')
instead of PW('LOOSE_TEXT')
.
Test 4
The fourth and last test is supposed to show you how to use a menu object:
: DEFine PROCedure test4 LOCal xmax,ymax,object_hit,hit% LOCal item1,canvas,lp% LOCal text$(2,20) : text$(0)="Item 1 "&CHR$(0) text$(1)="Item 2 "&CHR$(0) : REMark note the chr$(0) mem=0:hit%=0:object_hit=0 : outl=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_SLEEP_TEXT'),text$(1), PW('OUTLINE_QUIT'),PW('OUTLINE_QUIT_KEYPRESS'),27) REMark use chr$(2) = ESC as keypress for the quit item : item1=PWcreate(outl,PW('TYPE_MENU'), PW('MENU_ADD_ARRAY'), DIMN(text$,1)+1, DIMN(text$,2)+2, text$) : REMark now the loop which doesn't do anything other REMark than draw the window and wait for you to hit quit : REPeat lp% mem=PWactivate(outl,mem,object_hit,object_hit,hit%) IF NOT mem:EXIT lp% END REPeat lp% : PWremove outl : END DEFine test4 :As you can see, this sets up an outline, as usual, and a menu object. The menu object is set up by "adding" an array to it. Please note how the array is passed: first the two dimensions, then the array itself. For the second dimension (which corresponds to the maximum length of the elements), you ALWAYS must add 2 (which corresponds to the length word) or 3 if the maximum length of each array element is an uneven number!
Concerning the first dimension, you should add one: Never forget that
arrays start a element 0. Here, there are three elements in the array (DIM
array$(2,20)) but since I've only filled in the first two, there is an
empty menu slot at the end.
The Menu
So finally, we come to the menu that shows the different examples:
: DEFine FuNction set_menu REMark print the menu on the screen LOCal hit%,object,text$(2,40) LOCal loop%,robject,add_info DIM menu$(3,50) text$(1)='Sleeping beauty'&CHR$(0) text$(2)='ProWesS SBasic tests' menu$(0)="Simple test"&CHR$(0) menu$(1)="Canvas test"&CHR$(0) menu$(2)="Edline/item add test"&CHR$(0) menu$(3)="Menu test"&CHR$(0) object=0:hit%=0 mempointer=0 outline=PWcreate(0,PW('TYPE_OUTLINE'), PW('OUTLINE_SLEEP'), PW('OUTLINE_SLEEP_TEXT'),text$(1), PW('OUTLINE_TITLE_TEXT'),text$(2), PW('OUTLINE_QUIT'), PW('OUTLINE_QUIT_KEYPRESS'),27 ) menu_object=PWcreate(outline,PW('TYPE_MENU'), PW('MENU_ADD_ARRAY'), 4,DIMN(menu$,2)+2, menu$, PW('MENU_ACTION_SELECT'),HIT_ROUTINE) robject=-1 REPeat loop% mempointer=PWactivate(outline,mempointer,object,add_info,hit%) IF NOT mempointer:EXIT loop% SELect ON object =menu_object robject=PWquery(menu_object,PW('MENU_SELECTED_FIRST') ) robject=find_text(robject) PWbreak outline END SELect END REPeat loop% PWremove outline RETurn robject END DEFine set_menu : deFine FuNction find_text (address) LOCal string$,n string$=MKSTRING$(address)&CHR$(0) FOR n=0 TO 4:IF string$==menu$(n):RETurn n RETurn -1 END DEFine find_text :This should now be quite understandable: we set up an outline and a menu object. When the menu object is hit, we look to see which is the first item in the menu object to be selected, which is the item that was hit. We then break down the window (this is explained a bit more in the second example program), remove the window after coming back with mempointer=0 from the loop, and return with the value of the item hit.
This value is found in the function find_text: When you query the menu
object what the first item to be hit was with the
PW('MENU_SELECTED_FIRST')
tag, it does not return a number
telling you "this is it", but returns an address where you can find the
string corresponding to the item hit. In find_text we first convert the
address to a string with MKSTRING$ and then look for the string in the
array menu$.
It would also have been possible to use the
PW('MENU_SELECTED_FIRST_NUMBER')
tag. This does return the number
of the first element selected, starting from 0.