]> git.mxchange.org Git - flightgear.git/commitdiff
Initial revision.
authorcurt <curt>
Fri, 12 Jun 1998 01:04:52 +0000 (01:04 +0000)
committercurt <curt>
Fri, 12 Jun 1998 01:04:52 +0000 (01:04 +0000)
18 files changed:
PUI/Makefile.am [new file with mode: 0644]
PUI/pu.cxx [new file with mode: 0644]
PUI/pu.h [new file with mode: 0644]
PUI/puBox.cxx [new file with mode: 0644]
PUI/puButton.cxx [new file with mode: 0644]
PUI/puButtonBox.cxx [new file with mode: 0644]
PUI/puDialogBox.cxx [new file with mode: 0644]
PUI/puFrame.cxx [new file with mode: 0644]
PUI/puInput.cxx [new file with mode: 0644]
PUI/puInterface.cxx [new file with mode: 0644]
PUI/puLocal.h [new file with mode: 0644]
PUI/puMenuBar.cxx [new file with mode: 0644]
PUI/puObject.cxx [new file with mode: 0644]
PUI/puOneShot.cxx [new file with mode: 0644]
PUI/puPopup.cxx [new file with mode: 0644]
PUI/puPopupMenu.cxx [new file with mode: 0644]
PUI/puSlider.cxx [new file with mode: 0644]
PUI/puText.cxx [new file with mode: 0644]

