/****************************************************************************
  
  GLUI User Interface Toolkit
  ---------------------------

     glui.cpp


          --------------------------------------------------

  Copyright (c) 1998 Paul Rademacher

  This program is freely distributable without licensing fees and is
  provided without guarantee or warrantee expressed or implied. This
  program is -not- in the public domain.

*****************************************************************************/

#include "glui.h"
#include "glui_stdinc.h"


/*** This object must be used to create a GLUI ***/

GLUI_Master_Object GLUI_Master;


/************************************ finish_drawing() ************/

void finish_drawing( void ) 
{
    glFinish();
}

/************************************************ GLUI::GLUI() **********/

int GLUI::init( const char *text, long Flags, int x, int y, int Parent_window ) 
{
  int old_glut_window;

  this->flags = Flags;

  strncpy( window_name.string, text, sizeof(GLUI_String));

  /*** We copy over the current window callthroughs ***/
  /*** (I think this might actually only be needed for subwindows) ***/
  /*  glut_keyboard_CB = GLUI_Master.glut_keyboard_CB;
      glut_reshape_CB  = GLUI_Master.glut_reshape_CB;
      glut_special_CB  = GLUI_Master.glut_special_CB;
      glut_mouse_CB    = GLUI_Master.glut_mouse_CB;*/


  if ( (flags & GLUI_SUBWINDOW) != GLUI_SUBWINDOW ) {
    old_glut_window = glutGetWindow();

    create_standalone_window( window_name, x, y );
    setup_default_glut_callbacks();

    if ( old_glut_window > 0 )
      glutSetWindow( old_glut_window );

    top_level_glut_window_id = glut_window_id;
  } 
  else {
    old_glut_window = glutGetWindow();

    create_subwindow( Parent_window, flags );
    setup_default_glut_callbacks();

    if ( old_glut_window > 0 )
      glutSetWindow( old_glut_window );

    top_level_glut_window_id = Parent_window;

    /*
      glutReshapeFunc( glui_parent_window_reshape_func );
      glutSpecialFunc( glui_parent_window_special_func );
      glutKeyboardFunc( glui_parent_window_keyboard_func );
      glutMouseFunc( glui_parent_window_mouse_func );
      */
    
  }

  return true;
}


/**************************** GLUI_Main::create_standalone_window() ********/

void    GLUI_Main::create_standalone_window( const char *name, int x, int y )
{
  glutInitWindowSize( 100, 100 );
  if ( x >= 0 OR y >= 0 )
    glutInitWindowPosition( x, y );
  glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE ); /* | GLUT_DOUBLE );          */
  glut_window_id = glutCreateWindow( name );
  glDisable( GL_DEPTH_TEST );
  glCullFace( GL_BACK );
  glDisable( GL_CULL_FACE );
  glDisable( GL_LIGHTING );
  glDrawBuffer( GL_FRONT );
}


/******************************** GLUI_Main::create_subwindow() **********/

void     GLUI_Main::create_subwindow( int Parent_window,
                                      int /* window_alignment */ )
{
  glut_window_id = glutCreateSubWindow( Parent_window, 0,0, 100, 100 );
  glDisable( GL_DEPTH_TEST );
  glCullFace( GL_BACK );
  glDisable( GL_CULL_FACE );
  glDisable( GL_LIGHTING );  
  glDrawBuffer( GL_FRONT );

  this->parent_window = Parent_window;
}


/**************************** GLUI_Main::setup_default_glut_callbacks() *****/

void   GLUI_Main::setup_default_glut_callbacks( void )
{
  glutDisplayFunc( glui_display_func );
  glutReshapeFunc( glui_reshape_func );
  glutKeyboardFunc( glui_keyboard_func );
  glutSpecialFunc( glui_special_func );
  glutMouseFunc( glui_mouse_func );
  glutMotionFunc( glui_motion_func );
  glutPassiveMotionFunc( glui_passive_motion_func );
  glutEntryFunc( glui_entry_func );
  glutVisibilityFunc( glui_visibility_func );
  /*  glutIdleFunc( glui_idle_func );          */
}


/********************************************** glui_display_func() ********/

void glui_display_func( void )
{
  GLUI *glui;

  /*  printf( "display func\n" );          */

  glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

  if ( glui ) {
    glui->display(); 
    /* 
       Do not do anything after the above line, b/c the GLUI
       window might have just closed itself 
   */
  }
}


/********************************************** glui_reshape_func() ********/

void glui_reshape_func( int w, int h )
{
  GLUI             *glui;
  GLUI_Glut_Window *glut_window;
  int               current_window;

  /*printf( "glui_reshape_func(): %d  w/h: %d/%d\n", glutGetWindow(), w, h );          */

  current_window = glutGetWindow();

  /***  First check if this is main glut window ***/
  glut_window = GLUI_Master.find_glut_window( current_window );
  if ( glut_window ) {
    glut_window->glut_reshape_CB(w,h);

    /***  Now send reshape events to all subwindows  ***/
    glui = (GLUI*) GLUI_Master.gluis.first_child();
    while(glui) {
      if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
       glui->parent_window == current_window ) {
    glutSetWindow( glui->get_glut_window_id());
    glui->reshape(w,h);
    /*  glui->check_subwindow_position();          */
      }
      glui = (GLUI*) glui->next();
    }
  }
  else {
    /***  A standalone GLUI window  ***/

    glui = GLUI_Master.find_glui_by_window_id( current_window );

    if ( glui ) {
      glui->reshape(w,h);
    }
  }
}

/********************************************** glui_keyboard_func() ********/

void glui_keyboard_func(unsigned char key, int x, int y)
{
  GLUI              *glui;
  int                current_window;
  GLUI_Glut_Window  *glut_window;

  current_window = glutGetWindow();
  glut_window = GLUI_Master.find_glut_window( current_window );

  /*printf( "key: %d\n", current_window );          */

  if ( glut_window ) { /**  Was event in a GLUT window?  **/
    if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) {
      glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );
      
      GLUI_Master.active_control_glui->keyboard(key,x,y);    
      finish_drawing();
      
      glutSetWindow( current_window );
    }
    else {
      glut_window->glut_keyboard_CB( key, x, y );
    } 
  }
  else {   /***  Nope, event was in a standalone GLUI window  **/
    glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

    if ( glui ) {
      glui->keyboard(key,x,y);
      finish_drawing();
    }
  }
}


