//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// objectlist.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 TV_OBJLIST_H
#define TV_OBJLIST_H
using namespace std;
#include <vector>
#include "main.h"
#include "object3d.h"
#include "glview.h"
#include "camera.h"
#include "objectlayer.h"


//**************************************
// Définitions
//**************************************
#define OBJLIST_DEF ObjectList *objlist = (ObjectList*)(app_ref->obj3dlist);
#define MAX_BUTTONS 9
#define MAX_LBUTTONS 6


//**************************************
// Définition d'objet 3d créable
//**************************************
struct obj3ddef {
	const char *name;
	Object3DType type;
	const char *icon;
	const char *description;
	//bool from_library;
	//const char *path;
	//const char *filename;
	//bool from_plugin;
};
typedef obj3ddef Object3DDef;
#define OBJ3D_INLINE_DEF( name, type, icon, description ) { N_(name), type, icon, N_(description) }


//**************************************
// Object List
//**************************************
class ObjectList : public app_object {
	#define SENDER ((ObjectList*)data)
	friend void sign_layer_select( GtkWidget *wid, gint row, gint col, GdkEvent *ev, gpointer data ) { SENDER->select_layer( row, col ); }	
	friend void sign_layer_unselect( GtkWidget *wid, gint row, gint col, GdkEvent *ev, gpointer data ) { SENDER->unselect_layer( row, col ); }	
	friend void sign_select_lbuttons_clicked( GtkWidget *wid, gpointer data ) { SENDER->select_lbuttons_clicked(wid); }	
	
	friend void sign_object_select( GtkCTree *tree, GtkCTreeNode *node, gint col, gpointer data ) { SENDER->select_object(tree, node, col); }
	friend void sign_select_buttons_clicked( GtkWidget *wid, gpointer data ) { SENDER->select_buttons_clicked(wid); }	

	friend void sign_create_button_clicked( GtkWidget *wid, gpointer data ) { SENDER->create_button_clicked(); }	
	friend void sign_create_tree_select( GtkCTree *tree, GtkCTreeNode *node, gint col, gpointer data ) { SENDER->create_tree_select(tree, node, col); }		
	friend void sign_create_tree_click( GtkCList *list, gint row, gint col, GdkEventButton *ev, gpointer data ) { SENDER->create_tree_click( ev ); }		
	
