/*
     This file is part of P-GUIDE -
     PUI-based Graphical User Interface Designer.
     Copyright (C) 2002, 2006  John F. Fay

     P-GUIDE is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.

     P-GUIDE is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with P-GUIDE; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

     $Id: pGuide.cxx 2083 2006-05-01 13:14:50Z bram $
*/

#ifdef VERSION
#undef VERSION
#endif

#define VERSION = "0.1a"

// Program to allow the user to build a PUI Graphical User Interface

#include "WidgetList.h"

WidgetList *widgets = (WidgetList *)NULL ;
int max_layer = 1 ;

puObject *active_object = (puObject *)NULL ;
WidgetList *active_widget = (WidgetList *)NULL ;
static short activity_flag = 0 ;  // 0 - inactive; 1 - moving; 2 - resizing xmin, 3 - resizing ymin, 4 - resizing xmax, 5 - resizing ymax
static int resize_symmetric = 1 ;
static int resize_corner = 0 ;

static int mouse_x_position_in_object = 0 ;
static int mouse_y_position_in_object = 0 ;

static int pguide_last_buttons = 0 ; // Because puMouse isn't called, we have to do our own last_buttons checking

// Main window parameters
int main_window = 0 ;  // Main window handle
int main_window_width  = 600 ;
int main_window_height = 600 ;
char main_window_name [ PUSTRING_MAX ] ;
int main_window_x = 0, main_window_y = 0 ;

float main_window_color_r = 1.0, main_window_color_g = 1.0,
      main_window_color_b = 1.0, main_window_color_a = 1.0 ;

bool main_window_changed = false ;
static bool done_first_setup = false ;
bool currently_loading = false ;

static int ctrl_key_down = 0 ;

static int mouse_x = 0 ;
static int mouse_y = 0 ;

char pguide_current_directory [ PUSTRING_MAX ] ;

// Widget count
int widget_number = 0 ;

// Upon creation of new widgets, should they automatically be made "locked"?
bool autolock = false ;

// Properties popup
static puPopupMenu *context_menu;

// From the status window:
extern void setStatusWidgets ( WidgetList *wid ) ;

// From the properties window:
extern int properties_window;

// Definitions
#define RESIZING_BORDER_WIDTH   5
#define RESIZING_CORNER_BORDER_WIDTH   4
  /** 4 seems to be the best number for this define... this makes sure  *
   *  that the default widget size allows you to still resize along the *
   *  X axis without difficulty -  23 Jan 03 JCJ                       **/


// Properties Callback

static void cb_edit_properties ( puObject *ob )
{
    if (properties_window)
    {
        extern puGroup *properties_group; 
        /* Delete the widgets */
        puDeleteObject( properties_group );
        glutDestroyWindow( properties_window );
        properties_window = 0;
        glutSetWindow( main_window );
    }
    extern int define_properties_window () ;
    // Open the properties menu
    define_properties_window();
}

static void cb_lock_toggle ( puObject *ob )
{
  WidgetList *wid = widgets ;
  while ( wid )
  {
    if ( wid->obj == active_object )
    {
        if (wid->locked == false)
            wid->locked = true ;
        else
            wid->locked = false ;
    }
    wid = wid->next ;
  }
}

static void cb_popup_delete ( puObject *ob )
{
  WidgetList *wid = widgets ;
  WidgetList *prv = (WidgetList *)NULL ;
  while ( wid )
  {
    if ( wid->obj == active_object )
    {
      if ( prv )  // Remove the widget from the linked list
        prv->next = wid->next ;
      else
        widgets = wid->next ;

      delete wid->object_type_name ;  // Delete the widget
      delete wid->legend_text ;
      delete wid->label_text ;
      delete wid->obj ;
      delete wid->allowed ;
      delete wid->items ;
      delete wid ;
      active_widget = (WidgetList *)NULL ;
      active_object = (puObject *)NULL ;
      wid = (WidgetList *)NULL ;
      if (properties_window)
      {
        extern puGroup *properties_group; 
        /* Delete the widgets */
        puDeleteObject( properties_group );
        glutDestroyWindow( properties_window );
        properties_window = 0;
        glutSetWindow( main_window );
      }
    }
    else
    {
      prv = wid ;
      wid = wid->next ;
    }
  }
}