/************************************************ glui_special_func() ********/

void glui_special_func(int key, int x, int y)
{
  GLUI              *glui;
  int                current_window;
  GLUI_Glut_Window  *glut_window;

  current_window = glutGetWindow();
  glut_window = GLUI_Master.find_glut_window( current_window );

  if ( glut_window ) { /**  Was event in a GLUT window?  **/
    if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) {
      glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );
      
      GLUI_Master.active_control_glui->special(key,x,y);    
      finish_drawing();
      
      glutSetWindow( current_window );
    }
    else {
      glut_window->glut_special_CB( key, x, y );
    } 
  }
  else {   /***  Nope, event was in a standalone GLUI window  **/
    glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

    if ( glui ) {
      glui->special(key,x,y);
      finish_drawing();
    }
  }
}



/********************************************** glui_mouse_func() ********/

void glui_mouse_func(int button, int state, int x, int y)
{
  GLUI              *glui;
  int                current_window;
  GLUI_Glut_Window  *glut_window;

  current_window = glutGetWindow();
  glut_window = GLUI_Master.find_glut_window( current_window );

  if ( glut_window ) { /**  Was event in a GLUT window?  **/
    if ( GLUI_Master.active_control_glui != NULL ) 
      GLUI_Master.active_control_glui->disactivate_current_control();

    glut_window->glut_mouse_CB( button, state, x, y );
    finish_drawing();
  }
  else {               /**  Nope - event was in a GLUI standalone window  **/
    glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
    if ( glui ) {
      glui->passive_motion( 0,0 );
      glui->mouse( button, state, x, y );
      finish_drawing();
    }
  }
}


/********************************************** glui_motion_func() ********/

void glui_motion_func(int x, int y)
{
  GLUI *glui;

  glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

  if ( glui ) {
    glui->motion(x,y);
    finish_drawing();
  }

}


/**************************************** glui_passive_motion_func() ********/

void glui_passive_motion_func(int x, int y)
{
  GLUI *glui;

  glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

  if ( glui ) {
    glui->passive_motion(x,y);
    finish_drawing();
  }
}


/********************************************** glui_entry_func() ********/

void glui_entry_func(int state)
{
  GLUI *glui;

  glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

  if ( glui ) {
    glui->entry(state);
  }
}


/******************************************** glui_visibility_func() ********/

void glui_visibility_func(int state)
{
  GLUI *glui;

  /*  printf( "IN GLUI VISIBILITY()\n" );          */
  /*  fflush( stdout );          */

  glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );

  if ( glui ) {
    glui->visibility(state);
  }
}


/********************************************** glui_idle_func() ********/
/* Send idle event to each glui, then to the main window            */

void glui_idle_func(void)
{
  GLUI *glui;

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
    glui->idle();
    finish_drawing();
    
    glui = (GLUI*) glui->next();
  }

  if ( GLUI_Master.glut_idle_CB ) {
    /*** We set the current glut window before calling the user's
      idle function, even though glut explicitly says the window id is 
      undefined in an idle callback.  ***/
    
    /** Check what the current window is first ***/

    /*** Arbitrarily set the window id to the main gfx window of the 
      first glui window ***/
    /*   int current_window, new_window;          */
    /*   current_window = glutGetWindow();          */
    /*   if (GLUI_Master.gluis.first_child() != NULL ) {          */
    /*      new_window = ((GLUI_Main*)GLUI_Master.gluis.first_child())-> */
    /*   main_gfx_window_id;          */
    /*   if ( new_window > 0 AND new_window != old_window ) {          */
    /*   --- Window is changed only if its not already the current window ---*/
    /*  glutSetWindow( new_window );          */
    /* }          */
    /*}          */
    
    GLUI_Master.glut_idle_CB();
  }
}


/*********************************** GLUI_Master_Object::create_glui() ******/

GLUI    *GLUI_Master_Object::create_glui( const char *name, long flags,int x,int y )
{
  GLUI *new_glui;

  new_glui = new GLUI;
  
  if ( new_glui ) {
    new_glui->init( name, flags, x, y, -1 );
    new_glui->link_this_to_parent_last( &this->gluis );
    return new_glui;
  }
  else {
    return NULL;
  }
}


/************************** GLUI_Master_Object::create_glui_subwindow() ******/

GLUI   *GLUI_Master_Object::create_glui_subwindow( int parent_window, 
                           long flags )
{
  GLUI *new_glui;
  char  new_name[80];

  new_glui = new GLUI;

  if ( new_glui ) {
    sprintf( new_name, "subwin_%p", this );

    new_glui->init( new_name, flags | GLUI_SUBWINDOW, 0,0,
            parent_window );
    new_glui->main_panel->set_int_val( GLUI_PANEL_EMBOSSED );
    new_glui->link_this_to_parent_last( &this->gluis );
    return new_glui;
  }
  else {
    return NULL;
  }
}



/********************** GLUI_Master_Object::find_glui_by_window_id() ********/

GLUI  *GLUI_Master_Object::find_glui_by_window_id( int window_id )
{
  GLUI_Node *node;

  node = gluis.first_child();
  while( node ) {
    if ( ((GLUI*)node)->get_glut_window_id() == window_id ) 
      return (GLUI*) node;
    
    node = node->next();
  }
  return NULL;
}


/******************************************** GLUI_Main::display() **********/

