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

     glui_add_controls.cpp - Routines for adding controls to a GLUI window


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

  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"


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

GLUI_Checkbox   *GLUI:: add_checkbox( const char *name, int *value_ptr,
                      int id, GLUI_Update_CB callback )
{
  return add_checkbox_to_panel( main_panel,
                name, value_ptr, id, callback );
}


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

GLUI_Checkbox   *GLUI::add_checkbox_to_panel( GLUI_Panel *panel,
                          const char *name, int *value_ptr,
                          int id, 
                          GLUI_Update_CB callback )
{
  GLUI_Checkbox *control;

  control = new GLUI_Checkbox;

  if ( control ) {
    control->set_ptr_val( value_ptr );
    control->user_id    = id;
    control->set_name( name );
    control->callback    = callback;

    add_control( panel, control );

    control->init_live();

    return control;
  }
  else {
    return NULL;
  }
}



/************************************ GLUI_Main::add_control() **************/
 
int    GLUI_Main::add_control( GLUI_Node *parent, GLUI_Control *control )
{
  GLUI_Control *parent_control;

  /*** Collapsible nodes have to be handled differently, b/c the first and 
    last children are swapped in and out  ***/
  parent_control = ((GLUI_Control*)parent);
  if ( parent_control->collapsible == true ) {
    if ( NOT parent_control->is_open ) {
      /** Swap in the original first and last children **/
      parent_control->child_head  = parent_control->collapsed_node.child_head;
      parent_control->child_tail  = parent_control->collapsed_node.child_tail;

      /*** Link this control ***/
      control->link_this_to_parent_last( parent );

      /** Swap the children back out ***/
      parent_control->collapsed_node.child_head = parent_control->child_head;
      parent_control->collapsed_node.child_tail = parent_control->child_tail;
      parent_control->child_head = NULL;
      parent_control->child_tail = NULL;
    }
    else {
      control->link_this_to_parent_last( parent );
    }
  }
  else {
    control->link_this_to_parent_last( parent );
  }
  control->glui = (GLUI*) this;
  control->update_size();
  control->enabled = ((GLUI_Control*) parent)->enabled;
  control->glui->refresh();

  /** Now set the 'hidden' var based on the parent **/
  if ( parent_control->hidden OR 
       (parent_control->collapsible AND NOT parent_control->is_open ) )
  {
    control->hidden = true;
  }

  return true;
}


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

GLUI_Panel     *GLUI::add_panel( const char *name, int type )
{
  return add_panel_to_panel( main_panel, name, type );
}


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

GLUI_Panel     *GLUI::add_panel_to_panel( GLUI_Panel *parent_panel,
                      const char *name, int type )
{
  GLUI_Panel *panel;
  
  panel = new GLUI_Panel;

  if ( panel ) {
    panel->set_name( name );
    panel->user_id    = -1;
    panel->int_val    = type;

    add_control( parent_panel, panel );

    return panel;
  }
  else {
    return NULL;
  }  
}


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

GLUI_RadioGroup *GLUI::add_radiogroup( int *value_ptr,
                       int user_id, GLUI_Update_CB callback)
{
  return add_radiogroup_to_panel( main_panel, value_ptr,
                  user_id, callback );
}


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

GLUI_RadioGroup *GLUI::add_radiogroup_to_panel(  GLUI_Panel *panel,
                         int *value_ptr,
                         int user_id, GLUI_Update_CB callback)
{
  GLUI_RadioGroup *control;
  GLUI_String      buf;

  control = new GLUI_RadioGroup;

  if ( control ) {
    control->set_ptr_val( value_ptr );
    if ( value_ptr ) {
      control->int_val = *value_ptr;  /** Can't call set_int_val(), b/c that 
                    function will try to call the 
                    callback, etc */
      /** Actually, maybe not **/
      control->last_live_int = *value_ptr;
    }

    control->user_id    = user_id;
    sprintf( buf, "RadioGroup: %p", control );
    control->set_name( buf );
    control->callback   = callback;

    add_control( panel, control );

    control->init_live();

    return control;
  }
  else {
    return NULL;
  }

}


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

