Zum Inhalt springen

René’s Avigo Page: The Lotto Program

The Lotto Program

Lotto.gif
So here is my first application. I tried to keep it simple enough to be
understandable, but yet involved enough to show something. You may
download and try the complete source here. The included Bitmap is of
size 50×52, and I did it with Painbrush Pro. The size is the same as
the bitmap in the tutorial example. Above you can see a the logo
converted to GIF. It is probably best to keep the logo as simple as
possible. The complete application is here to try on your Avigo.

Lotto.app
16 kb
lotto.zip
2 kb

Now open a new project and add the C-file as source. Add the bitmap as
icon and convert it to dot format with the button on the icon page.
Then compile the source and start the simulator. Go to the applications
and start the Lotto program. You will see the following Avigo screen.

Lotto-Capture.jpg

It simply displays 6 numbers randomly chosen out of 49. It has a menu
on its left top containing entries "New Numbers" and "Exit", which is
dropped down at this moment, and it can be closed with the cross at the
top right. Nothing spectacular, and of little use. But it serves as a
demo for a simple Avigo program. By the way, you can do screen prints
with a menu item in the debugger.

While trying this in the simulator, I noticed that the menu selection
does not work properly with the mouse. You have to try a bit to get the
"New Numbers" entry to respond.

What follows is the source. I am going to explain most of it later.

/* you have to include all those header files

*/
#include "p100plib.h"
#include "ressdk.h"
#include "math.h"
#include "packet.h"

/* you have to decleare a static string for the window
title
*/
unsigned char test_title[] = "Test Title";

/* you have to declere the event handlers BANKED and extern
*/
extern BANKED void test_draw (VOID_PTR view);
extern BANKED void test_handle_event (VOID_PTR view,

unsigned short *evType, unsigned char x, unsigned char y);
/* define the command constants (belongs to a header file)
*/
#define cmdNew 1000

/* define the main menu structure
*/
const MENUITEM MainMenu[] =
{ {"New Numbers", cmdNew, 0},

{"Exit", cmCancel, 0},
{"\0", 0, 0}
};
/* those are the routines to generate Lotto numbers
*/

#define Ntotal 49
#define Nchosen 6
int Numbers[Ntotal];
void init_numbers ()

/* initialize the first 6 as chosen
*/
{ int i;
for (i=0; i<Ntotal; i++) Numbers[i]=0;
for (i=0; i<Nchosen; i++) Numbers[i]=1;

}
void mix_numbers ()
/* randomly mix them (thanks to the random() function)
*/
{ int i,j,h;

for (i=Ntotal-1; i>0; i–)
{ j=random(i+1);
if (j!=i)
{ h=Numbers[j]; Numbers[j]=Numbers[i]; Numbers[i]=h;

}
}
}
/* this is the definition of the drawing routine,
which is inserted for the main window with the

help of the BankedAssign() function.
*/
void test_draw (VOID_PTR view)
{ /* the pointer is really a point to a DESKBOX */

PDESKBOX *dsk;
dsk=(PDESKBOX *)view;
int i,y; /* C++ like (variables need not be at function start) */
PDESKBOX_draw(view); /* default, clears the view */

SetFontType (PRPFONT14B); /* biggest font available */
unsigned char s[256]; /* for forming the string */
y=dsk->top+40; /* the row of the first string */
for (i=0; i<Ntotal; i++) /* draw all chosen numbers */
if (Numbers[i])
{ /* convert to string and draw */
NumericToStr((double)(i+1),s,DTINTEGER);

WriteString(dsk->left+20,y,s,0);
y+=20; /* increment row */
}
}
/* the event handler for the menu commands and for
the main window
*/
void test_handle_event (VOID_PTR view,
unsigned short *evType, unsigned char x, unsigned char y)

{ /* convert view to deskbox */
PDESKBOX *dsk;
dsk=(PDESKBOX *)view;
/* call default handler (don’t know why) */

PDESKBOX_handleEvent(view,evType,x,y);
/* switch events */
if (*evType==evCommand)
{ switch (TOWORD(x,y))

{ case cmdNew : /* user wants other numbers */
ClearEvent(evType);
/* event taken */
mix_numbers(); /* shuffle */
dsk->draw(view);
/* redraw window */
break;

}
}
}
short main (void)
{

/* pointer to the main window (properly destroy it at end) */
PDESKBOX *dsk;
/* init our Lotto numbers */
init_numbers();
randomize();

mix_numbers();
/* create a window covering all of the screen
with a menu, a title and a close box */
dsk = (PDESKBOX *)CreateDeskBox(‚A‘,0,0,159,239,
MK_FAR_PTR(test_title),MK_FAR_PTR(MainMenu),0,
bafClose|bafDotTitle);
dsk->options &= ~ofFindable; /* no find in this application */
/* assign the event handlers to this window */
BankedAssign(dsk->handleEvent,test_handle_event);
BankedAssign(dsk->draw,test_draw);
/* seems to generate the main event loop */
ExecView ((PGROUP *) dsk);
/* destroy the window */
Destroy ((VOID_PTR) dsk);
return 0;
}