void    GLUI_Main::display( void )
{
  int       win_w, win_h;

  /*glutSetWindow(1);///WOW WHAT A HACK          */

  /**** This function is used as a special place to do 'safe' processing,
    e.g., handling window close requests.
    That is, we can't close the window directly in the callback, so 
    we set a flag, post a redisplay message (which eventually calls
    this function), then close the window safely in here.  ****/
  if ( closing == true ) {
    close_internal();
    return;
  }

  /*  if ( TEST_AND( this->flags, GLUI_SUBWINDOW ))
      check_subwindow_position();
      */

  /*******    Draw GLUI window     ******/

  glClearColor( (float) bkgd_color.r / 255.0,
        (float) bkgd_color.g / 255.0,
        (float) bkgd_color.b / 255.0,
        1.0 );
  glClear( GL_COLOR_BUFFER_BIT ); /* | GL_DEPTH_BUFFER_BIT );          */

  /*  glutSwapBuffers(); //performs flush also  // %%%%%%%%%%          */
  /*  return;          */

  win_w = glutGet( GLUT_WINDOW_WIDTH );
  win_h = glutGet( GLUT_WINDOW_HEIGHT );

  /*** Check here if the window needs resizing ***/
  if ( win_w != main_panel->w OR win_h != main_panel->h ) {
    glutReshapeWindow( main_panel->w, main_panel->h );
    glutPostRedisplay();
    return;
  }

  set_ortho_projection();

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  /*** Rotate image so y increases upwards, contrary to OpenGL axes ***/
  glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 );
  glRotatef( 180.0, 0.0, 1.0, 0.0 );
  glRotatef( 180.0, 0.0, 0.0, 1.0 );
  glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 );

  /*  glDrawBuffer( GL_BACK );  // Is there ever a need to draw to back buffer??           */

  //  main_panel->draw_bkgd_box( 0, 0, win_w, win_h );
  main_panel->draw_recursive( 0, 0 );

  /*glutSwapBuffers(); //performs flush also            */
  finish_drawing();
}




/*************************************** _glutBitmapWidthString() **********/

int _glutBitmapWidthString( void *font, const char *s )
{
  const char *p = s;
  int  width = 0;

  while( *p != '\0' )  {
    width += glutBitmapWidth( font, *p );
    p++;
  }

  return width;
}

/************************************ _glutBitmapString *********************/
/* Displays the contents of a string using GLUT's bitmap character function */
/* Does not handle newlines                                             */

void _glutBitmapString( void *font, const char *s )
{
  const char *p = s;

  while( *p != '\0' )  {
    glutBitmapCharacter( font, *p );
    p++;
  }
}



/****************************** GLUI_Main::reshape() **************/

void    GLUI_Main::reshape( int reshape_w, int reshape_h )
{
  int new_w, new_h;

  pack_controls();

  new_w = main_panel->w;/* + 1;          */
  new_h = main_panel->h;/* + 1;          */

  if ( reshape_w != new_w OR reshape_h != new_h ) {
    this->w = new_w;
    this->h = new_h;
    
    glutReshapeWindow( new_w, new_h );
    glutPostRedisplay();
  }
  else {
  }

  if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
    check_subwindow_position();

    /***** if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
      }
      ****/
  }
  
  glViewport( 0, 0, new_w, new_h );

  /*  printf( "%d: %d\n", glutGetWindow(), this->flags );          */

  /*  glutPostRedisplay();          */
}


/****************************** GLUI_Main::keyboard() **************/

void    GLUI_Main::keyboard(unsigned char key, int x, int y)
{
  GLUI_Control *new_control;

  curr_modifiers = glutGetModifiers();

  /*** If it's a tab or shift tab, we don't pass it on to the controls.
    Instead, we use it to cycle through active controls ***/
  if ( key == '\t' AND mouse_button_down == false ) {
    if ( curr_modifiers & GLUT_ACTIVE_SHIFT ) {
      new_control = find_prev_control( active_control );
    }
    else {
      new_control = find_next_control( active_control );
    }

    /*    if ( new_control )
      printf( "new_control: %s\n", new_control->name );
      */

    disactivate_current_control();
    activate_control( new_control, GLUI_ACTIVATE_TAB );
  }
  else if ( key == ' ' AND active_control 
        AND active_control->spacebar_mouse_click == true ) { 
    /*** If the user presses the spacebar, and a non-edittext control
      is active, we send it a mouse down event followed by a mouse up
      event (simulated mouse-click) ***/
    
    active_control->mouse_down_handler( 0, 0 );
    active_control->mouse_up_handler( 0, 0, true );
  } else {
    /*** Pass the keystroke onto the active control, if any ***/
    if ( active_control != NULL )
      active_control->key_handler( key, curr_modifiers );
  }
}


/****************************** GLUI_Main::special() **************/

void    GLUI_Main::special(int key, int x, int y)
{
  curr_modifiers = glutGetModifiers();

  /*** Pass the keystroke onto the active control, if any ***/
  if ( active_control != NULL )
    active_control->special_handler( key, glutGetModifiers() );
}



/****************************** GLUI_Main::mouse() **************/

void    GLUI_Main::mouse(int button, int state, int x, int y)
{
  int callthrough;
  GLUI_Control *control;

  /*  printf( "MOUSE: %d %d\n", button, state );          */

  callthrough = true;

  curr_modifiers = glutGetModifiers();

  if ( button == GLUT_LEFT ) {
    control = find_control( x, y );

    /*if ( control ) printf( "control: %s\n", control->name.string );          */
    
    if ( mouse_button_down AND active_control != NULL AND
     state == GLUT_UP ) {
      /** We just released the mouse, which was depressed at some
    control **/

      callthrough = active_control->
    mouse_up_handler( x, y, control==active_control);
      glutSetCursor( GLUT_CURSOR_LEFT_ARROW );

      if ( active_control AND 
       active_control->active_type == 
       GLUI_CONTROL_ACTIVE_MOUSEDOWN AND 0){
    /*** This is a control that needs to be disactivated when the
      mouse button is released ****/
    disactivate_current_control();
      }
    }
    else {
      if ( control ) {
    if ( NOT mouse_button_down AND state == GLUT_DOWN ) {
      /*** We just pressed the mouse down at some control ***/

      if ( active_control != control ) {
        if ( active_control != NULL ) {
          /** There is an active control still - disactivate it ***/
          disactivate_current_control();
        }
      }

      if ( control->enabled ) {
        activate_control( control, GLUI_ACTIVATE_MOUSE );
        callthrough    = control->mouse_down_handler( x, y );
      }
    }
      }
    }

    if ( state == GLUT_DOWN )
      mouse_button_down = true;
    else if ( state == GLUT_UP )
      mouse_button_down = false;
  }

  /**
    NO CALLTHROUGH NEEDED FOR MOUSE EVENTS
    if ( callthrough AND glut_mouse_CB )
    glut_mouse_CB( button, state, x, y );
    **/

  callthrough=callthrough; /* To get rid of compiler warnings */
}


/****************************** GLUI_Main::motion() **************/