GLUI_RadioButton *GLUI::add_radiobutton_to_group(  GLUI_RadioGroup *group,
                           const char *name )
{
  GLUI_RadioButton *control;

  if ( group->type != GLUI_CONTROL_RADIOGROUP ) {
    /*fprintf( stderr, "ERROR: Trying to add radiobutton to non-radiogroup\n" );              */
    /*fflush( stderr );              */
    return NULL;
  }

  control = new GLUI_RadioButton;

  if ( control ) {
    control->set_int_val( 0 );
    /*int_val = 0;              */

    /** A radio button's user id is always its ordinal number (zero-indexed)
      within the group */
    control->user_id    = group->num_buttons;
    group->num_buttons++;   /* Increments radiogroup's button count */
    control->set_name( name );
    control->group = group;

    add_control( group, control );

    /*** Now update button states ***/
    group->set_int_val( group->int_val ); /* This tells the group to
                         reset itself to its
                         current value, thereby
                         updating all its buttons */

    return control;
  }
  else {
    return NULL;
  }

}


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

GLUI_StaticText  *GLUI::add_statictext( const char *name )
{
  return add_statictext_to_panel( main_panel, name );
}


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

GLUI_StaticText  *GLUI::
add_statictext_to_panel( GLUI_Panel *panel, const char *name )
{
  GLUI_StaticText *control;

  control = new GLUI_StaticText;

  if ( control ) {
    control->set_name( name );
    add_control( panel, control );

    return control;
  }
  else {
    return NULL;
  }

}


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

GLUI_Button   *GLUI:: add_button( const char *name, 
                  int id, GLUI_Update_CB callback )
{
  return add_button_to_panel( main_panel,
                  name, id, callback );
}


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

GLUI_Button   *GLUI::add_button_to_panel( GLUI_Panel *panel,
                      const char *name, 
                      int id, 
                      GLUI_Update_CB callback )
{
  GLUI_Button *control;
  
  control = new GLUI_Button;
  
  if ( control ) {
    /*    control->set_ptr_val( value_ptr );
      if ( value_ptr ) {
      control->set_int_val( *value_ptr );
      }*/

    control->user_id     = id;
    control->callback    = callback;
    control->set_name( name );
    
    add_control( panel, control );
    
    return control;
  }
  else {
    return NULL;
  }
}



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

void  GLUI::add_separator( void )
{
  add_separator_to_panel( main_panel );
}


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

void      GLUI::add_separator_to_panel( GLUI_Panel *panel )
{
  GLUI_Separator *control = new GLUI_Separator;

  if ( control ) {
    add_control( panel, control );
  }
}


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

GLUI_EditText  *GLUI::add_edittext( const char *name, 
                    int data_type, void *data,
                    int id, GLUI_Update_CB callback)
{
  return add_edittext_to_panel( main_panel, name, data_type, data,
                id, callback );
}


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

GLUI_EditText  *GLUI::
add_edittext_to_panel( GLUI_Panel *panel, const char *name, 
               int data_type, void *data,
               int id, GLUI_Update_CB callback)
{
  GLUI_EditText *control;

  control = new GLUI_EditText;

  if ( control ) {
    control->set_name( name );
    
    control->data_type   = data_type;
    control->ptr_val     = data;
    control->user_id     = id;
    control->callback    = callback;
    
    if ( data_type == GLUI_EDITTEXT_TEXT ) {
      control->live_type = GLUI_LIVE_TEXT;
    }
    else if ( data_type == GLUI_EDITTEXT_INT ) {
      control->live_type = GLUI_LIVE_INT;
      if ( data == NULL )
    control->set_int_val(control->int_val);   /** Set to some default, in case of no live var **/
    }
    else if ( data_type == GLUI_EDITTEXT_FLOAT ) {
      control->live_type = GLUI_LIVE_FLOAT;
      control->num_periods = 1;
      if ( data == NULL )
    control->set_float_val(control->float_val);   /** Set to some default, in case of no live var **/
    }
    else {
      return NULL;   /* Did not pass in a valid data type */
    }

    add_control( panel, control );

    control->init_live();

    return control;
  }
  else {
    return NULL;
  }

}


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

