








MGUI

Brief programming guide

INTRODUCTION

MGUI (MORELLO Graphic User Interface) is a user interface currently 
available in DOS (16 and 32 bit), Windows, Win32 and Unix X-Window 
environments.
The main features of MGUI are:

n Total source code compatibility among all supported platforms.
n Identical look & feel in all environments (similar to OSF/Motif).
n Coding process is very smart and produces compact source code.
n A manager object automatically positions and resizes its children, 
making layout construction very simple.
n A design tool (MGUI Designer) generates C source files that can be 
compiled  in all supported environments.
n Supports 16 and 256 colors under DOS, up to 16 millions in Windows 
and X-Window environments.
n BMP, GIF, TIFF and JPEG formats are supported for image drawing.
n Log facility with run-time user modifiable tracing level.
n Resource file handling to customize Object attributes as text, font and 
color
n Run-time Object attribute changing (with optional store in the resource 
file)



MGUI has been successfully compiled and tested in the following 
environments:

n Borland C 4.5 with BGI graphics library (real mode) 
n Borland C 4.5 PowerPack with BGI graphics library (DPMI 16 bit) 
n Borland C 4.5 PowerPack with BGI graphics library (DPMI 32 bit).
n Borland C 4.5 with Csaba Biegl GRX 2 graphics library.
n DJGPP  with Csaba Biegl GRX 2 graphics library.
n RSXNTDJ/DJGPP Win32
n GNU-Win32
n Borland C 4.5 under Windows 3.1 and Win32
n Visual C 4.0 under Windows 95
n SUN Solaris 2.4 (x86 & sparc)
n IBM AIX 3.2.5 Risc 6000
n Linux 
n Watcom C 11.0 under DOS/4GW, Windows 3.1 and Win32

These features make MGUI useful to everyone who wants to realize 
multi platform applications, with absolutely no GUI porting needs.

MGUI was initially developed under DOS (Borland BGI), due to the 
missing in this environment of an advanced and simple to use GUI.
The library design was hardly conditioned by the knowledge acquired in 
the Unix X-Window environment. This has made very simple to obtain a 
Unix version of the MGUI library.
Then I decided to port the software in the DJGPP environment, and it 
became possible to create 32 bit DOS applications using the GNU gcc 
compiler and gaining great improvements in the graphics performance.
Finally, after a little tuning in the MGUI API, I realized the porting in the 
Windows environment.
Tanks to my friends Paolo (first MGUI user) and Sergio for their 
contribution in the testing and for their suggestions.


ARCHITECTURE

MGUI is coded in ANSI C and consists currently of about 28.000 source 
code lines. A small portion (10% - 15%) is highly system dependent, 
while the remaing 85% - 90% is completely system independent. The 
system specific code implements the interface between the specific 
graphic environment and the library Objects.
	This design makes MGUI easy to evolve and easy to port in other 
environments.
There are four main functional blocks in the library structure:

1) System Event Management		(SEM)
2) Graphics Request Management	(GRM)
3) TopLevel	Window Management	(TWM)
4) MGUI Objects

The first block handles all the system generated events:

- mouse button press
- mouse button release
- mouse move
- keyboard
- timeout
- window move
- window resize
- window expose


	When one of the above event occurs, the SEM block generates an 
event and passes it to the TWM block.
The DOS implementation uses a polling tecnique to handle mouse events, 
so mouse clicks and moves while the program is not waiting for input are 
lost.
	The TWM block major task is to handle all those events the system 
notifies to a window. Every system window owned by the application has 
a MGUI Object bound to, events are received by this Object (SHELL) 
and propagated to the destination Object following the layout hierarchy.
Since there is not a Window Manager in the DOS implementation, the 
TWM block handles window movement and focus delivery in this 
environment.
	The GRM block offers the API for the display functions: color and 
font management and drawing primitives.
	Last block, the greater and system independent one, contains the 
MGUI Objects API.
In the remainder of this guide are described details about Objects as well 
as the programming tecnique for a strict MGUI application. Refer to 
MGUI Reference Guide for more details about all available library 
functions.
	Every example mentioned in this guide can be obviously compiled 
and executed without changes in any of the supported platforms.


COLOR MANAGEMENT

	Color management reflects perfectly MGUI Library philosophy: 
it's simple, compact (and so limited) but offers a unique approach to the 
DOS, Windows and Unix systems! 
A program can operate in a 'palette' color mode or in a 'static' color mode, 
depending on the presence of a modifiable color palette in the graphic 
system.
	Palette mode is normally available when the number of colors 
simultaneusly viewable is small (typically 16 or 256), and the graphic 
card is capable of a wide range of selectable colors (256K in the standard 
VGA). When operating in this mode, the pixel value in the video memory 
is used as an index by the display adapter to address a table containing 
the actual R-G-B values. By using 8 bit per pixel (planes) it's possible to 
address 256 different entries in the table and any combination of R-G-B 
values (256K in the standard VGA) can be assigned to every entry 
(palette cell).
This mode is efficient because permits you to select colors in a wide 
range of available ones. Moreover it makes possible to realize color 
animation by simply changing R-G-B values in the palette.
	In the static mode, the graphic system operates with a fixed color 
palette. This can be achieved in 16 color mode under Windows or in 
HiColor mode which offers 15, 16 or 24 bit per pixel with respectively 
32K, 64K or 16M colors.
HiColor mode grants a superior photographic resolution, but reaches 
slower performances because requires 2 or 3 byte to code a single pixel, 
where the palette mode with 256 colors needs only one byte.
HiColor mode is not supported in DOS environment.
	If the MGUI application does not require color animation, it can 
actually ignore the number of available colors and the operanting mode 
(palette or static).
	If the application wants to know some detail about the graphic 