void    GLUI_Main::motion(int x, int y)
{
  int           callthrough;
  GLUI_Control *control;

  /*  printf( "MOTION: %d %d\n", x, y );          */

  callthrough = true;

  control = find_control(x,y);
  
  if ( mouse_button_down AND active_control != NULL ) {
    callthrough = 
      active_control->mouse_held_down_handler(x,y,control==active_control);
  }
  
  /**
    NO CALLTHROUGH NEEDED FOR MOUSE EVENTS

    if ( callthrough AND glut_motion_CB )
    glut_motion_CB(x,y);
    **/

  callthrough=callthrough; /* To get rid of compiler warnings */
}


/*********************** GLUI_Main::passive_motion() **************/

void    GLUI_Main::passive_motion(int x, int y)
{
  GLUI_Control *control;

  control = find_control( x, y );

  /*  printf( "%p %p\n", control, mouse_over_control );          */

  if ( control != mouse_over_control ) {
    if ( mouse_over_control ) {
      mouse_over_control->mouse_over( false, x, y );
    }

    if ( control ) {
      control->mouse_over( true, x, y );
      mouse_over_control = control;
    }
  }

  /*
    if ( curr_cursor != GLUT_CURSOR_INHERIT ) {
    curr_cursor = GLUT_CURSOR_INHERIT;
    glutSetCursor( GLUT_CURSOR_INHERIT );
    }*/

}


/****************************** GLUI_Main::entry() **************/

void    GLUI_Main::entry(int state)
{
  /*if ( NOT active_control OR ( active_control AND ( active_control->type == GLUI_CONTROL_EDITTEXT
    OR active_control->type == GLUI_CONTROL_SPINNER) ) )*/
  glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
}


/****************************** GLUI_Main::visibility() **************/

void    GLUI_Main::visibility(int state)
{
}


/****************************** GLUI_Main::idle() **************/

void    GLUI_Main::idle(void)
{
  /*** Pass the idle event onto the active control, if any ***/

  /*  printf( "IDLE \t" );          */

  if ( active_control != NULL ) {
    /* First we check if the control actually needs the idle right now.
       Otherwise, let's avoid wasting cycles and OpenGL context switching */

    if ( active_control->needs_idle() ) {
      /*** Set the current glut window to the glui window */
      /*** But don't change the window if we're already at that window ***/

      if ( glut_window_id > 0 AND glutGetWindow() != glut_window_id ) {
    glutSetWindow( glut_window_id );
      }
      
      active_control->idle();
    }
  }
}


/******************************************* GLUI_Main::find_control() ******/

GLUI_Control  *GLUI_Main::find_control( int x, int y )
{
  GLUI_Control *node, *last_container;

  last_container = NULL;

  node = main_panel;
  while( node != NULL ) {
    if ( node->type != GLUI_CONTROL_COLUMN AND
     PT_IN_BOX( x, y, 
            node->x_abs, node->x_abs + node->w, 
            node->y_abs, node->y_abs + node->h ) ) {
      /*** Point is inside current node ***/
      
      if ( node->first_child() == NULL ) {
    /*** SPECIAL CASE: for edittext boxes, we make sure click is
      in box, and not on name string.  This should be generalized
      for all controls later... ***/
    if ( node->type == GLUI_CONTROL_EDITTEXT ) {
      if ( x < node->x_abs + ((GLUI_EditText*)node)->text_x_offset )
        return (GLUI_Control*) node->parent();
    }

    return node;   /* point is inside this node, and node has no children,
              so return this node as the selected node */
      }
      else {
    /*** This is a container class ***/
    last_container = node;
    node = (GLUI_Control*) node->first_child();  /* Descend into child */
      }
      
    }
    else {
      node = (GLUI_Control*) node->next();
    }
  }
 
  /** No leaf-level nodes found to accept the mouse click, so
    return the last container control found which DOES accept the click **/
  
  if ( last_container ) {
    /*    printf( "ctrl: '%s'\n", last_container->name );          */
  
    return last_container;
  }
  else {
    return NULL;
  }
}


/************************************* GLUI_Main::pack_controls() ***********/

void      GLUI_Main::pack_controls( void )
{
  main_panel->pack(0,0);

  /**** Now align controls within their bounds ****/
  align_controls( main_panel );

  /***  If this is a subwindow, expand panel to fit parent window  ***/
  if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
    int parent_h, parent_w;
    int orig_window;

    orig_window = glutGetWindow();
    glutSetWindow( this->top_level_glut_window_id );
    parent_h = glutGet( GLUT_WINDOW_HEIGHT );
    parent_w = glutGet( GLUT_WINDOW_WIDTH );

    glutSetWindow( orig_window );

    /*      printf( "%d %d\n", parent_h, parent_w );          */

    if ( 1 ) {
      if ( TEST_AND(this->flags,GLUI_SUBWINDOW_TOP )) {
    main_panel->w = MAX( main_panel->w, parent_w );
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
    main_panel->h = MAX( main_panel->h, parent_h );
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) {
    main_panel->w = MAX( main_panel->w, parent_w );
      }
      else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
    main_panel->h = MAX( main_panel->h, parent_h );
      }
    }
  }

  this->w = main_panel->w;
  this->h = main_panel->h;
}


/************************************ GLUI_Main::align_controls() **********/

void    GLUI_Main::align_controls( GLUI_Control *control )
{
  GLUI_Control *child;

  control->align();

  child = (GLUI_Control*) control->first_child();

  while( child != NULL ) {
    align_controls( child );
    
    child = (GLUI_Control*)child->next();
  }  
}



/*********************************** GLUI::set_main_gfx_window() ************/

void   GLUI::set_main_gfx_window( int window_id )
{
  main_gfx_window_id = window_id;
}


/********************************* GLUI_Main::post_update_main_gfx() ********/

void   GLUI_Main::post_update_main_gfx( void )
{
  int old_window;

  if ( main_gfx_window_id > 0 ) {
    old_window = glutGetWindow();
    glutSetWindow( main_gfx_window_id );
    glutPostRedisplay();
    if( old_window > 0 )
      glutSetWindow( old_window );
  }
}


/********************************* GLUI_Main::set_front_draw_buffer() ********/

int          GLUI_Main::set_front_draw_buffer( void )
{
  GLint state;
  
  glGetIntegerv( GL_DRAW_BUFFER, &state );

  glDrawBuffer( GL_FRONT );
  
  return (int)state;
}
 

/********************************* GLUI_Main::restore_draw_buffer() **********/

void         GLUI_Main::restore_draw_buffer( int buffer_state )
{
  glDrawBuffer( buffer_state );
}


/******************************************** GLUI_Main::GLUI_Main() ********/