// GLUT Main Window Callbacks

static void process_key ( int key )
{
  extern int selected_object_type ;
  extern puButton *active_button ;

  ctrl_key_down = ( glutGetModifiers () & GLUT_ACTIVE_CTRL ) ;
#define NUDGE_DISTANCE    1
#define LARGE_NUDGE_DISTANCE    10

  if ( active_object )  // Active object; check the keys
  {
    main_window_changed = true ;

    int xo, yo ;
    active_object->getPosition ( &xo, &yo ) ;
    int dist = ctrl_key_down ? LARGE_NUDGE_DISTANCE : NUDGE_DISTANCE ;

    if ( key == GLUT_KEY_LEFT )
      active_object->setPosition ( xo-dist, yo ) ;
    else if ( key == GLUT_KEY_RIGHT )
      active_object->setPosition ( xo+dist, yo ) ;
    else if ( key == GLUT_KEY_UP )
      active_object->setPosition ( xo, yo+dist ) ;
    else if ( key == GLUT_KEY_DOWN )
      active_object->setPosition ( xo, yo-dist ) ;
    else if ( ( key == 127 ) || ( key == 8 ) )  // Delete or Backspace
    {
      WidgetList *wid = widgets ;
      WidgetList *prv = (WidgetList *)NULL ;
      while ( wid )
      {
        if ( wid->obj == active_object )
        {
          if ( prv )  // Remove the widget from the linked list
            prv->next = wid->next ;
          else
            widgets = wid->next ;

          delete wid->object_type_name ;  // Delete the widget
          delete wid->legend_text ;
          delete wid->label_text ;
          delete wid->obj ;
          delete wid->allowed ;
          delete wid->items ;
          delete wid ;
          active_widget = (WidgetList *)NULL ;
          active_object = (puObject *)NULL ;
          wid = (WidgetList *)NULL ;
        }
        else
        {
          prv = wid ;
          wid = wid->next ;
        }
      }
    }
    else if ( key == 27 )  // Escape key, deactivate the object
    {
      active_widget = (WidgetList *)NULL ;
      active_object = (puObject *)NULL ;
    }

    setStatusWidgets ( active_widget ) ;
  }

  if ( selected_object_type )
  {
    if ( key == 27 )  // Escape key, deactivate the selected button
    {
      selected_object_type = 0 ;
      active_button->setValue ( 0 ) ;
    }
  }

  glutPostRedisplay () ;
}

static void main_window_specialfn ( int key, int, int )
{
  process_key ( key ) ;
}

static void main_window_keyfn ( unsigned char key, int, int )
{
  process_key ( key ) ;
}