Actually, I do not understand a few things, which is to be expected
after only a few hours. Furthermore, the programming style is a bit
different to my favourite Java style, though there are related things.

The compiler is ANSI-C with a few restrictions described in the on-line
help. It has no // comments, but allows variable declarations at every
place in a function. It has a few more keywords like the BANKED
modifier, which marks a function as being available from outside its
16k bank. As you will guess by this memory organization, pointers are
16 Bit wide. So you have to convert pointers to 32 Bit, if you pass
them to system calls. This is done by the MK_FAR_PTR macro.

The main function has no arguments and returns a short. This program
uses main to generate the numbers for the Lotto run, to initialize a DeskBox?
and start the event loop. I won’t comment much on the generation of the
random numbers. There is a random function, which is useful here. Maybe
randomize initializes the random number generator with the Avigo time.

init_numbers();
randomize();

mix_numbers();

A DeskBox is an analoge of a window. It may have a title, a menu and a close button, all determined by the CreateDeskBox function arguments. And it has a drawing area. The Avigo SDK calls a DeskBox an object. There is a hierarchie of objects. The grandfather is a PVIEW. This program only uses the DeskBox. I do not understand the rest of the objects at this time.

dsk = (PDESKBOX *)CreateDeskBox(‚A‘,0,0,159,239,
MK_FAR_PTR(test_title),MK_FAR_PTR(MainMenu),0,
bafClose|bafDotTitle);
dsk->options &= ~ofFindable; /* no find in this application */

The second statement makes sure the find button is off while this application runs.

The application then assigns pointers to event handlers for the DeskBox? with the BankedAssign?
function. These handlers must be BANKED functions, because they are
called from outside. The correct way to do this is to declare a
function prototype at the beginning or in a header file. The test_draw
function is the redraw routine for the DeskBox? and the test_handle_event function will handle all events, like pen clicks or menus.

extern BANKED void test_draw (VOID_PTR view);

extern BANKED void test_handle_event (VOID_PTR view,
unsigned short *evType, unsigned char x, unsigned char y);
After this preperation, we are ready for the event loop. The event loop is entered with
ExecView ((PGROUP *) dsk);

It will exit as soon as a cmCancel command event is found. This event
is triggered by the close button or by the "Exit" menu entry, because I
gave it that value. The menu is defined in an array of MENUITEM
structures. This array is passed as a far pointer to the CreateDeskBox function.

const MENUITEM MainMenu[] =
{ {"New Numbers", cmdNew, 0},
{"Exit", cmCancel, 0},
{"\0", 0, 0}
};

We now discuss the test_draw function.

void test_draw (VOID_PTR view)
{ /* the pointer is really a point to a DESKBOX */
PDESKBOX *dsk;
dsk=(PDESKBOX *)view;
int i,y; /* C++ like (variables need not be at function start) */
PDESKBOX_draw(view); /* default, clears the view */
SetFontType (PRPFONT14B); /* biggest font available */
unsigned char s[256]; /* for forming the string */
y=dsk->top+40; /* the row of the first string */
for (i=0; i<Ntotal; i++) /* draw all chosen numbers */
if (Numbers[i])

{ /* convert to string and draw */
NumericToStr((double)(i+1),s,DTINTEGER);
WriteString(dsk->left+20,y,s,0);
y+=20; /* increment row */
}
}

As you see, the function gets a void pointer, which is actually a pointer to our "DeskBox?".
The type name PDESKBOX is somewhat misleading, because it not a pointer
but a structure. We first call the default drawing routine, which will
clear the window. Then we set the font and paint our numbers into the
window. The window margins are with the window bounds and the title
line. There seems to be no way to determine the interior drawing area.
However, it might be save to use absolute constants here. To format a
number, we can use the NumericToStr function.

The test_handle_event routine is very similar.
void test_handle_event (VOID_PTR view,
unsigned short *evType, unsigned char x, unsigned char y)
{ /* convert view to deskbox */
PDESKBOX *dsk;
dsk=(PDESKBOX *)view;
/* call default handler (don’t know why) */
PDESKBOX_handleEvent(view,evType,x,y);
/* switch events */

if (*evType==evCommand)
{ switch (TOWORD(x,y))
{ case cmdNew : /* user wants other numbers */
ClearEvent(evType);
/* event taken */
mix_numbers(); /* shuffle */
dsk->draw(view);

/* redraw window */
break;
}
}
}

It calls the default event handler by a reason beyond me. Then it
checks for the correct event type. Events are declared invalid by the
ClearEvent routine. This feature is the reason events are passed by a
pointer. The event number is hidden in the x and y parameters, which
might also serve to describe pen events. We simply mix our random
numbers and repaint the DeskBox with its drawing routine.

This is as much as I understood by now. Hope it helps you. More complex projects will follow.

René Grothmann

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.