GLUI_Main::GLUI_Main( void ) 
{
  mouse_button_down       = false;
  w                       = 0;
  h                       = 0;
  active_control          = NULL;
  mouse_over_control      = NULL;
  main_gfx_window_id      = -1;
  glut_window_id          = -1;
  curr_modifiers          = 0;
  closing                 = false;
  parent_window           = -1;
  glui_id                 = GLUI_Master.glui_id_counter;
  GLUI_Master.glui_id_counter++;

  font                    = GLUT_BITMAP_HELVETICA_12;
  curr_cursor             = GLUT_CURSOR_LEFT_ARROW;

  bkgd_color.set( 200, 200, 200 );
  bkgd_color_f[0] = 200.0 / 255.0;
  bkgd_color_f[1] = 200.0 / 255.0;
  bkgd_color_f[2] = 200.0 / 255.0;

  /*** Create the main panel ***/
  main_panel              = new GLUI_Panel;
  main_panel->set_int_val( GLUI_PANEL_NONE );
  main_panel->glui        = (GLUI*) this;
  main_panel->name        = "\0";
}

/************************************ GLUI_Main::draw_raised_box() **********/

void      GLUI_Main::draw_raised_box( int x, int y, int w, int h )
{
  w = w+x;
  h = h+y;

  glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b );
  glBegin( GL_LINE_LOOP );
  glVertex2i( x+1, y+1 );         glVertex2i( w-1, y+1 );
  glVertex2i( w-1, h-1 );     glVertex2i( x+1, h-1 );
  glEnd();

  glColor3d( 1.0, 1.0, 1.0 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( x, h );  glVertex2i( x, y );  glVertex2i( w, y );
  glEnd();

  glColor3d( 0.0, 0.0, 0.0 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( w, y );  glVertex2i( w, h );  glVertex2i( x, h );
  glEnd();

  glColor3d( .5, .5, .5 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( w-1, y+1 );  glVertex2i( w-1, h-1 );  glVertex2i( x+1, h-1 );
  glEnd();
}


/************************************ GLUI_Main::draw_lowered_box() **********/
/* Not quite perfect...      **/

void      GLUI_Main::draw_lowered_box( int x, int y, int w, int h )
{
  w = w+x;
  h = h+y;

  glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b );
  glBegin( GL_LINE_LOOP );
  glVertex2i( x+1, y+1 );         glVertex2i( w-1, y+1 );
  glVertex2i( w-1, h-1 );     glVertex2i( x+1, h-1 );
  glEnd();

  glColor3d( 0.0, 0.0, 0.0 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( x, h );  glVertex2i( x, y );  glVertex2i( w, y );
  glEnd();

  glColor3d( 1.0, 1.0, 1.0 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( w, y );  glVertex2i( w, h );  glVertex2i( x, h );
  glEnd();

  glColor3d( .5, .5, .5 );
  glBegin( GL_LINE_STRIP );
  glVertex2i( w-1, y+1 );  glVertex2i( w-1, h-1 );  glVertex2i( x+1, h-1 );
  glEnd();
}


/************************************* GLUI_Main::activate_control() *********/

void         GLUI_Main::activate_control( GLUI_Control *control, int how )
{
  /** Are we not activating a control in the same window as the
    previous active control? */
  if ( GLUI_Master.active_control_glui AND
       this != (GLUI_Main*) GLUI_Master.active_control_glui ) {
    GLUI_Master.active_control_glui->disactivate_current_control();
  }

  /*******      Now activate it      *****/
  if ( control != NULL AND control->can_activate AND control->enabled ) {
    active_control = control;
    
    control->activate(how);

    /*if ( NOT active_control->is_container OR           */
    /*      active_control->type == GLUI_CONTROL_ROLLOUT) {          */
    active_control->translate_and_draw_front();
    /*}          */
  }
  else {
    active_control = NULL;
  }

  /*  printf( "activate: %d\n", glutGetWindow() );          */
  GLUI_Master.active_control      = active_control;
  GLUI_Master.active_control_glui = (GLUI*) this;
}


/************************* GLUI_Main::disactivate_current_control() **********/

void         GLUI_Main::disactivate_current_control( void )
{
  int orig;

  if ( active_control != NULL ) {
    orig = active_control->set_to_glut_window();

    active_control->disactivate();
    
    /** If this isn't a container control, then redraw it in its 
      disactivated state.  Container controls, such as panels, look
      the same activated or not **/

    /*if ( NOT active_control->is_container OR           */
    /*      active_control->type == GLUI_CONTROL_ROLLOUT ) {        */
    active_control->translate_and_draw_front();
    /*}          */

    active_control->restore_window( orig );

    active_control = NULL;
  }

  /*  printf( "disactivate: %d\n", glutGetWindow() );          */
  GLUI_Master.active_control      = NULL;
  GLUI_Master.active_control_glui = NULL;
}


/****************************** GLUI_Main::find_next_control() **************/

GLUI_Control  *GLUI_Main::find_next_control_( GLUI_Control *control )
{
  /*** THIS IS NOT find_next_control()!  This is an unused older
    version (look at the underscore at the end) ***/

  if ( control == NULL )
    return find_next_control_rec( main_panel );
  else
    return find_next_control_rec( control );
}

/****************************** GLUI_Main::find_next_control() **************/

GLUI_Control  *GLUI_Main::find_next_control_rec( GLUI_Control *control )
{
  GLUI_Control *child = NULL, *rec_control, *sibling;

  /*** Recursively investigate children ***/
  child = (GLUI_Control*) control->first_child();
  if ( child ) {
    /*** If we can activate the first child, then do so ***/
    if ( child->can_activate AND child->enabled )
      return child;
    else     /*** Recurse into first child ***/
      rec_control = find_next_control_rec( child );    

    if ( rec_control )
      return rec_control;
  }

  /*** At this point, either we don't have children, or the child cannot
    be activated.  So let's try the next sibling ***/

  sibling = (GLUI_Control*) control->next();
  if ( sibling ) {
    if ( sibling->can_activate AND sibling->enabled )
      return sibling;
    else     /*** Recurse into sibling ***/
      rec_control = find_next_control_rec( sibling );    

    if ( rec_control )
      return rec_control;
  }
  
  return NULL;
}


/****************************** GLUI_Main::find_next_control() **************/

GLUI_Control  *GLUI_Main::find_next_control( GLUI_Control *control )
{
  GLUI_Control *tmp_control = NULL;
  int           back_up;
  
  if ( control == NULL )
    control = main_panel;

  while( control != NULL ) {
    /** see if this control has a child **/
    tmp_control = (GLUI_Control*) control->first_child();

    if ( tmp_control != NULL ) {
      if ( tmp_control->can_activate AND tmp_control->enabled )
    return tmp_control;
      
      control = tmp_control;  /* Descend into child */
      continue;
    }
    
    /*** At this point, control has no children ***/

    /** see if this control has a next sibling **/
    tmp_control = (GLUI_Control*) control->next();
    
    if ( tmp_control != NULL ) {
      if ( tmp_control->can_activate AND tmp_control->enabled )
    return tmp_control;
      
      control = tmp_control;  
      continue;
    }

    /** back up until we find a sibling of an ancestor **/
    back_up = true;
    while ( control->parent() AND back_up ) {
      control = (GLUI_Control*) control->parent();

      if ( control->next() ) {
    control = (GLUI_Control*) control->next();  
    if ( control->can_activate AND control->enabled )
      return control;
    else
      back_up = false;

    /***    if ( control->is_container ) {
      tmp_control = control;
      control     = NULL;
      break;
      }
      else {
      back_up = false;
      }
      ***/
      }
    }

    /** Check if we've cycled back to the top... if so, return NULL **/
    if ( control == main_panel ) {
      return NULL;
    }
  }
  /*
    if ( tmp_control != NULL AND tmp_control->can_activate AND
    tmp_control->enabled ) {
    return tmp_control;
    }*/

  return NULL;
}


/****************************** GLUI_Main::find_prev_control() **************/

GLUI_Control  *GLUI_Main::find_prev_control( GLUI_Control *control )
{
  GLUI_Control *tmp_control, *next_control;

  if ( control == NULL ) {        /* here we find the last valid control */
    next_control = main_panel;
  
    do {
      tmp_control  = next_control;
      next_control = find_next_control( tmp_control ); 
    } while( next_control != NULL );

    return tmp_control;    
  }
  else {                         /* here we find the actual previous control */
    next_control = main_panel;
  
    do {
      tmp_control  = next_control;
      next_control = find_next_control( tmp_control ); 
    } while( next_control != NULL AND next_control != control );
    
    if ( next_control == NULL OR tmp_control == main_panel )
      return NULL;
    else 
      return tmp_control;
  }
}

/************************* GLUI_Master_Object::set_glutIdleFunc() ***********/

void    GLUI_Master_Object::set_glutIdleFunc(void (*f)(void))
{
  glut_idle_CB = f;
  glutIdleFunc( glui_idle_func );
}


/**************************************** GLUI::disable() ********************/

void   GLUI::disable( void )
{ 
  disactivate_current_control();
  main_panel->disable(); 
}


/******************************************** GLUI::sync_live() **************/

void   GLUI::sync_live( void )
{
  main_panel->sync_live(true, true);
}


/********************************* GLUI_Master_Object::sync_live_all() *****/

void   GLUI_Master_Object::sync_live_all( void ) 
{
  GLUI *glui;

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
   
    glui->sync_live();  /** sync it **/
 
    glui = (GLUI*) glui->next();
  }  
}


/************************************* GLUI_Master_Object::close() **********/

void   GLUI_Master_Object::close_all( void ) 
{
  GLUI *glui;

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
   
    glui->close();  /** Set flag to close **/
 
    glui = (GLUI*) glui->next();
  }  
}


/************************************* GLUI_Main::close_internal() **********/

void   GLUI_Main::close_internal( void ) 
{
  glutDestroyWindow(glutGetWindow()); /** Close this window **/

  this->unlink();
  
  if ( GLUI_Master.active_control_glui == this ) {
    GLUI_Master.active_control      = NULL;
    GLUI_Master.active_control_glui = NULL;
  }
    
  if ( parent_window != -1 ) {
    glutSetWindow( parent_window );
    int win_w = glutGet( GLUT_WINDOW_WIDTH );
    int win_h = glutGet( GLUT_WINDOW_HEIGHT );
    glutReshapeWindow(win_w+1, win_h);
    glutReshapeWindow(win_w-1, win_h);
    glutPostRedisplay();
  }

  delete this->main_panel;

  delete this;
}


/************************************************** GLUI::close() **********/

void   GLUI::close( void ) 
{
  int   old_glut_window;

  closing = true;

  old_glut_window = glutGetWindow();
  glutSetWindow( get_glut_window_id() );
  glutPostRedisplay();

  glutSetWindow( old_glut_window );
}


/************************** GLUI_Main::check_subwindow_position() **********/

void   GLUI_Main::check_subwindow_position( void )
{
  /*** Reposition this window if subwindow ***/
  if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {

    int parent_w, parent_h, new_x, new_y;
    int old_window = glutGetWindow();

    glutSetWindow( glut_window_id );

    glutSetWindow( glutGet( GLUT_WINDOW_PARENT ));
    parent_w = glutGet( GLUT_WINDOW_WIDTH );
    parent_h = glutGet( GLUT_WINDOW_HEIGHT );

    glutSetWindow( glut_window_id );

    if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
      new_x = parent_w - this->w;
      new_y = 0;
    } 
    else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
      new_x = 0;
      new_y = 0;
    } 
    else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) {
      new_x = 0;
      new_y = parent_h - this->h;
    } 
    else {    /***   GLUI_SUBWINDOW_TOP    ***/
      new_x = 0;
      new_y = 0;
    }

    /** Now make adjustments based on presence of other subwindows **/
    GLUI *curr_glui;
    curr_glui = (GLUI*) GLUI_Master.gluis.first_child(); 
    while( curr_glui ) {
      if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND 
       curr_glui->parent_window == this->parent_window ) {

    if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
    }
    else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
    }
    else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
    }
    else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) AND 
          ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) OR
            TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) ) ) {
      /** If we are a RIGHT or LEFT subwindow, and there exists some 
        TOP subwindow, bump our position down  **/

      new_y += curr_glui->h;
    }

    /** CHeck multiple subwins at same position  **/
    /** We check the glui_id's:  only the glui with the higher
      ID number (meaning it was created later) gets bumped over **/
    if ( curr_glui != this AND this->glui_id > curr_glui->glui_id ) {
      if ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) AND
           TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
        new_x += curr_glui->w;
      }
      else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_TOP ) AND
            TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) {
        new_y += curr_glui->h;
      }
      else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_BOTTOM ) AND
            TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
        new_y -= curr_glui->h;
      }
      else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) AND
            TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
        new_x -= curr_glui->w;
      }

    }
      }

      curr_glui = (GLUI*) curr_glui->next();
    }
    

        
    CLAMP( new_x, 0, new_x );
    CLAMP( new_y, 0, new_y );

    glutPositionWindow( new_x, new_y );
    /*      glutPostRedisplay();          */

    glutSetWindow( old_window );
  }
}