static void main_window_motionfn ( int x, int yy )
{
  int y = main_window_height - yy ;

  mouse_x = x ;
  mouse_y = y ;
      
  // Dragging the mouse:  If there is an active object, slide it around
  if ( ( active_object ) && ( pguide_last_buttons != 4 ) )
  {
    WidgetList *wid = widgets ;
    while ( wid )
    {
        if ( wid->obj == active_object )
        {
            if (wid->locked == false)
            {
                extern puInput *object_position_x ;
                extern puInput *object_position_y ;
                extern puInput *object_size_x ;
                extern puInput *object_size_y ;

                main_window_changed = true ;

                int dist ;
                int xo, yo ;
                active_object->getPosition ( &xo, &yo ) ;
                int w, h ;
                active_object->getSize ( &w, &h ) ;

                if (resize_corner == 1)
                {
                    switch ( activity_flag )
                    {
                    case 2 : // Resize top-right
                    case 3 :
                        activity_flag = 6;
                        break ;

                    case 4 : // Resize bottom_left
                    case 5 :
                        activity_flag = 7;
                        break ;
                    }
                }

                switch ( activity_flag )
                {
                case 1 :  // Moving the object
                  active_object->setPosition ( x - mouse_x_position_in_object,
                                               y - mouse_y_position_in_object ) ;
                  break ;

                case 2 :  // Resizing on x-min
                  dist = x - xo ;
                  if (w - dist < 5) break ;
                  if ( resize_symmetric * dist > w ) dist = w / resize_symmetric - 1 ;
                  active_object->setPosition ( x, yo ) ;
                  active_object->setSize ( w - resize_symmetric * dist, h ) ;
                  break ;

                case 3 :  // Resizing on y-min
                  dist = y - yo ;
                  if (h - dist < 5) break ;
                  if ( resize_symmetric * dist > h ) dist = h / resize_symmetric - 1 ;
                  active_object->setPosition ( xo, y ) ;
                  active_object->setSize ( w, h - resize_symmetric * dist ) ;
                  break ;

                case 4 :  // Resizing on x-max
                  dist = x - xo - w ;
                  if (w + dist < 5) break ;
                  if ( resize_symmetric * dist < -w ) dist = 1 - w / resize_symmetric ;
                  active_object->setSize ( w + resize_symmetric * dist, h ) ;
                  if ( resize_symmetric == 2 ) active_object->setPosition ( xo - dist, yo ) ;
                  break ;

                case 5 :  // Resizing on y-max
                  dist = y - yo - h ;
                  if (h + dist < 5) break ;
                  if ( resize_symmetric * dist < -h ) dist = 1 - h / resize_symmetric ;
                  active_object->setSize ( w, h + resize_symmetric * dist ) ;
                  if ( resize_symmetric == 2 ) active_object->setPosition ( xo, yo - dist ) ;
                  break ;

                case 6 :  // Resizing bottom-left
                  if ( yo - y > xo - x )
                    dist = yo - y;
                  else
                    dist = xo - x;
                  if ( (w + dist < 5) || (h + dist < 5) ) break ;
                  active_object->setPosition ( xo - dist, yo - dist ) ;
                  active_object->setSize ( w + dist, h + dist ) ;
                  break ;

                case 7 :  // Resizing top-right
                  if (y-yo-h>x-xo-w)
                    dist = y - yo - h ;
                  else
                    dist = x - xo - w ;
                  if ( (w + dist < 5) || (h + dist < 5) ) break ;
                  active_object->setSize ( w + dist, h + dist ) ;
                  break ;

                case 8 :  // Resizing top-left
                  if (y-yo-h>x-xo-w)
                    dist = y - yo - h ;
                  else
                    dist = xo - x ;
                  if ( (w + dist < 5) || (h + dist < 5) ) break ;
		  active_object->setPosition ( xo - dist, yo ) ;
                  active_object->setSize ( w + dist, h + dist ) ;
                  break ;

                case 9 :  // Resizing bottom-right
                  if (y-yo-h>x-xo-w)
                    dist = yo - y ;
                  else
                    dist = x - xo - w ;
                  if ( (w + dist < 5) || (h + dist < 5) ) break ;
                  active_object->setPosition ( xo , yo - dist ) ;
                  active_object->setSize ( w + dist, h + dist ) ;
                  break ;
                }

                int a, b ;
                active_object->getPosition ( &a, &b ) ;
                object_position_x->setValue ( a ) ;
                object_position_y->setValue ( b ) ;

                active_object->getSize ( &a, &b ) ;
                object_size_x->setValue ( a ) ;
                object_size_y->setValue ( b ) ;
              }
        }
    wid = wid->next ;
    }
  }
  glutPostRedisplay () ;
}

static void main_window_passivefn ( int x, int yy )
{
  int y = main_window_height - yy ;

  // Dragging the mouse without a button down:  save the mouse coordinates
  mouse_x = x ;
  mouse_y = y ;
  /*if (context_menu->isVisible() == 1)
  {
      puBox *cont_box = context_menu->getABox();
      if ( ( x >= cont_box->min[0] ) && ( x <= cont_box->max[0] ) &&
           ( y >= cont_box->min[1] ) && ( y <= cont_box->max[1] ) )
      {
          context_menu->checkHit(-1, 0, mouse_x, mouse_y);
      }
  }*/
}

