SQLUG
SCOTTISH QL USERS GROUP
A Guide to the CPTR Programs
JOHN SADLER
Introduction
The CPTR suite of programs have been developed by George Gwilt to enable
programmers to create pointer environment programs using the C68 Compiler.
George has created a set of extensions CPTR, to supplement
the C68 extensions qptr.h which are a development of the
extensions tony Tebby created.
Setf to create Pointer Windows, and Alter
to change them.
Now George has combined setf and wintoc into one program
called setz.
However the pointer environment is not an easy one to use and so it was thought helpful to write this guide to help users with CPTR.
Pointer Environment
The Pointer Environment does not operate in mode 8. SuperBasic in mode 8 runs in its own mode 8 screen. It is possible to create pointer environment programs suitable for mode 8 but they still run in the pointer screen. For such programs it is necessary to specify csize as 2,0 and allow more room for icons with words. For example Esc occupies 40 pixels. When a program starts up, it starts in the mode current at the time and so if the display has been designed for mode 4, and it is started in mode 8 you may get error messages as it cannot display the windows properly. (You get the same problem with Superbasic programs but as we normally run in mode 4 we do not notice it.) The function mode% returns the mode and can be use to set the mode before any windows are opened.
Windows
Before comencing the coding of the program it is necessary to design your windows. There is no alternative to planning them beforehand as this is not an IDE and you are advised to use Setf. Each main window has a size and if it is resizable a minimum size which should be big enough to hold any other information windows, application windows and loose items. Loose items can be considered as buttons, icons etc for user inputs such as mouse clicks and key presses to initiate user requests. Information windows are for displaying messages. There are also application windows and menu items.
Hello_c
We will demonstrate setting up a pointer program with hello_c which is the standard demonstration program "Hello World" complete with resize, move, sleep and close buttons. There is also button to initiate the greeting.
Creating the Window Definition File
First of all create the window definition file using setz as explained in the article Using SETF in the TPTR Suite to create Hello World Window Definition File.
This still creates the wda file.
There is now no need to run WintoC on it to create a
Z file, and run spr to create the c version.
The Z file
First we do not need all the parameters for the alit functions so we can alter as follows.
int alit0_0(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst); int alit0_1(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst); int alit0_2(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst); int alit0_3(void); int alit0_4(WM_wwork_t *wwk, WM_litm_t *li);
int alit1_0(void);
The C Code
Scroll down to nearly the end of the file to just pass "End of Declarations".
Next we need to eliminate the end message, create a title (for the sleep button)
then there is no need to pass parameters or redirection so we can set these
NULL
void (*_consetup)() = NULL; char *_endmsg = NULL; char _prog_name[] = "Hello C Version 10"; void (*_cmd_params) () = NULL; long (*_cmdchannels) () = NULL; long (*_stackchannels) () = NULL;
Now we will declare the global variables we need.
WM_wwork_t *wwa0; chanid_ chid0; int err; static short count = 0;
Creating the windows functions
Now alter the getsze line by inserting it in windows_init functions as follows.
void windows_init(void){ if(getsze(&wd0, prtab, &ws[0], wd0_sizes, &num)) exit (ERR_NC); if (!(chid0 = fgetchid(stdout))) exit (ERR_NI); if (!wm_findv(chid)) exit (ERR_NF); if (!(wwa = malloc(wd0_sizes[win]))) exit (ERR_OM); if (wm_setup(chid, 0, 0, &wd0, &ws[0], &wwa0, 0)) exit (ERR_NI); }
Next we need a function to display the window. It first allocates the space for the working definition, then it connects channel id to standard out, then the window attaches itself to the channel id, it setsup the window, positions it and draws it. The function exits with an error code if it is not successful with any of these actions
void display_window(WM_wwork_t *wwk){ if (wwk == wwa0) { if(wm_prpos (wwk,DEFXY)) exit(ERR_NI); } else { if(wm_pulld (wwk, DEFXY)) exit(ERR_NI); } if (wm_wdraw (wwk)) exit(ERR_BO); }
One of the compromises of the pointer environment is that each window does not have an area of RAM to print and draw information so when a window is resized or the program is put to sleep then all that information is lost. So routines are requred to display it. Draw_window attaches a channel to the information window sets its ink (as it seems to be reset each time, and prints the number of greetings made. (Perhaps if I had used an application window it may have behaved differently.)
int draw_window(WM_wwork_t *wwk, short win){ int err; short i; chanid_t chid1; if ((chid1 = wm_swinf(wwk, win, -1)) < 1) exit (chid1); if ((err = sd_setin(chid1, - 1, 7)) < 0) return err; /* Make ink white */ for (i = 0; i < count; ++i){ err = printf("Hello World!\n"); if ((err < 0) || (err != 13)) return err;} return 0; }
We need a routine to move the window when required. It initiates the move icon to get the new position, redraws the window in the new position and makes the move buton to available.
int window_move(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst){ short dx,dy; int err; ws->evnt |= PT_WMOVE; /* Set the event vector -> "move" */ if (err = wm_chwin (wwk, &dx, &dy)) return err; /* Perform the move */
return slitem(wwk, li->item, 0); /* Reset loose item 0 to available */ }
Next we need a routine to put the program to sleep. It sets the sleep event, uses George's do_sleep3 routine to put the program to sleep in a button, draws information window contents on its return, and resets the the button sleep to available.
int window_sleep(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst, int *wdsizes){ int err; ws->evnt |= PT_ZZZZ; /* Set the event vector -> "sleep" */ do_sleep(wwk->chid, wwk, 0, _prog_name, NULL, wdsizes); if (err = draw_window()) return err; return slitem(wwk, li->item, 0); }
Now we come to the most complicated routine, resizing the window. It first gets the new size of the window, and places it in ddx & ddy. It then gets the existing size in dx & dy. Next it makes sure the new x is an even number and both and that the new window is not too big or too small. It then unsets the old window, sets up the new window, positions it, draws it, draws the contents in the information window, and then makes the resize button available.
int window_resize(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst, WM_wdef2_t *wd, short win){ int err; short ddx,ddy; short dx,dy; ws->evnt |= PT_WSIZE; /* Set the event vector -> "size" */ ddx = wwk->xsize + wwk->xorg + wd->wdefa.xorg; ddy = wwk->ysize + wwk->yorg + wd->wdefa.yorg; dx = 4*((dx + 3)/4); dy = 2*((dy + 2)/2); if (err = wm_chwin(wwk, &dx, &dy) < 0 return err; /* Now check that the size is credible */ dx = EVEN(MIN(wd->wdefa.xsize,MAX(wd->wdefb[win].xsize & 0x3FFF, wwk->xsize-dx))); dy = MIN(wd->wdefa.ysize,MAX(wd->wdefb[win].ysize & 0x3FFF, wwk->ysize-dy)); if (err = wm_unset(wwk)) return err; if (err = wm_setup(wwk->chid, dx ,dy, wd, &ws[win], &wwk, 0)) return err; if (err = wm_prpos(wwk, ddx - dx, ddy - dy)) return err; if (err = wm_wdraw(wwk)) return err; if (err = draw_window(wwk, 1)) return err; return slitem(wwk, li->item, 0); }
Now we connect the window routines to the appropiate loose item routines created by setz. First the move action.
int alit0_0(WM_wwork_t *wwk, WM_litm_t *li, WM_wstat_t *wst){ return window_move(wwk, li, wst); }
Next the resize button.
int alit0_1(WM_litm_t *li, WM_wstat_t *wst){ return window_resize(wwk, li, wst); }
Then the sleep loose item.
int alit0_2(WM_litm_t *li, WM_wstat_t *wst){ return window_sleep(wwk, li, wst, wd0_sizes); }
Next the Esc or close button. This program just exits with success.
int alit0_3(void) {
exit (EXIT_SUCCESS); /* Quit */ }
Then the greetings button, which redraws the information window and resets the button.
int alit0_4(WM_wwork_t *wwk, WM_litm_t *li){ int err; count++; if (err = draw_window(wwk, 1)) return err; return slitem(wwk, li->item, 0); }<>
Finally the information window, which if the program reaches here there is a problem so exit failure.
int alit1_0(void){ exit (EXIT_FAILURE); }
Then remove the int main and its brackets.
Now we can write the main function which initiate the window pointers, display the window, and finally read the window pointer until an error.
int main(void){ /* make mode 8 mode 4 */ short mode, type; mode = -1; type = -1; mt_dmode(&mode, &type); if (mode == 8) { mode = 4; mt_dmode(&mode, &type); } windows_init(); display_window(wwa0); while (!(err = wm_rptr(wwa))) ; free(wwa0); exit (err); }
After saving the file type ex spr;'hello' and the z file will be converted into a C source file for compiling under C68.
It is hoped this example will provide the basics of producing a program in C and will help people to write such programs using CPTR suite a lot easier than any other method.
Here is the z code for Hello World program so that you can check it to resolve any errors.