//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// objparam.h
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// Copyright (C) 2000-2001 Vincent LE PRINCE
// This file is part of the TRUEVISION Package

//   This program 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.
//
//   This program 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 this program; if not, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */ 
//*******************************************************************************************
#ifndef GEOMODIF_H
#define GEOMODIF_H
using namespace std;
#include "GL/gl.h"
#include "GL/glu.h"
#include <gnome.h>
#include "main.h"
#include "tvwidgets.h"
#include "material.h"
#include "rotation.h"
#include "glview.h"

//*********************************************
// Classe de base
//*********************************************
class ObjParam {
	protected:
		bool chgd;
		bool refresh;
		bool pmode_change;
		
	public:
		ObjParam( bool refr ) { chgd = false; refresh = refr; }
		ObjParam( ObjParam & ref ) { chgd = false; refresh = ref.refresh; }

		bool changed() { return chgd; }
		void unchange() { chgd = false; }
		virtual void swap_data( ObjParam *param ) {}
		void flush( app_objs *app_ref );

		virtual void grab_pointer( GdkCursorType cursor, app_objs *app_ref );
		virtual void ungrab_pointer() {}

		virtual void mouse_drag( struct drag_info *drag ) {}
		virtual void display( glview *view ) {}
};

//*********************************************
// Classe option combo
//*********************************************
class ObjParam_option_combo : public ObjParam, public TvWidget_option_combo {
	friend void sign_option_combo_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_option_combo*)data)->flush(); }

	public:
		ObjParam_option_combo( const char *name,const char *sname,  const char *tooltip, app_objs *appref, bool refr ) 
			: ObjParam( refr ),
			TvWidget_option_combo( name, sname, tooltip, appref) {}
		ObjParam_option_combo( ObjParam_option_combo & ref ) : ObjParam( ref ), TvWidget_option_combo( ref ) {}
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
};

//*********************************************
// Classe int
//*********************************************
class ObjParam_int : public ObjParam, public TvWidget_int {
	friend void sign_int_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_int*)data)->flush(); }

	public:
		ObjParam_int( const char *name, const char *sname, const char *tooltip, app_objs *appref,  bool refr, int val = 0 ) 
			: ObjParam( refr ),
			TvWidget_int( name, sname, tooltip, appref, val ) {}			
		ObjParam_int( ObjParam_int & ref ) : ObjParam( ref ) , TvWidget_int( ref ) {}
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
};

//*********************************************
// Classe float
//*********************************************
class ObjParam_float : public ObjParam, public TvWidget_float {
	friend void sign_float_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_float*)data)->flush(); }

	public:
		ObjParam_float( const char *name, const char *sname, const char *tooltip, app_objs *appref,  bool refr, float val = 0 ) 
			: ObjParam( refr ) ,
			TvWidget_float( name, sname, tooltip, appref, val ) {}
		ObjParam_float( ObjParam_float & ref ) : ObjParam( ref ), TvWidget_float( ref ) {}
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
};

//*********************************************
// Classe float angle
//*********************************************
class ObjParam_float_angle : public ObjParam_float {
	friend void sign_float_angle_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_float*)data)->flush(); }
	friend void sign_float_angle_clicked( GtkWidget *wid, gpointer data ) { ((ObjParam_float_angle*)data)->grab_pointer(); }

	protected:
		GtkWidget *button;
		bool changing;

	public:
		ObjParam_float_angle( const char *name,const char *sname, const char *tooltip, app_objs *appref,  bool refr, int val = 0 ) 
			: ObjParam_float( name, sname, tooltip, appref, refr, val ) { changing = false; }
		ObjParam_float_angle( ObjParam_float_angle & ref ) :  ObjParam_float(ref) { changing = false; }
		void get_widget( GtkWidget *box, bool tt );
		void flush() { if ( changing ) return; ObjParam_float::flush(); }

		void grab_pointer() { ObjParam::grab_pointer( GDK_EXCHANGE, app_ref ); }
		void ungrab_pointer() { if ( !pmode_change ) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), FALSE ); }
		void mouse_drag( struct drag_info *drag );		
};


