![]() |
PUI: A Picoscopic User InterfaceProgrammers Guide. |
PUI is now a part of PLIB.
The PUI FAQ list is here.
Like most similar GUI's (MUI, Xforms, FLTK, GLUI, etc), PUI is comprised of a base class (puObject) from which all the interesting widgets are derived. Most of the packages functionality is concentrated in the puObject class.
AbdulWajid Mohamed
Dave McClurg added the puListBox and puFilePicker widgets.
John Fay added a few widgets and other things and reworked this
document.
The needs of PUI are small - as a minimum, call the puMouse
function whenever the mouse is clicked or dragged, call the puKeyboard
function whenever a key is pressed, call the puDisplay
function frequently enough to maintain smooth interactions.
The creation of the user interface is similarly simple, calling the
constructor function for the objects you need (with the dimensions of the
active area of each object) - then add labels, legends, callback functions,
etc.
Whenever the puMouse function detects that the
mouse coordinate lies over an active widget, it calls the user-supplied
callback function and takes the necessary actions to update the graphics
on the next call to puDisplay.
When you declare most widgets, you must define the size of ABOX for
the widget. (This is actually the pixel coordinates of the rectangle around
the active area of the widget - with the origin at bottom-left of the window).
You can always find the type of an object derived from puObject by calling:
For the purposes of printing diagnostics, etc there is also:
You can also move or resize the ABOX of a widget after it has been declared
using:
The following functions allow you to manipulate
the value of the widget:
Some kinds of widget have a default value that they can easily be reset
to.
IMPORTANT NOTE: When you pass a 'char*' to setValuator, it is your responsibility
to ensure that this pointer is pointing at enough memory to store the longest
possible string that this widget can possibly need. The string in
the puValue class is defined as being PUSTRING_MAX characters long; currently
this is 80.
Passing NULL to setValuator causes PUI to revert to using an internal
variable to store the widget's state.
Each widget can also retain a pointer to user-supplied data:
Whilst most widgets default to a style of PUSTYLE_SHADED, some of the
more complex types such as sliders and menu's pick more complex defaults
in order to look 'reasonable'. You can still override those defaults -
but the results can often be less than desirable.
In addition to the pre-defined styles, PUI allows you to create his
own drawing function and save the related drawing data. This is done
by means of the "render data" and "render callback." A render callback
is a user-defined function that has the following definition:
PUI also has functions to allow the user to retrieve and invoke the
render callback:
There are occasionally times when you'd like the widget to be activated
when the user PRESSES the mouse button instead of when he RELEASES it (which
is the default). PUI lets you make widgets that are activated on both button-down
and button up. You can even tell PUI to call your callback continually
all the time the left button is pushed while the cursor is inside the widget:
puOneShot's have no special API - everything they need is in the puButton
API.
There are several choices to be made relating to when (or how often)
you wish your callback function to be called:
The puTriSlider has an additional option which allows you to freeze
the boxes on the ends of the slider bar. The following functions
let you do this:
puFrames have no special API - everything they need is in the puObject
API.
The only special API for puText is its constructor function:
Everything else that puText widgets need is in the puObject
API.
First, create the puInput object:
A puInput object can be in two states - accepting keystrokes - or ignoring
them. Use these functions to toggle between the two states:
The text area contains an 'I' bar cursor and a highlighted 'select'
area. You can get and set the character positions (not pixel coordinates)
of those entities:
When typing into a puInput box, the Backspace, Delete, Home, End, Left
and Right Arrows, Space, Return, Tab, Esc and ^U keys have the expected
functions. All printable characters are inserted into the text. Everything
else is not accepted by the puInput and is available to other functions.
If you want to restrict the characters that the input widget will accept,
you use the following functions:
The following functionality from the puInput widget is also implemented
in the puLargeInput widget:
The puLargeInput widget also has a few other functions which may be
handy:
The purpose of a puGroup is allow you to group together other puObjects
and to operate on them en-masse.
When you want to create a group of puObjects
using a puGroup, you construct the puGroup itself, then construct all the
widgets that you want to have inside it. When you have finished adding
widgets to the puGroup, you call:
Doing a puObject::hide() on a puGroup will hide all the objects inside
the puGroup. Doing a puObject::greyout() on a puGroup prevents anything
inside that group from being clicked. Colours, styles, etc are NOT propagated
from puGroup to its children.
The coordinates of puGroup child objects are always specified relative
to the bottom-left corner of the puGroup rather than in absolute screen
coordinates.
The puGroup widget is not drawn. It is commonly a good thing to
do, but certainly not essential, to make the first widget inside a puGroup
to be a puFrame of the group's desired size.
The frame will provide a background for all the other widgets in the group.
The difference between a simple puGroup and a puInterface is that when
an interface is enabled, it takes priority over other widgets so that they
cannot be clicked upon. Widgets such as popup menus are typically puInterfaces
which group a number of
puButtons.
The PUI system itself maintains a private global puInterface which is
used to group together all of the puObjects that
the application generates that are not grouped into other puInterfaces.
Like most other puObjects, puButtonBox has a 'value' that can be set
using puObject::setValue(int i) and read using puObject::getValue(). If
'one_button' is set TRUE then the puButtonBox will use its value as the
index of the radio-button that is currently pressed. If 'one_button' is
FALSE then the puButtonBox will limit the number of buttons to 32 and use
its value as a mask indicating which buttons are set ('1'==button pressed,
'0'==button not pressed).
By default, if one_button==TRUE then the first button is highlighted
since the 'value' of the puButtonBox is zero. If one_button==FALSE then
none of the buttons are pressed by default since the value is 0x00000000
and that indicates no buttons pushed.
In the one_button==TRUE case, setting the value to something out of
range will result in none of the radio buttons being highlighted.
One significant difference between puPopups and other puObjects is that
it starts off hidden (puObject::isVisible()==FALSE) - and the application
(or some other widget) has to make it visible in order for it to DO something.
It's possible to use a puPopup to create a popup menu, as a part of
a drop-down menu and to implement dialog boxes and alert boxes.
This causes the dialog box to pop up onto the screen. When the 'OK'
button is pressed (or the RETURN key is hit - since the button has makeReturnDefault(TRUE)
set), the 'go_away_callback' is called - which deletes the dialog box (which
in turn causes the destruction of all the contents of that box).
To create the puPopupMenu object:
Each item that you add will be translated into an appropriately sized,
styled and coloured puOneShot (which is only visible to the application
when passed to the callback function).
First, create the puMenuBar object:
Next, set up the colours for the menu - just as with any other puObject,
then add the individual items:
Each item that you add will be translated into an appropriately sized,
styled and coloured puPopupMenu which is hidden and revealed appropriately
as each name is clicked upon.
Don't forget (since this is a kind of puInterface) that you need to
call:
Example:
The puListBox widget supports three additional function calls in its
API. They are as follows:
The API for puFilePicker:
This function is typically called from the glutDisplayFunc callback.
Example:
The return result is TRUE if one of the widgets actually used the keystroke.
This can be used to determine if the keyboard event was 'consumed' by the
user interface - or whether it should be used in some other application-specific
way. It is also true to say that in a single-buffered application, the
puDisplay
function doesn't need to be called until puKeyboard() returns TRUE (unless
of course the application chooses to change a colour or a label or something).
Example:
These are the code symbols for the special keys:
Since GLUT doesn't tell you which mouse buttons are held while the mouse
is being 'dragged', the second form of the 'puMouse' function (which is
usually called from the glutMotionFunc and glutPassiveMotionFunc callbacks),
assumes that the mouse buttons are the same as for the last call to the
first form of the puMouse() call (which does have button information).
The return result is TRUE if one of the widgets was actually hit by
the mouse event. This can be used to determine if the mouse event was 'consumed'
by the user interface - or whether it should be used in some other application-specific
way. It is also true to say that in a single-buffered application, the
puDisplay
function doesn't need to be called until puMouse() returns TRUE (unless
of course the application chooses to change a colour or a label or something).
It is also possible to show and hide the PUI cursor (note that it is
hidden by default):
If you enable this function on a machine that does have a hardware (or
at least operating-system generated) cursor, then you will probably notice
that the PUI cursor lags behind the 'real' cursor. This is because the
PUI cursor can only be drawn at the end of the frame, after all the other
OpenGL drawing functions are complete. Also, if you are using a double-buffered
rendering context, the cursor won't appear in it's new position until the
buffers are swapped at the end of the frame.
Still, for all its faults, if there is no other cursor provided for
you - PUI's cursor is a lot better than nothing.
In fact, this neatly demolishes my hope that people would write their
WIN32 programs in GLUT/OpenGL/PUI and thus be able to port them over to
Linux at near zero effort.
Mark's changes are now in mainstream PUI, all you have to do is to compile
the PUI sources with:
The GLUT-less PUI cannot switch fonts - it always uses the system font.
It also requires the 'wgl' functions to be present in whichever OpenGL
is being used.
There is a demo of this PUI setup in the puiAlone directory. Notice
that this code is provided under somewhat different terms from the remainder
of PUI - nothing too onerous though.
A Truly PUI API:
Here are the elements that make up the PUI API:
Classes:
Non-class functions:
Note:
In the description of each widget class below, there is a small
screenshot of one example of that widget. You can see the code
used to generate those screenshots in the PLIB example program
widget_list.cxx
. However, by changing the rendering
style, you can make them look considerably different from this.
PUI Terminology.
Some terminology:
Hello World in PUI.
Here is a simple example program. It pops up a window with a single
button widget that prints 'Hello World.' to stdout when you click it. (This
program is in the PUI examples directory as 'simple.cxx').
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <math.h>
#include <GL/glut.h>
#include <plib/pu.h>
void motionfn ( int x, int y )
{
puMouse ( x, y ) ;
glutPostRedisplay () ;
}
void mousefn ( int button, int updown, int x, int y )
{
puMouse ( button, updown, x, y ) ;
glutPostRedisplay () ;
}
void displayfn ()
{
glClearColor ( 0.1, 0.4, 0.1, 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
puDisplay () ;
glutSwapBuffers () ;
glutPostRedisplay () ;
}
void button_cb ( puObject * )
{
fprintf ( stderr, "Hello World.\n" ) ;
}
int main ( int argc, char **argv )
{
glutInitWindowSize ( 240, 120 ) ;
glutInit ( &argc, argv ) ;
glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ) ;
glutCreateWindow ( "PUI Application" ) ;
glutDisplayFunc ( displayfn ) ;
glutMouseFunc ( mousefn ) ;
glutMotionFunc ( motionfn ) ;
puInit () ;
puOneShot *b = new puOneShot ( 50, 50, 200, 80 ) ;
b -> setLegend ( "Say Hello" ) ;
b -> setCallback ( button_cb ) ;
glutMainLoop () ;
return 0 ;
}
Notice that the program uses a pretty conventional GLUT startup sequence,
with the usual callbacks for mouse events and redisplay. You can even continue
to use GLUT popup menus which will work quite happily in conjunction with
PUI menus.
Multiple Windows in PUI
When you create a new widget, PUI places it in the current GLUT window.
If the your application opens multiple windows, you can place user interface
widgets in any window you please. The widget coordinates are calculated
from the lower left-hand corner of the window. There are a few recommended
practices when using PUI in connection with multiple windows:
This is a more complicated example in the PUI example directory called
'complex.cxx', it produces a menu and a button that float in front of a
tumbling cube that is rendered in OpenGL. In a second window are
two sliders which allow the user to control the speed and direction of
the cube's rotation. A third window contains a bi-slider and a tri-slider
which truncate the cube in two directions.
Object Picking
The most recent widget to be activated is called the "active widget."
Usually if you click the mouse on another widget the active widget immediately
deactivates and the new widget becomes the active widget. There are
times, however, when you will want to click the mouse somewhere in a window
and have the active widget operate on where you clicked the mouse.
You do this by setting and invoking the widget's "active callback."
A simple GLUT mouse function that does this is as follows:
static void mousefn ( int button, int updown, int x, int y )
{
if ( !puMouse ( button, updown, x, y ) )
{
// PUI didn't take the mouseclick, try the main window
mouse_x = x ;
mouse_y = puGetWindowHeight () - y ;
// Check for an active widget.
// If there is one, call its active callback
if ( puActiveWidget () )
puActiveWidget () -> invokeActiveCallback () ;
}
glutPostRedisplay () ;
}
First the mouse function calls "puMouse" to see if the user clicked
on a new PUI widget. If the user did not, "puMouse" returns FALSE
and the function executes the contents of the if-block. It saves
the mouse coordinates in a pair of global variables and, if there is an
active widget, it invokes the active widget's active callback. This
active callback will invoke the OpenGL select mode, create the pick matrix,
and redraw the window to get the selected objects. The PUI examples
directory has a program, "PointPicker", which does this.
Transparent GUI's
One very trendy idea is to use translucent GUI widgets. This is handy because
the GUI doesn't intrude quite so badly into the available screen area.
Translucent menus have always been possible in PUI - it's just that nobody
ever actually wanted to do it. Here's what you do:
Class Descriptions
puFont
A puFont is a simple class which can be constructed in one of two ways:
A GLUT Font.
puFont::puFont ( void *glut_font ) ;
Where 'glut_font' is GLUT_BITMAP font. Since there are only seven GLUT_BITMAP
fonts, these have all been pre-declared within PUI (mainly for backwards
compatability with PLIB versions before 1.0.7).
extern puFont PUFONT_8_BY_13 ; - 8x13 Fixed width
extern puFont PUFONT_9_BY_15 ; - 9x15 Fixed width
extern puFont PUFONT_TIMES_ROMAN_10 ; - 10-point Proportional
extern puFont PUFONT_TIMES_ROMAN_24 ; - 24-point Proportional
extern puFont PUFONT_HELVETICA_10 ; - 10-point Proportional
extern puFont PUFONT_HELVETICA_12 ; - 12-point Proportional
extern puFont PUFONT_HELVETICA_18 ; - 18-point Proportional
These are light on storage - but slow to render on most hardware-based
OpenGL implementations because GLUT uses glBitMap to render its glyphs.
If you wish to use PLIB on a software-only OpenGL implementation (Good
Luck!) then you'll want to use these GLUT fonts since glBitMap is usually
faster than texture-mapped text.
Using a pre-built FNT font
puFont::puFont ( fntTexFont *tex_font,
float pointsize, float slant = 0 ) ;
Where 'tex_font' is texture-based font created using the
FNT
library and setting the pointsize and optional italic slant (both measured
in pixels).
puObject
All PUI widgets are derived from the puObject abstract base class. User
programs should never declare objects of this type. puObjects are in turn
derived from an internally defined puValue class - but this is never visible
to the user and is not documented here.
puObject::puObject ( int minx, int miny, int maxx, int maxy ) ;
(Some widgets need more or fewer arguments to their constructor - but most
follow this scheme).
int puObject::getType() ;
This returns a bitmask showing the inheritance of any object derived from
the puObject base class:
#define PUCLASS_VALUE
#define PUCLASS_OBJECT
#define PUCLASS_GROUP
#define PUCLASS_INTERFACE
#define PUCLASS_FRAME
#define PUCLASS_TEXT
#define PUCLASS_BUTTON
#define PUCLASS_ONESHOT
#define PUCLASS_POPUP
#define PUCLASS_POPUPMENU
#define PUCLASS_MENUBAR
#define PUCLASS_INPUT
#define PUCLASS_BUTTONBOX
#define PUCLASS_SLIDER
#define PUCLASS_DIALOGBOX
#define PUCLASS_ARROW
#define PUCLASS_LISTBOX
#define PUCLASS_DIAL
#define PUCLASS_FILEPICKER
#define PUCLASS_BISLIDER
#define PUCLASS_TRISLIDER
#define PUCLASS_VERTMENU
#define PUCLASS_LARGEINPUT
Hence, if you declare an object of (say) class puOneShot, then calling
getType() for that object would return
PUCLASS_VALUE | PUCLASS_OBJECT | PUCLASS_BUTTON | PUCLASS_ONESHOT
(since a puOneShot is a kind of puButton which is a kind of puObject which
is [although not documented that way here] a kind of puValue).
char *puObject::getTypeString() ;
...which returns a pointer to a statically allocated string which is the
name of the top-level class to which that object belongs.
struct puBox { int min[2] ; int max[2] ; }
puBox *puObject::getABox () ;
puBox *puObject::getBBox () ;
get the ABOX (Activity Box) and BBOX (Bounding Box) of the object.
void puObject::setPosition ( int x, int y ) ;
void puObject::setSize ( int w, int h ) ;
void puObject::getPosition ( int *x, int *y ) ;
void puObject::getSize ( int *w, int *h ) ;
The bounding box is adjusted to fit around tha activity box and the label,
if any.
void puObject::clrValue () ;
void puObject::setValue ( int i ) ;
void puObject::setValue ( float f ) ;
void puObject::setValue ( char *s ) ;
void puObject::getValue ( int *i ) ;
void puObject::getValue ( float *f ) ;
void puObject::getValue ( char *s ) ; /* copies the string value into the string that is passed in */
void puObject::getValue ( char **s ) ; /* sets the argument to point to the string value */
int puObject::getValue () ;
float puObject::getFloatValue () ;
char puObject::getCharValue () ; /* returns the first character in the string value */
char *puObject::getStringValue () ;
The clrvalue() function has the special function of setting the string
value of the widget to the empty string - and the numeric parts to zero.
void puObject::defaultValue() ;
...allows you to return the widget to some known default value. The default
value can also be set and read:
void puObject::setDefaultValue ( int i ) ;
void puObject::setDefaultValue ( float f ) ;
void puObject::setDefaultValue ( char *s ) ;
void puObject::getDefaultValue ( int *i ) ;
void puObject::getDefaultValue ( float *f ) ;
void puObject::getDefaultValue ( char **s ) ;
int puObject::getDefaultValue () ;
There are many occasions when you'd really like to have the PUI widget
directly drive and/or reflect the value of some memory location in the
application code. These calls let you do that:
void puObject::setValuator ( int *i ) ;
void puObject::setValuator ( float *f ) ;
void puObject::setValuator ( char *s ) ;
Once you make one of these calls, PUI will automatically update the memory
location indicated with the current value of the widget whenever it changes
- and also update the appearance of the widget to reflect the value stored
in that memory location whenever the widget is redrawn. This is often a
lot more convenient than using a callback function to register changes
in the widget's value.
void puObject::setUserData ( void *data ) ;
void *puObject::getUserData () ;
When the widget is drawn, the application has control of the drawing style
and the colours in which the widget is drawn. Reasonable defaults are provided
by PUI if you don't set them:
void puObject::setStyle ( int style ) ;
int puObject::getStyle () ;
'style' is one of:
PUSTYLE_NONE
PUSTYLE_PLAIN
PUSTYLE_SHADED -- This is the Default.
PUSTYLE_SMALL_SHADED
PUSTYLE_BEVELLED
PUSTYLE_SMALL_BEVELLED
PUSTYLE_BOXED
PUSTYLE_DROPSHADOW
PUSTYLE_RADIO
The various styles are interpreted as follows:
In addition, you can use the negation of the style to swap the appearance
of the selected and deselected versions of an object. Hence, using a style
of -PUSTYLE_BEVELLED will produce a widget that appears to be pressed in
when its value is zero and popped out when it's value is non-zero.
void puObject::setColour ( int which, float r, float g, float b, float a = 1.0f ) ;
void puObject::getColour ( int which, float *r, float *g, float *b, float *a = NULL ) ;
'which' is one of:
PUCOL_FOREGROUND
PUCOL_BACKGROUND
PUCOL_HIGHLIGHT
PUCOL_LABEL
PUCOL_LEGEND
typedef void (*puRenderCallback)(class puObject *, int dx, int dy, void *) ;
The function takes four parameters: a pointer to the object whose
render callback this is, the x- and y-coordinates of the lower left-hand
of the widget, and a pointer to your render data. The user tells
PUI to use his rendering callback instead of the usual drawing function
by invoking the following function:
void puObject::setRenderCallback ( puRenderCallback *c, void *d = NULL ) ;
The two arguments are the name of the render callback and an optional pointer
to the user-defined render data. At the start of every widget's draw
function, it checks for the existence of a render callback and, if it exists,
it calls it instead of executing the code in the draw function.
puRenderCallback puObject::getRenderCallback ( void ) ;
void *puObject::getRenderCallbackData ( void ) ;
void puObject::invokeRenderCallback ( int dx, int dy ) ;
Picking all of the individual colours for each widget can be tedious,
so there is a handy function that sets a 'theme' colour for the widget
and then picks suitable colours near to that theme for the other colours
of the widget. This function works well enough that you will almost never
need to set the colours individually.
void puObject::setColourScheme ( float r, float g, float b, float a = 1.0f ) ;
When a widget is activated, its user-supplied callback function is called
(if it exists):
typedef void (*puCallback)(puObject *) ;
void puObject::setCallback ( puCallback c ) ;
puCallback puObject::getCallback () ;
void puObject::invokeCallback () ;
The callback is invoked (typically) when the user releases the left mouse
button when the cursor lies within the widget's active area. The user-supplied
function is called with the address of the widget as a parameter so that
the same callback can oftem be used with a variety of similar widgets.
It is also possible to invoke an object's callback explicitly using invokeCallback
- bear in mind that this does not change the value of the object - unless
the callback itself does so.
void puObject::setActiveDirn ( int dirn ) ;
int puObject::getActiveDirn () ;
where:
'dirn' is either PU_UP, PU_DOWN, PU_CONTINUAL or PU_UP_AND_DOWN.
As discussed earlier, PUI tracks the most recently invoked widget
and calls it the "active widget." PUI allows you to define a callback
to be invoked for the active widget when the user clicks the mouse outside
any user interface widgets. You can also define a callback for PUI
to call when the widget is being deactivated, when the user is activating
another widget. The following functions do these things:
void puObject::setActiveCallback ( puCallback c ) ;
puCallback puObject::getActiveCallback ( void ) ;
void puObject::invokeActiveCallback ( void ) ;
void puObject::setDownCallback ( puCallback c ) ;
puCallback puObject::getDownCallback ( void ) ;
virtual void puObject::invokeDownCallback ( void ) ;
Most widgets can have a LEGEND (text inside the active area of the widget),
and also a LABEL (text outside the active area). The application gets to
choose where the LABEL is placed relative to the active area of the widget.
You can also move the LEGEND text around inside the widget to a very limited
extent, although this is generally not recommended.
void puObject::setLegend ( char *str ) ;
void puObject::setLabel ( char *str ) ;
char *puObject::getLegend () ;
char *puObject::getLabel () ;
void puObject::setLegendFont ( puFont font ) ;
void puObject::setLabelFont ( puFont font ) ;
puFont puObject::getLegendFont () ;
puFont puObject::getLabelFont () ;
void puObject::setLabelPlace ( int place ) ;
int puObject::getLabelPlace () ;
where 'place' is one of:
PUPLACE_ABOVE
PUPLACE_BELOW
PUPLACE_LEFT
PUPLACE_RIGHT -- The default LABEL place.
PUPLACE_TOP_CENTER
PUPLACE_BOTTOM_CENTER
PUPLACE_LEFT_CENTER
PUPLACE_RIGHT_CENTER
void puObject::setLegendPlace ( int place ) ;
int puObject::getLegendPlace () ;
where 'place' is one of:
PUPLACE_LEFT
PUPLACE_RIGHT
PUPLACE_CENTERED -- The default LEGEND place.
Each widget can be hidden (so it isn't drawn - and can't be clicked
on), or simply 'greyed out' (so it can't be clicked on even though it's
drawn - but in a style that makes it clear that this is the case).
void puObject::greyOut () ;
void puObject::activate () ; -- Undo the 'greyout' effect
int puObject::isActive () ;
void puObject::hide () ;
void puObject::reveal () ; -- Undo the 'hide' effect
int puObject::isVisible () ;
If you want to see or change which window a widget is drawn in,
you use the following functions:
void puObject::setWindow ( int w ) ;
int puObject::getWindow () ;
If you have some generic data that your widget needs but that doesn't
fit anywhere else, you can save it in the widget's "user data" entry:
void puObject::setUserData ( void *data ) ;
void *puObject::getUserData ( void ) ;
Finally, an object can be made to react to the 'return' key on the
keyboard just as if it had been clicked with the mouse.
void puObject::makeReturnDefault ( int boolean ) ;
int puObject::isReturnDefault () ;
In general, it is very confusing to the user to have multiple objects set
up with ReturnDefault enabled (although PUI allows this). Typically, this
option is only used on buttons in simple Yes/No dialog boxes.
puButton
The
puButton class is derived from puObject. It implements
a simple push-button widget. When clicked its value alternates from '0'
to '1' and is highlighted graphically when in the '1' state. By default,
buttons 'latch' down when clicked. The application could change this to
a one-shot behaviour by resetting the value to '0' in the buttons callback
(although it is a lot more convenient to simply use the puOneShot
class for this).
puButton::puButton ( int minx, int miny, char *legend ) ;
puButton::puButton ( int minx, int miny, int maxx, int maxy ) ;
Apart from these convenient short-hand constructor functions, puButtons
have no special API - everything they need is in the puObject
API.
puArrowButton
The
puArrowButton class is derived from puButton. The
only difference is that puArrowButton renders as an arrow rather than as
a rectangular button.
puArrowButton::puArrowButton ( int minx, int miny, int maxx, int maxy,
int arrow_type ) :
Where 'arrow_type' is one of:
Single arrows:
PUARROW_UP
PUARROW_DOWN
PUARROW_LEFT
PUARROW_RIGHT
Double arrows:
PUARROW_FASTUP
PUARROW_FASTDOWN
PUARROW_FASTLEFT
PUARROW_FASTRIGHT
In addition, you can get/set the direction of the arrow in mid-run:
int puArrowButton::getArrowType ( void ) ;
void puArrowButton::setArrowType ( int i ) ;
puOneShot
The
puOneShot class is derived from puButton. It implements
a simple push-button widget which automatically pops back out again as
soon as the mouse is released. This means that it's value is always '1'
inside the callback function and '0' at all other times.
puSlider
The
puSlider class is derived from
puObject. It implements
a slider widget. When clicked, dragged or unclicked its value changes in
proportion to where it is clicked. For the value (as returned by
puObject::getValue(float
*f) ) ranges from 0.0 to 1.0 from the left to the right (or from the
bottom to the top). The application can change the position of the slider
using puObject::setValue(float f) with
a number in the range 0.0 to 1.0.
puSlider::puSlider ( int minx, int miny, int sz ) :
puSlider::puSlider ( int minx, int miny, int sz, TRUE ) :
puSlider::puSlider ( int minx, int miny, int sz, {TRUE|FALSE}, int width ) ;
The first version produces a HORIZONTAL slider, the second version produces
a VERTICAL slider. The third version produces a slider with a non-default
width.
void puSlider::setSliderFraction ( float f ) ;
float puSlider::getSliderFraction () ;
The 'slider fraction' is the proportion of the total width of the slider
widget that is taken up with the sliders' "handle". It defaults to 0.1
(ie one tenth of the width of the entire widget).
void puSlider::setCBMode ( int mode ) ;
float puSlider::getCBMode () ;
where 'mode' is one of:
PUSLIDER_CLICK - Only invoke the callback when
the mouse goes in the active direction.
PUSLIDER_DELTA - Invoke the callback only when the value
of the slider changes by more than a
certain amount.
PUSLIDER_ALWAYS - Invoke the callback all the time that
the mouse is in the widget with the mouse
button pushed down. (This is the default).
In the PUSLIDER_DELTA case, the amount of change required before the callback
is called is set by:
void puSlider::setDelta ( float f ) ;
float puSlider::getDelta () ;
The parameter is expressed as a fraction of the total slider width (ie
0.0f to 1.0f).
int puSlider::isVertical () ;
This returns TRUE for Vertical sliders - FALSE for Horizontal ones.
puDial
The
puDial class is derived from puSlider and implements a square widget
with a circle inscribed in it.
A radius of the circle is also drawn. The value of the widget is
proportional to the angle the radius makes with the vertical
with straight down being zero - then winding it clockwise, straight up
is 0.5 and straight down again being 1.0. The constructor takes three
arguments:
the coordinates of the lower left-hand corner of the widget and the widget
size:
puDial::puDial ( int minx, int miny, int sz ) ;
By default, you can move the pointer directly from 0.0 to 1.0 or
1.0 to 0.0 without winding it all the way around the dial. This
is called 'wrapping' the pointer. If you need to change the wrap
mode, you can call:
void puDial::setWrap ( int wrapmode ) ;
in puDial::getWrap () ;
Everything defined in the puSlider API can also
be applied to puDial widgets.
puBiSlider
The
puBiSlider class implements a slider with two sliding boxes inside the
slider bar. It is based on the puSlider class,
meaning that anything you can do with a puSlider
you can also do with a puBiSlider. You define it with the following
call:
puBiSlider::puBiSlider ( int minx, int miny, int sz, int vertical = FALSE ) ;
The puBiSlider differs from the puSlider in that the values of the slider
boxes are integers and you can set the minimum and maximum values that
they can take:
void puBiSlider::setMaxValue ( int i ) ;
void puBiSlider::setMinValue ( int i ) ;
Corresponding calls retrieve the minimum and maximum possible values:
int puBiSlider::setMaxValue ( void ) ;
int puBiSlider::setMinValue ( void ) ;
Since there are two sliding boxes, they are considered to be a current
minimum and current maximum value. These are both integers and neither
one is stored in the "puValue" as the widget's value. You set and
retrieve them with the following functions:
void puBiSlider::setCurrentMax ( int i ) ;
void puBiSlider::setCurrentMin ( int i ) ;
int puBiSlider::getCurrentMax ( void ) ;
int puBiSlider::getCurrentMin ( void ) ;
If the user clicks on the puBiSlider with his mouse, the box that is closer
to the mouse is activated and moves to the mouse position. The other
box will stay put. If the user drags the upper box over the lower
box or vice versa, the stationary box will move with the other box.
puTriSlider
The
puTriSlider class implements a slider with three sliding boxes inside the
slider bar. It is based on the puBiSlider
and includes everything that widget supports. You define it with
the following call:
puTriSlider::puTriSlider ( int minx, int miny, int sz, int vertical = FALSE ) ;
The third box in the puTriSlider stores its value in the widget's value.
You can set and retrieve the absolute minimum and maximum values that the
widget boxes can take, and you can set and retrieve the current minimum
and maximum values in the same way that you do with the puBiSlider.
You can set and retrieve the value of the middle box by using the "setValue"
and "getValue" functions.
void puTriSlider::setFreezeEnds ( int val ) ;
int puTriSlider::getFreezeEnds () ;
where "val" is either TRUE (the default) or FALSE.
puFrame
The
puFrame class is derived from puObject. It is designed
to provide some aesthetic layout and labelling to your user interface.
As such, the user can never do anything to the frame by clicking on it
- there is no point in creating a callback for this kind of object since
it will never be called. The frame renders as a large PUCOL_FOREGROUND
coloured rectangle (with legend and label) in the appropriate style.
puText
The
puText class is derived from puObject. It's function
is simply to allow text to be positioned on the user interface. Since puText
has no active area (it cannot be clicked), it has no legend text and the
text you want it to draw should be in the label string.
puText::puText ( int x, int y ) ;
By default, this is the bottom-left corner of the label - but you can of
course change that with puObject::setLabelPlace().
puInput
The
puInput class is derived from puObject. It's designed
for the specific purpose of allowing the user to input a string (or an
integer or floating point number).
puInput::puInput ( int minx, int miny, int maxx, int maxy ) ;
Note that puInput objects do not display their 'legend' string - the center
of the widget being used to draw the value as a string.
void puInput::acceptInput () ;
void puInput::rejectInput () ;
int puInput::isAcceptingInput () ;
When the user hits the 'Return' key, the puInput is automatically set to
reject further input. When the user clicks the mouse onto the puInput,
it is automatically set to accept input - and the I-bar cursor is moved
next to the character nearest to where the mouse was clicked.
void puInput::setCursor ( int pos ) ;
int puInput::getCursor () ;
void puInput::setSelectRegion ( int start, int end ) ;
void puInput::getSelectRegion ( int *start, int *end ) ;
Since a puInput uses the normal value getting and setting functions of
puObject, you are limited to PUSTRING_MAX characters (currently 80).
void puInput::setValidData ( char *data ) ; /* Sets list of valid characters to argument string */
void puInput::addValidData ( char *data ) ; /* Appends argument string to list of valid characters */
char *puInput::getValidData () ; /* Returns pointer to list of valid characters */
int puInput::isValidCharacter ( char c ) ; /* Returns 1 if character is valid and 0 if not */
This will avoid, for example, the user typing his name into an input box
that is supposed to accept his birthdate.
puLargeInput
The
puLargeInput widget resembles the puInput widget
but it is actually based on the puGroup widget.
The reason for this is that the widget contains sub-widgets within it:
there is puFrame widget to display the text area;
two puSlider widgets to allow the user to scroll
vertically and horizontally; and there are up to four puArrowButton
widgets to allow rapid vertical scrolling. The puLargeInput widget
allows the user to enter an arbitrarily large amount of text, including
multiple carriage returns. This text is stored in a separate text
buffer and is not connected to the widget value. You create a puLargeInput
widget with the following call:
puLargeInput::puLargeInput ( int x, int y, int w, int h, int arrows, int sl_width ) :
which creates a puLargeInput at location (x, y), with size (w, h), with
sliders of "sl_width" pixels wide, and with "arrows" pairs of up- and down-arrows
on the right-hand slider. Allowed values for "arrows" are 0, 1, and
2.
void puLargeInput::acceptInput () ;
void puLargeInput::rejectInput () ;
int puLargeInput::isAcceptingInput () ;
void puLargeInput::setCursor ( int pos ) ;
int puLargeInput::getCursor () ;
void puLargeInput::setSelectRegion ( int start, int end ) ;
void puLargeInput::getSelectRegion ( int *start, int *end ) ;
void puLargeInput::setValidData ( char *data ) ; /* Sets list of valid characters to argument string */
void puLargeInput::addValidData ( char *data ) ; /* Appends argument string to list of valid characters */
char *puLargeInput::getValidData () ; /* Returns pointer to list of valid characters */
int puLargeInput::isValidCharacter ( char c ) ; /* Returns 1 if character is valid and 0 if not */
Besides the obvious methods of typing or erasing, you can add text to and
remove text from the widget using the following calls:
void puLargeInput::setText ( char *l ) ; /* Erases current text and copies input string to text */
char *puLargeInput::getText ( void ) ; /* Returns the pointer to the text string */
void puLargeInput::addNewLine ( char *l ) ; /* Inserts input string at start of next line after cursor */
void puLargeInput::addText ( char *l ) ; /* Inserts input string at cursor position */
void puLargeInput::appendText ( char *l ) ; /* Adds input string to the end of text */
void puLargeInput::removeText ( int start, int end ) ; /* Removes the text between character positions */
The puLargeInput widget always stores a carriage return at the end of its
text. Even if you delete all the text in the widget, it will create
an empty carriage return.
int puLargeInput::getNumLines () ; /* Returns the number of lines in the text */
void puLargeInput::selectEntireLine ( void ) ; /* Expands the select region to include full lines */
void puLargeInput::setTopLineInWindow ( int val ) ; /* Sets the top line to be displayed in the widget window */
puGroup
The puGroup class is derived from puObject. When
declaring objects derived from puGroup, it is essential that these objects
be deleted in the reverse order to their creation (except when your program
is about to exit anyway). This is because PUI keeps a list of puGroup
widgets on a stack, and attempting to delete a puGroup from the middle
of the stack will cause an error.
void puGroup::close () ;
puGroup widgets can be placed inside other puGroup widgets to an arbitary
depth. When a puGroup is delete'ed, it will automatically delete everything
that it contains.
puInterface
The puInterface class is derived from puGroup. This
class is another abstract class - application programs should not declare
puInterface objects.
puButtonBox
The
puButtonBox class is derived from puInterface.
It is designed to automatically generate a number of 'radio' buttons with
a handful of member function calls and a single callback function. It can
optionally manage the problem of ensuring that exactly one of the buttons
is depressed at all times, or it can allow multiple buttons to be active
at the same time.
puButtonBox::puButtonBox ( int minx, int miny, int maxx, int maxy,
char *labels, int one_button ) ;
The 'labels' parameter is a NULL-terminated array of pointers-to-strings
containing the labels for each of the radio-buttons. These are drawn in
order from top to bottom of the Button Box.
int puButtonBox::isOneButton () ;
This function returns TRUE for a one_button box, FALSE otherwise.
puPopup
The puPopup class is derived from puInterface.
Its function is to pop up a bunch of other widgets on command.
puDialogBox
The
puDialogBox class is derived from puPopup. While
there is a puDialogBox in existence (ie Constructed and not yet destroyed)
nothing that isn't contained within that puDialogBox will be activated
by either keyboard or mouse (Although they will still be re-drawn).
puDialogBox::puDialogBox ( int x, int y ) ;
Here is a simple example where a callback function wants to tell the user
that its code hasn't been written yet...
puDialogBox *dialog_box = NULL ;
void go_away_callback ( puObject * )
{
delete dialog_box ;
dialog_box = NULL ;
}
void make_dialog ( char *txt )
{
if ( dialog_box != NULL )
return ;
dialog_box = new puDialogBox ( 50, 50 ) ;
{
new puFrame ( 0, 0, 400, 100 ) ;
new puText ( 10, 70 ) -> setLabel ( txt ) ;
puOneShot *ok = new puOneShot ( 180, 10, "OK" ) ;
ok -> makeReturnDefault ( TRUE ) ;
ok -> setCallback ( go_away_callback ) ;
}
dialog_box -> close () ;
dialog_box -> reveal () ;
}
void not_implemented_yet_callback ( puObject * )
{
make_dialog ( "Sorry, that function isn't implemented yet" ) ;
}
When 'not_implemented_yet_callback' is called (presumably from another
puObject), it calls 'make_dialog' to construct and activate a suitable
dialog box object.
puPopupMenu
The
puPopupMenu class is derived from puPopup. It's
designed for the specific purpose of building a simple popup menu - which
is actualy implemented as a stack of buttons (puOneShot's actually) with
callbacks.
puPopupMenu::puPopupMenu ( int x, int y, char *legends[], puCallback cb[] ) ;
The individual items in the menu are set up in a pair of NULL-terminated
arrays. The 'legends' array lists the strings that will appear in the menu
and the 'cb' array is the corresponding callback that will be made if that
menu item is clicked. (Both arrays should be NULL terminated but the puCallback
array can have other NULL pointers indicating items that have no action
when clicked upon).
puMenuBar
The
puMenuBar class is derived from puInterface.
It's designed for the specific purpose of building a horizontal strip menu
(typically at the top of the screen). Each entry in that menu turns into
a puPopupMenu when clicked upon.
puMenuBar::puMenuBar () ;
puMenuBar::puMenuBar ( int y ) ;
(If you omit 'y', the menu bar will attempt to remain at the top of the
screen, even if the screen is resized).
void *puMenuBar::add_submenu ( char *name, char *legends[], puCallback cb[] );
'name' is the name that appears on the menu bar, 'legends' is the NULL-terminated
list of strings that appear inside the popup menu and 'cb' is the list
of corresponding callback functions. (Both arrays should be NULL terminated
but the puCallback array can have other NULL pointers indicating PopupMenu
items that have no action when clicked upon).
puMenuBar::close() ;
...when you have finished creating the menu items.
char *file_submenu [] = { "Exit" , "Close", "--------", "Save" , NULL};
puCallback file_submenu_cb [] = { exit_cb, cull_cb, NULL, save_cb, NULL};
char *help_submenu [] = { "About...", "Help" , NULL } ;
puCallback help_submenu_cb [] = { about_cb , help_cb, NULL } ;
puMenuBar *menu = new puMenuBar ( -1 ) ;
menu->add_submenu ( "File", file_submenu, file_submenu_cb ) ;
menu->add_submenu ( "Help", help_submenu, help_submenu_cb ) ;
menu->close () ;
puVerticalMenu
The
puVerticalMenu is derived from the puGroup class
and is designed to create a menu with its entries one above the other.
You create it with the following call:
puVerticalMenu::puVerticalMenu ( int x = -1, int y = -1 ) ;
where using a default value for "x" will place the menu on the left-hand
side of its window and using a default value for "y" will place it on the
top of its window. Its behavior is essentially the same as that of
the puMenuBar widget.
puListBox
The puListBox widget is a multiple-line text widget which was designed
to support the puFilePicker widget. It
is derived from the puButton widget and supports
that widget's entire API. You create a puListBox by invoking the
contructor method:
puListBox::puListBox ( int minx, int miny, int maxx, int maxy, char** list ) ;
In this case "list" is a null-terminated array of character strings that
contain the items that go into the list box. You are responsible
for supplying this array and for making sure that it is still around the
entire time the puListBox widget is using it. The widget does not
make its own copy of the array.
int puListBox::getNumItems () ; /* Return the number of items in the list */
int puListBox::getTopItem () const ; /* Return the index of the top item that is displayed in the list */
void puListBox::setTopItem ( int item_index ) ; /* Set the index of the top item to be displayed */
puFilePicker
The
puFilePicker class is derived from puDialogBox.
FilePicker creates a dialog box for selecting a file. The puFilePicker
widget contains a puListBox widget, a puSlider
widget, two puOneShot button widgets, and zero,
two, or four puArrowButton widgets, depending
on what you ask for.
puFilePicker::puFilePicker ( int x, int y, const char* dir,
const char* title ) ;
puFilePicker::puFilePicker ( int x, int y, int arrows,
const char* dir, const char* title ) ;
puFilePicker::puFilePicker ( int x, int y, int w, int h,
const char* dir, const char* title ) ;
puFilePicker::puFilePicker ( int x, int y, int w, int h,
int arrows, const char* dir,
const char* title ) ;
The first constructor sets the possition but uses a default value for the
size of the dialog box, currently defaulting to 170,220. The second
is like the first but also allows you to specify up- and down-arrows (0
for none, 1 for single arrows, 2 for single and double arrows) next to
the list box. The third and fourth constructors allow you to also
select the size of the dialog box as well. The "dir" argument is
a character string which is the name of the directory whose files are to
be listed, and "title" is a title that is displayed in the puFilePicker
widget.
puFilePicker::setSize ( int w, int h) ;
This method is used to set the current width and height of the dialog box.
Non-Class Functions.
The following functions are not a part of any classes:
Setting Defaults
It can be pretty tedious coding in the colours, fonts and style for every
puObject. There are a number of routines that alter the defaults that will
be assumed for all subsequently constructed puObjects...
void puSetDefaultStyle ( int style ) ;
int puGetDefaultStyle () ;
void puSetDefaultFonts ( puFont legendFont, puFont labelFont ) ;
void puGetDefaultFonts ( puFont *legendFont, puFont *labelFont ) ;
puFont puGetDefaultLabelFont () ;
puFont puGetDefaultLegendFont () ;
void puSetDefaultColourScheme ( float r, float g, float b, float a = 1.0 );
void puGetDefaultColourScheme ( float *r, float *g, float *b, float *a = NULL);
These take the same arguments as the corresponding puObject class members.
puInit
This must be the first PUI function that you call. It must be called after
GLUT window setup but before glutMainLoop().
void puInit () ;
puDisplay
Causes PUI to redraw all of the currently created widgets.
void puDisplay () ;
It sets up the GL transforms as follows:
int w = puGetWindowWidth () ;
int h = puGetWindowHeight () ;
glPushAttrib ( GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_TRANSFORM_BIT ) ;
glDisable ( GL_LIGHTING ) ;
glDisable ( GL_FOG ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_DEPTH_TEST ) ;
glViewport ( 0, 0, w, h ) ;
glMatrixMode ( GL_PROJECTION ) ;
glPushMatrix () ;
glLoadIdentity () ;
gluOrtho2D ( 0, w, 0, h ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPushMatrix () ;
glLoadIdentity () ;
...and after it finishes rendering the GUI and the puCursor (see below),
it restores state like this:
glMatrixMode ( GL_PROJECTION ) ;
glPopMatrix () ;
glMatrixMode ( GL_MODELVIEW ) ;
glPopMatrix () ;
glPopAttrib () ;
All drawing code is done with whatever glMaterial/glTexture/glEnabled facilities
are curently set. All PUI rendering is done with simple colours and 2D
drawing functions such as glRect and glDrawPixels.
void my_display_func ()
{
glClearColor ( 0.1, 0.4, 0.1, 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
...do your own OpenGL rendering...
puDisplay () ;
glutSwapBuffers () ;
glutPostRedisplay () ;
}
.
.
puInit () ;
glutDisplayFunc ( my_display_func ) ;
.
.
glutMainLoop() ;
puKeyboard
This routine takes keystroke events (presumably generated by GLUT) and
uses them to decide which (if any) widgets changed state as a result. puKeyboard
doesn't do any actual graphics - so you have to call puDisplay
if you want the display to be upated.
int puKeyboard ( int key, int state ) ;
'key' is either an ASCII character, or one of the
PU_KEY_xxx symbols. These are named similarly
to the GLUT_KEY_xxx symbols but are numerically
set such that:
PU_KEY_xxx == GLUT_KEY_xxx + PU_KEY_GLUT_SPECIAL_OFFSET
'state' is one of
PU_DOWN (which is the same as GLUT_DOWN)
PU_UP (which is the same as GLUT_UP)
(At present, GLUT can only generate PU_DOWN events for the
keyboard - and PUI won't do anything with PU_UP events.
Notice that this function will accept either an ASCII character or a special
keycode.
void my_keyboard_func ( unsigned char key, int x, int y )
{
puKeyboard ( key, PU_DOWN ) ;
glutPostRedisplay () ;
}
void my_special_func ( int special_key, int x, int y )
{
puKeyboard ( special_key + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN ) ;
glutPostRedisplay () ;
}
.
.
puInit () ;
glutKeyboardFunc ( my_keyboard_func ) ;
glutSpecialFunc ( my_special_func ) ;
.
.
glutMainLoop() ;
Note: PU_KEY_GLUT_SPECIAL_OFFSET is required since the definitions of the
GLUT_KEY_xxx symbols overlap the ASCII character range but the PU_KEY_xxx
symbols don't. Hence PU_KEY_GLUT_SPECIAL_OFFSET is currently defined to
be 256.
PU_KEY_F1 PU_KEY_F2 PU_KEY_F3 PU_KEY_F4
PU_KEY_F5 PU_KEY_F6 PU_KEY_F7 PU_KEY_F8
PU_KEY_F9 PU_KEY_F10 PU_KEY_F11 PU_KEY_F12
PU_KEY_LEFT PU_KEY_UP PU_KEY_RIGHT PU_KEY_DOWN
PU_KEY_PAGE_UP PU_KEY_PAGE_DOWN PU_KEY_HOME PU_KEY_END
PU_KEY_INSERT
puMouse
This routine take mouse events (presumably generated by GLUT) and uses
them to decide which (if any) widgets changed state as a result. puMouse
doesn't do any actual graphics - so you have to call puDisplay
if you want the display to be upated.
int puMouse ( int buttons, int state, int x, int y ) ;
int puMouse ( int x, int y ) ;
'buttons' is one of
PU_LEFT_BUTTON (which is the same as GLUT_LEFT_BUTTON)
PU_MIDDLE_BUTTON (which is the same as GLUT_MIDDLE_BUTTON)
PU_RIGHT_BUTTON (which is the same as GLUT_RIGHT_BUTTON)
'state' is one of
PU_DOWN (which is the same as GLUT_DOWN)
PU_UP (which is the same as GLUT_UP)
Notice that this function will accept exactly the arguments that GLUT passes
to the glutMouseFunc, glutMotionFunc and glutPassiveMotionFunc callbacks.
This means that the 'y' coordinate is reversed compared to those used in
OpenGL. The coordinate is flipped back inside the function before comparing
it to the active areas of all the widgets.
The PUI 'soft' Cursor
PUI can take motion events (presumably generated by GLUT - and passed on
to puMouse) and use them to draw a mouse cursor. Typically, the underlying
window manager will draw a perfectly good cursor for you - but there are
a few (rare) cases where such facilities are not available and a cursor
drawn using OpenGL is needed.
void puShowCursor () ;
void puHideCursor () ;
int puCursorIsHidden () ;
The cursor is always drawn in black, with a white border - it is about
18 pixels wide and 18 pixels high and is drawn as an arrow pointing north-west.
At present, there is no way to change the cursor shape or colour.
Example of puMouse and puShowCursor usage:
Example:
void my_mouse_func ( int button, int updown, int x, int y )
{
puMouse ( button, updown, x, y ) ;
glutPostRedisplay () ;
}
void my_motion_func ( int x, int y )
{
puMouse ( x, y ) ;
glutPostRedisplay () ;
}
.
.
puInit () ;
glutMouseFunc ( my_mouse_func ) ;
glutMotionFunc ( my_motion_func ) ;
glutPassiveMotionFunc ( my_motion_func ) ;
if ( my_hardware_doesnt_have_a_cursor )
puShowCursor () ;
.
.
glutMainLoop () ;
Active Widget Functions
PUI has three functions which you can use to manipulate the active widget.
Here they are:
void puDeactivateWidget () ; /* Sets the Active Widget to NULL */
void puSetActiveWidget ( puObject *w ) ; /* Sets the Active Widget */
puObject *puActiveWidget () ; /* Returns the active widget */
Cut and Paste
You can cut and paste text between different puInput widgets and puLargeInput
widgets. The cut, copy, and paste commands are the standard CTRL-X,
CTRL-C, and CTRL-V.
Miscellany
Mark Danks
-DPU_NOT_USING_GLUT
Since there is no longer any way for PUI to glutGet() the screen dimensions,
your application must now tell PUI every time it changes the screen dimensions.
puSetWindowSize ( int width, int height ) ;
There are two portability functions:
int puGetWindowWidth () ;
int puGetWindowHeight () ;
These return the most recent puSetWindowSize parameters under Marks raw
WIN32 environment - and do a nice portable glutGet() on all other setups.
Steve J. Baker. <sjbaker1@airmail.net>