/********************************* GLUI_Master_Object::reshape() **********/
/* This gets called by the user from a GLUT reshape callback.  So we look */
/* for subwindows that belong to the current window                   */

void  GLUI_Master_Object::reshape( void )
{
  GLUI *glui;
  int   current_window;

  current_window = glutGetWindow();
  
  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
    if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
     glui->parent_window == current_window ) {
      glutSetWindow( glui->get_glut_window_id());
      glui->check_subwindow_position();
    }
    
    glui = (GLUI*) glui->next();
  }  

  glutSetWindow(current_window);
}


/**************************** GLUI_Master_Object::set_glutReshapeFunc() *****/

void GLUI_Master_Object::set_glutReshapeFunc(void (*f)(int width, int height))
{
  glutReshapeFunc( glui_reshape_func );
  add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_RESHAPE, (void*) f);
}


/**************************** GLUI_Master_Object::set_glutKeyboardFunc() ****/

void GLUI_Master_Object::set_glutKeyboardFunc(void (*f)(unsigned char key, 
                            int x, int y))
{
  glutKeyboardFunc( glui_keyboard_func );
  add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_KEYBOARD, (void*) f);
}


/*********************** GLUI_Master_Object::set_glutSpecialFunc() **********/

void GLUI_Master_Object::set_glutSpecialFunc(void (*f)(int key, 
                               int x, int y))
{
  glutSpecialFunc( glui_special_func );
  add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_SPECIAL, (void*) f);
}