	friend void sign_object_drag(GtkWidget *widget, GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data  ) { SENDER->object_drag( dc, selection_data ); }			
	friend void sign_object_drop_on_layer( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { SENDER->object_drop_on_layer( dc, x, y, selection_data, info );  }
	friend void sign_object_motion_on_layer( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { SENDER->object_motion_on_layer( dc, x, y );  }	
	friend void sign_object_drop_on_tree( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { SENDER->object_drop_on_tree( dc, x, y, selection_data, info );  }	
	friend void sign_object_motion_on_tree( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { SENDER->object_motion_on_tree( dc, x, y );  }	
	
	friend void sign_obj_save_with_fbox( GtkWidget *wid, gpointer data ) { SENDER->object_save(); }	
	friend void sign_obj_del_filebox( GtkWidget *wid, gpointer data ) { SENDER->delete_filebox(); }	
	friend void sign_obj_load_with_fbox( GtkWidget *wid, gpointer data ) { SENDER->object_load(); }		
	friend void sign_objlist_load_object( GtkWidget *wid, gpointer data ) { SENDER->load_object(); }		
	friend void sign_objlist_save_object( GtkWidget *wid, gpointer data ) { SENDER->save_object(); }		
	#undef SENDER


	private:
		app_objs *app_ref;
		vector<ObjectLayer*> Layers;
		ObjectLayer *selected_layer;
		vector<Object3D*> object_liste;
		Camera *MainCamera;
		GtkWidget *filebox;
		unsigned int current_pick_name;

		static GtkStyle *old_item_style;
		static GtkStyle *new_item_style;
		Object3D *drag_focus;
		int drag_layer_focus;

		// Edition de l'objet courrant
		Object3D* current;
		Object3D *cut_or_copied;
		bool is_cut;
		ObjParam* current_param;
		void refresh_edit();
		GtkWidget *edit_widget, *edit_box;
	
		// Arbre de séléction
		GtkWidget *select_widget, *select_tree;
		GtkWidget *layer_clist;
		//GtkCTreeNode *objects_tree, *lights_tree, *atmos_tree;
		GtkWidget *select_buttons[MAX_BUTTONS];
		GtkTooltips *select_tooltips[MAX_BUTTONS];
		GtkWidget *select_lbuttons[MAX_LBUTTONS];
		GtkTooltips *select_ltooltips[MAX_LBUTTONS];		
		void select_layer( gint row, gint col );
		void unselect_layer( gint row, gint col );
		void select_buttons_clicked( GtkWidget *wid );
		void select_object( GtkCTree *tree, GtkCTreeNode *node, gint col );
 		void select_lbuttons_clicked( GtkWidget *wid );

		// Create
		GtkWidget *create_tree;
		GtkWidget *descr_text;
		GdkPixmap *create_def_pix, *create_def_mask;
		Object3DDef *current_objdef;
		void add_subtree( const char *name, const char *icon, Object3DDef *defs, const int def_num );
		void create_tree_select( GtkCTree *tree, GtkCTreeNode *node, gint col );
		void create_button_clicked();
		void create_tree_click( GdkEventButton *ev );

		// Lampes
		bool *light_list;
		GLint light_num;
		
		// Drag & Drop
		void object_drag( GdkDragContext *dc, GtkSelectionData *selection_data );
		void object_drop_on_layer( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info );
		void object_motion_on_layer( GdkDragContext *dc, gint x, gint y );
		void object_drop_on_tree( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info );
		void object_motion_on_tree( GdkDragContext *dc, gint x, gint y );
		
		// Save & load objects
		void object_save();
		void object_load();
		void delete_filebox() { gtk_widget_destroy( filebox ); }	
		char *default_path;
		void store_default_path( char *path );

	public:
		ObjectList( app_objs *app_ref );
		~ObjectList() { delete light_list; }
		void pref_changed();
		int get_size() { return object_liste.size(); }
		void output_to_povray( ofstream & file );
		void add_object( Object3D *obj ) { object_liste.push_back( obj ); }
		void remove_object( Object3D *obj );
		void unselect_object();

		//Generation de noms uniques
		bool test_name_exist( char *name );
		char *create_name( char *name );
		bool layer_name_exist( char *name, ObjectLayer *layer );

		// Affichage OpenGL
		void display( glview *view );
		void invalidate_lists();

		// Boite de selection
		void set_edit_widget( GtkWidget *wid ) { edit_widget = wid; refresh_edit(); }
		void set_select_widget( GtkWidget *wid );
		void set_create_widget( GtkWidget *wid );
		gint get_layer_index( ObjectLayer *layer );

		// Parametre courrant
		ObjParam* get_current_param() { return current_param; }
		void set_current_param( ObjParam* param );
		void clear_current_param() { current_param = NULL; }
		void display_current_param( glview *view ) { if ( current_param != NULL ) current_param->display( view ); }
		void flush() { if ( current != NULL ) current->flush(); }

		// Manipulation de l'objet courant
		Object3D* get_current() { return current; }
		void clear_current_object() { current = NULL; }
		
		// Layer Manipulation
		ObjectLayer *get_current_layer() { return selected_layer; }
		void remove_layer( ObjectLayer *layer );
		void insert_layer( ObjectLayer *layer, int position );
		void move_layer( ObjectLayer *layer, int sens );

		// Interaction avec l'objet courant
		void mouse_interact_drag( struct drag_info *drag ) { if ( current != NULL ) current->mouse_drag( drag ); }

		// Lampes
		int light_request();
		void light_release( int light_id ) { if ( light_id != -1 ) light_list[light_id] = false; }
		void light_set_properties( int light_id, float *location, float *color );
		void light_set_properties( int light_id, float *location, float *direction, float cutoff, float *color );
		void light_enable( int light_id );
		void light_disable( int light_id );
		void light_disable_all();
		
		
		void save( ofstream & file );
		bool load( ifstream & file, char * tag );
		Object3D *create_object( char *tag );
		void clear();
		void new_scene();
		
		void init_pick_names();
		unsigned int get_pick_name() { return current_pick_name++; }
		void select_picked( int name );
		
		Object3D *get_camera() { return MainCamera; }
		void set_camera( Object3D *cam ) { MainCamera = (Camera*)cam; }
		
		void load_object();
		void save_object();
};

#endif