diff --git a/PUI/Makefile.am b/PUI/Makefile.am
new file mode 100644 (file)
index 0000000..05a1a54
--- /dev/null
@@ -0,0 +1,24 @@
+libdir = ${exec_prefix}/lib
+
+lib_LTLIBRARIES = libPui.la
+
+libPui_la_SOURCES = \
+       pu.h puLocal.h \
+       pu.cxx \
+       puBox.cxx \
+       puButton.cxx \
+       puButtonBox.cxx \
+       puDialogBox.cxx \
+       puFrame.cxx \
+       puInput.cxx \
+       puInterface.cxx \
+       puMenuBar.cxx \
+       puObject.cxx \
+       puOneShot.cxx \
+       puPopup.cxx \
+       puPopupMenu.cxx \
+       puSlider.cxx \
+       puText.cxx
+
+INCLUDES += -I$(top_builddir)
+
diff --git a/PUI/pu.cxx b/PUI/pu.cxx
new file mode 100644 (file)
index 0000000..cde921b
--- /dev/null
@@ -0,0 +1,238 @@
+
+#include "puLocal.h"
+
+#define PU_STRING_X_FUDGE 6
+#define PU_STRING_Y_FUDGE 6
+
+int puRefresh = TRUE ;
+
+puColour _puDefaultColourTable[] =
+{
+  { 0.5, 0.5, 0.5, 1.0 }, /* PUCOL_FOREGROUND */
+  { 0.3, 0.3, 0.3, 1.0 }, /* PUCOL_BACKGROUND */
+  { 0.7, 0.7, 0.7, 1.0 }, /* PUCOL_HIGHLIGHT  */
+  { 0.0, 0.0, 0.0, 1.0 }, /* PUCOL_LABEL      */
+  { 1.0, 1.0, 1.0, 1.0 }, /* PUCOL_TEXT       */
+
+  { 0.0, 0.0, 0.0, 0.0 }  /* ILLEGAL */
+} ;
+
+puValue::~puValue () {}  
+
+static int _puCursor_enable = FALSE ;
+static int _puCursor_x      = 0 ;
+static int _puCursor_y      = 0 ;
+static float _puCursor_bgcolour [4] = { 1.0f, 1.0f, 1.0f, 1.0f } ; 
+static float _puCursor_fgcolour [4] = { 0.0f, 0.0f, 0.0f, 1.0f } ;  
+
+void   puHideCursor ( void ) { _puCursor_enable = FALSE ; }
+void   puShowCursor ( void ) { _puCursor_enable = TRUE  ; }
+int    puCursorIsHidden ( void ) { return ! _puCursor_enable ; }
+
+void puCursor ( int x, int y )
+{
+  _puCursor_x = x ;
+  _puCursor_y = y ;
+}
+
+int puGetStringDescender ( void *fnt )
+{
+  if ( fnt == NULL )
+    fnt = GLUT_BITMAP_9_BY_15 ;
+
+  if ( fnt == GLUT_BITMAP_8_BY_13        ) return 2 ;
+  if ( fnt == GLUT_BITMAP_9_BY_15        ) return 3 ;
+  if ( fnt == GLUT_BITMAP_TIMES_ROMAN_10 ) return 2 ;
+  if ( fnt == GLUT_BITMAP_TIMES_ROMAN_24 ) return 5 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_10   ) return 2 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_12   ) return 3 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_18   ) return 4 ;
+
+  return 0 ;
+}
+
+int puGetStringHeight ( void *fnt )
+{
+  /* Height *excluding* descender */
+
+  if ( fnt == NULL )
+    fnt = GLUT_BITMAP_9_BY_15 ;
+
+  if ( fnt == GLUT_BITMAP_8_BY_13        ) return  9 ;
+  if ( fnt == GLUT_BITMAP_9_BY_15        ) return 10 ;
+  if ( fnt == GLUT_BITMAP_TIMES_ROMAN_10 ) return  7 ;
+  if ( fnt == GLUT_BITMAP_TIMES_ROMAN_24 ) return 17 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_10   ) return  8 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_12   ) return  9 ;
+  if ( fnt == GLUT_BITMAP_HELVETICA_18   ) return 14 ;
+
+  return 0 ;
+}
+
+int puGetStringWidth ( void *fnt, char *str )
+{
+  if ( str == NULL )
+    return 0 ;
+
+  if ( fnt == NULL )
+    fnt = GLUT_BITMAP_9_BY_15 ;
+
+  int res = 0 ;
+
+  while ( *str != '\0' )
+  {
+    res += glutBitmapWidth ( fnt, *str ) ;
+    str++ ;
+  }
+
+  return res ;
+}
+
+
+void puDrawString ( void *fnt, char *str, int x, int y )
+{
+  if ( str == NULL )
+    return ;
+
+  if ( fnt == NULL )
+    fnt = GLUT_BITMAP_9_BY_15 ;
+
+  glRasterPos2f ( x, y ) ;
+
+  while ( *str != '\0' )
+  {
+    glutBitmapCharacter ( fnt, *str ) ;
+    str++ ;
+  }
+}
+
+
+static void puDrawCursor ( int x, int y )
+{
+  glColor4fv ( _puCursor_bgcolour ) ;  
+
+  glBegin    ( GL_TRIANGLES ) ;
+  glVertex2i ( x, y ) ;
+  glVertex2i ( x + 13, y -  4 ) ;
+  glVertex2i ( x +  4, y - 13 ) ;
+
+  glVertex2i ( x +  8, y -  3 ) ;
+  glVertex2i ( x + 17, y - 12 ) ;
+  glVertex2i ( x + 12, y - 17 ) ;
+
+  glVertex2i ( x + 12, y - 17 ) ;
+  glVertex2i ( x +  3, y -  8 ) ;
+  glVertex2i ( x +  8, y -  3 ) ;
+  glEnd      () ;
+
+  glColor4fv ( _puCursor_fgcolour ) ;  
+
+  glBegin    ( GL_TRIANGLES ) ;
+  glVertex2i ( x+1, y-1 ) ;
+  glVertex2i ( x + 11, y -  4 ) ;
+  glVertex2i ( x +  4, y - 11 ) ;
+
+  glVertex2i ( x +  8, y -  5 ) ;
+  glVertex2i ( x + 15, y - 12 ) ;
+  glVertex2i ( x + 12, y - 15 ) ;
+
+  glVertex2i ( x + 12, y - 15 ) ;
+  glVertex2i ( x +  5, y -  8 ) ;
+  glVertex2i ( x +  8, y -  5 ) ;
+  glEnd      () ;
+}
+
+void  puInit ( void )
+{
+  static int firsttime = TRUE ;
+
+  if ( firsttime )
+  {
+    puInterface *base_interface = new puInterface ( 0, 0 ) ;
+    puPushInterface     ( base_interface ) ;
+    puPushLiveInterface ( base_interface ) ;
+    firsttime = FALSE ;
+  }
+}
+
+static void puSetOpenGLState ( void )
+{
+  int w = glutGet ( (GLenum) GLUT_WINDOW_WIDTH  ) ;
+  int h = glutGet ( (GLenum) GLUT_WINDOW_HEIGHT ) ;
+
+  glPushAttrib   ( GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_TRANSFORM_BIT ) ;
+  glDisable      ( GL_LIGHTING   ) ;
+  glDisable      ( GL_FOG        ) ;
+  glDisable      ( GL_TEXTURE_2D ) ;
+  glDisable      ( GL_DEPTH_TEST ) ;
+  glDisable      ( GL_CULL_FACE  ) ;
+  glViewport     ( 0, 0, w, h ) ;
+  glMatrixMode   ( GL_PROJECTION ) ;
+  glPushMatrix   () ;
+  glLoadIdentity () ;
+  gluOrtho2D     ( 0, w, 0, h ) ;
+  glMatrixMode   ( GL_MODELVIEW ) ;
+  glPushMatrix   () ;
+  glLoadIdentity () ;
+}
+
+static void puRestoreOpenGLState ( void )
+{
+  glMatrixMode   ( GL_PROJECTION ) ;
+  glPopMatrix    () ;
+  glMatrixMode   ( GL_MODELVIEW ) ;
+  glPopMatrix    () ;
+  glPopAttrib    () ;
+}
+
+
+void  puDisplay ( void )
+{
+  puSetOpenGLState () ;
+  puGetUltimateLiveInterface () -> draw ( 0, 0 ) ;
+
+  if ( _puCursor_enable )
+    puDrawCursor ( _puCursor_x,
+                   glutGet((GLenum)GLUT_WINDOW_HEIGHT) - _puCursor_y ) ;
+
+  puRestoreOpenGLState () ;
+}
+
+int puKeyboard ( int key, int updown )
+{
+  return puGetBaseLiveInterface () -> checkKey ( key, updown ) ;
+}
+
+
+static int last_buttons = 0 ;
+
+int puMouse ( int button, int updown, int x, int y )
+{
+  puCursor ( x, y ) ;
+
+  if ( updown == PU_DOWN )
+    last_buttons |=  ( 1 << button ) ;
+  else
+    last_buttons &= ~( 1 << button ) ;
+
+  return puGetBaseLiveInterface () -> checkHit ( button, updown, x,
+                                 glutGet((GLenum)GLUT_WINDOW_HEIGHT) - y ) ;
+}
+
+int puMouse ( int x, int y )
+{
+  puCursor ( x, y ) ;
+
+  if ( last_buttons == 0 )
+    return FALSE ;
+
+  int button = (last_buttons & (1<<PU_LEFT_BUTTON  )) ?  PU_LEFT_BUTTON   :
+               (last_buttons & (1<<PU_MIDDLE_BUTTON)) ?  PU_MIDDLE_BUTTON :
+               (last_buttons & (1<<PU_RIGHT_BUTTON )) ?  PU_RIGHT_BUTTON  : 0 ;
+
+  return puGetBaseLiveInterface () -> checkHit ( button, PU_DRAG, x,
+                                 glutGet((GLenum)GLUT_WINDOW_HEIGHT) - y ) ;
+}
+
diff --git a/PUI/pu.h b/PUI/pu.h
new file mode 100644 (file)
index 0000000..dd26e9a
--- /dev/null
+++ b/PUI/pu.h
@@ -0,0 +1,744 @@
+#ifndef _PU_H_
+#define _PU_H_
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#  include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <GL/glut.h>
+
+#ifndef TRUE
+#define TRUE  1
+#define FALSE 0
+#endif
+
+/*
+  Webster's Dictionary (for American English) permits
+  Color or Colour as acceptable spellings - but
+  The Oxford English Dictionary (for English) only
+  permits Colour.
+
+  Hence, the logical thing to do is to use 'colour',
+  which *ought* to be acceptable on both sides of
+  the atlantic.
+
+  However, as a concession to the illogical:
+*/
+
+#define setColorScheme          setColourScheme
+#define setColor                setColour
+#define getColor                getColour
+#define puColor                 puColour
+#define puSetColor              puSetColour
+#define puSetDefaultColorScheme puSetDefaultColourScheme
+#define puGetDefaultColorScheme puGetDefaultColourScheme
+
+
+typedef void *puFont ;
+
+#define PUFONT_8_BY_13        GLUT_BITMAP_8_BY_13
+#define PUFONT_9_BY_15        GLUT_BITMAP_9_BY_15
+#define PUFONT_TIMES_ROMAN_10 GLUT_BITMAP_TIMES_ROMAN_10
+#define PUFONT_TIMES_ROMAN_24 GLUT_BITMAP_TIMES_ROMAN_24
+#define PUFONT_HELVETICA_10   GLUT_BITMAP_HELVETICA_10
+#define PUFONT_HELVETICA_12   GLUT_BITMAP_HELVETICA_12
+#define PUFONT_HELVETICA_18   GLUT_BITMAP_HELVETICA_18
+
+#define PU_LEFT_BUTTON   GLUT_LEFT_BUTTON
+#define PU_MIDDLE_BUTTON GLUT_MIDDLE_BUTTON
+#define PU_RIGHT_BUTTON  GLUT_RIGHT_BUTTON
+#define PU_DOWN          GLUT_DOWN
+#define PU_UP            GLUT_UP
+#define PU_UP_AND_DOWN   254
+#define PU_DRAG          255
+#define PU_CONTINUAL     PU_DRAG
+
+#define PU_KEY_GLUT_SPECIAL_OFFSET  256
+#define PU_KEY_F1        (GLUT_KEY_F1        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F2        (GLUT_KEY_F2        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F3        (GLUT_KEY_F3        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F4        (GLUT_KEY_F4        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F5        (GLUT_KEY_F5        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F6        (GLUT_KEY_F6        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F7        (GLUT_KEY_F7        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F8        (GLUT_KEY_F8        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F9        (GLUT_KEY_F9        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F10       (GLUT_KEY_F10       + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F11       (GLUT_KEY_F11       + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_F12       (GLUT_KEY_F12       + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_LEFT      (GLUT_KEY_LEFT      + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_UP        (GLUT_KEY_UP        + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_RIGHT     (GLUT_KEY_RIGHT     + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_DOWN      (GLUT_KEY_DOWN      + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_PAGE_UP   (GLUT_KEY_PAGE_UP   + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_PAGE_DOWN (GLUT_KEY_PAGE_DOWN + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_HOME      (GLUT_KEY_HOME      + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_END       (GLUT_KEY_END       + PU_KEY_GLUT_SPECIAL_OFFSET)
+#define PU_KEY_INSERT    (GLUT_KEY_INSERT    + PU_KEY_GLUT_SPECIAL_OFFSET)
+
+#define PUPLACE_DEFAULT  PUPLACE_RIGHT
+#define PUPLACE_ABOVE    0
+#define PUPLACE_BELOW    1
+#define PUPLACE_LEFT     2
+#define PUPLACE_RIGHT    3
+
+#define PUCOL_FOREGROUND 0
+#define PUCOL_BACKGROUND 1
+#define PUCOL_HIGHLIGHT  2
+#define PUCOL_LABEL      3
+#define PUCOL_LEGEND     4
+#define PUCOL_MAX        5
+
+#define PUSLIDER_CLICK   0
+#define PUSLIDER_ALWAYS  1
+#define PUSLIDER_DELTA   2
+
+/* These styles may be negated to get 'highlighted' graphics */
+
+#define PUSTYLE_DEFAULT    PUSTYLE_BEVELLED
+#define PUSTYLE_NONE       0
+#define PUSTYLE_PLAIN      1
+#define PUSTYLE_BEVELLED   2
+#define PUSTYLE_BOXED      3
+#define PUSTYLE_DROPSHADOW 4
+#define PUSTYLE_SPECIAL_UNDERLINED 5
+#define PUSTYLE_SMALL_BEVELLED     6
+#define PUSTYLE_RADIO      7
+#define PUSTYLE_MAX        8
+
+/* These are the gaps that we try to leave around text objects */
+
+#define PUSTR_TGAP   5
+#define PUSTR_BGAP   5
+#define PUSTR_LGAP   5
+#define PUSTR_RGAP   5
+#define PUSTR_MAX_HEIGHT  ( 25 + PUSTR_TGAP + PUSTR_BGAP )
+
+#define PU_RADIO_BUTTON_SIZE 16
+
+extern int puRefresh ;
+
+#define PUCLASS_VALUE            0x00000001
+#define PUCLASS_OBJECT           0x00000002
+#define PUCLASS_INTERFACE        0x00000004
+#define PUCLASS_FRAME            0x00000008
+#define PUCLASS_TEXT             0x00000010
+#define PUCLASS_BUTTON           0x00000020
+#define PUCLASS_ONESHOT          0x00000040
+#define PUCLASS_POPUP            0x00000080
+#define PUCLASS_POPUPMENU        0x00000100
+#define PUCLASS_MENUBAR          0x00000200
+#define PUCLASS_INPUT            0x00000400
+#define PUCLASS_BUTTONBOX        0x00000800
+#define PUCLASS_SLIDER           0x00001000
+#define PUCLASS_DIALOGBOX        0x00002000
+
+class puValue            ;
+class puObject           ;
+class puInterface        ;
+class puButtonBox        ;
+class puFrame            ;
+class puText             ;
+class puButton           ;
+class puOneShot          ;
+class puPopup            ;
+class puPopupMenu        ;
+class puMenuBar          ;
+class puInput            ;
+class puSlider           ;
+
+typedef float puColour [ 4 ] ;  /* RGBA */
+
+struct puBox
+{
+  int min [ 2 ] ;
+  int max [ 2 ] ;
+
+  void draw   ( int dx, int dy, int style, puColour colour[], int am_default ) ;
+  void extend ( puBox *bx ) ;
+
+  void empty   ( void ) { min[0]=min[1]=1000000 ; max[0]=max[1]=-1000000 ; }
+  int  isEmpty ( void ) { return min[0]>max[0] || min[1]>max[1] ; }
+} ;
+
+#define PUSTRING_MAX 80
+
+/* If you change - or add to these, be sure to change _puDefaultColourTable */
+
+extern puColour _puDefaultColourTable[] ;
+
+
+inline void puSetColour ( puColour dst, puColour src )
+{
+  dst[0] = src[0] ; dst[1] = src[1] ; dst[2] = src[2] ; dst[3] = src[3] ;
+}
+
+inline void puSetColour ( puColour c, float r, float g, float b, float a = 1.0f )
+{
+  c [ 0 ] = r ; c [ 1 ] = g ; c [ 2 ] = b ; c [ 3 ] = a ;
+}
+
+
+void  puInit           ( void ) ;
+void  puDisplay        ( void ) ;
+int   puMouse          ( int button, int updown, int x, int y ) ;
+int   puMouse          ( int x, int y ) ;
+int   puKeyboard       ( int key, int updown ) ;
+void  puHideCursor     ( void ) ;
+void  puShowCursor     ( void ) ;
+int   puCursorIsHidden ( void ) ;
+
+void puDrawString         ( puFont fnt, char *str, int x, int y ) ;
+int  puGetStringWidth     ( puFont fnt, char *str ) ;
+int  puGetStringHeight    ( puFont fnt = NULL ) ;
+int  puGetStringDescender ( puFont fnt = NULL ) ;
+
+class puValue
+{
+protected:
+  int   type    ;
+  int   integer ;
+  float floater ;
+  char  string  [ PUSTRING_MAX ] ;
+public:
+  puValue () { type = PUCLASS_VALUE ; clrValue () ; }
+
+  virtual ~puValue () ;
+
+  int  getType ( void ) { return type ; }
+  char *getTypeString ( void ) ;
+  void clrValue ( void ) { setValue ( "" ) ; }
+
+  void setValue ( puValue *pv )
+  {
+    integer = pv -> integer ;
+    floater = pv -> floater ;
+    strcpy ( string, pv -> string ) ;
+    puRefresh = TRUE ;
+  }
+
+  void setValue ( int   i ) { integer = i ; floater = (float) i ; sprintf ( string, "%d", i ) ; puRefresh = TRUE ; }
+  void setValue ( float f ) { integer = (int) f ; floater = f ; sprintf ( string, "%g", f ) ; puRefresh = TRUE ; }
+  void setValue ( char *s ) { 
+                              if ( s == NULL || s[0] == '\0' )
+                              {
+                                integer = 0 ;
+                                floater = 0.0f ;
+                                s = "" ;
+                              }
+                              else
+                              {
+                                integer = atoi(s) ;
+                                floater = atof(s) ;
+
+                                if ( string != s ) strcpy ( string, s ) ;
+                              }
+                              puRefresh = TRUE ;
+                            }
+
+  void getValue ( int   *i ) { *i = integer ; }
+  void getValue ( float *f ) { *f = floater ; }
+  void getValue ( char **s ) { *s = string  ; }
+  void getValue ( char  *s ) { strcpy ( s, string ) ; }
+
+  int  getValue ( void ) { return integer ; }
+} ;
+
+typedef void (*puCallback)(class puObject *) ;
+
+void puSetDefaultStyle ( int  style ) ;
+int  puGetDefaultStyle ( void ) ;
+void puSetDefaultFonts ( puFont  legendFont, puFont  labelFont ) ;
+void puGetDefaultFonts ( puFont *legendFont, puFont *labelFont ) ;
+void puSetDefaultColourScheme ( float r, float g, float b, float a = 1.0 ) ;
+void puGetDefaultColourScheme ( float *r, float *g, float *b, float *a = NULL );
+
+class puObject : public puValue
+{
+protected:
+  puValue default_value ;
+
+  puBox bbox ;   /* Bounding box of entire Object */
+  puBox abox ;   /* Active (clickable) area */
+  puColour colour [ PUCOL_MAX ] ;
+  puInterface *parent ;
+
+  int active_mouse_edge ; /* is it PU_UP or PU_DOWN (or both) that activates this? */
+  int style       ;
+  int visible     ;
+  int active      ;
+  int highlighted ;
+  int am_default  ;
+
+  char *label  ; puFont  labelFont ; int labelPlace ;
+  char *legend ; puFont legendFont ;
+
+  void *user_data ;
+  puCallback cb ;
+
+  virtual void draw_label  ( int dx, int dy ) ;
+  virtual int  isHit ( int x, int y ) { return isVisible() && isActive() &&
+                                               x >= abox.min[0] &&
+                                               x <= abox.max[0] &&
+                                               y >= abox.min[1] &&
+                                               y <= abox.max[1] ; }
+  virtual void doHit ( int button, int updown, int x, int y ) ;
+
+public:
+   puObject ( int minx, int miny, int maxx, int maxy ) ;
+  ~puObject () ;
+
+  puObject *next ;
+  puObject *prev ;
+  puBox *getBBox ( void ) { return & bbox ; }
+  puBox *getABox ( void ) { return & abox ; }
+
+  void setPosition ( int x, int y )
+  {
+    if ( abox.isEmpty() )
+    {
+      abox.max[0] = abox.min[0] = x ;
+      abox.max[1] = abox.min[1] = y ;
+    }
+    else
+    {
+      abox.max[0] += x - abox.min[0] ;
+      abox.max[1] += y - abox.min[1] ;
+      abox.min[0]  = x ;
+      abox.min[1]  = y ;
+    }
+    recalc_bbox() ; puRefresh = TRUE ;
+  }
+
+  void setSize ( int w, int h )
+  {
+    abox.max[0] = abox.min[0] + w ;
+    abox.max[1] = abox.min[1] + h ;
+    recalc_bbox() ; puRefresh = TRUE ;
+  }
+
+  void getPosition ( int *x, int *y )
+  {
+    if ( abox . isEmpty () )
+    {
+      if ( x ) *x = 0 ;
+      if ( y ) *y = 0 ;
+    }
+    else
+    {
+      if ( x ) *x = abox.min[0] ;
+      if ( y ) *y = abox.min[1] ;
+    }
+  }
+
+  void getSize ( int *w, int *h )
+  {
+    if ( abox . isEmpty () )
+    {
+      if ( w ) *w = 0 ;
+      if ( h ) *h = 0 ;
+    }
+    else
+    {
+      if ( w ) *w = abox.max[0] - abox.min[0] ;
+      if ( h ) *h = abox.max[1] - abox.min[1] ;
+    }
+  }
+
+  virtual void recalc_bbox ( void ) ;
+  virtual int  checkHit ( int button, int updown, int x, int y ) ;
+  virtual int  checkKey ( int key   , int updown ) ;
+  virtual void draw ( int dx, int dy ) = 0 ;
+
+  puInterface *getParent     ( void ) { return parent ; }
+  puObject    *getNextObject ( void ) { return next   ; }
+  puObject    *getPrevObject ( void ) { return prev   ; }
+
+  void       setCallback ( puCallback c ) { cb = c ;    }
+  puCallback getCallback ( void )               { return cb ; }
+  void       invokeCallback ( void ) { if ( cb ) (*cb)(this) ; }
+
+  void  makeReturnDefault ( int def ) { am_default = def ; }
+  int   isReturnDefault   ( void )          { return am_default ; }
+
+  void  setActiveDirn ( int e ) { active_mouse_edge = e ; }
+  int   getActiveDirn ( void ) { return active_mouse_edge ; }
+
+  void  setLegend ( char *l ) { legend = l ; recalc_bbox() ; puRefresh = TRUE ; }
+  char *getLegend ( void ) { return legend ; }
+
+  void  setLegendFont ( puFont f ) { legendFont = f ; recalc_bbox() ; puRefresh = TRUE ; }
+  puFont getLegendFont ( void ) { return legendFont ; }
+
+  void  setLabel ( char *l ) { label = l ; recalc_bbox() ; puRefresh = TRUE ; }
+  char *getLabel ( void ) { return label ; }
+
+  void  setLabelFont ( puFont f ) { labelFont = f ; recalc_bbox() ; puRefresh = TRUE ; }
+  puFont getLabelFont ( void ) { return labelFont ; }
+
+  void  setLabelPlace ( int lp ) { labelPlace = lp ; recalc_bbox() ; puRefresh = TRUE ; }
+  int   getLabelPlace ( void ) { return labelPlace ; }
+
+  void activate   ( void ) { if ( ! active  ) { active  = TRUE  ; puRefresh = TRUE ; } }
+  void greyOut    ( void ) { if (   active  ) { active  = FALSE ; puRefresh = TRUE ; } }
+  int  isActive   ( void ) { return active ; }
+
+  void highlight  ( void ) { if ( ! highlighted ) { highlighted = TRUE  ; puRefresh = TRUE ; } }
+  void lowlight   ( void ) { if (   highlighted ) { highlighted = FALSE ; puRefresh = TRUE ; } }
+  int isHighlighted( void ){ return highlighted ; }
+
+  void reveal     ( void ) { if ( ! visible ) { visible = TRUE  ; puRefresh = TRUE ; } }
+  void hide       ( void ) { if (   visible ) { visible = FALSE ; puRefresh = TRUE ; } }
+  int  isVisible  ( void ) { return visible ; }
+
+  void setStyle ( int which )
+  {
+    style = which ;
+    recalc_bbox () ;
+    puRefresh = TRUE ;
+  }
+
+  int  getStyle ( void ) { return style ; }
+
+  void setColourScheme ( float r, float g, float b, float a = 1.0f ) ;
+
+  void setColour ( int which, float r, float g, float b, float a = 1.0f )
+  {
+    puSetColour ( colour [ which ], r, g, b, a ) ;
+    puRefresh = TRUE ;
+  }
+
+  void getColour ( int which, float *r, float *g, float *b, float *a = NULL )
+  {
+    if ( r ) *r = colour[which][0] ;
+    if ( g ) *g = colour[which][1] ;
+    if ( b ) *b = colour[which][2] ;
+    if ( a ) *a = colour[which][3] ;
+  }
+
+  void  setUserData ( void *data ) { user_data = data ; }
+  void *getUserData ( void )             { return user_data ; }
+
+  void defaultValue ( void ) { setValue ( & default_value ) ; }
+
+  void setDefaultValue ( int    i ) { default_value . setValue ( i ) ; }
+  void setDefaultValue ( float  f ) { default_value . setValue ( f ) ; }
+  void setDefaultValue ( char  *s ) { default_value . setValue ( s ) ; }
+
+  void getDefaultValue ( int   *i ) { default_value . getValue ( i ) ; }
+  void getDefaultValue ( float *f ) { default_value . getValue ( f ) ; }
+  void getDefaultValue ( char **s ) { default_value . getValue ( s ) ; }
+  int  getDefaultValue ( void )    { return default_value . getValue () ; }
+} ;
+
+/*
+  The 'live' interface stack is used for clicking and rendering.
+*/
+
+void         puPushLiveInterface        ( puInterface *in ) ;
+void         puPopLiveInterface         ( void ) ;
+int          puNoLiveInterface          ( void ) ;
+puInterface *puGetBaseLiveInterface     ( void ) ;
+puInterface *puGetUltimateLiveInterface ( void ) ;
+
+/*
+  The regular interface stack is used for adding widgets
+*/
+
+void         puPushInterface        ( puInterface *in ) ;
+void         puPopInterface         ( void ) ;
+int          puNoInterface          ( void ) ;
+puInterface *puGetCurrInterface     ( void ) ;
+
+class puInterface : public puObject
+{
+protected:
+  int num_children ;
+  puObject *dlist ;
+
+  void doHit       ( int button, int updown, int x, int y ) ;
+
+public:
+
+  puInterface ( int x, int y ) : puObject ( x, y, x, y )
+  {
+    type |= PUCLASS_INTERFACE ;
+    dlist = NULL ;
+    num_children = 0 ;
+    puPushInterface ( this ) ;
+    puPushLiveInterface ( this ) ;
+  }
+
+  ~puInterface () ;
+
+  void recalc_bbox ( void ) ;
+  virtual void add    ( puObject *new_object ) ;
+  virtual void remove ( puObject *old_object ) ;
+
+  void draw        ( int dx, int dy ) ;
+  int  checkHit    ( int button, int updown, int x, int y ) ;
+  int  checkKey    ( int key   , int updown ) ;
+
+  puObject *getFirstChild ( void ) { return dlist ; }
+  int getNumChildren ( void ) { return num_children ; }
+
+  virtual void close ( void )
+  {
+    if ( puGetCurrInterface () != this )
+      fprintf ( stderr, "PUI: puInterface::close() is mismatched!\n" ) ;
+    else
+      puPopInterface () ;
+  }
+} ;
+
+class puFrame : public puObject
+{
+protected:
+  virtual int  isHit ( int /* x */, int /* y */ ) { return FALSE ; }
+public:
+  void draw ( int dx, int dy ) ;
+  puFrame ( int minx, int miny, int maxx, int maxy ) :
+             puObject ( minx, miny, maxx, maxy )
+  {
+    type |= PUCLASS_FRAME ;
+  }
+} ;
+
+
+class puText : public puObject
+{
+protected:
+  virtual int  isHit ( int /* x */, int /* y */ ) { return FALSE ; }
+public:
+  void draw ( int dx, int dy ) ;
+  puText ( int x, int y ) : puObject ( x, y, x, y )
+  {
+    type |= PUCLASS_TEXT ;
+  }
+} ;
+
+
+class puButton : public puObject
+{
+protected:
+public:
+  void doHit ( int button, int updown, int x, int y ) ;
+  void draw  ( int dx, int dy ) ;
+  puButton   ( int minx, int miny, char *l ) :
+                 puObject ( minx, miny,
+                            minx + puGetStringWidth  ( NULL, l ) + PUSTR_LGAP + PUSTR_RGAP,
+                            miny + puGetStringHeight () + puGetStringDescender () + PUSTR_TGAP + PUSTR_BGAP )
+  {
+    type |= PUCLASS_BUTTON ;
+    setLegend ( l ) ;
+  }
+
+  puButton   ( int minx, int miny, int maxx, int maxy ) :
+                 puObject ( minx, miny, maxx, maxy )
+  {
+    type |= PUCLASS_BUTTON ;
+  }
+} ;
+
+
+class puSlider : public puObject
+{
+protected:
+  int vert ;
+  float last_cb_value ;
+  float cb_delta ;
+  int   cb_mode ;
+  float slider_fraction ;
+public:
+  void doHit ( int button, int updown, int x, int y ) ;
+  void draw  ( int dx, int dy ) ;
+  puSlider ( int minx, int miny, int sz, int vertical = FALSE ) :
+     puObject ( minx, miny, vertical ?
+                             ( minx + puGetStringWidth ( NULL, "W" ) +
+                                      PUSTR_LGAP + PUSTR_RGAP ) :
+                             ( minx + sz ),
+                            vertical ?
+                             ( miny + sz ) :
+                             ( miny + puGetStringHeight () +
+                                      puGetStringDescender () +
+                                      PUSTR_TGAP + PUSTR_BGAP )
+                           )
+  {
+    type |= PUCLASS_SLIDER ;
+    slider_fraction = 0.1f ;
+    getValue ( & last_cb_value ) ;
+    vert = vertical ;
+    cb_delta = 0.1f ;
+    cb_mode = PUSLIDER_ALWAYS ;
+  }
+
+  void setCBMode ( int m ) { cb_mode = m ; }
+  float getCBMode ( void ) { return cb_mode ; }
+
+  int  isVertical ( void ) { return vert ; }
+
+  void setDelta ( float f ) { cb_delta = (f<=0.0f) ? 0.1f : (f>=1.0) ? 0.9 : f ; }
+  float getDelta ( void ) { return cb_delta ; }
+
+  void setSliderFraction ( float f ) { slider_fraction = (f<=0.0f) ? 0.1f : (f>=1.0) ? 0.9 : f ; }
+  float getSliderFraction ( void ) { return slider_fraction ; }
+} ;
+
+
+
+class puOneShot : public puButton
+{
+protected:
+public:
+  void doHit ( int button, int updown, int x, int y ) ;
+
+  puOneShot ( int minx, int miny, char *l ) : puButton   ( minx, miny, l )
+  {
+    type |= PUCLASS_ONESHOT ;
+  }
+
+  puOneShot ( int minx, int miny, int maxx, int maxy ) :
+                 puButton ( minx, miny, maxx, maxy )
+  {
+    type |= PUCLASS_ONESHOT ;
+  }
+} ;
+
+
+
+class puPopup : public puInterface
+{
+protected:
+public:
+  puPopup ( int x, int y ) : puInterface ( x, y )
+  {
+    type |= PUCLASS_POPUP ;
+    hide () ;
+  }
+} ;
+
+class puPopupMenu : public puPopup
+{
+protected:
+public:
+  puPopupMenu ( int x, int y ) : puPopup ( x, y )
+  {
+    type |= PUCLASS_POPUPMENU ;
+  }
+
+  puObject *add_item ( char *str, puCallback cb ) ;
+  int  checkHit ( int button, int updown, int x, int y ) ;
+  int  checkKey ( int key   , int updown ) ;
+  void close ( void ) ;
+} ;
+
+
+class puMenuBar : public puInterface
+{
+protected:
+public:
+  puMenuBar ( int h = -1 ) :
+    puInterface ( 0, h < 0 ? glutGet((GLenum) GLUT_WINDOW_HEIGHT ) -
+                      ( puGetStringHeight() + PUSTR_TGAP + PUSTR_BGAP ) : h )
+  {
+    type |= PUCLASS_MENUBAR ;
+  }
+
+  void add_submenu ( char *str, char *items[], puCallback cb[] ) ;
+  void close ( void ) ;
+} ;
+
+
+class puInput : public puObject
+{
+  int accepting ;
+  int cursor_position ;
+  int select_start_position ;
+  int select_end_position ;
+
+  void normalize_cursors ( void ) ;
+
+public:
+  void draw     ( int dx, int dy ) ;
+  void doHit    ( int button, int updown, int x, int y ) ;
+  int  checkKey ( int key, int updown ) ;
+
+  int  isAcceptingInput ( void ) { return accepting ; }
+  void rejectInput      ( void ) { accepting = FALSE ; }
+  void acceptInput      ( void ) { accepting = TRUE ;
+                             cursor_position = strlen ( string ) ;
+                             select_start_position = select_end_position = -1 ; }
+
+  int  getCursor ( void )        { return cursor_position ; }
+  void setCursor ( int c ) { cursor_position = c ; }
+
+  void setSelectRegion ( int s, int e )
+  {
+    select_start_position = s ;
+    select_end_position   = e ;
+  }
+
+  void getSelectRegion ( int *s, int *e )
+  {
+    if ( s ) *s = select_start_position ;
+    if ( e ) *e = select_end_position   ;
+  }
+
+  puInput ( int minx, int miny, int maxx, int maxy ) :
+             puObject ( minx, miny, maxx, maxy )
+  {
+    type |= PUCLASS_INPUT ;
+
+    accepting = FALSE ;
+
+    cursor_position       =  0 ;
+    select_start_position = -1 ;
+    select_end_position   = -1 ;
+
+    setColourScheme ( 0.8, 0.7, 0.7 ) ; /* Yeukky Pink */
+  }
+} ;
+
+
+class puButtonBox : public puObject
+{
+protected:
+  int one_only ;
+  int num_kids ;
+  char **button_labels ;
+
+public:
+
+  puButtonBox ( int minx, int miny, int maxx, int maxy, 
+                char **labels, int one_button ) ;
+
+  int isOneButton ( void ) { return one_only ; }
+
+  int checkKey ( int key   , int updown ) ;
+  int checkHit ( int button, int updown, int x, int y ) ;
+  void draw    ( int dx, int dy ) ;
+} ;
+
+
+
+class puDialogBox : public puPopup
+{
+protected:
+public:
+
+  puDialogBox ( int x, int y ) : puPopup ( x, y )
+  {
+    type |= PUCLASS_DIALOGBOX ;
+  }
+} ;
+
+#endif
+
diff --git a/PUI/puBox.cxx b/PUI/puBox.cxx
new file mode 100644 (file)
index 0000000..0fcb524
--- /dev/null
@@ -0,0 +1,193 @@
+#include "puLocal.h"
+
+#define PU_BEVEL              5
+#define PU_SMALL_BEVEL        2
+#define PU_DFLT_OFFSET        8
+#define PU_BOX_WIDTH          2
+#define PU_DROPSHADOW_OFFSET 10
+
+void puBox::extend ( puBox *bx )
+{
+  if ( bx -> isEmpty () ) return ;
+
+  if ( min[0]>bx->min[0] ) min[0] = bx->min[0] ;
+  if ( min[1]>bx->min[1] ) min[1] = bx->min[1] ;
+  if ( max[0]<bx->max[0] ) max[0] = bx->max[0] ;
+  if ( max[1]<bx->max[1] ) max[1] = bx->max[1] ;
+}
+
+void puBox::draw ( int dx, int dy, int style, puColour colour[], int am_default  )
+{
+  int hi, mid, lo ;
+
+  /* Colour assignments */
+
+  switch ( style )
+  {
+    case  PUSTYLE_NONE       :
+      return ;
+
+    case  PUSTYLE_PLAIN      :
+    case  PUSTYLE_DROPSHADOW :
+      mid = PUCOL_FOREGROUND ;
+      lo  = PUCOL_BACKGROUND ;
+      break ;
+
+    case  PUSTYLE_SMALL_BEVELLED :
+    case  PUSTYLE_BEVELLED   :
+    case  PUSTYLE_BOXED      :
+    case  PUSTYLE_SPECIAL_UNDERLINED :
+      mid = PUCOL_FOREGROUND ;
+      hi  = PUCOL_HIGHLIGHT  ;
+      lo  = PUCOL_BACKGROUND ;
+      break ;
+
+    case  PUSTYLE_RADIO      :
+    case -PUSTYLE_RADIO      :
+      hi  = PUCOL_HIGHLIGHT  ;
+      lo  = PUCOL_BACKGROUND ;
+      break ;
+
+    case -PUSTYLE_PLAIN      :
+    case -PUSTYLE_DROPSHADOW :
+      mid = PUCOL_HIGHLIGHT  ;
+      lo  = PUCOL_BACKGROUND ;
+      break ;
+
+    case -PUSTYLE_SMALL_BEVELLED :
+    case -PUSTYLE_BEVELLED   :
+    case -PUSTYLE_BOXED      :
+    case -PUSTYLE_SPECIAL_UNDERLINED :
+      mid = PUCOL_FOREGROUND ;
+      hi  = PUCOL_BACKGROUND ;
+      lo  = PUCOL_HIGHLIGHT  ;
+      break ;
+
+    default :
+      fprintf ( stderr, "PUI: Unrecognised 'style' %d\n", style ) ;
+      return ;
+  }
+
+  switch ( abs(style) )
+  {
+    case  PUSTYLE_PLAIN      :
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0], dy + min[1],
+               dx + max[0], dy + max[1] ) ;
+      break ;
+
+    case  PUSTYLE_SMALL_BEVELLED   :
+      glColor4fv ( colour [ hi  ] ) ;
+      glBegin ( GL_QUAD_STRIP ) ;
+       glVertex2i ( dx + min[0] + PU_SMALL_BEVEL, dy + min[1] + PU_SMALL_BEVEL ) ;
+       glVertex2i ( dx + min[0], dy + min[1] ) ;
+       glVertex2i ( dx + min[0] + PU_SMALL_BEVEL, dy + max[1] - PU_SMALL_BEVEL ) ;
+       glVertex2i ( dx + min[0], dy + max[1] ) ;
+       glVertex2i ( dx + max[0] - PU_SMALL_BEVEL, dy + max[1] - PU_SMALL_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + max[1] ) ;
+      glEnd () ;
+       glColor4fv ( colour [ lo  ] ) ;
+      glBegin ( GL_QUAD_STRIP ) ;
+       glVertex2i ( dx + min[0], dy + min[1] ) ;
+       glVertex2i ( dx + min[0] + PU_SMALL_BEVEL, dy + min[1] + PU_SMALL_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + min[1] ) ;
+       glVertex2i ( dx + max[0] - PU_SMALL_BEVEL, dy + min[1] + PU_SMALL_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + max[1] ) ;
+       glVertex2i ( dx + max[0] - PU_SMALL_BEVEL, dy + max[1] - PU_SMALL_BEVEL ) ;
+      glEnd () ;
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0] + PU_SMALL_BEVEL, dy + min[1] + PU_SMALL_BEVEL,
+               dx + max[0] - PU_SMALL_BEVEL, dy + max[1] - PU_SMALL_BEVEL ) ;
+      break ;
+
+    case  PUSTYLE_BEVELLED   :
+      glColor4fv ( colour [ hi  ] ) ;
+      glBegin ( GL_QUAD_STRIP ) ;
+       glVertex2i ( dx + min[0] + PU_BEVEL, dy + min[1] + PU_BEVEL ) ;
+       glVertex2i ( dx + min[0], dy + min[1] ) ;
+       glVertex2i ( dx + min[0] + PU_BEVEL, dy + max[1] - PU_BEVEL ) ;
+       glVertex2i ( dx + min[0], dy + max[1] ) ;
+       glVertex2i ( dx + max[0] - PU_BEVEL, dy + max[1] - PU_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + max[1] ) ;
+      glEnd () ;
+       glColor4fv ( colour [ lo  ] ) ;
+      glBegin ( GL_QUAD_STRIP ) ;
+       glVertex2i ( dx + min[0], dy + min[1] ) ;
+       glVertex2i ( dx + min[0] + PU_BEVEL, dy + min[1] + PU_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + min[1] ) ;
+       glVertex2i ( dx + max[0] - PU_BEVEL, dy + min[1] + PU_BEVEL ) ;
+       glVertex2i ( dx + max[0], dy + max[1] ) ;
+       glVertex2i ( dx + max[0] - PU_BEVEL, dy + max[1] - PU_BEVEL ) ;
+      glEnd () ;
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0] + PU_BEVEL, dy + min[1] + PU_BEVEL,
+               dx + max[0] - PU_BEVEL, dy + max[1] - PU_BEVEL ) ;
+      break ;
+
+    case  PUSTYLE_BOXED      :
+      glColor4fv ( colour [ hi  ] ) ;
+      glRecti ( dx + min[0], dy + min[1],
+               dx + max[0], dy + max[1] ) ;
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0]+PU_BOX_WIDTH, dy + min[1]+PU_BOX_WIDTH,
+               dx + max[0]-PU_BOX_WIDTH, dy + max[1]-PU_BOX_WIDTH ) ;
+      break ;
+
+    case  PUSTYLE_RADIO      :
+      glColor4fv ( colour [ lo  ] ) ;
+      glBegin ( GL_LINE_LOOP ) ;
+        glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE/2, dy + min[1]                          ) ;
+        glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE  , dy + min[1] + PU_RADIO_BUTTON_SIZE/2 ) ;
+        glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE/2, dy + min[1] + PU_RADIO_BUTTON_SIZE   ) ;
+        glVertex2i ( dx + min[0]                         , dy + min[1] + PU_RADIO_BUTTON_SIZE/2 ) ;
+      glEnd () ;
+
+      if ( style < 0 )
+      {
+       glColor4fv ( colour [ hi  ] ) ;
+       glBegin ( GL_QUADS ) ;
+         glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE/2, dy + min[1] + 2                      ) ;
+         glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE-2, dy + min[1] + PU_RADIO_BUTTON_SIZE/2 ) ;
+         glVertex2i ( dx + min[0] + PU_RADIO_BUTTON_SIZE/2, dy + min[1] + PU_RADIO_BUTTON_SIZE-2 ) ;
+         glVertex2i ( dx + min[0] + 2                     , dy + min[1] + PU_RADIO_BUTTON_SIZE/2 ) ;
+       glEnd () ;
+      }
+      break ;
+
+    case  PUSTYLE_SPECIAL_UNDERLINED :
+      glColor4fv ( colour [ hi  ] ) ;
+      glRecti ( dx + min[0], dy + min[1],
+               dx + max[0], dy + min[1]+2 ) ;
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0], dy + min[1]+1,
+               dx + max[0], dy + max[1] ) ;
+      break ;
+
+    case  PUSTYLE_DROPSHADOW :
+      glColor4fv ( colour [ lo  ] ) ;
+      glRecti ( dx + min[0] + PU_DROPSHADOW_OFFSET, dy + min[1] - PU_DROPSHADOW_OFFSET,
+               dx + max[0] + PU_DROPSHADOW_OFFSET, dy + max[1] - PU_DROPSHADOW_OFFSET ) ;
+      glColor4fv ( colour [ mid ] ) ;
+      glRecti ( dx + min[0], dy + min[1],
+               dx + max[0], dy + max[1] ) ;
+      break ;
+  }
+
+  if ( am_default )
+  {
+    glColor4fv ( colour [ PUCOL_BACKGROUND ] ) ;
+    glLineStipple ( 1, 0xF0F0 ) ;
+    glEnable ( GL_LINE_STIPPLE ) ;
+    glBegin ( GL_LINE_LOOP ) ;
+      glVertex2i ( dx + min[0] + PU_DFLT_OFFSET, dy + min[1] + PU_DFLT_OFFSET ) ;
+      glVertex2i ( dx + min[0] + PU_DFLT_OFFSET, dy + max[1] - PU_DFLT_OFFSET ) ;
+      glVertex2i ( dx + max[0] - PU_DFLT_OFFSET, dy + max[1] - PU_DFLT_OFFSET ) ;
+      glVertex2i ( dx + max[0] - PU_DFLT_OFFSET, dy + min[1] + PU_DFLT_OFFSET ) ;
+    glEnd () ;
+    glDisable ( GL_LINE_STIPPLE ) ;
+  }
+}
+
+
diff --git a/PUI/puButton.cxx b/PUI/puButton.cxx
new file mode 100644 (file)
index 0000000..24a9802
--- /dev/null
@@ -0,0 +1,50 @@
+
+#include "puLocal.h"
+
+void puButton::draw ( int dx, int dy )
+{
+  if ( !visible ) return ;
+
+  /* If button is pushed or highlighted - use inverse style for button itself */
+
+  abox . draw ( dx, dy, ( getValue() ^ highlighted ) ? -style : style, colour,
+                                            isReturnDefault() ) ;
+
+  /* If greyed out then halve the opacity when drawing the label and legend */
+
+  if ( active )
+    glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
+  else
+    glColor4f ( colour [ PUCOL_LEGEND ][0],
+                colour [ PUCOL_LEGEND ][1],
+                colour [ PUCOL_LEGEND ][2],
+                colour [ PUCOL_LEGEND ][3] / 2.0 ) ; /* 50% more transparent */
+
+  int xx = ( abox.max[0] - abox.min[0] - puGetStringWidth(legendFont,legend) ) / 2 ;
+  int yy = ( abox.max[1] - abox.min[1] - puGetStringHeight(legendFont) ) / 2 ;
+
+  puDrawString ( legendFont, legend,
+                  dx + abox.min[0] + xx,
+                  dy + abox.min[1] + yy ) ;
+
+  draw_label ( dx, dy ) ;
+}
+
+
+void puButton::doHit ( int button, int updown, int, int )
+{
+  if ( button == PU_LEFT_BUTTON )
+  {
+    if ( updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN )
+    {
+      lowlight () ;
+      setValue ( (int) ! getValue () ) ;
+      invokeCallback () ;
+    }
+    else
+      highlight () ;
+  }
+  else
+    lowlight () ;
+}
+
diff --git a/PUI/puButtonBox.cxx b/PUI/puButtonBox.cxx
new file mode 100644 (file)
index 0000000..4969c83
--- /dev/null
@@ -0,0 +1,100 @@
+
+#include "puLocal.h"
+
+puButtonBox::puButtonBox ( int minx, int miny, int maxx, int maxy,
+                char **labels, int one_button ) :
+                    puObject ( minx, miny, maxx, maxy )
+{
+  type |= PUCLASS_BUTTONBOX ;
+  one_only = one_button ;
+
+  button_labels = labels ;
+
+  for ( num_kids = 0 ; button_labels [ num_kids ] != NULL ; num_kids++ )
+    /* Count number of labels */ ;
+}
+
+
+int puButtonBox::checkKey ( int key, int updown )
+{
+  if ( updown == PU_UP ||
+       ! isReturnDefault() ||
+       ( key != '\r' && key != '\n' ) )
+    return FALSE ;
+
+  int v = getValue () ;
+
+  if ( ! one_only )
+    v = ~v ;
+  else
+  if ( v++ > num_kids )
+    v = 0 ;
+
+  setValue ( v ) ;
+  invokeCallback() ;
+  return TRUE ;
+}
+
+
+int puButtonBox::checkHit ( int button, int updown, int x, int y )
+{
+  if ( ! isHit ( x, y ) ||
+       ( updown != active_mouse_edge &&
+         active_mouse_edge != PU_UP_AND_DOWN ) )
+    return FALSE ;
+
+  int i = num_kids - 1 - (( y - abox.min[1] - PUSTR_BGAP ) * num_kids ) /
+                          ( abox.max[1] - abox.min[1] - PUSTR_BGAP - PUSTR_TGAP ) ;
+
+  if ( i < 0 ) i = 0 ;
+  if ( i >= num_kids ) i = num_kids - 1 ;
+
+  if ( one_only )
+    setValue ( i ) ;
+  else
+    setValue ( getValue () ^ ( 1 << i ) ) ;
+
+  invokeCallback () ;
+  return TRUE ;
+}
+
+
+void puButtonBox::draw ( int dx, int dy )
+{
+  if ( !visible ) return ;
+
+  abox . draw ( dx, dy, style, colour, isReturnDefault() ) ;
+
+  for ( int i = 0 ; i < num_kids ; i++ )
+  {
+    puBox tbox ;
+
+    tbox . min [ 0 ] = abox.min [ 0 ] + PUSTR_LGAP + PUSTR_LGAP ;
+    tbox . min [ 1 ] = abox.min [ 1 ] + ((abox.max[1]-abox.min[1]-PUSTR_TGAP-PUSTR_BGAP)/num_kids) * (num_kids-1-i) ;
+    tbox . max [ 0 ] = tbox.min [ 0 ] ;
+    tbox . max [ 1 ] = tbox.min [ 1 ] ;
+
+    if (( one_only && i == getValue() ) ||
+        ( !one_only && ((1<<i) & getValue() ) != 0 ) ) 
+      tbox . draw ( dx, dy + PUSTR_BGAP + PUSTR_BGAP, -PUSTYLE_RADIO, colour, FALSE ) ;
+    else
+      tbox . draw ( dx, dy + PUSTR_BGAP + PUSTR_BGAP, PUSTYLE_RADIO, colour, FALSE ) ;
+
+    /* If greyed out then halve the opacity when drawing the label and legend */
+
+    if ( active )
+      glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
+    else
+      glColor4f ( colour [ PUCOL_LEGEND ][0],
+                  colour [ PUCOL_LEGEND ][1],
+                  colour [ PUCOL_LEGEND ][2],
+                  colour [ PUCOL_LEGEND ][3] / 2.0 ) ; /* 50% more transparent */
+
+    puDrawString ( legendFont, button_labels[i],
+                   dx + tbox.min[0] + PU_RADIO_BUTTON_SIZE + PUSTR_LGAP,
+                   dy + tbox.min[1] + puGetStringDescender(legendFont) + PUSTR_BGAP  + PUSTR_BGAP) ;
+  }
+
+  draw_label ( dx, dy ) ;
+}
+
diff --git a/PUI/puDialogBox.cxx b/PUI/puDialogBox.cxx
new file mode 100644 (file)
index 0000000..8ce592b
--- /dev/null
@@ -0,0 +1,4 @@
+
+#include "puLocal.h"
+
+
diff --git a/PUI/puFrame.cxx b/PUI/puFrame.cxx
new file mode 100644 (file)
index 0000000..4aaf831
--- /dev/null
@@ -0,0 +1,30 @@
+
+
+#include "puLocal.h"
+
+void puFrame::draw ( int dx, int dy )
+{
+  if ( !visible ) return ;
+
+  abox . draw ( dx, dy, style, colour, FALSE ) ;
+
+  /* If greyed out then halve the opacity when drawing the label and legend */
+
+  if ( active )
+    glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
+  else
+    glColor4f ( colour [ PUCOL_LEGEND ][0],
+                colour [ PUCOL_LEGEND ][1],
+                colour [ PUCOL_LEGEND ][2],
+                colour [ PUCOL_LEGEND ][3] / 2.0 ) ; /* 50% more transparent */
+
+  int xx = ( abox.max[0] - abox.min[0] - puGetStringWidth ( legendFont, legend ) ) / 2 ;
+
+  puDrawString ( legendFont, legend,
+                  dx + abox.min[0] + xx,
+                  dy + abox.min[1] + puGetStringDescender ( legendFont ) + PUSTR_BGAP ) ;
+
+  draw_label ( dx, dy ) ;
+}
+
+
diff --git a/PUI/puInput.cxx b/PUI/puInput.cxx
new file mode 100644 (file)
index 0000000..31d3129
--- /dev/null
@@ -0,0 +1,225 @@
+
+#include "puLocal.h"
+
+void puInput::normalize_cursors ( void )
+{
+  char val [ PUSTRING_MAX ] ;
+  getValue ( val ) ;
+  int sl = strlen ( val ) ;
+
+  /* Clamp the positions to the limits of the text.  */
+
+  if ( cursor_position       <  0 ) cursor_position       =  0 ;
+  if ( select_start_position <  0 ) select_start_position =  0 ;
+  if ( select_end_position   <  0 ) select_end_position   =  0 ;
+  if ( cursor_position       > sl ) cursor_position       = sl ;
+  if ( select_start_position > sl ) select_start_position = sl ;
+  if ( select_end_position   > sl ) select_end_position   = sl ;
+
+  /* Swap the ends of the select window if they get crossed over */
+
+  if ( select_end_position < select_start_position )
+  {
+    int tmp = select_end_position ;     
+    select_end_position = select_start_position ;     
+    select_start_position = tmp ;
+  }
+}
+
+void puInput::draw ( int dx, int dy )
+{
+  normalize_cursors () ;
+
+  if ( !visible ) return ;
+
+  /* 3D Input boxes look nicest if they are always in inverse style. */
+
+  abox . draw ( dx, dy, (style==PUSTYLE_SMALL_BEVELLED) ? -style :
+                        (accepting ? -style : style ), colour, FALSE ) ;
+
+  int xx = puGetStringWidth ( legendFont, " " ) ;
+  int yy = ( abox.max[1] - abox.min[1] - puGetStringHeight(legendFont) ) / 2 ;
+
+  if ( accepting )
+  {
+    char val [ PUSTRING_MAX ] ;
+    getValue ( val ) ;
+
+    /* Highlight the select area */
+
+    if ( select_end_position > 0 &&
+         select_end_position != select_start_position )    
+    {
+      val [ select_end_position ] = '\0' ;
+      int cpos2 = puGetStringWidth ( legendFont, val ) + xx + dx + abox.min[0] ;
+      val [ select_start_position ] = '\0' ;
+      int cpos1 = puGetStringWidth ( legendFont, val ) + xx + dx + abox.min[0] ;
+
+      glColor3f ( 1.0, 1.0, 0.7 ) ;
+      glRecti ( cpos1, dy + abox.min[1] + 6 ,
+                cpos2, dy + abox.max[1] - 6 ) ;
+    }
+  }
+
+  /* Draw the text */
+
+  {
+    /* If greyed out then halve the opacity when drawing the label and legend */
+
+    if ( active )
+      glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
+    else
+      glColor4f ( colour [ PUCOL_LEGEND ][0],
+                 colour [ PUCOL_LEGEND ][1],
+                 colour [ PUCOL_LEGEND ][2],
+                 colour [ PUCOL_LEGEND ][3] / 2.0 ) ; /* 50% more transparent */
+
+    char val [ PUSTRING_MAX ] ;
+    getValue ( val ) ;
+
+    puDrawString ( legendFont, val,
+                  dx + abox.min[0] + xx,
+                  dy + abox.min[1] + yy ) ;
+
+    draw_label ( dx, dy ) ;
+  }
+
+  if ( accepting )
+  { 
+    char val [ PUSTRING_MAX ] ;
+    getValue ( val ) ;
+
+    /* Draw the 'I' bar cursor. */
+
+    if ( cursor_position >= 0 )
+    {
+      val [ cursor_position ] = '\0' ;
+
+      int cpos = puGetStringWidth ( legendFont, val ) + xx + dx + abox.min[0] ;
+
+      glColor3f ( 0.1, 0.1, 1.0 ) ;
+      glBegin   ( GL_LINES ) ;
+      glVertex2i ( cpos    , dy + abox.min[1] + 7 ) ;
+      glVertex2i ( cpos    , dy + abox.max[1] - 7 ) ;
+      glVertex2i ( cpos - 1, dy + abox.min[1] + 7 ) ;
+      glVertex2i ( cpos - 1, dy + abox.max[1] - 7 ) ;
+      glVertex2i ( cpos - 4, dy + abox.min[1] + 7 ) ;
+      glVertex2i ( cpos + 3, dy + abox.min[1] + 7 ) ;
+      glVertex2i ( cpos - 4, dy + abox.max[1] - 7 ) ;
+      glVertex2i ( cpos + 3, dy + abox.max[1] - 7 ) ;
+      glEnd      () ;
+    }
+  }
+}
+
+
+void puInput::doHit ( int button, int updown, int x, int /* y */ )
+{
+  if ( button == PU_LEFT_BUTTON )
+  {
+    /* Most GUI's activate a button on button-UP not button-DOWN. */
+
+    if ( updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN )
+    {
+      lowlight () ;
+
+      char *strval ;
+      getValue ( & strval ) ;
+      char *tmpval = new char [ strlen(strval) + 1 ] ;
+      strcpy ( tmpval, strval ) ;
+
+      int i = strlen ( tmpval ) ;
+
+      while ( x <= puGetStringWidth ( legendFont, tmpval ) + abox.min[0] &&
+              i >= 0 )
+        tmpval[--i] = '\0' ;
+    
+      accepting = TRUE ;
+      cursor_position = i ;
+      normalize_cursors () ;
+      invokeCallback () ;
+    }
+    else
+      highlight () ;
+  }
+  else
+    lowlight () ;
+}
+
+int puInput::checkKey ( int key, int updown )
+{
+  (updown,updown);
+
+  if ( ! isAcceptingInput() || ! isActive () || ! isVisible () )
+    return FALSE ;
+
+  normalize_cursors () ;
+
+  char *p ;
+
+  switch ( key )
+  {
+    case PU_KEY_PAGE_UP   :
+    case PU_KEY_PAGE_DOWN :
+    case PU_KEY_INSERT    : return FALSE ; 
+
+    case PU_KEY_UP   :
+    case PU_KEY_DOWN :
+    case 0x1B /* ESC */ :
+    case '\t' :
+    case '\r' :
+    case '\n' : /* Carriage return/Line Feed/TAB  -- End of input */
+      rejectInput () ;
+      normalize_cursors () ;
+      invokeCallback () ;
+      break ;
+
+    case '\b' : /* Backspace */
+      if ( cursor_position > 0 ) 
+        for ( p = & string [ --cursor_position ] ; *p != '\0' ; p++ )
+          *p = *(p+1) ;
+      break ;
+
+    case 0x7F : /* DEL */
+      if ( select_start_position != select_end_position )
+      {
+        char *p1 = & string [ select_start_position ] ;
+        char *p2 = & string [ select_end_position   ] ;
+
+        while ( *p1 != '\0' )
+          *p1++ = *p2++ ;
+
+        select_end_position = select_start_position ;
+      }
+      else
+       for ( p = & string [ cursor_position ] ; *p != '\0' ; p++ )
+         *p = *(p+1) ;
+      break ;
+
+    case 0x15 /* ^U */ : string [ 0 ] = '\0' ; break ;
+    case PU_KEY_HOME   : cursor_position = 0 ; break ;
+    case PU_KEY_END    : cursor_position = PUSTRING_MAX ; break ;
+    case PU_KEY_LEFT   : cursor_position-- ; break ;
+    case PU_KEY_RIGHT  : cursor_position++ ; break ;
+
+    default:
+      if ( key < ' ' || key > 127 ) return FALSE ;
+
+      if ( strlen ( string ) >= PUSTRING_MAX )
+        return FALSE ;
+
+      for ( p = & string [ strlen(string) ] ;
+               p != &string[cursor_position] ; p-- )
+        *(p+1) = *p ;
+
+      *p = key ;
+      cursor_position++ ;
+      break ;
+  }
+
+  setValue ( string ) ;
+  normalize_cursors () ;
+  return TRUE ;
+}
+
+
diff --git a/PUI/puInterface.cxx b/PUI/puInterface.cxx
new file mode 100644 (file)
index 0000000..cac02c3
--- /dev/null
@@ -0,0 +1,245 @@
+
+#include "puLocal.h"
+
+#define PUSTACK_MAX 100
+
+static int currLiveInterface = -1 ;
+static puInterface *liveInterfaceStack [ PUSTACK_MAX ] ;
+static int currInterface = -1 ;
+static puInterface *interfaceStack [ PUSTACK_MAX ] ;
+
+void puPushLiveInterface ( puInterface *in )
+{
+  if ( currLiveInterface < PUSTACK_MAX )
+    liveInterfaceStack [ ++currLiveInterface ] = in ;
+  else
+    fprintf ( stderr, "PUI: Too many live puInterfaces open at once!\n" ) ;
+}
+
+void puPushInterface ( puInterface *in )
+{
+  if ( currInterface < PUSTACK_MAX )
+    interfaceStack [ ++currInterface ] = in ;
+  else
+    fprintf ( stderr, "PUI: Too many puInterfaces open at once!\n" ) ;
+}
+
+void  puPopLiveInterface ( void )
+{
+  if ( currLiveInterface > 0 )
+    --currLiveInterface ;
+  else 
+    fprintf ( stderr, "PUI: Live puInterface stack is empty!\n" ) ;
+}
+
+void  puPopInterface ( void )
+{
+  if ( currInterface > 0 )
+    --currInterface ;
+  else 
+    fprintf ( stderr, "PUI: puInterface stack is empty!\n" ) ;
+}
+
+int  puNoLiveInterface ( void )
+{
+  return currLiveInterface < 0 ;
+}
+
+int  puNoInterface ( void )
+{
+  return currInterface < 0 ;
+}
+
+puInterface *puGetUltimateLiveInterface ( void )
+{
+  if ( currLiveInterface < 0 )
+  {
+    fprintf ( stderr, "PUI: No Live Interface!\n" ) ;
+    return NULL ;
+  }
+
+  return liveInterfaceStack [ 0 ] ;
+}
+
+
+puInterface *puGetBaseLiveInterface ( void )
+{
+  if ( currLiveInterface < 0 )
+  {
+    fprintf ( stderr, "PUI: No Live Interface!\n" ) ;
+    return NULL ;
+  }
+
+  /*
+    Work down the interface stack until you
+    either get to the bottom or find a block
+    in the form of a puDialogBox.
+  */
+
+  for ( int i = currLiveInterface ; i > 0 ; i-- )
+    if ( liveInterfaceStack [ i ] -> getType () & PUCLASS_DIALOGBOX )
+      return liveInterfaceStack [ i ] ; 
+
+  return liveInterfaceStack [ 0 ] ;
+}
+
+puInterface *puGetCurrInterface ( void )
+{
+  if ( currInterface < 0 )
+  {
+    fprintf ( stderr, "PUI: No Interface!\n" ) ;
+    return NULL ;
+  }
+
+  return interfaceStack [ currInterface ] ;
+}
+
+void puInterface::remove ( puObject *obj )
+{
+  if ( dlist == NULL )
+    return ;
+
+  /* Are we the first object in the list */
+
+  if ( obj -> prev == NULL )
+    dlist = obj -> next ;
+  else
+    obj -> prev -> next = obj -> next ;
+
+  /* Are we the last object in the list */
+
+  if ( obj -> next != NULL )
+    obj -> next -> prev = obj -> prev ;
+
+  obj -> next = NULL ;
+  obj -> prev = NULL ;
+
+  num_children-- ;
+  recalc_bbox () ;
+}
+
+void puInterface::add ( puObject *new_obj )
+{
+  if ( dlist == NULL )
+  {
+    dlist = new_obj ;
+    new_obj -> next = NULL ;
+    new_obj -> prev = NULL ;
+  }
+  else
+  {
+    puObject *last ;
+
+    for ( last = dlist ; last->next != NULL ; last = last->next )
+      /* Search for end of list. */ ;
+
+    last -> next = new_obj ;
+    new_obj -> prev = last ;
+    new_obj -> next = NULL ;
+  }
+
+  num_children++ ;
+  recalc_bbox () ;
+}
+
+int puInterface::checkKey ( int key, int updown )
+{
+  if ( dlist == NULL || ! isVisible () || ! isActive () )
+    return FALSE ;
+
+  puObject *bo ;
+
+  /*
+    We have to walk the list backwards to ensure that
+    the click order is the same as the DRAW order.
+  */
+
+  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
+    /* Find the last object in our list. */ ;
+
+  for ( ; bo != NULL ; bo = bo->prev )
+    if ( bo -> checkKey ( key, updown ) )
+      return TRUE ;
+
+  return FALSE ;
+}
+
+int puInterface::checkHit ( int button, int updown, int x, int y )
+{
+  if ( dlist == NULL || ! isVisible () || ! isActive () )
+    return FALSE ;
+
+  /*
+    This might be a bit redundant - but it's too hard to keep
+    track of changing abox sizes when daughter objects are
+    changing sizes.
+  */
+
+  recalc_bbox () ;
+
+  puObject *bo ;
+
+  x -= abox.min[0] ;
+  y -= abox.min[1] ;
+
+  /*
+    We have to walk the list backwards to ensure that
+    the click order is the same as the DRAW order.
+  */
+
+  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
+    /* Find the last object in our list. */ ;
+
+  for ( ; bo != NULL ; bo = bo->prev )
+    if ( bo -> checkHit ( button, updown, x, y ) )
+      return TRUE ;
+
+  return FALSE ;
+}
+
+
+void puInterface::draw ( int dx, int dy )
+{
+  if ( isVisible () )
+    for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
+      bo -> draw ( dx + abox.min[0], dy + abox.min[1] ) ;
+}
+
+
+void puInterface::recalc_bbox ( void ) 
+{
+  puBox contents ;
+  contents . empty () ;
+
+  for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
+    contents . extend ( bo -> getBBox() ) ;
+
+  if ( contents . isEmpty () )
+  {
+    abox . max[0] = abox . min[0] ;
+    abox . max[1] = abox . min[1] ;
+  }
+  else
+  {
+    abox . max[0] = abox . min[0] + contents . max[0] ;
+    abox . max[1] = abox . min[1] + contents . max[1] ;
+  }
+
+  puObject::recalc_bbox () ;
+}
+
+
+void puInterface::doHit ( int, int, int, int )
+{
+}
+
+
+puInterface::~puInterface ()
+{
+  puPopLiveInterface () ;
+
+  for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
+    delete bo ;
+}
+
+
diff --git a/PUI/puLocal.h b/PUI/puLocal.h
new file mode 100644 (file)
index 0000000..14a66ed
--- /dev/null
@@ -0,0 +1,16 @@
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#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 "pu.h"
+
diff --git a/PUI/puMenuBar.cxx b/PUI/puMenuBar.cxx
new file mode 100644 (file)
index 0000000..87a2299
--- /dev/null
@@ -0,0 +1,83 @@
+
+#include "puLocal.h"
+
+void drop_down_the_menu ( puObject *b )
+{
+  puPopupMenu *p = (puPopupMenu *) b -> getUserData () ;
+
+  if ( b -> getValue () )
+    p->reveal () ;
+  else
+    p->hide () ;
+
+  for ( puObject *child = b -> getParent () -> getFirstChild () ;
+        child != NULL ; child = child -> next )
+  {
+    if (( child -> getType() & PUCLASS_BUTTON    ) != 0 && child != b ) child -> clrValue () ;
+    if (( child -> getType() & PUCLASS_POPUPMENU ) != 0 && child != p ) child -> hide     () ;
+  }
+}
+
+void puMenuBar::add_submenu ( char *str, char *items[], puCallback cb[] )
+{
+  int w, h ;
+  getSize ( &w, &h ) ;
+
+  puOneShot    *b = new puOneShot ( w+10, 0, str ) ;
+  b -> setStyle ( PUSTYLE_SPECIAL_UNDERLINED ) ;
+  b -> setColourScheme ( colour[PUCOL_FOREGROUND][0],
+                         colour[PUCOL_FOREGROUND][1],
+                         colour[PUCOL_FOREGROUND][2],
+                         colour[PUCOL_FOREGROUND][3] ) ;
+  b -> setCallback ( drop_down_the_menu ) ;
+  b -> setActiveDirn ( PU_UP_AND_DOWN ) ;
+
+  puPopupMenu *p = new puPopupMenu ( w+10, 0 ) ;
+
+  b -> setUserData ( p ) ;
+
+  for ( int i = 0 ; items[i] != NULL ; i++ )
+    p -> add_item ( items[i], cb[i] ) ;
+
+  p->close () ;
+  recalc_bbox () ;
+}
+
+void puMenuBar::close (void)
+{
+  puInterface::close () ;
+
+  if ( dlist == NULL )
+    return ;
+
+  int width = 0 ;
+  puObject *ob ;
+
+  /*
+    Use alternate objects - which gets the puOneShot/puPopupMenu pairs
+  */
+
+  for ( ob = dlist ; ob != NULL ; ob = ob -> next )
+  {
+    int w, h ;
+
+    /* Reposition the button so it looks nice */
+
+    ob -> getSize ( &w, &h ) ;
+    ob -> setPosition ( width, 0 ) ;
+    ob = ob -> next ;
+
+    /* Reposition the submenu so it sits under the button */
+
+    int w2, h2 ;
+    ob -> getSize ( &w2, &h2 ) ;
+    ob -> setPosition ( width, -h2 ) ;
+
+    /* Next please! */
+    width += w ;
+  }
+
+  recalc_bbox () ;
+}
+
+
diff --git a/PUI/puObject.cxx b/PUI/puObject.cxx
new file mode 100644 (file)
index 0000000..1230396
--- /dev/null
@@ -0,0 +1,222 @@
+
+#include "puLocal.h"
+
+inline float clamp01 ( float x )
+{
+  return (x >= 1.0) ? 1.0 : x ;
+}
+
+static void load_colour_scheme ( float col[][4], float r, float g,
+                                                 float b, float a )
+{
+  puSetColour ( col [ PUCOL_FOREGROUND ], r, g, b, a ) ;
+  puSetColour ( col [ PUCOL_BACKGROUND ], r/2, g/2, b/2, a ) ;
+  puSetColour ( col [ PUCOL_HIGHLIGHT  ], clamp01(r*1.3), clamp01(g*1.3),
+                                             clamp01(b*1.3), a ) ;
+
+  if ( 4 * g + 3 * r + b > 0.5 )
+    puSetColour ( col [ PUCOL_LEGEND ], 0.0, 0.0, 0.0, a ) ;
+  else
+    puSetColour ( col [ PUCOL_LEGEND ], 1.0, 1.0, 1.0, a ) ;
+}
+
+
+static int    defaultStyle = PUSTYLE_DEFAULT ;
+static puFont defaultLegendFont = NULL ;
+static puFont defaultLabelFont  = NULL ;
+static float  defaultColourScheme [ 4 ] ;
+
+void puSetDefaultStyle ( int  style ) { defaultStyle = style ; }
+int   puGetDefaultStyle ( void ) { return defaultStyle ; }
+
+void puSetDefaultFonts ( puFont legendFont, puFont labelFont )
+{
+  defaultLegendFont = legendFont ;
+  defaultLabelFont  = labelFont ;
+}
+
+void puGetDefaultFonts ( puFont *legendFont, puFont *labelFont )
+{
+  if ( legendFont ) *legendFont = defaultLegendFont ;
+  if ( labelFont  ) *labelFont  = defaultLabelFont  ;
+}
+
+void puSetDefaultColourScheme ( float r, float g, float b, float a )
+{
+  defaultColourScheme[0] = r ;
+  defaultColourScheme[1] = g ;
+  defaultColourScheme[2] = b ;
+  defaultColourScheme[3] = a ;
+  load_colour_scheme ( _puDefaultColourTable, r, g, b, a ) ;
+}
+
+void puGetDefaultColourScheme ( float *r, float *g, float *b, float *a )
+{
+  if ( r ) *r = defaultColourScheme[0] ;
+  if ( g ) *g = defaultColourScheme[1] ;
+  if ( b ) *b = defaultColourScheme[2] ;
+  if ( a ) *a = defaultColourScheme[3] ;
+}
+
+
+
+void puObject::setColourScheme ( float r, float g, float b, float a )
+{
+  load_colour_scheme ( colour, r, g, b, a ) ;
+}
+
+puObject::puObject ( int minx, int miny, int maxx, int maxy ) : puValue ()
+{
+  type |= PUCLASS_OBJECT ;
+  bbox.min[0] = abox.min[0] = minx ;
+  bbox.min[1] = abox.min[1] = miny ;
+  bbox.max[0] = abox.max[0] = maxx ;
+  bbox.max[1] = abox.max[1] = maxy ;
+
+  active_mouse_edge = PU_UP ;
+  style      = defaultStyle ;
+  visible = active  = TRUE  ;
+  highlighted       = FALSE ;
+  am_default        = FALSE ;
+
+  cb          = NULL ;
+  user_data   = NULL ;
+  next = prev = NULL ;
+  label       = NULL ;
+  labelPlace  = PUPLACE_DEFAULT   ;
+  labelFont   = defaultLabelFont  ;
+  legend      = NULL ;
+  legendFont  = defaultLegendFont ;
+
+  for ( int i = 0 ; i < PUCOL_MAX ; i++ )
+    puSetColour ( colour[i], _puDefaultColourTable[i] ) ;
+
+  if ( ! puNoInterface() )
+  {
+    parent = puGetCurrInterface() ;
+    parent -> add ( this ) ;
+  }
+  else
+    parent = NULL ;
+}
+
+
+puObject::~puObject ()
+{
+  if ( parent != this && parent != NULL )
+    parent -> remove ( this ) ;
+}
+
+void puObject::recalc_bbox ( void )
+{
+  bbox = abox ;
+
+  if ( label != NULL )
+    switch ( labelPlace )
+    {
+      case PUPLACE_ABOVE : bbox.max[1] += puGetStringHeight ( getLabelFont() ) + puGetStringDescender ( getLabelFont () ) + PUSTR_TGAP + PUSTR_BGAP ; break ;
+      case PUPLACE_BELOW : bbox.min[1] -= puGetStringHeight ( getLabelFont() ) + puGetStringDescender ( getLabelFont () ) + PUSTR_TGAP + PUSTR_BGAP ; break ;
+      case PUPLACE_LEFT  : bbox.min[0] -= puGetStringWidth  ( getLabelFont(), getLabel() ) + PUSTR_LGAP + PUSTR_RGAP ; break ;
+      case PUPLACE_RIGHT : bbox.max[0] += puGetStringWidth  ( getLabelFont(), getLabel() ) + PUSTR_LGAP + PUSTR_RGAP ; break ;
+    }
+
+  if ( parent != NULL )
+    parent -> recalc_bbox () ;
+}
+
+void puObject::draw_label ( int dx, int dy )
+{
+  if ( !visible ) return ;
+
+  /* If greyed out then halve the opacity when drawing the label */
+
+  if ( active )
+    glColor4fv ( colour [ PUCOL_LABEL ] ) ;
+  else
+    glColor4f ( colour [ PUCOL_LABEL ][0],
+                colour [ PUCOL_LABEL ][1],
+                colour [ PUCOL_LABEL ][2],
+                colour [ PUCOL_LABEL ][3] / 2.0 ) ; /* 50% more transparent */
+
+  switch ( labelPlace )
+  {
+    case PUPLACE_ABOVE : puDrawString ( labelFont, label, dx + abox.min[0] + PUSTR_LGAP, dy + abox.max[1] + puGetStringDescender(labelFont) + PUSTR_BGAP ) ; break ;
+    case PUPLACE_BELOW : puDrawString ( labelFont, label, dx + abox.min[0] + PUSTR_LGAP, dy + bbox.min[1] + puGetStringDescender(labelFont) + PUSTR_BGAP ) ; break ;
+    case PUPLACE_LEFT  : puDrawString ( labelFont, label, dx + bbox.min[0] + PUSTR_LGAP, dy + abox.min[1] + puGetStringDescender(labelFont) + PUSTR_BGAP ) ; break ;
+    case PUPLACE_RIGHT : puDrawString ( labelFont, label, dx + abox.max[0] + PUSTR_LGAP, dy + abox.min[1] + puGetStringDescender(labelFont) + PUSTR_BGAP ) ; break ;
+  }
+}
+
+
+int puObject::checkKey ( int key, int updown )
+{
+  if ( updown == PU_UP )
+    return FALSE ;
+
+  if ( isReturnDefault() && ( key == '\r' || key == '\n' ) )
+  {
+    checkHit ( PU_LEFT_BUTTON, PU_DOWN, (abox.min[0]+abox.max[0])/2,
+                                        (abox.min[1]+abox.max[1])/2 ) ;
+    checkHit ( PU_LEFT_BUTTON, PU_UP  , (abox.min[0]+abox.max[0])/2,
+                                        (abox.min[1]+abox.max[1])/2 ) ;
+    return TRUE ;
+  }
+
+  return FALSE ;
+}
+
+
+void puObject::doHit ( int button, int updown, int x, int y )
+{
+  (x,x);(y,y);
+
+  if ( button == PU_LEFT_BUTTON )
+  {
+    if ( updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN )
+    {
+      lowlight () ;
+      invokeCallback () ;
+    }
+    else
+      highlight () ;
+  }
+  else
+    lowlight () ;
+}
+
+int puObject::checkHit ( int button, int updown, int x, int y )
+{
+  if ( isHit( x, y ) )
+  {
+    doHit ( button, updown, x, y ) ;
+    return TRUE ;
+  }
+
+  lowlight () ;
+  return FALSE ;
+}
+
+char *puValue::getTypeString ( void )
+{
+  int i = getType () ;
+
+  if ( i & PUCLASS_DIALOGBOX   ) return "puDialogBox" ;
+  if ( i & PUCLASS_SLIDER      ) return "puSlider" ;
+  if ( i & PUCLASS_BUTTONBOX   ) return "puButtonBox" ;
+  if ( i & PUCLASS_INPUT       ) return "puInput" ;
+  if ( i & PUCLASS_MENUBAR     ) return "puMenuBar" ;
+  if ( i & PUCLASS_POPUPMENU   ) return "puPopupMenu" ;
+  if ( i & PUCLASS_POPUP       ) return "puPopup" ;
+  if ( i & PUCLASS_ONESHOT     ) return "puOneShot" ;
+  if ( i & PUCLASS_BUTTON      ) return "puButton" ;
+  if ( i & PUCLASS_TEXT        ) return "puText" ;
+  if ( i & PUCLASS_FRAME       ) return "puFrame" ;
+  if ( i & PUCLASS_INTERFACE   ) return "puInterface" ;
+  if ( i & PUCLASS_OBJECT      ) return "puObject" ;
+  if ( i & PUCLASS_VALUE       ) return "puValue" ;
+
+  return "Unknown Object type." ;
+}
+
+
diff --git a/PUI/puOneShot.cxx b/PUI/puOneShot.cxx
new file mode 100644 (file)
index 0000000..7d0f7c9
--- /dev/null
@@ -0,0 +1,9 @@
+
+#include "puLocal.h"
+
+void puOneShot::doHit ( int button, int updown, int x, int y )
+{
+  puButton::doHit ( button, updown, x, y ) ;
+  setValue ( 0 ) ;
+}
+
diff --git a/PUI/puPopup.cxx b/PUI/puPopup.cxx
new file mode 100644 (file)
index 0000000..59a5fef
--- /dev/null
@@ -0,0 +1,3 @@
+
+#include "puLocal.h"
+
diff --git a/PUI/puPopupMenu.cxx b/PUI/puPopupMenu.cxx
new file mode 100644 (file)
index 0000000..52ffbd9
--- /dev/null
@@ -0,0 +1,127 @@
+
+#include "puLocal.h"
+
+#define PUMENU_BUTTON_HEIGHT       25
+#define PUMENU_BUTTON_EXTRA_WIDTH  25
+
+puObject *puPopupMenu::add_item ( char *str, puCallback cb )
+{
+  int w, h ;
+  getSize ( &w, &h ) ;
+  puOneShot *b = new puOneShot ( 0, h, str ) ;
+  b->setStyle        ( PUSTYLE_PLAIN ) ;
+  b->setColourScheme ( colour[PUCOL_FOREGROUND][0],
+                      colour[PUCOL_FOREGROUND][1],
+                      colour[PUCOL_FOREGROUND][2],
+                      colour[PUCOL_FOREGROUND][3] ) ;
+  b->setCallback     ( cb ) ;
+  recalc_bbox () ;
+  return b ;
+}
+
+void puPopupMenu::close ( void )
+{
+  puPopup::close () ;
+
+  int widest = 0 ;
+  puObject *ob = dlist ;
+
+  for ( ob = dlist ; ob != NULL ; ob = ob -> next )
+  {
+    int w, h ;
+
+    ob -> getSize ( &w, &h ) ;
+
+    if ( w > widest ) widest = w ;
+  }
+
+  for ( ob = dlist ; ob != NULL ; ob = ob -> next )
+    ob -> setSize ( widest, PUMENU_BUTTON_HEIGHT ) ;
+
+  recalc_bbox () ;
+}
+
+
+int puPopupMenu::checkKey ( int key, int updown )
+{
+  if ( dlist == NULL || ! isVisible () || ! isActive () )
+    return FALSE ;
+
+  if ( updown == PU_DOWN )
+  {
+    hide () ;
+
+    /* Turn everything off ready for next time. */
+
+    for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
+      bo -> clrValue () ;
+  }
+
+  puObject *bo ;
+
+  /*
+    We have to walk the list backwards to ensure that
+    the click order is the same as the DRAW order.
+  */
+
+  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
+    /* Find the last object in our list. */ ;
+
+  for ( ; bo != NULL ; bo = bo->prev )
+    if ( bo -> checkKey ( key, updown ) )
+      return TRUE ;
+
+  return FALSE ;
+}
+
+
+int puPopupMenu::checkHit ( int button, int updown, int x, int y )
+{
+  if ( dlist == NULL || ! isVisible () || ! isActive () )
+    return FALSE ;
+
+  /* Must test 'isHit' before making the menu invisible! */
+
+  int hit = isHit ( x, y ) ;
+
+  if ( updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN )
+  {
+    hide () ;
+
+    /* Turn everything off ready for next time. */
+
+    for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
+      bo -> clrValue () ;
+  }
+
+  if ( ! hit )
+    return FALSE ;
+
+  /*
+    This might be a bit redundant - but it's too hard to keep
+    track of changing abox sizes when daughter objects are
+    changing sizes.
+  */
+
+  recalc_bbox () ;
+
+  puObject *bo ;
+
+  x -= abox.min[0] ;
+  y -= abox.min[1] ;
+
+  /*
+    We have to walk the list backwards to ensure that
+    the click order is the same as the DRAW order.
+  */
+
+  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
+    /* Find the last object in our list. */ ;
+
+  for ( ; bo != NULL ; bo = bo->prev )
+    if ( bo -> checkHit ( button, updown, x, y ) )
+      return TRUE ;
+
+  return FALSE ;
+}
+
diff --git a/PUI/puSlider.cxx b/PUI/puSlider.cxx
new file mode 100644 (file)
index 0000000..298269e
--- /dev/null
@@ -0,0 +1,106 @@
+
+#include "puLocal.h"
+
+void puSlider::draw ( int dx, int dy )
+{
+  if ( !visible ) return ;
+
+  abox . draw ( dx, dy,
+                style==PUSTYLE_BEVELLED ? -PUSTYLE_BOXED : -style,
+                colour, FALSE ) ;
+
+  int sd, od ;
+
+  if ( isVertical() ) { sd = 1 ; od = 0 ; } else { sd = 0 ; od = 1 ; }
+
+  int sz = abox.max [sd] - abox.min [sd] ;
+
+  float val ;
+
+  getValue ( & val ) ;
+
+  if ( val < 0.0f ) val = 0.0f ;
+  if ( val > 1.0f ) val = 1.0f ;
+
+  val *= (float) sz * (1.0f - slider_fraction) ;
+
+  puBox bx ;
+    
+  bx . min [ sd ] = abox . min [ sd ] + (int) val ;
+  bx . max [ sd ] = (int) ( (float) bx . min [ sd ] + (float) sz * slider_fraction ) ;
+  bx . min [ od ] = abox . min [ od ] + 2 ;
+  bx . max [ od ] = abox . max [ od ] - 2 ;
+
+  bx . draw ( dx, dy, PUSTYLE_SMALL_BEVELLED, colour, FALSE ) ;
+
+  /* If greyed out then halve the opacity when drawing the label and legend */
+
+  if ( active )
+    glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
+  else
+    glColor4f ( colour [ PUCOL_LEGEND ][0],
+                colour [ PUCOL_LEGEND ][1],
+                colour [ PUCOL_LEGEND ][2],
+                colour [ PUCOL_LEGEND ][3] / 2.0 ) ; /* 50% more transparent */
+
+  int xx = ( abox.max[0] - abox.min[0] - puGetStringWidth(legendFont,legend) ) / 2 ;
+  int yy = ( abox.max[1] - abox.min[1] - puGetStringHeight(legendFont) ) / 2 ;
+
+  puDrawString ( legendFont, legend,
+                  dx + abox.min[0] + xx,
+                  dy + abox.min[1] + yy ) ;
+
+  draw_label ( dx, dy ) ;
+}
+
+
+void puSlider::doHit ( int button, int updown, int x, int y )
+{
+  if ( button == PU_LEFT_BUTTON )
+  {
+    int sd = isVertical() ;
+    int sz = abox.max [sd] - abox.min [sd] ;
+    int coord = isVertical() ? y : x ;
+
+    float next_value ;
+
+    if ( sz == 0 )
+      next_value = 0.5f ;
+    else
+    {
+      next_value = ( (float)coord - (float)abox.min[sd] - (float)sz * slider_fraction / 2.0f ) /
+                   ( (float) sz * (1.0f - slider_fraction) ) ;
+    }
+
+    next_value = (next_value < 0.0f) ? 0.0f : (next_value > 1.0) ? 1.0f : next_value ;
+
+    setValue ( next_value ) ;
+
+    switch ( cb_mode )
+    {
+      case PUSLIDER_CLICK :
+        if ( updown == active_mouse_edge )
+        {
+         last_cb_value = next_value ;
+         invokeCallback () ;
+        }
+        break ;
+
+      case PUSLIDER_DELTA :
+        if ( fabs ( last_cb_value - next_value ) >= cb_delta )
+        {
+         last_cb_value = next_value ;
+         invokeCallback () ;
+        }
+        break ;
+
+      case PUSLIDER_ALWAYS :
+      default :
+        last_cb_value = next_value ;
+        invokeCallback () ;
+        break ;
+    }
+  }
+}
+
+
diff --git a/PUI/puText.cxx b/PUI/puText.cxx
new file mode 100644 (file)
index 0000000..032c016
--- /dev/null
@@ -0,0 +1,8 @@
+
+#include "puLocal.h"
+
+void puText::draw ( int dx, int dy )
+{
+  draw_label ( dx, dy ) ;
+}
+