/*********************** GLUI_Master_Object::set_glutMouseFunc() **********/

void GLUI_Master_Object::set_glutMouseFunc(void (*f)(int button, int state,
                             int x, int y))
{
  glutMouseFunc( glui_mouse_func );
  add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_MOUSE, (void*) f);
}


/****************************** glui_parent_window_reshape_func() **********/
/* This is the reshape callback for a window that contains subwindows      */

void glui_parent_window_reshape_func( int w, int h )
{
  int   current_window;
  GLUI  *glui;
  int   first = true;

  /*  printf( "glui_parent_window_reshape_func: %d\n", glutGetWindow() );          */

  current_window = glutGetWindow();

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
    if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
     glui->parent_window == current_window ) {
      glutSetWindow( glui->get_glut_window_id());
      glui->check_subwindow_position();
      glutSetWindow( current_window );

      if ( first ) {
    glui->glut_reshape_CB( w, h );
    
    first = false;
      }
    }
    
    glui = (GLUI*) glui->next();
  }  
}


/****************************** glui_parent_window_keyboard_func() **********/

void glui_parent_window_keyboard_func(unsigned char key, int x, int y)
{
  /*  printf( "glui_parent_window_keyboard_func: %d\n", glutGetWindow() );          */

  int   current_window;
  GLUI  *glui;

  current_window = glutGetWindow();

  if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) {
    glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );

    GLUI_Master.active_control_glui->keyboard(key,x,y);    

    glutSetWindow( current_window );
  }
  else {
    glui = (GLUI*) GLUI_Master.gluis.first_child();
    while( glui ) {
      if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
       glui->parent_window == current_window ) {
    glui->glut_keyboard_CB( key, x, y );
    break;
      }
    
      glui = (GLUI*) glui->next();
    }
  } 
}


/****************************** glui_parent_window_special_func() **********/

void glui_parent_window_special_func(int key, int x, int y)
{
  /*printf( "glui_parent_window_special_func: %d\n", glutGetWindow() );          */

  int   current_window;
  GLUI  *glui;

  /**  If clicking in the main area of a window w/subwindows, 
    disactivate any current control  **/
  if ( GLUI_Master.active_control_glui != NULL ) 
    GLUI_Master.active_control_glui->disactivate_current_control();

  /***   Now pass on the mouse event   ***/

  current_window = glutGetWindow();

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
    if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
     glui->parent_window == current_window ) {
      glutSetWindow( glui->get_glut_window_id());
      glui->glut_special_CB( key, x, y );
      break;
    }
    
    glui = (GLUI*) glui->next();
  }  
}


/****************************** glui_parent_window_mouse_func() **********/

void glui_parent_window_mouse_func(int button, int state, int x, int y)
{
  int   current_window;
  GLUI  *glui;

  /**  If clicking in the main area of a window w/subwindows, 
    disactivate any current control  **/
  if ( GLUI_Master.active_control_glui != NULL ) 
    GLUI_Master.active_control_glui->disactivate_current_control();


  /***   Now pass on the mouse event   ***/

  current_window = glutGetWindow();

  glui = (GLUI*) GLUI_Master.gluis.first_child();
  while( glui ) {
    if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND 
     glui->parent_window == current_window ) {
      glutSetWindow( glui->get_glut_window_id());
      glui->glut_mouse_CB( button, state, x, y );
      break;
    }
    
    glui = (GLUI*) glui->next();
  }  
  
}


/************************** GLUI_Master_Object::find_glut_window() **********/

GLUI_Glut_Window  *GLUI_Master_Object::find_glut_window( int window_id )
{
  GLUI_Glut_Window *window;

  window = (GLUI_Glut_Window*) glut_windows.first_child();
  while( window ) {
    if ( window->glut_window_id == window_id ) 
      return window;
    
    window = (GLUI_Glut_Window*) window->next();
  }

  /***  Window not found - return NULL ***/
  return NULL;
}


/******************** GLUI_Master_Object::add_cb_to_glut_window() **********/