//*********************************************
// Classe bool
//*********************************************
class ObjParam_bool : public ObjParam, public TvWidget_bool {
	friend void sign_bool_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_bool*)data)->flush(); }

	public:
		ObjParam_bool( const char *name, const char *sname, const char *tooltip, app_objs *appref,  bool refr, bool val = false ) 
			: ObjParam( refr ) ,
			TvWidget_bool( name, sname, tooltip, appref, val ) {}
		ObjParam_bool::ObjParam_bool( ObjParam_bool & ref ) : ObjParam( ref ), TvWidget_bool( ref ) {}
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
		virtual void output_to_povray( ofstream & file ) { file << data ? "on" : "off"; }
};

//*********************************************
// Classe bool activator
//*********************************************
class ObjParam_bool_activator : public ObjParam, public TvWidget_bool_activator {
	friend void sign_bool_activator_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_bool_activator*)data)->flush(); }

	public:
		ObjParam_bool_activator( const char *name, const char *sname, const char *tooltip, app_objs *appref,  bool refr, bool val = false ) 
			: ObjParam( refr ),
			TvWidget_bool_activator( name, sname, tooltip, appref, val ) {}
		ObjParam_bool_activator( ObjParam_bool_activator & ref ) : ObjParam(ref), TvWidget_bool_activator(ref) {}
		void get_widget( GtkWidget *box, bool tt );
		void get_widget( GtkWidget *box, bool tt, GtkWidget *targ ) { set_target(targ); get_widget(box, tt ); }		
		void flush();
		void swap_data( ObjParam *param );
		virtual void output_to_povray( ofstream & file ) { file << data ? "on" : "off"; }
};

//*********************************************
// Classe color
//*********************************************
class ObjParam_color : public ObjParam, public TvWidget_color {
	friend void sign_color_flush( GtkWidget *wid, gint a, gint b, gint c, gint d, gpointer data ) { ((ObjParam_color*)data)->flush(); }

	public:
		ObjParam_color( const char *name, const char *sname, const char *tooltip, app_objs *appref, bool refr ) 
			: ObjParam( refr ), 
			TvWidget_color( name, sname, tooltip, appref) {}
		ObjParam_color( ObjParam_color & ref ) : ObjParam( ref ), TvWidget_color( ref ) {}
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
		void pref_changed() {}
};



//*********************************************
// Classe point
//*********************************************
class ObjParam_point : public ObjParam, public TvWidget_point {
#define SENDER   ((ObjParam_point*)data)
	friend void sign_point_flush( GtkWidget *wid, gpointer data ) { SENDER->flush(); }
	friend void sign_point_clicked( GtkWidget *wid, gpointer data ) { SENDER->grab_pointer(); }
	friend void sign_menu_clicked( GtkWidget *wid, GdkEventButton *but, gpointer data ) { cout << "\nkey pressed !"; cout.flush(); }	
#undef SENDER

	protected:
		GtkWidget *button;
		bool changing;

	public:
		ObjParam_point( const char *name, const char *sname, const char *tooltip, app_objs *appref, bool refr ) 
			: ObjParam( refr ), 
			TvWidget_point( name, sname, tooltip, appref) { changing = false; }
		ObjParam_point( ObjParam_point & ref ) : ObjParam( ref ), TvWidget_point( ref ) { changing = false; }
		void get_widget( GtkWidget *box, bool tt );
		void get_widget_no_button( GtkWidget *box, bool tt );
		void flush();
		void  swap_data( ObjParam *param );

		void grab_pointer() { ObjParam::grab_pointer( GDK_TCROSS, app_ref ); }
		void ungrab_pointer() { if ( !pmode_change ) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), FALSE ); }
		void mouse_drag( struct drag_info *drag );

		void output_to_povray( ofstream & file ) { file << '<' << data[0] << ',' << data[1] << ',' << -data[2] << '>'; }
};