static void main_window_mousefn ( int button, int updown, int x, int yy )
{
  int y = main_window_height - yy ;

  mouse_x = x ;
  mouse_y = y ;

  if ( updown == PU_DOWN )
    pguide_last_buttons |=  ( 1 << button ) ;
  else
    pguide_last_buttons &= ~( 1 << button ) ;

  if ( button == PU_RIGHT_BUTTON )
  {
  /* Pressed the right mouse button -- popup the manipulation window. */
      WidgetList *wid = widgets ;
      while ( wid )
      {
        puBox *box = wid->obj->getABox () ;
        if ( wid->visible && ( x >= box->min[0] ) && ( x <= box->max[0] ) &&
                             ( y >= box->min[1] ) && ( y <= box->max[1] ) )
        {

          active_widget = wid ;
          active_object = wid->obj ;
          /* We can modify mouse_x and mouse_y, because theyre not used again if we're in the right mouse function */
          /* If we're real close to the right of the screen, modify the X position ...*/
          if (mouse_x > main_window_width - 110 ) mouse_x = main_window_width - 110 ;
          /* If we're real close to the top of the screen, modify the Y position...*/
          if (mouse_y > main_window_height - 140) mouse_y = main_window_height - 140 ;

          context_menu->setPosition(mouse_x, mouse_y) ;
          context_menu->reveal() ;
          //puSetActiveWidget(context_menu, mouse_x, mouse_y) ;
          break ;
        }
        wid = wid->next ;
      }

  } else {
      if ( puActiveWidget() && ( active_object != puActiveWidget() ) )
      {
        puActiveWidget() -> invokeDownCallback () ;
        puDeactivateWidget () ;
      }

      ctrl_key_down = ( glutGetModifiers () & GLUT_ACTIVE_CTRL ) ;

      if ( ( context_menu->isVisible() == 1) && ( active_widget ) )
      {
          puBox *cont_box = context_menu->getABox();
          if ( ( x >= cont_box->min[0] ) && ( x <= cont_box->max[0] ) &&
               ( y >= cont_box->min[1] ) && ( y <= cont_box->max[1] ) )
          {
              context_menu->checkHit(button, updown, mouse_x, mouse_y);
          } else {
              context_menu->hide();
          }
      } else /*if ( context_menu->isVisible() == 1) { context_menu->hide(); } * The user did something funny, so hide the menu since they've been naughty */
      {
      // Downclick:  Place a new widget, activate an existing widget, deactivate widget, or select from menu.
      if ( updown == GLUT_DOWN )
      {
        // If there is a selected object, create a new one of that type.
    //    extern puObject *createWidget ( int type ) ;
        extern int selected_object_type ;

        if ( selected_object_type )
        {
          extern bool selected_object_sticky ;
          extern char *selected_type_string ;
          extern puButton *active_button ;

          main_window_changed = true ;

    //      puObject *new_obj = createWidget ( selected_object->getType () ) ;
          puObject *new_obj = new puFrame ( 0, 0, 90, 20 ) ;
          char *object_type_name = new char [ PUSTRING_MAX ] ;
          strcpy ( object_type_name, selected_type_string ) ;
          new_obj->setLegend ( object_type_name ) ;

          // Add the new object to the list of widgets
          WidgetList *new_wid = new WidgetList ;
          new_wid->obj = new_obj ;
          new_wid->label_text = (char *)NULL ;
          new_wid->legend_text = (char *)NULL ;
          new_wid->allowed = (char *)NULL ;
          new_wid->items = (char *)NULL ;
          new_wid->object_type_name = object_type_name ;
          new_wid->object_type = selected_object_type ;
          new_wid->callbacks = 1 ;  // Default:  up callback enabled, others disabled
          sprintf ( new_wid->object_name, "widget%d", widget_number++ ) ;
          new_wid->visible = true ;
          new_wid->locked = autolock ; /* Set it to the autolock var (true or false ) */
          new_wid->layer = max_layer - 1 ;
          new_wid->next = widgets ;
          widgets = new_wid ;

          // Set the new widget's position
          new_obj->setPosition ( x, y ) ;

          mouse_x_position_in_object = 0 ;
          mouse_y_position_in_object = 0 ;


          /* Set up the widget's default data values */
          new_wid->intval1 = 0;
          new_wid->intval2 = 0;
          new_wid->boolval1 = false;
          new_wid->boolval2 = false;
          new_wid->boolval3 = false;
          new_wid->floatval1 = 0.0f;
          new_wid->floatval2 = 0.0f;
          new_wid->floatval3 = 0.0f;
          new_wid->floatval4 = 0.0f;
          new_wid->floatval5 = 0.0f;
          new_wid->floatval6 = 0.0f;

          if (new_wid->object_type == PUCLASS_TEXT)
          {
               new_obj->setSize(5,20);
          }
          if (new_wid->object_type == PUCLASS_COMBOBOX)
          {
               new_wid->intval1 = 1;
               new_wid->boolval1 = true;
          }

          if (new_wid->object_type == PUCLASS_SELECTBOX)
          {
               new_wid->intval1 = 1;
          }

          if (new_wid->object_type == PUCLASS_BUTTONBOX)
          {
               new_wid->boolval1 = true;
          }

          if (new_wid->object_type == PUCLASS_COMBOBOX)
          {
               new_wid->intval1 = 1;
               new_wid->boolval1 = true;
          }

          if ( (new_wid->object_type == PUCLASS_SLIDER )       || 
               (new_wid->object_type == PUCLASS_BISLIDER )     || 
               (new_wid->object_type == PUCLASS_TRISLIDER )    || 
               (new_wid->object_type == PUCLASS_DIAL )         || 
               (new_wid->object_type == PUCLASS_SPINBOX )      || 
               (new_wid->object_type == PUCLASS_SCROLLBAR )    )
          {
                new_wid->floatval1 = 1.0f;
                new_wid->floatval2 = 0.0f;
                new_wid->floatval3 = 0.0f;
                new_wid->boolval1 = true;
          }

         if ( (new_wid->object_type == PUCLASS_SLIDER )       || 
              (new_wid->object_type == PUCLASS_BISLIDER )     || 
              (new_wid->object_type == PUCLASS_TRISLIDER )     )  
         {
                new_wid->boolval2 = true;
         }

         if (new_wid->object_type == PUCLASS_SLIDER)
         {
            new_wid->floatval4 = 0.5f;
         }

         if (new_wid->object_type == PUCLASS_BISLIDER)
         {
            new_wid->floatval4 = 1.0f;
            new_wid->floatval5 = 0.0f;
         }
                  
         if (new_wid->object_type == PUCLASS_TRISLIDER)
         {
            new_wid->floatval4 = 1.0f;
            new_wid->floatval5 = 0.0f;
            new_wid->floatval6 = 0.5f;
            new_wid->boolval3 = false;
         }

         if (new_wid->object_type == PUCLASS_DIAL)
         {
            new_obj->setSize(50,50);
            new_wid->boolval2 = true;
         }

         if (new_wid->object_type == PUCLASS_SPINBOX)
         {
            new_wid->boolval2 = true;
            new_wid->floatval4 = 0.5f;
         }
         
         if (new_wid->object_type == PUCLASS_SCROLLBAR)
         {
           /* Not Yet Implemented */
         }

         if (new_wid->object_type == PUCLASS_SPINBOX)
         {
            new_wid->boolval2 = true;
            new_wid->floatval4 = 0.5f;
         }
         
         if (new_wid->object_type == PUCLASS_INPUT)
         {
            new_wid->boolval1 = true;
         }

         if (new_wid->object_type == PUCLASS_LARGEINPUT)
         {
            new_wid->boolval1 = true;
            new_wid->intval1 = 1;
            new_wid->intval2 = 5;
         }

         if (new_wid->object_type == PUCLASS_MENUBAR)
         {
            new_obj->setSize( 120, 30) ;
            new_obj->setPosition( 0, puGetWindowHeight()-30) ;
            new_wid->locked = true ;
         }

         if (new_wid->object_type == PUCLASS_VERTMENU)
         {
            new_obj->setSize( 45, 120) ;
            new_obj->setPosition( 0, puGetWindowHeight()-120) ;
            new_obj->setLegend("");
            new_obj->setLabelPlace(PUPLACE_BOTTOM_LEFT);
            new_obj->setLabel("puVerticalMenu");
            new_wid->locked = true ;
         }
             
          // Make the new widget the active widget
          active_object = new_obj ;
          active_widget = new_wid ;

          // If the "sticky" flag is not set, reset the selected object
          if ( !selected_object_sticky )
          {
            selected_object_type = 0 ;
            active_button->setValue ( 0 ) ;
          }
        }
        else
        {
          // Clicking on a widget in the main widget list activates it
          WidgetList *wid = widgets ;
          while ( wid )
          {
            puBox *box = wid->obj->getABox () ;
            if ( wid->visible && ( x >= box->min[0] ) && ( x <= box->max[0] ) &&
                                 ( y >= box->min[1] ) && ( y <= box->max[1] ) )
            {
              active_widget = wid ;
              active_object = wid->obj ;
              if ( abs ( x - box->min[0] ) < RESIZING_BORDER_WIDTH )
                activity_flag = 2 ;  // Resizing on x-min
              else if ( abs ( x - box->max[0] ) < RESIZING_BORDER_WIDTH )
                activity_flag = 4 ;  // Resizing on x-max
              else if ( abs ( y - box->min[1] ) < RESIZING_BORDER_WIDTH )
                activity_flag = 3 ;  // Resizing on y-min
              else if ( abs ( y - box->max[1] ) < RESIZING_BORDER_WIDTH )
                activity_flag = 5 ;  // Resizing on y-max
              else
                activity_flag = 1 ;  // Away from edges, we're moving it

       /* Now we check and see if we're clicking on a corner - the sensitivity for
       the determiniation of whether we're clicking a corner or not is held by the
       definition of "RESIZING_CORNER_BORDER_WIDTH" which is at the top of this file */
                
	      int corner_resize_width = RESIZING_CORNER_BORDER_WIDTH + (((box->max[0] - box->min[0]) + (box->max[1] - box->min[1]) / 2 ) / 50 ) * 2 ;

              if ( activity_flag != 1 )
	      {
                  // Bottom Right Corner
                  if ( ( abs( y - box->min[1] ) < corner_resize_width  ) && (abs ( x - box->max[0] ) < corner_resize_width ) )
		    activity_flag = 9;

                  // Bottom Left Corner
                  if ( ( abs( y - box->min[1] ) < corner_resize_width ) && (abs ( x - box->min[0] ) < corner_resize_width ) )
		    activity_flag = 6;

                  // Top Right Corner
                  if ( ( abs( y - box->max[1] ) < corner_resize_width ) && (abs ( x - box->max[0] ) < corner_resize_width ) )
		    activity_flag = 7;

                  // Top Left Corner
                  if ( ( abs( y - box->max[1] ) < corner_resize_width ) && (abs ( x - box->min[0] ) < corner_resize_width ) )
		    activity_flag = 8;
	      }

              /* If CTRL is held down, symmetric resize is forced. */

              resize_symmetric = ctrl_key_down ? 2 : 1 ;

              if (active_widget->object_type == PUCLASS_DIAL)
                  resize_corner = 1 ;
	      else
                  resize_corner = 0;

              int object_x, object_y ;
              active_object->getPosition ( &object_x, &object_y ) ;
              mouse_x_position_in_object = x - object_x ;
              mouse_y_position_in_object = y - object_y ;

              break ;
            }

            wid = wid->next ;
          }

          if ( ( !wid ) && ( context_menu->isVisible()==0 ) )  // Ran through the entire list, deactivate any active widget
          {
            active_widget = (WidgetList *)NULL ;
            active_object = (puObject *)NULL ;
          }
        }
}

        setStatusWidgets ( active_widget ) ;
      }
    }
  glutPostRedisplay () ;
}