environment in which operates, it can call the MPaletteMode() function 
which return 'True' when in palette mode. The MGetNColors() function 
returns the number of simultaneously viewable colors in the system and 
MGetNPlanes() returns the number of color planes.
	Before using a color, the program must allocate it in the library. 
There are several allocation functions, each returning the color identifier 
that can be used in the drawing functions or to set a new color to an 
Object. The MAllocColor() function allocates a color specified by the 
three argument values (in the range 0-255), identifying the R-G-B color 
components. When the color is no more needed, it should be freed by 
calling the MFreeColor() function.


Palette Mode

When operating in palette mode, a copy of the video palette is hold in 
memory by the library with a counter and a status flags for each entry 
(color cell). If so, a color identifier is equivalent to a cell index. Each 
counter value is initially set to zero and the status flag to 'free'. As a color 
allocation request occurs, the following situations can be in effect:
If none of the already used cells contains the desired R-G-B values and 
there is a free cell, it's status is set to 'used', the counter to 1 and cell R-G-
B values are filled in with the requested ones. The cell index is returned 
as the new color identifier.
If there is a cell containing the desired R-G-B values, then its counter is 
incremented by one and its index is assumed as the color identifier.
Finally, if none cell contains the right values and theree aree no free cell 
available, the library computes which is the cell whose R-G-B values are 
closest to the requested ones, increments its counter and returns the cell 
index as the color identifier.
	When a color is freed, the corresponding palette index counter is 
decremented by one. Moreover, if the counter reaches the zero value, the 
cell flag is reset to 'free' and the palette entry becomes available for 
further allocations.
This handling policy causes an optimal use of the palette resource, 
provided that the application correctly frees all no more needed colors.
	To obtain the palette animation feature, the application should 
reserve one or more palette cells for this purpose via the MAllocCell() 
function call. The cell becomes 'reserved' and its R-G-B values can be set 
at any time by using the MSetCellColor() function call. Moreover its 
index is not used by the library for successive color allocation requests, 
until the program frees the cell using the MFreeCell() function.
If there are no free cells available, MAllocCell() returns, as an error, the 
black color identifier. In this case, every attempt to set the cell R-G-B 
values will obviously fail.


FONT MANAGEMENT

MGUI library provides ten preallocated (static) fonts in any platform, 
referenced in the source code as macros. There are four fixed picth fonts: 
DEFAULT_FONT, FIXED_SMALL, FIXED_MEDIUM and 
FIXED_LARGE. The others are proportional  Times ed Helvetica: 
TIMES_SMALL, TIMES_MEDIUM, TIMES_LARGE, HELV_SMALL, 
HELV_MEDIUM and HELV_LARGE.
Except for the DOS BGI platform, it's possible to load additional fonts 
via the MLoadFont() function call, specifying the font family, font size, 
bold and italic options. The font family is a case unsentive string which 
specifies the font name.
The standard "Times", "Helvetica", "Courier" and "Symbol" values are 
recognized in all environments (except for DOS BGI), but the program 
may load, if required, system specific fonts like 'Terminal' in Windows.
The font size specifies the desired font height. The returned font can have 
an actual height smaller than the requested one, if the system doesn't 
support scaleable fonts or the font itself is fixed size.
An application can load up to 24 new fonts. Notice that, since every font 
loading request allocates an entry even if the the requested font has 
already been loaded before, it's highly recommended to unload any 
unused font via the MUnloadFont() function call.
If the MLoadFont() request cannot be satisfied, the function returns the 
predefined value DEFAULT_FONT as an error. This also offers the 
application the opportunity to continue without testing the returned font 
identifier since it's always valid.


RESOURCE HANDLING

