The current version uses Allegro, which is a very useful multi-platform graphics library, and has been tested in Windos and Linux.
The basic theory behind MAD is that you can do most of what you want in an application by using plain C for data manipulation and GEM for the GUI functions, if your application can call routines in some other library to mimic the effect of the GEM calls, and the other library needs to be no more visible than the TOS.
Handles and windows are not properly supported because I am only working
at the application level, but all the GEM calls I used on the ST have near
equivalents in MAD.
int Setcolor(int colorno, unsigned char *color)
void Palettize(int lemgth, unsigned char *index, unsigned char *palette)
void Storepalette(short from, short total, char *colors)
void Forcepalette(short from, short total, char *colors)
void Getcolor(int colno, unsigned char *savecolor)
int Grabpalette(unsigned char *savepalette)
int vsl_color(int handle, int color)
int vsf_color(int handle, int color)
int vst_color(int handle, int color)
int vst_effects(int handle, int effects)
int vst_font(int handle, int fontno)
int vst_load_font(int handle, const char *fontname)
int vst_user_font(int handle, GFONT *font)
int vst_unload_font(int handle, int fontno)
void v_gtext(int handle, int ox, int oy, const char *text)
void v_pline(int handle, int count, short *pxy)
void v_bar(int handle, short *pxy)
void vs_clip(int handle, int flag, short *pxy);
void v_show_c(int handle, int count)
void vq_mouse(int handle, short *butn, short *x, short *y)
void vq_key_s(int handle, short *kbstat)
void vro_cpyfm(int handle, int mode, short *pxy, FDB *src, FDB *dest)
int rsrc_load(const char *filename)
int rsrc_gaddr(int type, int index, void *address)
int objc_draw(OBJECT *dialog, int startobj, int depth, int clipx, int clipy, int clipw, int cliph)
int objc_find(OBJECT *dialog, int seekobj, int depth, int mx, int my)
int objc_offset(OBJECT *dialog, int seekobj, int depth, short *screenx, short *screeny)
int graf_rubberbox(int ox, int oy, int minw, int minh, short *lastw, short *lasth)
int graf_slidebox(OBJECT *slider, int S_Gauge,
int S_Slide, int slvh)
int form_center(OBJECT *dialog, short *x, short *y, short *w, short *h)
int form_dial(int fo_diflag, int fo_dilittx, int
fo_dilitty, int fo_dilittw,
int fo_dilitth, int dix, int diy, int diw, int
dih)
int form_do(OBJECT *dialog, int editobj)
int form_alert(int dfault, const char *alert)
int form_error_text(char *text)
int form_infobox(OBJECT *dialog)
int form_input(int length, char *ptmplt, int default, char *label)
void form_input_text(int length, char *ptemplate,
char *text, char *label)
int menu_bar(OBJECT *menu, int flag)
int menu_tnormal(OBJECT *menu, int title, int norm)
int menu_icheck(OBJECT *menu, int title, int check)
int menu_ienable(OBJECT *menu, int title, int
enable)
int evnt_timer(int locount, int hicount)
int evnt_mouse(int mflags, int mx, int my, int
mwidth, int mheight,
short *x, short *y, short *butn, short
*kstate)
int evnt_mesag(short *msgbuff)
int evnt_multi(int aflags, int bmaxclicks, int
bmask, int bstate,
int m1flags, int m1x, int m1y, int m1width, int
m1height,
int m2flags, int m2x, int m2y, int m2width, int
m2height,
short *msgbuff, int locount, int hicount, short
*x, short *y,
short *butn, short *kstate, short *kreturn, short
*breturn)
int fsel_input(char *path, char *selfile, short *button)
void fsel_set_extn(char *type)
CARRET 13 /*Return key*/
AKEY 'a'
BKEY 'b'
CKEY 'c'
DKEY 'd'
EKEY 'e'
FKEY 'f'
GKEY 'g'
IKEY 'i'
LKEY 'l'
NKEY 'n'
PKEY 'p'
QKEY 'q'
RKEY 'r'
SKEY 's'
UKEY 'u'
XKEY 'x'
YKEY 'y'
COMMAKEY ','
STOPKEY '.'
SLASHKEY '/'
SPACEKEY ' '
ESCKEY 27
TABKEY 9
BCKKEY 127 /*Backspace*/
DELKEY 128 /*Delete*/
F1KEY 323 /*F1*/
F2KEY 324
F3KEY 325
F4KEY 326
/*Spot what's missing*/
UAKEY 354 /*Up arrow*/
DAKEY 360
RAKEY 358
LAKEY 356
STLBUT 1 /*Right mouse button*/
STRBUT 2 /*Left mouse button*/
Resources can be built and re-edited with Madorcs.
The various structures and macros used are:
typedef struct rshdr {
unsigned short rsh_rssize; /* total bytes in resource */
unsigned short rsh_tedinfo; /* offset to tedinfo[] */
unsigned short rsh_object; /* offset to object[] */
unsigned short rsh_trindex; /* offset to object tree index */
short rsh_nteds; /* number of tedinfos */
short rsh_nobs; /* number of objects */
short rsh_ntrees; /* number of trees */
} RSHDR;
The header for a resource.
typedef struct object {
short ob_next;
short ob_head;
short ob_tail;
unsigned char ob_type;
unsigned char ob_flags;
unsigned char ob_colbyte;
unsigned char ob_font;
unsigned char ob_border;
unsigned char ob_fill;
char *ob_spec;
short ob_x;
short ob_y;
short ob_width;
short ob_height;
} OBJECT;
typedef struct tedinfo {
char *te_ptext;
char *te_ptmplt;
short te_pvalid;
short te_ptxtlen;
} TEDINFO;
Most of the detail here should be irrelevant even to the programmer, once the resource is set up. The coordinates are simple pixel measurements with respect to the object directly above in the hierarchy. The flags are detailed below. The ob_spec contains the single character for R_CHAR, the address of a tedinfo for R_FTEXT and R_STEXT, and the text address for the other text types.
MAX_DEPTH 8
The maximum depth of search or draw
Resource Types
R_BLOCK 20 A rectangle of the background color
R_IBOX 25 A notional rectangle, ie you can see through it
R_CHAR 27 A single character
R_TEXT 28 A simple string, neither editable nor formatted
R_FTEXT 29 A string which will be printed with certain formatting rules
R_ETEXT 30 A text which can be edited by the user
R_STEXT 31 An editable text which can scroll, used in the file selector
R_TITLE 32 A string used in menu headings
Object Flags
NONE 0
DEFAULT 1 Pressing return equals
clicking on this
EXIT 2 Resource handling is terminated
CHECKED 4 Object is checked
LASTOB 8 The last object in a tree
(set of objects}
HIDETREE 16 This object and any
contained in it are neither drawn nor available
SELECTED 32 Object has been selected
and is shown recolored
DISABLED 64 Object can't be selected
and is shown feint
OUTLINED 128 Object is outlined
short Getrez()
Returns the resolution for the console or the window size in X.
The resolutions used are:
0: 320*200
1: 640*480
2: 800*600
All screens are 8-bit, 256 colors.
char *Physbase()
Actually returns NULL. The copying routines use this to signal the
need to switch to screen manipulation functions.
char *Logbase()
Returns the address of a pre-allocated virtual screen. This facilitates
performing all the graphics operations off-screen and page-flipping.
void Setscreen(int, int)
If the first parameter is -1, the second parameter is the resolution
that will be set, otherwise the second parameter is ignored.
0 copies the virtual screen to the physical screen, and sets the handle
to point to the physical screen.
1 copies the physical screen to the virtual screen, and sets the handle
to the virtual screen.
void Setpalette()
Refreshes the screen palette to the MAD palette.
Setpallete is defined to this; the original C compiler for the ST misspelled
the word and people grew accustomed to it.
int Getpalette()
Returns the number of colors which are currently assigned.
int Resetpalette(int number)
If the parameter is 256, the number of colors is reset to the starting
number, actually 16. Otherwise it is set to the parameter. The return is
the actual number of colors now recognized.
Note that this routine does not change the screen colors.
int Setcolor(int colorno, unsigned char *color)
If the first parameter is less than 256, the color at that point in
the MAD palette is changed to the second parameter and the first parameter
is returned.
Otherwise, the second parameter is checked against the used palette.
If one of the used colors is no more than 1 point each of RGB away, its
number is returned.
Failing this, if there is room, a new color is added and the return
is its number.
If all else fails, the number of the nearest color is returned.
void Palettize(int lemgth, unsigned char *index,
unsigned char *palette)
This routine is passed a length and an index array and color array
of that length. It puts the colors into the MAD palette using Setcolor
and stores the assigned palette numbers in the index.
The index can now be used to map a picture's pixels onto the screen
or into memory.
void Storepalette(short from, short total,
char *colors)
This routine puts the colors in the array into the palette, starting
at a point, for a length, ignoring any duplicates or already assigned colors.
It does not change the screen palette.
void Forcepalette(short from, short total,
char *colors)
This routine does change the screen palette.
void Defaultpalette()
Restores all palette conditions to what they were at startup.
void Getcolor(int colno, unsigned char *savecolor)
Atari Setcolor returns the old color; mine returns the number.
Palettize means I don't know my actual colors, so this tells me what
color I have in a slot.
int Grabpalette(unsigned char *savepalette)
Copies the whole palette to savepalette, so it can be restored.
Returns the number of colors actually used.
int vsl_color(int handle, int color)
Sets the color, ie palette number, with which lines are drawn.
int vsf_color(int handle, int color)
Sets the color for fills.
int vst_color(int handle, int color)
Sets the color of text.
int vst_effects(int handle, int effects)
Sets the text effects used by v_gtext.
NORMAL 0 No effects
THICKENED 1 The text is 1 pixel thicker, giving a bolder look
SHADED 2 Only odd pixels are printed, giving a feint look
SLANTED 4 The top of the text is displaced to the right
UNDERLINED 8 The text is underlined, apart from spaces
DOUBLED 16 The text is twice as thick, at the original height
int vst_font(int handle, int fontno)
There are 3 fonts in MAD as standard, and more may be loaded up to
a total of 8. This routine sets the font used to one of them.
int vst_load_font(int handle, const char
*fontname)
Loads from disk a font by name for the next available slot, and returns
the font number, or -1 if it fails.
int vst_user_font(int handle, GFONT
*font)
For convenience, this routine can take the address of a font file that
has been compiled into an application, assign it as a usable font and return
the font number. Again, -1 indicates a failure.
int vst_unload_font(int handle, int fontno)
Clears a font slot (not the 3 defaults) and moves fonts up to fill
the gap. Returns the new number of fonts or -1.
void v_gtext(int handle, int ox, int oy, const
char *text)
This routine prints a string in the set font, in the chosen color,
with the chosen effects. Printing starts at ox, oy, and will be clipped
if necessary.
void v_pline(int handle, int count, short *pxy)
Draws a set of connected lines. The second parameter is the number
of points, and the third is an array of xy screen coordinates.
void v_bar(int handle, short *pxy)
Fills a rectangle. The array of 4 shorts gives the top left and bottom
right points of the rectangle.
vr_recfl is defined to this.
int v_opnvwk(int *handle);
This should open a virtual workstation, set up certain parameters of
it, fill an array with useful data about it and return a handle to it.
In practice it doesn't do any harm.
void v_clrwk(int handle)
This clears the current screen.
void v_clsvwk(int handle)
This should close the virtual workstation.
void vs_clip(int handle, int flag, short *pxy);
if the second parameter is 1, the clipping rectangle is defined by
the 4 points of the array. If it is 0, clipping is disabled.
void v_hide_c(int handle);
This hides the mouse cursor, unless it is already hidden, and keeps
track of how often it has been called.
void v_show_c(int handle, int count)
If v_hide_c has not been called, this routines returns immediately,
as there is nothing for it to do.
If the second parameter is 1, it cancels out one v_hide_c; if it is
0, it cancels all of them.
If all v_hide_c calls have been cancelled, it shows the cursor.
void vq_mouse(int handle, short *butn, short
*x, short *y)
This returns immediately with the current state of the mouse button
and the x and y positions of the cursor in its pointers.
void vq_key_s(int handle, short *kbstat)
This returns immediately with the pointer holding part or all of the
following bit pattern.
1 Right Shift was pressed
2 Left Shift was pressed
4 A Control key was pressed
8 Alt was pressed
int vq_keybd(int handle)
If a key has been pressed, this returns the key value. Otherwise it
returns 0. Note: the keypress is no longer available after this routine.
void vro_cpyfm(int handle, int mode, short *pxy,
FDB *src, FDB *dest)
A versatile blitting routine.
The array of 8 shorts gives the coordinates of top left/bottom right
of a source rectangle and a destination rectangle with respect to the top
left of the Frame they are contained by.
The second parameter is the mode, the blitting operation itself. 4
types are supported:
ALL_WHITE 0 The source
rectangle is filled with color 0
S_ONLY
3 The source is blitted to the destination
D_ONLY
5 The source is blitted to the destination, except for
pixels which are color 0 in the source
ALL_BLACK 15 The source rectangle is
filled with color 1
The last 2 parameters are pointers to a source and destination Frame
Definition Block, a structure with the following definition:
void *fd_addr;
short fd_w;
short fd_h;
short fd_wdwidth;
short fd_stand;
short fd_nplanes;
short fd_r1;
short fd_r2;
short fd_r3;
Only the first 3 elements are used. The first is the starting address
of the frame; if this is NULL, it is assumed that the physical screen is
being referred to. fd_w and fd_h are the width and height of the frame.
int appl_init(int res)
This has to be called at the beginning of a program, with the desired
resolution as the parameter.
It sets up the standard fonts and the error-message and file-selector
resources, initializes the mouse and clears the screen.
int appl_exit()
This tidies up anything which needs tidying and exits.
int rsrc_load(const char *filename)
Loads a resource. If it fails, there is no point in continuing, so
it reports this and closes down the program.
int rsrc_free()
Frees up the resource.
int rsrc_include(void *array)
Makes a compiled-in array into the user resource. A convenience when
you decide you no longer need to re-edit the resource.
int rsrc_gaddr(int type, int index, void *address)
This is normally used to get into an OBJECT pointer the address of
a tree in the resource, in which case the first parameter is 0, the second
the number of the tree in the resource's list (more usually a macro produced
by the resource editor).
Theoretically, it can also get the address of any object or tedinfo.
int objc_draw(OBJECT *dialog, int startobj,
int depth, int clipx, int clipy, int clipw, int cliph)
This draws an object (generally a full tree), from a starting object
within it (generally 0), to a depth (generally MAX_DEPTH as the routine
will stop when it runs out of objects anyway). I don't use the last 4 parameters.
int objc_find(OBJECT *dialog, int seekobj, int
depth, int mx, int my)
This finds the deepest object in a dialog under the given co-ordinates
and returns its number, or -1 if there is no such object. Depth is currently
ignored.
int objc_offset(OBJECT *dialog, int seekobj,
int depth, short *screenx, short *screeny)
This puts the screen co-ordinates of the sought object in screenx,
screeny. Depth is currently ignored.
int graf_rubberbox(int ox, int oy, int
minw, int minh, short *lastw, short *lasth)
Draws a box right and down from ox, oy, with a minimum width, minw,
and height, minh, to the mouse position while the left button is held down.
The final width and height are returned in lastw, lasth.
int graf_dragbox(int movew, int moveh, int
ox, int oy, int bordx, int bordy, int bordw, int bordh, short *lastx, short
*lasty)
Drags a box of size movew, moveh, starting at ox, oy, around the screen
between the boundaries given by bordx, bordy, bordw and bordh, as long
as the left mouse button is held down. The top left corner of the
final position is returned in lastx, lasty.
int graf_slidebox(OBJECT *slider, int S_Gauge,
int S_Slide, int slvh)
Moves an object within the limits of another object, either vertically
(slvh==1) or horizontally (slvh==0).
Returns the position of the center of the slider relative to the gauge.
int form_center(OBJECT *dialog, short *x,
short *y, short *w, short *h)
This does nothing but work out the x and y coordinates for the top
left of an object that will center it on the screen, and pass them with
the object's width and height to the parameters and to the dialog itself.
If you want to do your own placement, you can ignore this; the width
and height are already correct in the dialog.
int form_dial(int fo_diflag, int fo_dilittx,
int fo_dilitty, int fo_dilittw,
int fo_dilitth, int dix, int diy, int diw, int dih)
This prepares for drawing the form or undraws it.
If the first parameter is less than 2, a section of the screen with
coordinates given by the last four parameters (usually those set by form_center)
is saved.
Otherwise, the previously saved screen is blitted back in, erasing
the form.
int form_do(OBJECT *dialog, int editobj)
The actual messing with the dialog (but not the drawing - that has
to be done with objc_draw).
If the second parameter is non-zero, the text cursor is positioned
in the text of the object with that number. Otherwise, the text cursor
goes in the first editable object it can find.
Tab cycles through the editables. Backspace and delete both delete
from the end of the text. Escape deletes the entire text.
Clicking on an object with EXIT in its flags or pressing return terminates
this routine, and the return is either the number of the clicked object
or that of the default object.
int form_alert(int dfault, const char *alert)
This on its own calls up a small dialog with limited but useful functionality,
using up to 3 buttons and up to 5 lines of text.
The int is the number of the button which pressing return will simulate;
this will be shown as the default.
The string is of the form [number][text|text|...][button|button...],
where number is the number of buttons, text stands for a line of text and
button stands for a button text.
The return is the button, 1-3, actually pressed.
int form_error(int number)
The ST form_error returned a report of violations of the underlying
operating system. I can't manage that so this is basically a debugging
device which shows a message with the parameter included and waits.
int form_error_text(char *text)
Like form_error, but puts up a message instead of a number.
int form_infobox(OBJECT *dialog)
Puts up a user-created dialog with only one exit button, mainly
to present information to the user. The dialog can contain editable
strings, but reading them must be handled explicitly by the program
int form_input(int length, char *ptmplt, int
default, char *label)
Pops up a little dialog box in which you can type a number of length
digits on a line starting with the template. The default is the default
number given. The label is optional.
The return is the number you typed.
void form_input_text(int length, char
*ptemplate, char *text, char *label)
Gets a string in text. The label is, again, optional. The text
should be at least length+1 characters long, to allow for the terminator.
int menu_bar(OBJECT *menu, int flag)
If the flag is 1, the menu headings are put at the top of the screen,
and the pixels they displace are saved.
Otherwise (assuming one was actually drawn earlier) the menu is erased.
int menu_tnormal(OBJECT *menu, int title,
int norm)
The first int is an object number within the menu.
If the second is 0, this object is written as SELECTED, otherwise it
is un-marked.
int menu_icheck(OBJECT *menu, int title, int
check)
The first int is an object number within the menu.
If the second is 1, this object is marked as CHECKED, otherwise
it is un-marked.
int menu_ienable(OBJECT *menu, int title,
int enable)
The first int is an object number within the menu.
If the second is 1, this object can be selected, otherwise it is written
FEINT and can't be selected. As MAD doesn't distinguish menus from other
dialogs, this can be useful in ordinary dialogs as well.
int evnt_timer(int locount, int hicount)
The precision of this is implementation dependent. locount/hicount
is in milleseconds
int evnt_mouse(int mflags, int mx, int my,
int mwidth, int mheight,
short *x, short *y, short *butn, short *kstate)
If mflags is set, this returns 1 when the mouse leaves a rectangle;
otherwise it returns 1 when it enters. The mouse coordinates and button
state are passed in the pointers.
int evnt_keybd()
Waits for a keypress and returns it.
int evnt_button(int bmaxclicks, int bmask,
int bstate, short *x, short *y, short *butn, short *kstate)
Waits for the number of clicks set in the first parameter, and returns
that number.
The next parameter is the buttons which will register as clicks; 1
is left, 2 is right, 3 is either. The third parameter sets whether button
up (0) or button down (1, 2 or 3) is counted.
When the routine exits, the 4th and 5th parameters contain the x and
y of the mouse position, the 6th the button states, in the same form as
the second parameter aand the last the same information as is returned
by vq_key_s.
int evnt_mesag(short *msgbuff)
This routine is only partially implemented, and used for menu operations.
If the mouse moves to the top menu, the dropdown menus appear. A click
in one of them will result in the message buffer (an array of 8 shorts)
containing:
short 0: 10 (a macro, MN_SELECTED, is the mnemonic for this)
short 3: The object index of the menu title
short 4: The object index of the menu entry
Moving outside the active menu area sets the 1st short to 0, and undraws
the menu box
int evnt_multi(int aflags, int bmaxclicks,
int bmask, int bstate,
int m1flags, int m1x, int m1y, int m1width, int m1height,
int m2flags, int m2x, int m2y, int m2width, int m2height,
short *msgbuff, int locount, int hicount, short *x, short *y,
short *butn, short *kstate, short *kreturn, short *breturn)
This routine is only partially implemented, but is basically a conflation
of all the other event routines.
The first parameter is the types of event expected, and the return
is the types which actually occurred, using the following flags:
MU_KEYBD 1 keyboard event
MU_BUTTON 2 button event
MU_M1 4 mouse rectangle event 1
MU_M2 8 mouse rectangle event 2
MU_MESAG 16 message event
MU_TIMER 32 timer event
The next 3 have the same meaning as in evnt_button.
The next 10 (to the short pointer) are 2 images of the evnt_mouse function.
The msgbuff is as in evnt_mesag.
The locount and hicount are the low word and high word of the number
of milliseconds that the routine will wait for an event. Take this with
a large grain of salt; I've tried for an approximation to equivalence to
ST timings.
The next 4 pointers are as in evnt_button.
The penultimate is the key pressed or 0.
The last is the number of clicks as for evnt_button.
In use, all of the last set of pointers which are unnecessary can be
the same variable.
int graf_mouse(int mode, void *shape)
This routine carries out 2 quite distinct functions, depending on the
mode, which can be one of:
ARROW 0
TEXT_CRSR 1
HOURGLASS 2
POINT_HAND 3
FLAT_HAND 4
THIN_CROSS 5
THICK_CROSS 6
OUTLN_CROSS 7
USER_DEF 255
M_OFF 256
M_ON 257
M_OFF and M_ON function like v_hide_c and v_show_c. Note that the GEM
strictures against mixing VDI and AES do not apply in MAD.
The other modes change the cursor. There are 8 predefined shapes and
USER_DEF can access new shapes attached to the program. The structure of
a shape is:
short hot_x, hot_y The active point of the cursor
short foreground, background Mouse colors; 255 is invalid
short shape[16] The central shape; foreground color
short mask[16] The surrounding mask; background color
For every set bit in the shape and mask a pixel is set to the foreground
or background color in the cursor.
The shape parameter is normally set to NULL, except for USER_DEF.
int fsel_exinput(char *path, char *selfile,
short *button, const char *label)
MAD comes with a default file selector which can handle long filenames.
The path is the name of the directory, and should have space for 256
(FMSIZE) characters. The selfile is the name of the file, and should have
space for 128 (FNSIZE) characters. You might get away with less, but don't
blame me if you don't.
The label is a message which appears at the top of the file selector.
On return, the button contains 0 for selection cancelled, or 1 for
selection. In the latter case, the path contains the full pathname of the
selected directory, the selfile the filename within the directory.
There is a set of 6 default clickable extensions which will stay throughout
a session and include the extensions of files already selected.
The Dos/Windows version comes with a few drive buttons.
int fsel_input(char *path, char *selfile, short
*button)
The same as fsel_exinput, but with a default message.
void fsel_set_extn(char *type)
A convenience to let you add an extension to the list of default extensions.