GLUI_Spinner  *GLUI::add_spinner( const char *name, 
                  int data_type, void *data,
                  int id, GLUI_Update_CB callback)
{
  return add_spinner_to_panel( main_panel, name, data_type, data,
                   id, callback );
}


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

GLUI_Spinner  *GLUI::
add_spinner_to_panel( GLUI_Panel *panel, const char *name, 
              int data_type, void *data,
              int id, GLUI_Update_CB callback)
{
  GLUI_Spinner *control;
  int           text_type;

  control = new GLUI_Spinner;
 
  if ( NOT strcmp( name, "Spinner Test" ))
    id=id;


  if ( control ) {
    if ( data_type == GLUI_SPINNER_INT ) {
      text_type = GLUI_EDITTEXT_INT;
      /*      control->live_type = GLUI_LIVE_INT;              */
    }
    else if ( data_type == GLUI_SPINNER_FLOAT ) {
      text_type = GLUI_EDITTEXT_FLOAT;
      /*      control->live_type = GLUI_LIVE_FLOAT;              */
    }
    else {
      return NULL;   /* Did not pass in a valid data type */
    }

    GLUI_EditText *edittext = 
      add_edittext_to_panel( (GLUI_Panel*) control, name, text_type, data,
                 id, callback );

    if ( edittext ) {
      control->set_name( name );
      control->edittext    = edittext;  /* Link the edittext to the spinner */
      /*      control->ptr_val     = data;               */
      control->user_id     = id;
      control->data_type   = data_type;
      control->callback    = callback;
    
      edittext->spinner    = control; /* Link the spinner to the edittext */
            
      add_control( panel, control );
      
      return control;
    }
    else {
      return NULL;
    }
  }
  else {
    return NULL;
  }

}


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

void   GLUI::add_column( int draw_bar )
{
  add_column_to_panel( main_panel, draw_bar );
}


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

void   GLUI::add_column_to_panel( GLUI_Panel *panel, int draw_bar )
{
  GLUI_Column *control = new GLUI_Column;

  if ( control ) {
    control->int_val = draw_bar; /* Whether to draw vertical bar or not */

    add_control( panel, control );
  }
  else {
  }
}


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

GLUI_Listbox   *GLUI:: add_listbox( const char *name, int *value_ptr,
                    int id, GLUI_Update_CB callback )
{
  return add_listbox_to_panel( main_panel,
                   name, value_ptr, id, callback );
}


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

GLUI_Listbox   *GLUI::add_listbox_to_panel( GLUI_Panel *panel,
                        const char *name, int *value_ptr,
                        int id, 
                        GLUI_Update_CB callback )
{
  GLUI_Listbox *control;

  control = new GLUI_Listbox;

  if ( control ) {
    control->set_ptr_val( value_ptr );
    control->user_id    = id;
    control->set_name( name );
    control->callback    = callback;

    add_control( panel, control );

    control->init_live();

    return control;
  }
  else {
    return NULL;
  }
}


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

GLUI_Rotation   *GLUI:: add_rotation( const char *name, float *value_ptr,
                      int id, GLUI_Update_CB callback )
{
  return add_rotation_to_panel( main_panel,
                name, value_ptr, id, callback );
}


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

GLUI_Rotation   *GLUI::add_rotation_to_panel( GLUI_Panel *panel,
                          const char *name, float *value_ptr,
                          int id, 
                          GLUI_Update_CB callback )
{
  GLUI_Rotation *control;

  control = new GLUI_Rotation;

  if ( control ) {
    control->set_ptr_val( value_ptr );
    control->user_id    = id;
    control->set_name( name );
    control->callback    = callback;
    add_control( panel, control );
    control->init_live();

    /*** Init the live 4x4 matrix.  This is different than the standard
      live variable behavior, since the original value of the 4x4 matrix
      is ignored and reset to Identity  ***/
    if ( value_ptr != NULL ) {
      int i, j, index;
      for( i=0; i<4; i++ ) {
    for( j=0; j<4; j++ ) {
      index = i*4+j;
      if ( i==j )
        value_ptr[index] = 1.0;
      else
        value_ptr[index] = 0.0;
    }
      }
    }

    /*init_ball();              */
        
    return control;
  }
  else {
    return NULL;
  }
}

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