Since release 1.9, the library provides support for resource handling in 
ascii text configuration file with standard .ini format under Windows 
and DOS, with standard .Xdefaults format under X11.
A system configuration file, in the /mgui/sys directory, defines general 
resources as the resolution sensitive static fonts or the default 
background and foreground colors.
The name of this file is system dependant: MGui under X11, mgui.ini 
under Windows, mgui.bcf under BGI, mgui.gcf under DJGPP, 
mgui.wcf under Watcom DOS.
Colors are specified in the standard X format (eg: <yellow> or 
<#ffff00>) under X11. Three decimal values, separated by commas, are 
used instead in all other environments (eg: <255,255,0> for yellow).
Static fonts in the system configuration file are specified in the standard 
X format under X11, using the font file name (.mfn) under BGI and 
Watcom, using the font file name (.fnt) under DJGPP/GRX. In the 
Windows environment the fonts are defined in the format 
<family,height,bold> (eg: <arial,20,1> for arial 20 points bold).

Another resource file is used to determine the resources of a MGUI 
program. This file is located in same directory where the executable 
resides (in the user home directory under Unix) and has the same name 
of the program, with the appropriate extension (.nomeprog under 
Unix).

A resource is identified by the combination of an object name and a 
resource name.
Valid resources for GUI object are the following attributes: 
background/foreground colors, font, text and shadow.
The Object font resource must be expressed as a static font name (eg: 
TIMES_LARGE or FIXED_MEDIUM).
All resources are loaded at program startup, Object resources are 
enabled via the function call MObjectEnableOptions(), after the Object 
creation.
For example, the code:

	label = MCreateLabel(mainshell, "Ctrl+Shift+MouseClick here to customize", 
FIXED_MEDIUM);
	MObjectEnableOptions(label, "label_1", MO_ALL);

will cause the Object 'label' to be customized with all available 
resources for the object named 'label_1'.
Object resources, enabled via MObjectEnableOptions (), can be saved 
to the application resource file at any time by using the call 
MObjectSaveOptions().

MGUI provides a run-time advanced feature that lets the user change, 
and optionally store in the application file, the resources enabled for a 
given Object. This can be done via a dialog window, open by clicking 
the mouse button in an enabled Object while holding down the 
<Ctrl+Shift> keys.

The library API also lets the programmer load/save general application 
resources, by specifying arbitrary object and resource names.

 
EVENT PROPAGATION

Events are messages for MGUI Objects or timeouts that cause a callback 
call.
A callback is a user defined function assigned to a particular event. As 
this event occurs, the library invokes that function as an action for the 
event.
When the application sets a callback, it has the opportunity to join a void 
pointer to it.
This pointer is supplied by the library to callback as the third argument.
Object events are: mouse and keyboard input, window expose and resize, 
or internally generated events such as 'text change', 'color change' or 
'shadow change'.
Unlike many high level programming environments (like OSF/Motif or 
Windows) which require a system window for each Object, MGUI 
requires only a system window for each individual desktop window, 
whatever complex is the Object hierarchy.
System events are received by the library to each window owned by the 
MGUI application, despatched to the 'SHELL' Object (the only one 
bound to the system window) and then received by the destination Object 
via the layout hierarchy.
Mouse events are normally despatched to the Object below the mouse 
pointer. Once an Object has received a 'mouse button press' event, it can 
'grab' the mouse so it can receive all mouse events including the 'button 
release', even if the mouse is over another Object.
Notice that the 'mouse move' event is currently generated and reported 
only if there is a grabbing Object.
Keyboard events are reported by the system to the top level window that 
has the 'input focus'. This window is normally highlighted with a different 
color in the title bar.
When a MGUI top level window receives the input focus, there is a 
single destination Object that can really process keyboard events and it is 
highlighted with a thin black border to indicate it.
Input focus is shifted to other Objects by explicit user selection with the 
mouse, by a MSelectObject() function call in the program, or by 
spontaneous Object grant (as a result to the user pressing on arrow or tab 
keys.
Up and left arrow keys (if not processed by the Object) cause the input 
focus transferring to the previous 'brother' Object. Similarly, down and 
right arrow keys cause the focus to be transferred to the next brother 
Object. Tab and <Shift+Tab> transfer the input focus (if not processed) 
respectively to the next 'cousin' and the previous cousin.


HELLO WORLD

This paragraph shows the source code needed to realize the MGUI 
version of the 'Hello' program (first example in the Kernighan & Ritchie 
C language bible).

/*
 * example 1
 */
#include "mgui.h"

void MGUIMain(int argc, char **argv)
{
	MMessageDialog("Example 1", "Hello, world", " Ok ", NULL);
}

This program generates a window, named 'Example 1', which shows the 
text 'Hello, world' and a push button with the string 'Ok'. The program 
terminates when the user presses the 'Return' key, or when the left mouse 
button is pressed and then released over the push button.
The first program line includes the MGUI include file which contains the 
library function prototypes and structures definitions needed to the 
application. It includes 'mguidefs.h' which includes 'mevent.h' and 
'keycodes.h'.
As you can notice, the program does not start with the canonical main() 
function, due to Windows compatibility requirement (Windows programs 
start at WinMain()).
Unlike Windows imposed WinMain() entry point, MGUIMain() supplies 
the usual 'argc', 'argv' arguments to the application (including the 
Windows platform).
This sample program uses only the MMessageDialog() utility function. 
The first argument the application must supply is a character string which 
identifies the dialog window title. The second one is the message text that 
appears centered in the dialog window. The first button text is specified 
as the third argument, followed by a NULL terminated list of optional 
additional button text. The function return value is an integer that 
specifies which button has been selected by the user (0 for the first 
button, 1 for the second, and so on).
This example shows how simple and compact is MGUI code.


MGUI OBJECTS

There are four MGUI Object categories:

- Root
- Manager
- Main terminal
- Compound terminal

The Root Object is the SHELL. Its main task is to redirect all system 
events received from the TopLevel Window Manager block (keyboard 
and mouse input, window move, resize and expose), to its descendant 
Objects.
SHELL is the only Object with no parent; it has only one direct child 
which is a FORM Object (created automatically with the SHELL).
The FORM belongs to the Manager Object category and it's the only one, 
except for the SHELL, that may contain other Objects (eventually other 
FORMs). It plays a fundamental role in the library architecture taking 
care of children resizing, positioning policy. In addition it despatches to 
the appropriate child any event, not processed by itself, received from its 
parent.
Besides the simple FORM Object are the 'Paged', the 'Clipped' and the 
'Scrolled' FORMs. The first lets you create several children series and 
manage then one by one. The second makes the visible Object area a 
portion of a larger virtual area. By using the MFormSetClip[XY]() 
function calls, the application can change the starting offset of the visible 
area. The Scrolled FORM is a Clipped FORM with a vertical and an 
horizontal SCROLLBAR Objects that permit the user to easily change 
the visible portion of the FORM content.
Main terminal Objects are all the remaining not compound Objects. 
LABEL, EDIT, PBUTTON (push button), TBUTTON (toggle button), 
RBUTTON (radio button), MENU, DRAWAREA and SCROLLBAR 
belong to this category .
Compound terminal Objects are composed by a Main terminal which 
needs the contribution of some Manager and some other Main terminal 
Object to operate.
This category includes the Option EDIT (a combobox) and all LIST 
varieties.
The Scrolled FORM is actually a Compound Manager because it's 
composed by a simple FORM containg a Clipped FORM and two 
SCROLLBARs.
Except for the SHELL, all Object creation functions requires the 'parent' 
Object identifier as the first argument. It must be a FORM or a SHELL 
Object type (the SHELL actually redirects the creation to its FORM 
child).
After the creation, every Object has a gray background and a black text 
color (also if not used). These colors can be changed at any time via the 
MObjectSetColor(), MObjectSetBackgroundRGB() and 
MObjectSetForegroundRGB() function calls.
Objects have a default shadow that can be be modified after the creation 
via the MObjectSetShadow() function call. Allowed shadow types are 
those identified by the macros: WS_SHADOW_IN, 
WS_SHADOW_OUT, 
WS_HATCHED_IN and WS_HATCHED_OUT.
When changing a shadow, you should not contort it, for example, making 
a LABEL look like a PBUTTON.
Additional colors allocation (and free) to generate the 3-D look are made 
by the Object itself, both on creation and when the application assignes 
new colors to it.
Although Object font (when needed) is specified in the creation function 
call, it's possible to change it futher, by using the MObjectSetFont() .

The typical MGUI application flow is summarized in the following:

- SHELL Object creation
- Manager and Terminal Object creation
- Callback setting in some Object
- SHELL window realize
- Wait for user interaction in a loop library function
- Callback execution on Object demands
- Program termination when the appropriate callback is called

The following example shows a program, similar to the first example, 
that uses the above flow.

/*
 * example 2
 */
#include <stdlib.h>
#include "mgui.h"

void ExitCB(MOBJECT obj, void *a, void *b)
{
	if (MMessageDialog("EXIT",
	  "Are you sure you want to quit?", "Sure", "Abort", NULL) 
!= 0)
		return;
	obj = MObjectShell(obj); 
	MShellUnrealize(obj);
	MShellDestroy(obj);
	MGUITerm();
	exit(0);
}

void MGUIMain(int argc, char **argv)
{
	MOBJECT shell, pushbutton;

	shell = MCreateShell("Example 2", 0);
	MCreateLabel(shell, "Hello, world", HELV_L_FONT);
	pushbutton = MCreatePButton(shell, "Ok", TIMES_L_FONT);
	MPButtonSetCallback(pushbutton, ExitCB, NULL);
	MShellRealize(shell);

	MMainLoop();
}

The ExitCB() function uses the typical MGUI Object callback prototype. 
First argument is the calling Object identifier. The second, notifying 
Object data, depends on the particular callback type. The third is the 
application user data, supplied at the callback setting time.
In this case, only the first argument is used. In fact it offers the possibility 
to go back to SHELL Object, ancestor of the calling push button Object, 
via the MObjectShell() function call. The SHELL identifier is then used 
to remove its window from the screen (with MUnrealizeShell()) and to 
destroy the SHELL itself and all its descendant by using the 
MShellDestroy() call.
The callback proceeds calling the termination function MGUITerm() to 
free all resources, and then the canonical exit() function.
Notice that the call to MGUITerm() is particularly important in 
Windows, since it doesn't automatically free resources allocated by a 
terminating program.
	For simplicity, in the following examples, ExitCB() will be used as 
the termination callback, even if its source code will not appear in the 
examples.
	This program code creates a SHELL Object, then a LABEL and a 
PBUTTON as its children.
LABEL Object's task is to show multi line text within a window. By 
default it has no visible shadow and the text is center aligned in the 
horizontal direction. Alignment can be changed via the 
MLabelSetAlignment() function call.
Text to be displayed and the font to be used are speficied respectively as 
the second and third argument of the LABEL creation function.
The PBUTTON Object also shows multi line text, unlike the LABEL it 
has a shadow that gives it a particular 3 D look and provides a callback 
for the mouse button press and release user action.
In this example the push button is created with the "Ok" text, Times 
Large font and the termination callback ExitCB() is set.
The MMainLoop() function call places the program in the application 
events main loop. This function never returns, so the program can 
terminate only via an application defined callback (like ExitCB()).
Next example shows an alternative method to handle the event loop.

/*
 * example 3
 */
#include "mgui.h"

static int quitting = False;

void QuitCB(MOBJECT obj, void *a, void *shell)
{
	MShellUnrealize((MOBJECT)shell);
	MShellDestroy((MOBJECT)shell);
	quitting = True;
}

void MGUIMain(int argc, char **argv)
{
	MOBJECT shell, pushbutton;

	shell = MCreateShell("Example 3", 0);
	MCreateLabel(shell, "Hello, world", HELV_L_FONT);
	pushbutton = MCreatePButton(shell, "Ok", TIMES_L_FONT);
	MPButtonSetCallback(pushbutton, QuitCB, shell);
	MShellRealize(shell);

	MLoopWhileFlag(&quitting, False);
}

As you can note, the termination callback QuitCB() does not call 
MGUITerm() and exit(). It only destroys the shell and sets to True the 
global variable 'quitting'. When the QuitCB() callback returns, the 
program continues execution within the MLoopWhileFlag() function. As 
the value of 'quitting' is no more equal to False (as required by the call), 
MLoopWhileFlag() returns and so does also MGUIMain(). In this case 
the MGUITerm() and exit() function calls are made internally by the 
library (as happens in the example 1).
When setting the QuitCB() callback, the example code passes the 'shell' 
variable as the callback user data. For this reason QuitCB() receives the 
SHELL identifier as the third argument and can use it to destroy the 
SHELL before terminating.
This event loop handling method, used internally by the 
MMessageDialog(), can be used whenever the application needs to 
temporarily block the program flow (also within a callback execution), 
handling events and callbacks, and to resume the control flow after the 
MLoopWhileFlag().


FORM

The simplest version of the FORM Object acts as a container that 
arranges its children one per row ('RowForm') or one per column 
('ColForm'), separated by a given spacing offset. Its natural dimensions 
are those which make possible to display all children at their default 
dimensions. 
Particularly, the dimension corresponding to the child insert direction 
(height in case of RowForm) is equal to the sum of any child dimension 
plus the spacing offsets. The other dimension equals the maximum 
corresponding one among all children plus the spacing offset.
In some child attachment condition or in response to a user resize 
request, the FORM Object adapts its children dimensions and/or 
positions. This positioning and resizing policy is also conditioned by the 
child Object resize capability. Every Object has a default resize capability 
for each direction that can be modified via the MObjectSetResize() 
function call. For example a LABEL can be resized, by default, only in 
the horizontal dimension, while a PBUTTON cannot be resized in both 
directions.
When constructing the layout hierarchy, as Objects are added to a FORM  
the attachment policy acts as follows.
The bottom and right Object outline is always attached to the FORM, the 
top outline is attached to the FORM if it is a 'ColForm', to the previous 
Object otherwise. Finally, the left outline is attached to the FORM if it is 
a 'RowForm', to the previous Object otherwise.
The library provides two functions to change Object's attachment. 
MObjectSetAttachment() is used to remove any of the four links (top, 
bottom, left, right). MObjectSetOffset() can be used to modify the 
corresponding attachment offsets.
The FORM resize capability depends on its own attachment and on its 
children attachments and resize capability.
The FORM Object is always resizeable in a given direction, unless an 
attachment in the same direction is removed, or if every contained child 
is not resizeable and the FORM is not attached to the same parent in both 
ends.
When a resize occurs in a given direction, if every contained Object is 
linked to a brother or to the parent, the size increase/decrease is equally 
distributed among all those children resizeable in that direction. If no 
Object is resizeable, then child spacing is increased/decreased.
If you want to make a FORM unsensitive to a resize request, it's 
sufficient to remove an attachment in a given direction to any of its 
contained Objects.
Next example shows the FORM's child geometry managent policy.

/*
 * example 4
 */
#include <stdlib.h>
#include "mgui.h"

void MGUIMain(int argc, char **argv)
{
	MOBJECT shell, rform, cform, pb, lbl;

	shell = MCreateShell("Example 4", 0);

	rform = MCreateRowForm(shell); 
	lbl = MCreateLabel(rform, "This Label establishes the 
width", DEFAULT_FONT);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	lbl = MCreateLabel(rform, "Small Label", DEFAULT_FONT);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	lbl = MCreateLabel(rform, "Not resizeable Label", 
DEFAULT_FONT); 
	MObjectSetOffset(lbl, -1, -1, 15, -1);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	MObjectSetResize(lbl, False, False); 

	cform = MCreateColForm(shell); 
	pb = MCreatePButton(cform, "dummy", TIMES_L_FONT); 
	pb = MCreatePButton(cform, "Quit", TIMES_L_FONT);
	MObjectSetAttachment(pb, True, True, False, True);
	MPButtonSetCallback(pb, ExitCB, NULL);
	MShellRealize(shell);

	MMainLoop();
}

Objects which have a SHELL as parent are actually contained in a main 
FORM (SHELL's child), so 'cform' is arranged on bottom of 'cform'.
The window dimensions equal the main FORM ones, increased by its 
margins.
The FORM width is determined by its largest child Object, while its 
height is equal to the sum of any child dimension plus the spacing offsets.
The container 'rform' has three LABEL children with a shadow imposed 
to make their dimensions visible. The first forces the parent width 
because it's the largest child. The second is enlarged by the FORM since 
it's resizeable. The last LABEL is moved since its resize capability has 
been inhibited and its natural width is smaller than it's parent one.
The ColForm 'cform' contains two push buttons arranged by columns (in 
the same row). Its natural width is smaller than it's parent one and both 
children are not resizeable in the horizontal direction. However, since its 
left and right ends are attached to the same container, 'cform' is resized 
horizontally to match 'rform' width. The size increase affects only the 
children relative spacing since their relative attachment has been 
removed.


PAGED FORM

The PagedForm contains various children series, visible one at a time, 
each one having its own attachment relationships. The Object's width and 
height are those corresponding to the maxima among all Object series.
The active page can be selected in the source code via the 
MPagedFormSetActivePage() function call, or by the user keyboard 
action in the PageUp, PageDown, Home or the End key, while the input 
focus is owned by an Object within the PagedForm. There is also an 
'extended' version of this Object, which shows the active page number in 
a little LABEL and provides four push buttons to select the active page.
The number of pages in the FORM is specified in the creation function 
call. In order to bind an Object to a particular page, this should be 
selected by first calling MFormSetActivePage() (counting from zero).


CLIPPED FORM

This Object has virtual width and height, corresponding to its natural 
dimensions, and actual width and height, corresponding to its visible 
area.
Virtual dimensions only depend on its contained children and are 
unsensitive to external resize, while actual dimensions are enstablished 
on Object creation and can always be resized.
In order to have only one virtual dimension in effect, it's sufficient to 
specify a negative value (invalid) for the other one.
The clipped area (that visible) can be moved within the virtual area by 
changing its x and/or y coordinates via the MFormSetClipX() and 
MFormSetClipY() function calls.


SCROLLED FORM

Scrolled FORM is just a clipped FORM that provides two SCROLLBAR 
Objects to change the clipping coordinates. Therefore it's actually a 
Compound Object, since it needs two 'brother' Objects (the 
SCROLLBAR) and a parent Object (transparent to the programmer) 
which contains both the FORM and the SCROLLBARs.
As with the clipped FORM, it is possible to have only one virtual 
dimension. In this case, only the SCROLLBAR corresponding to such 
dimension is created.
MGUI functions that create compound Objects all return the terminal 
Object identifier. Some user requests made to a compound terminal 
Object are automatically redirected by the library to the ancestor of the 
compound Object as a whole. This happens for map/unmap, delete/insert 
and for attachment change requests.
The following example uses a scrolled FORM to contains the same 
Object hierarchy as the previous example.

/*
 * example 5
 */
#include <stdlib.h>
#include "mgui.h"

void MGUIMain(int argc, char **argv)
{
	MOBJECT shell, sform, rform, cform, pb, lbl;

	shell = MCreateShell("Example 5", 0);

	sform = MCreateScrolledForm(shell, 80, 60);
 
	rform = MCreateRowForm(sform);
	lbl = MCreateLabel(rform, "This Label establishes the 
width", DEFAULT_FONT);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	lbl = MCreateLabel(rform, "Small Label", DEFAULT_FONT);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	lbl = MCreateLabel(rform, "Not resizeable Label", 
DEFAULT_FONT); 
	MObjectSetOffset(lbl, -1, -1, 15, -1);
	MObjectSetShadow(lbl, WS_SHADOW_IN, 1, 0); 
	MObjectSetResize(lbl, False, False); 

	cform = MCreateColForm(sform); 
	pb = MCreatePButton(cform, "dummy", TIMES_L_FONT); 
	pb = MCreatePButton(cform, "Quit", TIMES_L_FONT);
	MObjectSetAttachment(pb, True, True, False, True);
	MPButtonSetCallback(pb, ExitCB, NULL);

	MShellRealize(shell);

	MMainLoop();
}

The scrolled FORM is 80x60 pixel wide and shows both horizontal and 
vertical SCROLLBARs. If you run this program in Windows or X-
Window, you can notice how the SCROLLBAR adapts to the new 
dimensions when the window is resized.


RBUTTON

The radio-button is used to make an exclusive selection in a group of 
available ones. The group is formed simply by creating all buttons as 
children of the same parent. When a radio-button is selected, the one, if 
any, that was previously selected is automatically deselected. Both the 
Objects generate a callback to notify the application about their new 
selection status. The object data supplied by the callback in the second 
argument is a boolean value that specifies the Object selection status.
Radio-buttons are always created deselected, so, to make the initial 
selection in the Object group, you can use the function call 
MRButtonActivate().
This Object has a particular default color assigning policy: it assumes its 
parent background and foreground color. However, it's possible to change 
them via the provided color setting function calls (like 
MObjectSetColor()).

/*
 * example 6
 */
#include <stdio>
#include <stdlib.h>
#include "mgui.h"

MOBJECT label;

void RadioButtonCB(MOBJECT rb, MVALUE status, void *ii)
{
	char str[64];

	if (status) {
		sprintf(str, "Selected button %d", (int)ii);
		MObjectSetText(label, str);
	}
}

void MGUIMain(int argc, char **argv)
{
	int ii;
	char str[16];
	MOBJECT shell, rform, pb, rb;

	shell = MCreateShell("Example 6", 0);

	rform = MCreateRowForm(shell);
	for (ii=0; ii < 4; ii++) {
		sprintf(str, "Radio %d", ii);
		rb = MCreateRButton(rform, str, HELV_L_FONT);
		MRButtonSetCallback(rb, RadioButtonCB, (void *)ii);
	}
	label = MCreateLabel(rform, "", DEFAULT_FONT);
	MRButtonActivate(rb);

	pb = MCreatePButton(shell, "Quit", TIMES_L_FONT);
	MPButtonSetCallback(pb, ExitCB, NULL);

	MShellRealize(shell);

	MMainLoop();
}

The callback RadioButtonCB() sets the LABEL 'label' text showing 
which is the currently selected button. The Object index is supplied to the 
callback via the application data 'ii', set with the callback. Only when the 
Object status evolves from 0 to 1 the callback changes the LABEL text.
Notice that the initial selection made via the MRButtonActivate() call is 
realized after the LABEL 'label' creation. This is necessary because the 
LABEL is referenced in the callback code, so 'label' must be a valid 
Object identifier.


TBUTTON

The toggle-button is an on/off button, used to operate option selections. 
Unlike radio-buttons, toggle-buttons are never grouped, so they always 
have independent selection status. The default color is taken form the 
parent and the activation callback acts as for the radio-button Object.
Via MTButtonActivate() and MTButtonDeactivate() it's possible to set 
the button activation status.

/*
 * example 7
 */
#include <stdio>
#include <stdlib.h>
#include <string.h>
#include "mgui.h"

#define N_TOGGLE_BUTTON	4

MOBJECT label;
int toggle_status[N_TOGGLE_BUTTON];

void ToggleButtonCB(MOBJECT rb, MVALUE status, void *ii)
{
	char str[128];
	int i;

	toggle_status[(int)ii] = (int)status;
	strcpy(str, "Buttons status: ");
	for (i=0; i < N_TOGGLE_BUTTON; i++)
		strcat(str, (toggle_status[i] ? "  ON" : " OFF"));
	MObjectSetText(label, str);
}

void MGUIMain(int argc, char **argv)
{
	int ii;
	char str[64];
	MOBJECT shell, rform, pb, tb;

	shell = MCreateShell("Example 7", 0);

	rform = MCreateRowForm(shell);
	for (ii=0; ii < N_TOGGLE_BUTTON; ii++) {
		sprintf(str, "Toggle %d", ii);
		tb = MCreateTButton(rform, str, HELV_L_FONT);
		MTButtonSetCallback(tb, ToggleButtonCB, (void *)ii);
	}
	label = MCreateLabel(rform, "", DEFAULT_FONT); 
	MTButtonActivate(tb);

	pb = MCreatePButton(shell, "Quit", TIMES_L_FONT);
	MPButtonSetCallback(pb, ExitCB, NULL);

	MShellRealize(shell);

	MMainLoop();
}

The callback prototype is identical to that for the RBUTTON Object.
By activating the last created toggle-button (MTButtonActivate(tb)), the 
'label' LABEL changes its text before the SHELL (the window) is 
realized.


EDIT

This Object allows the user to supply text input to the application, 
operating in single or multi line mode. In single line mode the text lenght 
is fixed at creation time, while in multi line mode it's limited by the 
macro MAXINT.
The EDIT Object provides a filter facility and five callbacks to control 
input on it.
A callback can be set to intercept the 'Enter' key press; another one is 
called whenever the Object is about to lose the input focus; a callback is 
also available to intercept and optionally refuse user input; a callback can 
be set to receive notification by the EDIT whenever its content changes; 
the last callback notifies the cursor position changing.
The EDIT Object has a validation status which can be set explicitly or 
within a callback. It's possible to show the Object in different colors, 
depending on the validation status.
Arrow keys move the cursor within the Object text, 'Ins' toggles the 
overwrite/insert mode.

/*
 * example 8
 */
#include <stdlib.h>
#include "mgui.h"

#define IsEven(a)	(!((a)&1))

int ValidateString(char *ps)
{
	int val, even, old;

	val = True;
	old = IsEven(*ps);
	if (*ps != '\0') {
		for (ps++; *ps && val; ps++, old=even)
			val = old ^ (even = IsEven(*ps));
	}
	return val;
}

void ValidateCB(MOBJECT edit, EDIT_VAL *ev, void *ii)
{
	ev->text_validated = ValidateString(ev->text);
	if (!ev->text_validated && !ev->focus_lost)
		ev->focus_leave = False;
}

void ValueChangeCB(MOBJECT edit, EDIT_CHANGE *ec, void *ii)
{
	char buff[128];

	if (!strcmp(ec->current_text, "1234567890")) {
		ec->exec = False;
		return;
	}
	strncpy(buff, ec->current_text, ec->pos);
	strcpy(buff + ec->pos, ec->change);
	strcat(buff, ec->current_text + ec->pos + ec->len);
	ec->exec = ValidateString(buff);
}

void NewValueCB(MOBJECT edit, char *new, void *label)
{
	MObjectSetText((MOBJECT )label, new);
}

void ActivateCB(MOBJECT edit, char *text, void *ed)
{
	static int notify;

	notify ^= 1;
	MEditSetTextExt((MOBJECT )ed, text, False, notify);
}

void NewPosCB(MOBJECT edit, EDIT_CURS *ec, void *label)
{
	char str[128];

	sprintf(str, "%-3d - %-3d", ec->pos_y, ec->pos_x);
	MObjectSetText((MOBJECT )label, str);
}

void MGUIMain(int argc, char **argv)
{
	MOBJECT shell, pb, edit, edit2, label;
	MTColor black, white, seagreen, cadetblue;

	black = MBlackColor();
	white = MWhiteColor();
	cadetblue = MAllocColor(0x60, 0x85, 0x95);
	seagreen = MAllocColor(0x70, 0xa5, 0xa0);

	shell = MCreateShell("Sample 8", 0);

	edit = MCreateEdit(shell, "", 20, DEFAULT_FONT); 
	MEditSetFilter(edit, DIGIT, "");
	MEditSetValCallback(edit, ValidateCB, NULL); 
	MEditSetValidatedColors(edit, cadetblue, white);
	MEditSetNotValidatedColors(edit, seagreen, black);

	edit = MCreateEdit(shell, "", 20, DEFAULT_FONT); 
	MEditSetFilter(edit, DIGIT, "");
	MEditSetValueChangeCallback(edit, ValueChangeCB, NULL);

	label = MCreateLabel(shell, "", DEFAULT_FONT);

	edit = MCreateClippedEdit(shell, "", 15, 20, DEFAULT_FONT);
	MEditSetNewValueCallback(edit, NewValueCB, label);

	edit2 = MCreateEdit(shell, "", 20, DEFAULT_FONT);
	MEditSetFilter(edit2, UPALPHA, "_");
	MEditSetActCallback(edit2, ActivateCB, edit);

	label = MCreateLabel(shell, "", DEFAULT_FONT);

	edit = MCreateClippedMLEdit(shell, "", 15, 4, DEFAULT_FONT);
	MEditSetCursorPosCallback(edit, NewPosCB, label);

	pb = MCreatePButton(shell, "Quit", TIMES_L_FONT);
	MPButtonSetCallback(pb, ExitCB, NULL);

	MShellRealize(shell);

	MMainLoop();
}

Example 8 shows the use of the five callbacks available, each set in a 
different Object.
The function ValidateString() returns 'True' when the text string 
argument consists of alternating even and odd ASCII characters.
The ValidateCB() function is called when the first EDIT Object is about 
to lose input focus voluntarily (for example after pressing the 'Tab' key) 
or by force (for example if another window is activated or another Object 
is selected via MSelectObject()).
The structure EDIT_VAL, passed as pointer in the second argument to 
the callback, is defined as follows :

typedef struct {
	char *text;		/* EDIT text */
	short len;		/* Text lenght */
	int key;		/* Key code originator (0 if not 
applicable) */
	unsigned focus_lost;    /* If True, EDIT will lose the focus 
anyway */
	unsigned focus_leave;   /* If set to False, EDIT will keep 
focus */
	unsigned text_changed;  /* If set to True EDIT redraws 
itself */
	unsigned text_validated; /* If set to True EDIT becomes 
validated */
} EDIT_VAL;

EDIT uses this structure to notify the callback about: the Object text 
(with the 'text'field); current text lenght (with the 'len' field); the code of 
the key that caused the call (with the 'key'field) which is equal to zero if 
the call occurs due to an event other than a key press; finally the 
'focus_lost' field notifies whether the application can request the Object 
to keep the input focus or not.
If the 'focus_leave' field is set by the callback to False (and 'focus_lost' 
is False), then the EDIT Object retains the input focus.
Within the callback code the application can change the 'text' string and 
set the 'text_changed' field to True. In this case the Object will perform a 
redraw.
The 'focus_leave' field is preset to True by the Object before calling the 
callback. If the application wants the EDIT to keep the input focus, then 
the callback code should set to False this field.
It's also possible to change the EDIT content from within this callback by 
directly writing the new value in the 'text' pointer and setting the 
'text_changed' field to True.This feature should only be used in single-
line EDIT Objects.
The 'text_validated' field determines the desired validation status for the 
Object.
The ValidateCB() in the above example uses the function 
ValidateString() to set the validation status. Moreover, if  this status is 
False and the input focus not lost, the callback queries the Object to keep 
the input focus.
The ValueChange callback is activated every time the content in the 
EDIT Object changes. This callback lets the application control the input 
in the EDIT and optionally inhibit a change when needed.

In the following is described the structure passed to the callback as the 
second parameter:

typedef struct {
	char *current_text;	/* EDIT text before the change */
	char *change;		/* New text to be inserted */
	int pos;			/* Change start position */
	int len;			/* Changing text lenght */
	unsigned validate;	/* Validation flag */
	unsigned exec;		/* Change accepted by the callback 
*/
} EDIT_CHANGE;

The first field points to the EDIT value before the change occurs, while 
the second points to the new text to inserted (eventually a null string).
The 'pos' field specifies the insert position relative to the current text 
value. The new text, specified by 'change' will substitute 'current_text' 
starting from 'pos' and with lenght 'len' with the value in 'change'.
The 'validate' field is preset to False, unless the callback is called due to 
the application call to MEditSetTextExt(), in which case it has the value 
specified as the third argument in that call.
This field can be changed within the callback to set the desired validation 
status.
If the last field is set to False, then the change is refused.
The callback function ValueChangeCB() in example 8 refuses a text 
modification when it has reached the value "1234567890". Otherwise the 
change is permitted only if the resulting new text causes a True return 
from the ValidateString() function.
	The NewValue callback is the simplest one that lets the application 
control the input. It receives as the Object data (second argument) 
directly the current text value, after the change occurs.
The NewValueCB() in the above example uses its current text to set the 
value in a LABEL Object, identified by the callback application data (the 
third argument).
Notice that the third EDIT in the example is created via a 
MCreateClippedEdit() function call. This function has an additional 
argument which lets the EDIT Object have an actual lenght greater than 
the visible one.
The Activate callback, called by the EDIT Object when the 'Enter' 
key is pressed on it, receives as second argument the Object text. In the 
above example the ActivateCB() function is used to set its current text in 
the third EDIT Object. When the value of the 'notify' parameter passed 
to MEditSetTextExt() is a boolean True, the third Object will call its 
ValueChange callback.
	Functions MBlackColor() and MWhiteColor() respectively return 
the preallocated black and white color identifiers. The 'seagreen' and 
'cadetblue' colors, allocated via the MAllocColor() function, should be 
freed with a call to MFreeColor() when no more needed. This is however 
not necessary since they are used for the entire program execution, and 
they are automatically freed by the MGUITerm() function call.
A filter is set to the first EDIT Object making it accepts digit characters 
only. The validation status for this Object is highlighted with different 
colors.
The filter set in the fourth EDIT lets it accept alphabetic characters, 
converted to upper case, and the additional character '_'.
Last EDIT is a clipped multi-line type. A scrolled version is also available 
via the MCreateScrolledMLEdit(), with the same arguments.
The CursorPosition callback is set to this Object in the example. It traces 
cursor position within the EDIT while it changes.
The structure notified by the EDIT to this callback (a pointer to it as the 
second parameter) is described in the follwing:

typedef struct {
	int pos;		/* position in the stream */
	int pos_x;		/* position x */
	int pos_y;		/* position y */
} EDIT_CURS;


SCROLLBAR

The SCROLLBAR Object is primarily present in the library to implement 
compound Objects as the scrolled FORM or LIST. It is here described 
because it's useful for creating new compound Objects. 
Available in horizontal and vertical appearance, it's resizable only in the 
scrolling direction and the size is imposed by the Objects it's attached to.
The SCROLLBAR has three long integer attributes: Max, N, Pos. Max 
and N are specified by the program at Object creation time, but they can 
be changed later via the API. The last is usually changed via the user 
scrolling action and can be changed via fuction call.


... Something still missing here ... Sorry ...

TRACING LOG MESSAGES

The library provides utility functions to help in tracing the program 
execution, giving the opportunity to write messages in a file and/or to 
show them at any time in a window, activated by the key sequence  
<Shift-Ctrl-F1>.
The optional filename must be specified in the call to MLogInit(), 
normally in the MGUIMain() function. MLogInit() sets also the initial 
tracing level, the log window geometry and the number of messages to 
hold in the buffer.
A log message is generated by the program via the call to Mlog(). The 
first argument specifies the message's level, the remaining are a format 
string and the value list, with printf() syntax.
The call to Mlog() will take effect only if the current tracing level is equal 
yo or higher than the value of the first argument.
For example, the call:

Mlog(3, "this is line: %d", __LINE__);

will generate a log message only if the current tracing level is equal to or 
higher than 3.
The tracing level can be changed at any time by the program code via a 
call to the function MLogSetLevel(). The user can also change this level 
run-time, activating the control dialog with the key sequence <Shift-Ctrl-
F2>.
A more sophisticated filtering can be obtained by using the function 
MMaskedLog().
The message will take effect if the current tracing level is equal to or 
higher than the level in the call and the current bit-mask has at least one 
bit in common with the mask specified in the call.