static void main_window_reshapefn ( int w, int h )
{
  extern puInput *window_size_x ;
  extern puInput *window_size_y ;

  if (done_first_setup)
    main_window_changed = true ;
  else
    done_first_setup = true ;

  if ( ( !currently_loading ) && (
       ( mouse_x < main_window_width/2 ) ||  // Grabbed the left edge ...
       ( mouse_y < main_window_height/2 ) ) )  // or the bottom edge, move the widgets
  {
    WidgetList *wid = widgets ;
    int deltax = 0 ;
    int deltay = 0 ;

    if ( mouse_x < main_window_width/2  ) deltax = w - main_window_width ;
    if ( mouse_y < main_window_height/2 ) deltay = h - main_window_height ;

    while ( wid )
    {
      int x, y ;
      wid->obj->getPosition ( &x, &y ) ;
      wid->obj->setPosition ( x + deltax, y + deltay ) ;

      wid = wid->next ;
    }
  }

  main_window_width = w ;
  main_window_height = h ;

  window_size_x->setValue ( w ) ;
  window_size_y->setValue ( h ) ;

  currently_loading = false ;
}

static void main_window_displayfn ( void )
{
  /* Clear the screen */
  glutSetWindow ( main_window ) ;

  glClearColor ( main_window_color_r, main_window_color_g, main_window_color_b, main_window_color_a ) ;
  glClear      ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;

  // Set the OpenGL to draw PUI widgets

  int w = puGetWindowWidth  () ;
  int h = puGetWindowHeight () ;

  glPushAttrib   ( GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_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 () ;

  // Draw the widgets
  int layer ;
  for ( layer = 0; layer < max_layer; layer++ )
  {
    WidgetList *wid = widgets ;
    while ( wid )
    {
      if ( wid->visible && ( wid->layer == layer ) ) wid->obj->draw ( 0, 0 ) ;
      wid = wid->next ;
    }
  }

  if ( active_object )
  {
    puBox *box = active_object->getBBox () ;
    glColor4f ( 0.0f, 0.0f, 0.0f, 1.0f ) ;
    glLineWidth ( 3.0f ) ;
    glBegin ( GL_LINES ) ;
    glVertex2i ( box->min[0]-1, box->min[1]-1 ) ;
    glVertex2i ( box->max[0]+1, box->min[1]-1 ) ;
    glVertex2i ( box->max[0]+1, box->max[1]+1 ) ;
    glVertex2i ( box->min[0]-1, box->max[1]+1 ) ;
    glVertex2i ( box->min[0]-1, box->min[1]-1 ) ;
    glEnd () ;
  }

  context_menu->draw(0,0);

  /* Update GLUT */

  glutSwapBuffers   () ;
  glutPostRedisplay () ;

}

int main ( int argc, char **argv )
{
  extern int define_widget_window () ;
  extern int define_status_window () ;
  int i = 0;

  strcpy ( main_window_name, "PUI GUI Builder" ) ;

  glutInitWindowPosition( 100,   0 ) ;
  glutInitWindowSize    ( main_window_width, main_window_height ) ;
  glutInit              ( &argc, argv ) ;
  glutInitDisplayMode   ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ) ;
  main_window = glutCreateWindow      ( main_window_name ) ;
  glutDisplayFunc       ( main_window_displayfn ) ;
  glutKeyboardFunc      ( main_window_keyfn     ) ;
  glutSpecialFunc       ( main_window_specialfn ) ;
  glutMouseFunc         ( main_window_mousefn   ) ;
  glutMotionFunc        ( main_window_motionfn  ) ;
  glutPassiveMotionFunc ( main_window_passivefn ) ;
  glutReshapeFunc       ( main_window_reshapefn ) ;
  glutIdleFunc          ( main_window_displayfn ) ;

// If we're using windows, ignore the C: or whatnot 

#ifdef WIN32
  #define PATH_SEPARATOR   '\\'
  strcpy (pguide_current_directory, argv[0]+2);
#else
  #define PATH_SEPARATOR   '/'
  strcpy (pguide_current_directory, argv[0]);
#endif
  i = strlen(pguide_current_directory);


  while (pguide_current_directory[i] != PATH_SEPARATOR) {
      if (i>0) i-- ;
      else break ;
  }
  pguide_current_directory[i+1] = '\0';
  
  puInit () ;

#ifdef VOODOO
  puShowCursor () ;
#endif

  puSetDefaultStyle        ( PUSTYLE_SMALL_SHADED ) ;
  puSetDefaultColourScheme ( 0.8f, 0.8f, 0.8f, 1.0f ) ;

  // Add the properties context menu
  context_menu = new puPopupMenu( 0, 0 ) ;
  context_menu->add_item("Properties", cb_edit_properties) ;
  context_menu->add_item("Lock/Unlock", cb_lock_toggle) ;
  context_menu->add_item("Delete", cb_popup_delete) ;
  context_menu->add_item("Cut", NULL) ;
  context_menu->add_item("Copy", NULL) ;
  context_menu->add_item("Change Class", NULL) ;
  context_menu->close() ;

  // Set up the other windows
  define_widget_window () ;
  define_status_window () ;

  glutMainLoop () ;
  return 0 ;
}

