Let us start with the easiest ProWesS program you can imagine. All this does is create a window with one item in it, which says "Hello World". The item can be indicated (the status will change), but this will do nothing.
#include <ProWesS.h> void init() { PWObject first; PWCreate(NULL,&first,PW_TYPE_LOOSE_ITEM, PW_LOOSE_TEXT, "Hello World", NULL); PWActivate(first); }
Obviously, the first line includes the definition of all the prototypes and the tags of the standard types. The program just creates a loose item, with "Hello World" as text. The system thus created is then activated.
The program given above is as simple as you can get. Unfortunately it is a bit too limited. It would be useful to be able to terminate the program gracefully. Also it would be nice to be able to put the program to sleep, and a title bar wouldn't go astray. Therefore, some little changes.
#include <ProWesS.h> void init() { PWObject outl; PWCreate(NULL,&outl,PW_TYPE_OUTLINE, PW_OUTLINE_QUIT, PW_OUTLINE_SLEEP, NULL); PWCreate(outl,NULL,PW_TYPE_LOOSE_ITEM, PW_LOOSE_TEXT, "Hello World", NULL); PWActivate(outl); }
All the things we want to add (and more) are provided by the outline type of object. Therefore, it is also sufficient to create an outline object in the window. The outline always contains a title bar with the program name (by default). We have specified that it should also contain a quit and a sleep item.
The outline is designed such that all other objects in the window should preferably be children of the outline. Therefore the outline has to be created first, and the contents are created later.
This example program contains a scrollable application window which can display something (a piece of big text in this case).
#include <sms.h> #include <win.h> #include <ProWesS.h> void init() { PWObject outl; LinkPROforma(); /* get a DLL link to PROforma */ PWCreate(NULL, &outl, PW_TYPE_OUTLINE, PW_OUTLINE_SLEEP_TEXT, "PROforma applic test", PW_OUTLINE_QUIT, NULL); PWCreate(outl, NULL, PW_TYPE_APPLIC, PW_APPLIC_CANVAS_LIST, PW_CANVAS_SIZE_PIX, 100,40, PW_CANVAS_ACTION_REDRAW, &redraw, PW_CANVAS_POINTER, SPRITE_HAND, NULL, PW_APPLIC_SCROLLBAR_Y, PW_APPLIC_YSCROLL_LIST, PW_SCROLL_MINDIST, short2pt(20), PW_SCROLL_MAXDIST, -short2pt(20), PW_SCROLL_MAXIMUM, YMAX, NULL, PW_APPLIC_SCROLLBAR_X, PW_APPLIC_XSCROLL_LIST, PW_SCROLL_MINDIST, short2pt(20), PW_SCROLL_MAXDIST, -short2pt(20), PW_SCROLL_MAXIMUM, XMAX, NULL, NULL); PWActivate(outl); }
The first call to PWCreate will create and "outline" object, which is the title bar for the application. The title defaults to the job name, so we don't have to worry about that. We then make sure the application can be put to sleep, and give the text which should be displayed when the program is sleeping (the PW_OUTLINE_SLEEP_TEXT tag with one parameter, the text). The PW_OUTLINE_QUIT tag makes sure that there is also a quit item. The NULL terminates the list of tags. If we wanted a confirmation request when quitting the program, we could have included the PW_OUTLINE_QUIT_CONFIRM tag which needs a boolean parameter.
Then the application window is created. An application window is in fact a composite object, built from a canvas (which displays the info) and scrollbars. Therefore the window is instructed that is should contain a scrollbar in each direction, and lists of tags are passed on to the underlying objects. These lists specify the size of the canvas (in pixels in this case), how to draw the window, and the pointer which should be used inside the window. The scrollbars are passed the distances for scrolling (MINDIST for a HIT, MAXDIST for a DO on the scroll arrow, the negative value indicates canvas "size+distance"). Then the maximum value for the scroll is passed (the minimum defaults to zero).
All that remains to be done is write the routine to draw the canvas.
#define FONT "English 157" #define STRING FONT #define SIZE short2pt(100) #define XMAX short2pt(500) #define YMAX SIZE*2 Error redraw(PWObject object, CanvasInfo *rinfo) { int i,j,siz; Gstate gid=rinfo->gstate; /* set colour for drawing and clear "window" */ PFPaperColourRGB(gid,pt_hundred,pt_hundred,pt_hundred); PFColourRGB(gid,0,0,0); PFClearPage(gid); /* clear background */ /* adjust page origin to reflect position in applic */ PFSetPageOrigin(gid,rinfo->xorg,rinfo->yorg); /* draw the contents (just some text) */ PFLoadFont(gid,FONT); PFScaleFont(gid,SIZE); PFMoveTo(gid,short2pt(10),SIZE); PFShowString(gid,STRING); }
This is a relatively straightforward piece of code which just prints the name of a font (using the same font). The page origin is set to reflect that the window may have been scrolled. The gstate is automatically set to the area of the canvas with (0,0) as coordinate at the top left in the canvas.
This is a program example program which demonstrates the support for dynamic windows and for reentrant code. The user can edit a line, and when he/she confirms it (presses <enter>), an item is added in the window displaying that line of text.
#include <mem.h> #include <ProWesS.h> #define MAXLEN 50 void init() { PWObject obj,it1; PWCreate(NULL,&obj,PW_TYPE_OUTLINE, PW_OUTLINE_SLEEP, PW_OUTLINE_QUIT, PW_OUTLINE_ACTION_DO, &newitem, NULL); PWCreate(obj,&it1,PW_TYPE_EDLINE, PW_EDLINE_SET, "type text here", PW_EDLINE_MAXLENGTH, MAXLEN, NULL); PWChange(obj,PW_GLOBAL_AUXILIARY,it1,NULL); PWActivate(obj); }
Again we start by creating an outline which contains a sleep and quit item (the sleep button will now contain the job name as text). It will also contain a "do" item. When "do" is indicated or a DO is generated somewhere in the window the "newitem" event handler will be called.
Also the item to edit a line of text is added. The text inside the item is set, and the maximum length of the text is also set (this is an example of a creation tag).
To make sure that no global variables are needed, the data which is needed by the event handler routine is put in a global auxiliary variable. In ProWesS each object and the window (global) have an int/long sized global variable. This can be used to store e.g. pointers to global data structures.
Error newitem(PWObject object) { PWObject edline; char str[MAXLEN]; PWQuery(object,PW_GLOBAL_AUXILIARY,&edline); PWChange(edline,PW_EDLINE_GET,MAXLEN,str,NULL); return PWCreate(edline,NULL,PW_TYPE_LOOSE_ITEM, PW_LOOSE_TEXT_COPY, str, PW_POSITION_BELOW, edline, NULL); }
To start, we need to get the object id of the edline object, so we can get the string from it. Then the string is copied into a local string. Because we have to pass the buffer size, PWQuery can't be used, so it is handled by PWChange. The actual work is done in the call to PWCreate. A new item with the text from the edline is created. The text is set with PW_LOOSE_TEXT_COPY. Normally, just the pointer to the text is used by a loose item, but because the text is now stored in local memory which will be released at the end of the function, the string has to be copied by the loose item. The new item is positioned below the edline object (thus above previously added objects).
This also shows that ProWesS never explicitly works with coordinates. In some cases the size of the object has to be given, but the position is determined either by default rules, or by positioning it above, below, left or right of another object.
Let's make some progress here, and more to a somewhat useful program. This one is just a window which has a title and an area to view the file. The user can indicate "Load file" and a file select window will be displayed. The thus indicated file will then be displayed in the view area.
This is a rather crude file viewer which is really only suited for text files, as the infotext type is used to display the file. This means that if the file contains a NULL character, the rest will no longer be displayed.
#include <ProWesS.h> typedef struct { PWObject file,it; char *base; int length; } Global; Error init() { PWObject obj; Global g; Error err; g.base=NULL; g.length=0; err=PWCreate(NULL,&obj,PW_TYPE_OUTLINE, PW_OUTLINE_SLEEP, PW_OUTLINE_QUIT, PW_OUTLINE_QUIT_KEYPRESS, 27, PW_OUTLINE_INFO_TEXT, "Load file", PW_OUTLINE_ACTION_INFO, loadfile, PW_GLOBAL_AUXILIARY, &g, NULL); if (err) return err; err=PWCreate(obj,&g.it,PW_TYPE_INFOTEXT, PW_INFOTEXT_WIDTH_FS, short2pt(30), PW_INFOTEXT_LINES, 12, NULL); if (err) return err; err=PWCreate(obj,&g.file,PW_TYPE_FILESELECT, PW_KEYPRESS, 'l', PW_FILESELECT_ACTION, doload, NULL); if (err) return err; err=PWActivate(obj); return err; }
As usual this just creates an outline object, and then puts an infotext in that. The infotext will be used to display the file. Some kind a minimum size is given to the infotext, this is rather approximate.
To include the "Load file" item, we used the info item in the outline. This is an auxiliary item which can be used for any purpose, and load file is just one example (it is intended to be used for displaying program info like the author, version, etc). An event handler has to be provided for the "Load file" item to activate the fileselect window.
Error loadfile(PWObject object) { Global *g; PWQuery(object,PW_GLOBAL_AUXILIARY,&g); return PWChange(g->file,PW_FILESELECT_ACTIVATE,NULL); }
The fileselect window is very straightforward. It can be activated by pressing 'l' or 'L', or indicating the "Load file" item. The fileselect is passed an action routine, which has to be executed when a file selection is confirmed (when the fileselect window is quitted from).
Error doload(PWObject object, char *dir, char *name) { Channel ch; Global *g; Size size; Error err; PWQuery(object,PW_GLOBAL_AUXILIARY,&g); err=IOOpenPath(name,OPEN_READ,dir,&ch); if (err) return err; IOLength(ch,&size); size++; if (size>g->length) { if (g->base) MEMRelease(g->base); g->base=NULL; g->length=0; err=MEMAllocate(size,&g->base); if (err) return err; g->length=size; } size--; IOLoadFile(ch,size,g->base); g->base[size]='\0'; IOClose(ch); return PWChange(g->it,PW_INFOTEXT_TEXT,g->base,NULL); }
This routine doesn't have much to do with the window manager. The global data structure has to be retrieved (with PWQuery), and the the file has to be loaded in memory. A end-of-string marker has to be added and the new text for the infostring has to be set (abra cadabra, that's it).