void     GLUI_Master_Object::add_cb_to_glut_window(int window_id,
                           int cb_type,void *cb)
{
  GLUI_Glut_Window *window;

  window = find_glut_window( window_id );
  if ( NOT window ) {
    /***  Allocate new window structure  ***/
    
    window                 = new GLUI_Glut_Window;
    window->glut_window_id = window_id;
    window->link_this_to_parent_last( (GLUI_Node*) &this->glut_windows );
  }

  switch( cb_type ) {
  case GLUI_GLUT_RESHAPE:
    window->glut_reshape_CB   = (void(*)(int,int)) cb;
    break;
  case GLUI_GLUT_DISPLAY:
    window->glut_display_CB   = (void(*)()) cb;
    break;
  case GLUI_GLUT_KEYBOARD:
    window->glut_keyboard_CB  = (void(*)(unsigned char,int,int)) cb;
    break;
  case GLUI_GLUT_SPECIAL:
    window->glut_special_CB   = (void(*)(int,int,int)) cb;
    break;
  case GLUI_GLUT_MOUSE:
    window->glut_mouse_CB     = (void(*)(int,int,int,int)) cb;
    break;
  case GLUI_GLUT_MOTION:
    window->glut_motion_CB    = (void(*)(int,int)) cb;
    break;
  case GLUI_GLUT_PASSIVE_MOTION:
    window->glut_passive_motion_CB = (void(*)(int,int)) cb;
    break;
  case GLUI_GLUT_ENTRY:
    window->glut_entry_CB     = (void(*)(int)) cb;
    break;
  case GLUI_GLUT_VISIBILITY:
    window->glut_visibility_CB= (void(*)(int)) cb;
    break;
  }
}


/************* GLUI_Master_Object::set_left_button_glut_menu_control() *****/

void  GLUI_Master_Object::set_left_button_glut_menu_control( 
                                GLUI_Control *control )
{
  curr_left_button_glut_menu = control;
}


/******************************* GLUI_Main::set_ortho_projection() **********/

void  GLUI_Main::set_ortho_projection( void )
{
  int win_h, win_w;

  win_w = glutGet( GLUT_WINDOW_WIDTH );
  win_h = glutGet( GLUT_WINDOW_HEIGHT );

  glViewport(0, 0, win_w, win_h);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  /*  gluOrtho2D( 0.0, (float) win_w, 0.0, (float) win_h );          */
  glOrtho( 0.0, (float)win_w, 0.0, (float) win_h, -1000.0, 1000.0 );

  glMatrixMode( GL_MODELVIEW );
 
  return; /****-----------------------------------------------***/

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  /*** Rotate image so y increases upwards, contrary to OpenGL axes ***/
  glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 );
  glRotatef( 180.0, 0.0, 1.0, 0.0 );
  glRotatef( 180.0, 0.0, 0.0, 1.0 );
  glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 );
}


/******************************* GLUI_Main::set_viewport() **********/

void  GLUI_Main::set_viewport( void )
{
  glViewport( 0, 0, main_panel->w, main_panel->h );
}


/****************************** GLUI_Main::refresh() ****************/

void    GLUI_Main::refresh( void )
{
  int orig;
  int new_w, new_h;

  /******  GLUI_Glut_Window *glut_window;
    int              current_window;
    current_window = glutGetWindow();
    glut_window    = GLUI_Master.find_glut_window( current_window );
    if ( glut_window ) {
    glut_window->glut_reshape_CB(w,h);
    ******/

  orig  = glutGetWindow();

  pack_controls();

  if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
    /*** GLUI subwindow ***/

    check_subwindow_position();

    if ( glut_window_id > 0 )
      glutSetWindow( glut_window_id );
    glutPostRedisplay();

    /*  printf( "top_level: %d\n", top_level_glut_window_id );*/
    glutSetWindow( top_level_glut_window_id );
  }
  else {
    /*** Standalone GLUI window ***/

    if ( glut_window_id > 0 )
      glutSetWindow( glut_window_id );
  
    new_h = glutGet( GLUT_WINDOW_HEIGHT );
    new_w = glutGet( GLUT_WINDOW_WIDTH );
    
    new_h = this->h;
    new_w = this->w;

    glutReshapeWindow( new_w, new_h );

    glutPostRedisplay();
  }

  glutSetWindow( orig);
}



/***************** GLUI_Master_Object::get_main_gfx_viewport() ***********/

void     GLUI_Master_Object::get_viewport_area( int *x, int *y, 
                        int *w, int *h )
{
  GLUI *curr_glui;
  int   curr_x, curr_y, curr_w, curr_h;
  int   curr_window;

  curr_window = glutGetWindow();
  curr_x = 0;
  curr_y = 0;
  curr_w = glutGet( GLUT_WINDOW_WIDTH );
  curr_h = glutGet( GLUT_WINDOW_HEIGHT );

  curr_glui = (GLUI*) gluis.first_child(); 
  while( curr_glui ) {
    if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND 
     curr_glui->parent_window == curr_window ) {

      /*            printf( "%s -> %d   %d %d\n", curr_glui->window_name.string, curr_glui->flags,
                curr_glui->w, curr_glui->h );*/

      if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
    curr_x += curr_glui->w;
    curr_w -= curr_glui->w;
      }
      else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
    curr_y += curr_glui->h;
    curr_h -= curr_glui->h;
      }
      else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
    curr_w -= curr_glui->w;
      }
      else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) {
    curr_h -= curr_glui->h;
      }
    }

    curr_glui = (GLUI*) curr_glui->next();
  }

  curr_x = MAX( 0, curr_x );
  curr_y = MAX( 0, curr_y );
  curr_w = MAX( 0, curr_w );
  curr_h = MAX( 0, curr_h );

  *x = curr_x;
  *y = curr_y;
  *w = curr_w;
  *h = curr_h;
}


/*****************GLUI_Master_Object::auto_set_main_gfx_viewport() **********/

void           GLUI_Master_Object::auto_set_viewport( void )
{
  int x, y, w, h;

  get_viewport_area( &x, &y, &w, &h );
  glViewport( MAX(x,0), MAX(y,0), MAX(w,0), MAX(h,0) );
}



/***************************************** GLUI::show() **********************/

void            GLUI::show( void )
{
  int orig_window;

  orig_window = main_panel->set_to_glut_window();

  glutShowWindow();

  main_panel->restore_window(orig_window);
}



/***************************************** GLUI::hide() **********************/

void            GLUI::hide( void )
{
  int orig_window;

  this->disactivate_current_control();

  orig_window = main_panel->set_to_glut_window();

  glutHideWindow();

  main_panel->restore_window(orig_window);
}
