Files
plib/doc/pui/BasicPUI.html

637 lines
25 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="John F. Fay">
<meta name="GENERATOR" content="Mozilla/4.75 [en] (Win98; U) [Netscape]">
<meta name="keywords" content="PUI, PLIB, OpenGL, UI, user, interface, library, portable, picoscopic, widget, GUI, fast, GLUT, introduction, callback, puButton, puButtonBox, puFrame, puInput, puMenuBar, puOneShot, puText, puInit">
<meta name="description" content="The PLIB Picoscopic User Interface (PUI) Library is designed to be a simple, easy-to-use graphical user interface. It is based on the OpenGL graphics language and requires a windowing system, either the OpenGL Utility Toolkit (GLUT) or another similar one. This document's purpose is to provide an introduction to the basics of PUI.">
<title>BasicPUI</title>
</head>
<body>
<center>
<h1>
Introduction to Using the Picoscopic User Interface</h1></center>
<center>
<h1>
John F. Fay</h1></center>
<center>
<h1>October 18, 2000</h1>
(Updated by <a href="mailto:ude@handshake.de">Sebastian Ude</a> on October 02, 2001)
</center>
<h2>
Contents</h2>
<table>
<tr>
<td>1.</td>
<td><a href="#Introduction: Graphical User Interfaces and">Introduction:&nbsp;
Graphical User Interfaces and Windowed Programs</a></td>
</tr>
<tr>
<td>2.</td>
<td><a href="#Elementary PUI">Elementary PUI</a></td>
</tr>
<tr><td></td>
<td>2.1 <a href="#Creating User Interface Widgets">Creating User Interface
Widgets</a></td>
</tr>
<tr><td></td>
<td>2.2 <a href="#Invoking PUI">Invoking PUI</a></td>
</tr>
<tr><td></td>
<td>2.3 <a href="#Widget Callbacks">Widget Callbacks</a></td>
</tr>
<tr>
<td>3.</td>
<td><a href="#Conclusion">Conclusion</a></td>
</tr>
</table>
<h2>
<a NAME="Introduction: Graphical User Interfaces and"></a>1.&nbsp; Introduction:&nbsp;
Graphical User Interfaces and Windowed Programs</h2>
The Picoscopic User Interface (PUI) is designed to be a simple, easy-to-use
graphical user interface.&nbsp; It is based on the OpenGL graphics language
and requires a windowing system, either the OpenGL Utility Toolkit (GLUT)
or another similar one.&nbsp; The gentle reader is assumed either to be
familiar with OpenGL and his windowing system or at least to have their
manuals at hand.
<p>Basic to a GUI is the idea of a widget.&nbsp; A widget is something
that appears on the computer screen and which transfers data from the user
to the program or from the program to the user.&nbsp; The user can activate
a widget by pressing a key, clicking a mouse button, or by using some other
input device.&nbsp; This lets the user send information to the program.&nbsp;
A widget can also display text or a graphic, allowing the program to transfer
information to the user.
<p>A windowing system requires a specific style of program which differs
from a text-based program in several fundamental ways.&nbsp; First, instead
of starting at the beginning of a problem and stopping at the end, a windowed
program starts by creating the windows and then enters an infinite loop
in which it responds to user inputs.&nbsp; Second, instead of having a
self-contained hierarchy of functions which call each other, a windowed
program is controlled by the windowing system which calls functions as
it sees fit.&nbsp; The following diagram shows the structure of a typical
windowed program.
<pre>
+------------------+
| Main Program | The application developer
| Set up window(s) | supplies this.
| and widget(s) |
+------------------+
|
V
+----------------+
| Window Manager | The window manager library
| (like GLUT) | supplies this.
+----------------+
|
+------+--------+---------------+---------------+----&gt; etc.
| | | |
V V V V
+----------+ +----------+ +----------+ +----------+
| Window | | Window | | Window | | Window | The application
| Mouse | | Keyboard | | Idle | | Display | developer
| Callback | | Callback | | Callback | | Callback | supplies these.
+----------+ +----------+ +----------+ +----------+
| | | |
V V V V
+----------+ +----------+ May call +----------+
| PUI | | PUI | PUI functions | PUI | PUI
| Mouse | | Keyboard | for default | Display | supplies
| Function | | Function | behaviors | Function | these.
+----------+ +----------+ +----------+
| |
+-------+-------+
|
+-------+-------+---------------+------&gt; etc.
| | |
V V V
+----------+ +----------+ +----------+
| Widget 1 | | Widget 2 | | Widget 3 | The application developer
| Callback | | Callback | | Callback | supplies these.
+----------+ +----------+ +----------+
</pre>
<p>The functions that the application developer supplies are called "callbacks"
because the windowing system or user interface system "calls back" into
the application.
<p>A windowed program with a user interface, then, consists of a main program
and a set of callbacks.&nbsp; The callbacks may invoke other function in
turn, but these are all arranged in hierarchical trees underneath the callbacks.
<p>A windowed program executes differently from a typical hierarchical
program as well.&nbsp; It begins with the main program setting up the window(s)
and the user interface.&nbsp; The main program then calls the window manager,
which contains an infinite loop and never returns control to the main program.&nbsp;
(GLUT in particular has this behavior; I cannot speak for all window managers.)&nbsp;
When the window manager needs to redraw the display that is shown on the
screen, it calls the application's Window Display Callback.&nbsp; When
the user moves the mouse or clicks a mouse button, the window manager calls
the application's Window Mouse Callback.&nbsp; When the user presses a
key on the keyboard, the window manager calls the application's Window
Keyboard Callback.&nbsp; Other input devices cause the window manager to
call other callbacks in the application.&nbsp; Finally, if the user hasn't
done anything for a while, the window manager will call the application's
Window Idle Callback.
<p>In building a window callback, the application developer must be sure
to call the appropriate PUI functions.&nbsp; The applications's Window
Mouse Callback, for example, must call the PUI mouse function "puMouse"
if the user interface is to process a mouse click.&nbsp; The application's
Window Display Callback, besides rendering any graphics in the window,
must also call the PUI display function "puDisplay" in order to display
the widgets in the user interface.
<p>When the application developer's window callback calls the appropriate
PUI function, PUI determines which (if any) widget the user has just activated
with his mouse, keyboard, or other input device.&nbsp; PUI then calls that
widget's callback function which the application developer must supply
and which provides the actual heart of the interface.&nbsp; The callback
for an input widget will probably read the text that the user has typed
there and pass it on to the application.&nbsp; The callback for a button
widget may turn something in the program on or off.&nbsp; What a callback
does is limited only by the application developer's imagination.
<h2>
<a NAME="Elementary PUI"></a>2.&nbsp; Elementary PUI</h2>
Using the Picoscopic User Interface on an elementary level requires three
things:&nbsp; setting up the user interface widgets, invoking PUI from
the window callbacks, and supplying the widget callbacks.
<p>PUI was written in C++, designed to be invoked from C++ programs.&nbsp;
The following text and examples will assume a program written in C++.
<h3>
<a NAME="Creating User Interface Widgets"></a>2.1 Creating User Interface
Widgets</h3>
Most (or all) widgets have certain properties in common.&nbsp; These are:
<ul>
<li>
position - the x- and y-coordinates, in pixels, of the lower left-hand
corner of the widget relative to the lower left-hand corner of the window</li>
<li>
size - the width and height of the widget, in pixels</li>
<li>
callback - the application program's function which is called when the
widget is activated</li>
<li>
value - a number or character string that is associated with the widget</li>
<li>
label - text that is printed next to the widget</li>
<li>
legend - text that is printed inside the widget (some widgets only)</li>
</ul>
PUI supports other widget properties, but these are enough to allow the
application developer to create a simple user interface.
<p>Each widget in the Picoscopic User Interface is an object in C++.&nbsp;
The application developer creates a widget by defining a variable to point
to the object and creating a new object:
<pre>
puButton *button = new puButton ( 10, 10, 100, 30 ) ;
</pre>
<p>To set the properties of a widget, the application developer calls methods
in the object:
<pre>
button->setPosition ( x, y ) ; // Sets the position of the widget to
(x, y)
button->setSize ( w, h ) ; // Sets the size of the widget to (w, h)
button->setCallback ( widget_cb ) ; // Sets the callback to
"void widget_cb ( puObject *ob )"
button->setLegend ( "Press Me" ) ; // Sets the legend
button->setLabel ( "A Button:" ) ; // Sets the label
button->setLabelPlace ( PUPLACE_LOWER_LEFT ) ; // Makes the label print on the button's
left
</pre>
<p>Other allowed values for the label position are:
<ul>
<li>PUPLACE_ABOVE_LEFT
<li>PUPLACE_ABOVE_RIGHT
<li>PUPLACE_TOP_LEFT
<li>PUPLACE_TOP_CENTERED
<li>PUPLACE_TOP_RIGHT
<li>PUPLACE_UPPER_LEFT
<li>PUPLACE_UPPER_RIGHT
<li>PUPLACE_CENTERED_LEFT
<li>PUPLACE_CENTERED_RIGHT
<li>PUPLACE_LOWER_LEFT
<li>PUPLACE_LOWER_RIGHT (default)
<li>PUPLACE_BOTTOM_LEFT
<li>PUPLACE_BOTTOM_CENTERED
<li>PUPLACE_BOTTOM_RIGHT
<li>PUPLACE_BELOW_LEFT
<li>PUPLACE_BELOW_RIGHT
</ul>
<p>For a detailed description of these have a look at the
<a href="http://plib.sf.net/pui/">PUI Programmers Guide</a>.
<p>All of these calls are optional.&nbsp; If the application developer
does not want to label a widget, he simply does not call "setLabel" or
"setLabelPlace".&nbsp; Similarly, if he has set the widget's position and
size while creating the widget, there is no need to call "setPosition"
or "setSize".
<p>The following subsections describe some of the widget types that PUI
supports.
<h4>
2.1.1 Button</h4>
The button ("puButton") is a rectangle, usually containing a legend, which
is activated when the user clicks the mouse on it.&nbsp; It has two possible
values, off and on; its actual value changes each time the user clicks
on it.
<p>The button has two possible methods of construction:
<ul>
<li>
puButton ( x1, y1, x2, y2 ) - creates a button with lower left-hand coordinates
of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
<li>
puButton ( x1, y1, "text" ) - creates a button with lower left-hand coordinates
of (x1, y1) and containing the text "text".&nbsp; The size is set by the
size of the text.</li>
</ul>
<h4>
2.1.2 Button Box</h4>
The button box ("puButtonBox") is a large rectangle containing a set of
buttons, each with text next to it, which the user can select.&nbsp; It
is sometimes called a radio button.&nbsp; It is created by creating a null-terminated
list of labels and then by calling the constructor function:
<pre>
char **labels = { "Label1", "Label2", "This is Label3", "Four", NULL } ;
puButtonBox my_box = new puButtonBox ( x1, x2, y1, y2, labels, &lt;0|1&gt; ) ;
</pre>
<p>This creates a button box with lower left-hand coordinates of (x1, y1)
and upper right-hand coordinates (x2, y2).&nbsp; The number of buttons
is specified by the number of entries in the "labels" array; each string
before the NULL gets a button.&nbsp; The final argument in the constructor
specifies whether the user can select multiple buttons (0) or whether selecting
a new button will deactivate the previously-selected button (1).
<p>The button box should not be given a legend.
<h4>
2.1.3 Frame</h4>
The frame ("puFrame") is a rectangular area that provides a background
for other widgets.&nbsp; It should be defined before any other widgets
that go inside it or else it will cover them up.&nbsp; It is constructed
by the following function call:
<ul>
<li>
puFrame ( x1, y1, x2, y2 ) - creates a frame with lower left-hand coordinates
of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
</ul>
The frame should not be given a legend.&nbsp; It does not support a callback
either.
<h4>
2.1.4 Input Box</h4>
The input box ("puInput") is a rectangular area into which the user can
type text.&nbsp; The user must first click the mouse inside the area and
then type the text.&nbsp; He concludes by pressing &lt;Enter&gt; or &lt;Tab&gt;
or by clicking the mouse outside the input box.
<p>An input box is constructed by the following function call:
<ul>
<li>
puInput ( x1, y1, x2, y2 ) - creates an input box with lower left-hand
coordinates of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
</ul>
The input box should not be given a legend.
<h4>
2.1.5 Menu Bar</h4>
The menu bar ("puMenuBar") is easily the most complicated widget written
up here.&nbsp; It consists of a horizontal bar containing buttons which
the user can click on.&nbsp; The bar is always situated on the left-hand
edge of the window and is usually in the upper left-hand corner.&nbsp;
It is constructed by the following function call:
<br>
<ul>
<li>
puMenuBar *menu = puMenuBar ( y ) - creates a menu bar with the lower left-hand
corner "y" pixels above the lower left-hand corner of the window.&nbsp;
A value of -1 for "y" will put the menu bar in the upper left-hand corner
of the window.</li>
</ul>
<p><br>Once the menu bar has been constructed, it must be loaded with its
entries and submenus.&nbsp; A submenu is the list that drops down when
the user clicks on an entry in the menu.&nbsp; A typical menu bar will
have the entries "File", "Edit", "Search", and "Help".&nbsp; Under the
"File" entry is a submenu with entries "New", "Open", "Save", "Save As",
a separator, "Page Setup", "Print", another separator, and "Exit".&nbsp;
Each entry in the submenu has its own widget callback function.&nbsp; To
create a submenu, the application developer must first create two null-terminated
lists of character strings and callback functions:
<pre>
char *file_submenu [] = { "Exit", "-----", "Print", "Page Setup", "-----",
"Save As", "Save", "Open", "New", NULL } ;
puCallback file_submenu_cb[] = { exit_cb, NULL, print_cb, page_setup_cb, NULL,
save_as_cb, save_cb, open_cb, new_cb, NULL } ;
</pre>
<p>Notice here that the submenu entries are placed in the list from bottom
to top.&nbsp; After the last character string is a NULL entry; this tells
PUI that there aren't any more entries in the submenu.&nbsp; The callbacks
for the separators are also null, indicating that there is no callback
for the separator.&nbsp; The submenu is added to the menu bar with a call
to the "add_submenu" function:
<pre>
menu->add_submenu ( "File", file_submenu, file_submenu_cb ) ;
</pre>
<p>Further calls to "add_submenu" add the other submenus:
<pre>
char *edit_submenu [] = { "Select All", "-----", "Paste", "Copy", "Cut",
"-----", "Undo", NULL } ;
puCallback edit_submenu_cb[] = { select_all_cb, NULL, paste_cb, copy_cb, cut_cb,
NULL, undo_cb, NULL } ;
menu->add_submenu ( "Edit", edit_submenu, edit_submenu_cb ) ;
char *search_submenu [] = { "Find Next", "Find", NULL } ;
puCallback search_submenu_cb[] = { find_next_cb, find_cb, NULL } ;
menu->add_submenu ( "Search", search_submenu, search_submenu_cb ) ;
char *help_submenu [] = { "About", "Help", NULL } ;
puCallback help_submenu_cb[] = { about_cb, help_cb, NULL } ;
menu->add_submenu ( "Help", help_submenu, help_submenu_cb ) ;
</pre>
<p>When the last submenu has been added, the application developer must
close the menu bar:
<pre>
menu->close() ;
</pre>
<p>This is absolutely necessary or else PUI will think that any widgets
the application defines later are supposed to go into the menu bar.
<p>The menu bar does not support a legend.&nbsp; It does not support a
callback itself, although all the entries in the submenus certainly do
support callbacks.&nbsp; Repositioning and resizing a menu bar will be
problematic as well.&nbsp; There may be an occasion when a menu bar can
take a label, but this would be rare.
<h4>
2.1.6 One-Shot Button</h4>
The one-shot button ("puOneShot") is a button whose value is always reset
immediately to zero after it has been activated.&nbsp; In all other respects
it is the same as the regular button.&nbsp; It is created in the same way
as the button:
<ul>
<li>
puOneShot ( x1, y1, x2, y2 ) - creates a one-shot button with lower left-hand
coordinates of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
<li>
puOneShot ( x1, y1, "text" ) - creates a one-shot button with lower left-hand
coordinates of (x1, y1) and containing the text "text".&nbsp; The size
is set by the size of the text.</li>
</ul>
<h4>
2.1.7 Text Box</h4>
The text box ("puText") is an output-only widget which displays a character
string.&nbsp; It is created by the following constructor:
<ul>
<li>
puText ( x, y ) - creates a text box at the point (x, y) in the window</li>
</ul>
The application actually adds the text by assigning a label and a label
place to the text box.&nbsp; The label place will determine where relative
to the position of the text box the text itself will appear.
<h3>
<a NAME="Invoking PUI"></a>2.2 Invoking PUI</h3>
The summary of invoking PUI is very simple:
<ul>
<li>
At the beginning of the program, before creating any widgets, the application
must call the function "puInit ()".</li>
<li>
If the application developer wants PUI to process a mouse click, he must
have the application call the function "puMouse ( button, updown, x, y
)".</li>
<li>
If the application developer wants PUI to process a mouse motion, he must
have the application call the function "puMouse ( x, y )".</li>
<li>
If the application developer wants PUI to process a key from the keyboard,
he must have the application call the function "puKeyboard ( key, updown
)".</li>
<li>
If the application developer wants PUI to display the user interface, he
must have the application call the function "puDisplay ()".</li>
</ul>
The application developer must create window callbacks for the window manager
to call when the user interacts with the computer.&nbsp; The following
are taken from GLUT, but another window manager will have similar callback
requirements.
<h4>
2.2.1 Main Program Code</h4>
In the main program, the application developer usually places the following
or similar statements:
<pre>
// Create the GLUT window and the OpenGL context
glutCreateWindow ( "PUI Application" ) ;
// Set up the GLUT window callbacks
glutDisplayFunc ( displayfn ) ; // display the window
glutMouseFunc ( mousefn ) ; // process mouse clicks
glutMotionFunc ( motionfn ) ; // process mouse moves
glutPassiveMotionFunc ( motionfn ) ;
glutKeyboardFunc ( keyboardfn ) ; // process key presses
glutIdleFunc ( displayfn ) ; // what to do when nothing's happening
// Initialize PUI
puInit () ;
// Set up the widgets here
</pre>
<h4>
2.2.2 Window Callbacks</h4>
The application's window callbacks should generally look like this.&nbsp;
Again, these are written assuming GLUT; other window managers should be
similar.
<pre>
void displayfn ( void )
{
// stuff to display any non-PUI drawings
// update any PUI widgets that update by themselves ... like a timer display
// redisplay PUI
puDisplay () ;
// Finish up
glutSwapBuffers () ;
glutPostRedisplay () ;
}
void mousefn ( int button, int updown, int x, int y )
{
// Invoke the PUI mouse function
puMouse ( button, updown, x, y ) ;
glutPostRedisplay () ;
}
void motionfn ( int x, int y )
{
// Invoke the PUI mouse motion function
puMouse ( x, y ) ;
glutPostRedisplay () ;
}
void keyboardfn ( unsigned char key, int, int )
{
// Invoke the PUI keyboard function
puKeyboard ( key, PU_DOWN ) ;
glutPostRedisplay () ;
}
</pre>
<h4>
2.2.3 Miscellaneous Other Tidbits</h4>
If the application developer wishes to delete a widget, he should not delete
the object directly.&nbsp; Instead he should call the PUI function "puDeleteObject
( ob )" with his widget pointer as the argument.
<h3>
<a NAME="Widget Callbacks"></a>2.3 Widget Callbacks</h3>
The final pieces to the puzzle are the widget callbacks.&nbsp; These are
of the form
<pre>
void widget_cb ( puObject *ob )
{
// code goes here
}
</pre>
<p>where "puObject" is the C++ type for a generic widget.&nbsp; When PUI
calls a widget callback, it passes to it the address of the widget whose
activation caused the callback.&nbsp; This is useful because it allows
a single callback for multiple widgets:
<pre>
void widget_cb ( puObject *ob )
{
if ( ob == button ) // the button from section 2.1
{
...
}
else if ( ob == my_box ) // the button box from section 2.1.2
{
...
}
else
{
printf ( "Error - unknown widget" ) ;
}
}
</pre>
<p>A widget callback needs to be either a regular function (global
or defined in the same file that contains the widget's definition) or a
static member function of a class.&nbsp; It cannot be a regular member
function of a class.
<h4>
2.3.1 Widget Values</h4>
It is frequently very useful in a callback to know the value of a widget.&nbsp;
A PUI widget has an integer value, a floating-point value, and a character
string value.&nbsp; These values are kept synchronized as much as possible.&nbsp;
For example, if the application assigns an integer value to a widget, the
floating-point value is set equal to the integer and the integer is printed
into the character string.
<p>An application program can use the following function to retrieve the
value of a PUI widget ("ob" is the pointer to the object):
<pre>
int ivalue1 = ob->getValue () ; // No argument, return the integer value
int ivalue2 ;
ob->getValue ( &amp;ivalue2 ) ; // Place the integer value in the argument
float fvalue ;
ob->getValue ( &amp;fvalue ) ; // Place the floating-point value in the argument
char svalue[PUSTRING_MAX] ; // Create a string
ob->getValue ( svalue ) ; // Copy the string value into the argument
// Note that the argument is of type "char *"
char *sptr ;
ob->getValue ( &amp;sptr ) ; // Have the pointer point to the string value
// Note that the argument is of type "char **"
</pre>
<p>The values of the various widgets have the following meanings:
<ul>
<li>
Button:&nbsp; 0 - turned off; 1 - turned on</li>
<li>
Button Box:&nbsp; If only one button can be activated at a time, the value
is the number of the button which is activated.&nbsp; If multiple buttons
can be activated at once, then the bits in the integer value corresponding
to the activated buttons are one and the bits corresponding to the inactive
buttons are zero.</li>
<li>
Frame:&nbsp; no value</li>
<li>
Input:&nbsp; the string value is the character string that the user has
typed in</li>
<li>
Menu Bar:&nbsp; no value</li>
<li>
One Shot Button:&nbsp; value is always zero</li>
<li>
Text:&nbsp; no value</li>
</ul>
<h2>
<a NAME="Conclusion"></a>3.&nbsp; Conclusion</h2>
This has been offered as an introduction to the Picoscopic User Interface.&nbsp;
It makes no warranty as to its accuracy although efforts have been made
to make it correct.&nbsp; It is offered in the hope that the gentle reader
will find it useful.
<p>The PUI has considerably greater capabilities than have been listed
here.&nbsp; There are well over a dozen additional types of widgets.&nbsp;
Additionally, the application developer can do many more things with this
widgets than have been described here.
<p>"As to more than these, my son, beware.&nbsp; Of the making of many
books there is no end, and in much study there is weariness for the flesh."
- Ecclesiastes 12:12
</body>
</html>