//*********************************************
// Classe point virtual
//*********************************************
class ObjParam_point_virtual : public ObjParam_point {
	public:
		ObjParam_point_virtual( const char *name,const char *sname, const char *tooltip, app_objs *appref, bool refr )
			: ObjParam_point( name, sname, tooltip, appref, refr ) {}
		ObjParam_point_virtual( ObjParam_point_virtual & ref ) : ObjParam_point( ref ) {}
		void display( glview *view );
};

//*********************************************
// Classe scale ( vector )
//*********************************************
class ObjParam_scale : public ObjParam_point {
	public:
		ObjParam_scale( const char *name, const char *sname, const char *tooltip, app_objs *appref, bool refr )
			: ObjParam_point( name, sname, tooltip, appref, refr ) {}
		ObjParam_scale( ObjParam_point_virtual & ref ) : ObjParam_point( ref ) {}
		void mouse_drag( struct drag_info *drag );
};


//*********************************************
// Classe rotation
//*********************************************
class ObjParam_rotation : public ObjParam, public TvWidget {
	friend void sign_rotation_flush( GtkWidget *wid, gpointer data ) { ((ObjParam_rotation*)data)->flush(); }
	friend void sign_rotation_clicked( GtkWidget *wid, gpointer data ) { ((ObjParam_rotation*)data)->grab_pointer(); }

	protected:
		double data[3], undo_data[3];
		Rotation rotate;
		GtkWidget *button;
		GtkWidget *spins[3];
		bool changing;

	public:
		ObjParam_rotation( const char *name, const char *sname, const char *tooltip, app_objs *appref, bool refr ) 
			: ObjParam( refr ) , 
			TvWidget( name, sname, tooltip, appref) { changing = false; }
		ObjParam_rotation( ObjParam_rotation & ref );
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void  swap_data( ObjParam *param );
		Rotation *get_rotation() { return &rotate; }

		void gl_rotate() { rotate.gl_rotate(); }
		void set( float a, float b, float c ) { data[0]=a; data[1]=b; data[2]=c; }
		void grab_pointer() { ObjParam::grab_pointer( GDK_EXCHANGE, app_ref ); }
		void ungrab_pointer() { if ( !pmode_change ) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), FALSE ); }
		void mouse_drag( struct drag_info *drag );

		//void output_to_povray( ofstream & file ) { file << "rotate <" << data[0] << ',' << data[1] << ',' << -data[2] << '>'; }
		void output_to_povray( ofstream & file ) { file << "rotate z*" << -data[2] << " rotate y*" << data[1] << " rotate x*" << data[0]; }
		void save( ofstream & file );
		bool load( ifstream & file, char *tag );
};


//*********************************************
// Texture ref
//*********************************************
class ObjParam_texref : public ObjParam, public TvWidget {
	friend void sign_ref_changed( GtkWidget *wid, gpointer data ) { ((ObjParam_texref*)data)->flush(); }
	
	private:
		//ObjParam_color *quick_color;
		TvWidget_option_combo *tex_link;
		Material *current;
		bool in_update;

	public:
		ObjParam_texref( const char *name, const char *sname, const char *tooltip, app_objs *appref, bool refr ); 
		ObjParam_texref( ObjParam_texref & ref );
		void get_widget( GtkWidget *box, bool tt );
		void flush();
		void swap_data( ObjParam *param );
		void pref_changed() {}
		void output_to_povray( ofstream & file );
		void clear_widget();
		void update_ref_list();
		bool gl_set_material() { if ( current != NULL ) current->set_gl_material(); else return false; return true; }
		Material *get_current() { return current; }
		
		void save( ofstream & file );
		bool load( ifstream & file, char *tag );
		void get_material( vector<Material*> & mlist );
};

#endif