GLUI_Slider   *GLUI:: add_slider( 
	const char *name,
	int data_type,
	float lo,
	float hi,
	void *data,
	int id, 
	GLUI_Update_CB callback )
{
  return add_slider_to_panel( main_panel,
				name, data_type, lo, hi, data, id, callback );
}


/*********************************** GLUI:: add_slider_to_panel() **********/
GLUI_Slider   *GLUI::add_slider_to_panel( 
	GLUI_Panel *panel,
	const char *name,
	int data_type,
	float lo,
	float hi,
	void *data,
	int id, 
	GLUI_Update_CB callback )
{
	GLUI_Slider *control;

	control = new GLUI_Slider;

	if ( control ) 
	{
		control->set_name( name );
		control->data_type   = data_type;
		control->ptr_val     = data;
		control->user_id     = id;
		control->callback    = callback;
    
		if ( data_type == GLUI_SLIDER_INT ) {
			control->set_int_limits((int)lo, (int)hi);
			if ( data == NULL )
			{
				control->set_int_val(control->int_low);   
				control->live_type = GLUI_LIVE_NONE;
			}
			else
				control->live_type = GLUI_LIVE_INT;
		}
		else if ( data_type == GLUI_SLIDER_FLOAT ) {
			control->set_float_limits(lo,hi);
			if ( data == NULL )
			{
				control->set_float_val(control->float_low);   
				control->live_type = GLUI_LIVE_NONE;
			}
			else
				control->live_type = GLUI_LIVE_FLOAT;
		}
		else {
			delete control;
			return NULL;   
		}

		add_control( panel, control );

		control->init_live();

		//In case the live var was out of range,
		//(and got clamped) we update the live
		//var to the internal value
		control->output_live(false);

		return control;
	}
	else {
		return NULL;
	}

}


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

GLUI_Translation   
  *GLUI:: add_translation( const char *name, int trans_type,
               float *value_ptr, int id, GLUI_Update_CB callback )
{
  return add_translation_to_panel( main_panel,name,trans_type, 
                   value_ptr, id, callback );
}


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

GLUI_Translation   
   *GLUI::add_translation_to_panel( 
                   GLUI_Panel *panel, const char *name, 
                   int trans_type, float *value_ptr,
                   int id, GLUI_Update_CB callback )
{
  GLUI_Translation *control;

  control = new GLUI_Translation;

  if ( control ) {
    control->set_ptr_val( value_ptr );
    control->user_id    = id;
    control->set_name( name );
    control->callback    = callback;
    add_control( panel, control );
    control->init_live();

    control->trans_type = trans_type;

    if ( trans_type == GLUI_TRANSLATION_XY ) {
      control->float_array_size = 2;
    }
    else if ( trans_type == GLUI_TRANSLATION_X ) {
      control->float_array_size = 1;
    }
    else if ( trans_type == GLUI_TRANSLATION_Y ) {
      control->float_array_size = 1;
    }
    else if ( trans_type == GLUI_TRANSLATION_Z ) {
      control->float_array_size = 1;
    }

    return control;
  }
  else {
    return NULL;
  }
}


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

GLUI_Rollout   *GLUI::add_rollout( const char *name, int open )
{
  return add_rollout_to_panel( main_panel, name, open );
}


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

GLUI_Rollout *GLUI::add_rollout_to_panel(GLUI_Panel *panel,const char *name,int open)
{
  GLUI_Rollout     *rollout;
  
  rollout = new GLUI_Rollout;

  if ( rollout ) {
    rollout->set_name( name );
    rollout->user_id    = -1;
    rollout->int_val    = GLUI_PANEL_EMBOSSED;
        
    if ( NOT open ) {
      rollout->is_open = false;
      rollout->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
    }

    add_control( panel, rollout );

    return rollout;
  }
  else {
    return NULL;
  }  
}
