//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// glview.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 GLVIEW_H
#define GLVIEW_H
using namespace std;
#include "main.h"
#include <gtk/gtkgl.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "tvwidgets.h"
#include "rotation.h"
#include "dlgutils.h"
#include <vector>

// Wireframe line width
// Should be somewhere else
#define LINE_WIDTH 0.2
class glview;

//*******************************************
// View types
// TOP, FRONT, RIGHT -> 2D views ( glview2d object , in glview2d.h )
// 3D -> generic perspective ( glview3d object, in glview3d.h  )
// CAMERA -> camera view ( glviewcamera object, in glview3d.h )
//*******************************************
enum viewtype {
	TV_VIEW_TOP=0,
	TV_VIEW_FRONT,
	TV_VIEW_RIGHT,	
	TV_VIEW_3D,
	TV_VIEW_CAMERA
	};
typedef viewtype ViewType;


//*******************************************
// Drag & drop infos structure
//*******************************************
struct drag_info {
	bool first_click;                      // Is it the first time
	int current_x;                        // Current mouse position
	int current_y;
	int previous_x;                     // Mouse position at previous motion callback
	int previous_y;
	int origin_x;                          // Mouse postion at fist click
	int origin_y;
	int center_x;                        // Center of the edited object
	int center_y;
	glview *view;                       // Focused view
	bool shift;                             // Shift key modifier flag
	bool control;                        // Control key modifier flag
	Rotation *rotation;
	GdkRectangle *gdkview;
};


//*******************************************
// Classe de base
//*******************************************
class glview {
	#define SENDER ((glview*)data)
	// OpenGL callback functions
	friend void initgl( GtkWidget *wid, gpointer data ) { SENDER->init_view(); }
	friend void display( GtkWidget *wid, GdkEventExpose *ev, gpointer data ) { SENDER->display_view(ev); }
	friend void reshape( GtkWidget *wid, GdkEventConfigure *ev, gpointer data ) { SENDER->reshape_view(NULL); }

	// OpenGL variables toggle callbacks
	friend void sign_toggle_lighting( GtkWidget *wid, gpointer data ) { SENDER->gl_lighting->toggle(); SENDER->gl_variables_refresh(); }
	friend void sign_toggle_solid( GtkWidget *wid, gpointer data ) { SENDER->gl_solid->toggle(); SENDER->gl_variables_refresh(); }
	friend void sign_toggle_smooth( GtkWidget *wid, gpointer data ) { SENDER->gl_smooth->toggle(); SENDER->gl_variables_refresh(); }
 
	// Mouse callbacks
	friend void sign_mouse_button_pressed( GtkWidget *wid, GdkEventButton *ev, gpointer data ) { SENDER->click(ev); }
	friend void sign_mouse_moved( GtkWidget *wid, GdkEventMotion *ev, gpointer data ) { SENDER->mouse_moved(ev); }
	friend void sign_mouse_scroll( GtkWidget *wid, GdkEventScroll *ev, gpointer data ) { SENDER->mouse_scrolled(ev); }

	// Menu popup callbacks
	friend void popup_detacher( GtkWidget *wid, GtkMenu *men ) {}
	friend void sign_view_refresh( GtkWidget *wid, gpointer data ) { SENDER->force_refresh(); }	
	friend void sign_view_home( GtkWidget *wid, gpointer data ) { SENDER->reset_home(); }	
	friend void sign_toggle_axis( GtkWidget *wid, gpointer data ) { SENDER->axis->toggle(); }
	friend void sign_change_view_type( GtkWidget *wid, gpointer data ) { SENDER->mutate( wid ); }

	// Title bar buttons callbacks
	friend void sign_maximize( GtkWidget *wid, gpointer data ) { SENDER->MaximizeRestore(); }	
	friend void sign_roll( GtkWidget *wid, gpointer data ) { SENDER->RollUp(); }
	friend void sign_pop_menu( GtkWidget *wid, gpointer data ) { SENDER->show_menu(); }

	// Title bar widget callbaks
	friend void sign_glview_tbar_expose( GtkWidget *wid, GdkEventExpose *ev, gpointer data ) { SENDER->tbar_expose(ev); }
	friend void sign_glview_tbar_configure( GtkWidget *wid, GdkEventConfigure *ev, gpointer data ) { SENDER->tbar_configure(); }
	friend void sign_glview_tbar_mouse_click( GtkWidget *wid, GdkEventButton *ev, gpointer data ) { SENDER->tbar_mouse_click(ev); }	
	friend void sign_glview_tbar_focus_in( GtkWidget *wid, GdkEventFocus *ev, gpointer data ) { SENDER->select(); }	
	friend void sign_glview_tbar_focus_out( GtkWidget *wid, GdkEventFocus *ev, gpointer data ) { SENDER->unselect(); }	
	friend void sign_glview_tbar_key_press( GtkWidget *wid, GdkEventKey *ev, gpointer data ) { SENDER->key_press(ev); }		
	#undef SENDER


	public:
		static const int buttons_num = 3;						// Number of buttons in the title bar
		static const int but_pixmaps_num = 5;
		static const int view_type_num = 5;                // Number of view types

	private:
		// Widgets used to create the view
		GtkWidget *tbar, *frame, *tframe, *container, *tbbox;

		// Buttons
		GtkWidget *buttons_widget[buttons_num];       // Title bar buttons widgets
		GtkWidget *buttons_gpix[buttons_num];          // Title bar buttons pixmaps
		GtkTooltips *buttons_tooltips[buttons_num];	// Title bar buttons tooltips	
		static	GdkGC *tbar_gc;                                   // Titlebar graphic context ( changed when getting focus, ie color )
		static char *but_pixmaps_fnames[but_pixmaps_num];
		bool tbar_focus;                                                // Do we have the focus
		char *tbar_str;                                                  // Title bar title string
		
		// Create a new button in the title bar
		GtkWidget *title_bar_button_new( GtkWidget *hbox, int but, int pix, const gchar *ttip, GtkSignalFunc func );
		// Title bar widget managing functions
		void tbar_expose( GdkEventExpose *ev );
		void tbar_configure();
		void tbar_mouse_click( GdkEventButton *ev );
		void tbar_redraw();

	protected:
		ViewType type;                                  // The view type
		static app_objs *app_ref;                  // Pointer to global objects reference structure
		GtkWidget *area;                              // The GtkGlArea
		TvWidget_color *background;         //  Background color for this view
		vector<TvWidget*> tv_widgets;      // View TvWidgets list
		static drag_info drag;                                 // Drag & drop infos
		Rotation rotate;	                                // Camera rotation infos
		
		// Lookat
		// Point the camera for this OpenGL view is pointed at ( != pov camera )
		// the common one is used if views are linked
		TvWidget_point *local_lookat;
		static TvWidget_point *common_lookat;
		TvWidget_point *lookat;

		// View parameters ( internal use )
		bool tooltips;
		TvWidget_bool *maximized;
		TvWidget_bool *rolled_up;
		bool visible;

		// View variables
		// saved & loaded in scene file
		TvWidget_bool *gl_solid;
		TvWidget_bool *gl_smooth;
		TvWidget_bool *gl_lighting;
		TvWidget_bool *axis;
		TvWidget_bool *label;
		TvWidget_float *grid_scale;
		// not yet implemented
		//TvWidget_bool *gl_antialias;
		//TvWidget_bool *gl_depthcue;
		//TvWidget_bool *gl_alphablending;

		// Widgets used for popup menu
		GtkWidget *popup;
		GtkWidget *menu_axis;
		GtkWidget *menu_view_types[view_type_num];
		GtkWidget *mi_dtypes[2];
		GtkWidget *menu_gl_lighting;
		GtkWidget *menu_gl_smooth;
		GtkWidget *menu_gl_solid;
		
		// Display lists for axis & grid
		static GlDisplayList axis_list;
		static GlDisplayList grid_lists[3];
		static GdkGLContext *glcontext;
		static GdkGLConfig *glconfig;
		// common drawing function for 2d & 3d views
		void draw_grid( int mode );

				
	protected:
		// Area widget functions
		virtual void init_view();
		virtual void display_view( GdkEventExpose *ev );
		virtual void reshape_view( GdkEventConfigure *ev );
		virtual void set_viewport() {}
		
		// OpenGL settings functions
		virtual void set_gl_variables();
		void gl_variables_refresh() { set_gl_variables(); refresh(); }

		// Mouse interaction functions		
		virtual void click( GdkEventButton *ev );
		virtual void mouse_moved( GdkEventMotion *ev ) {}
		virtual void mouse_scrolled( GdkEventScroll *ev ) {}
		
		// Keyboard shortcuts functions
		virtual void key_press( GdkEventKey *ev ) {}
		
		// OpenGL picking function
		virtual void pick_object( GdkEventButton *ev );

		// Menu manipulation function
		virtual void add_menu() {}
		virtual void set_menus() {}
		void show_menu() { gtk_menu_popup( GTK_MENU(popup), NULL, NULL, NULL, NULL, 1, 0 ); }
		void attach_popup();
		void add_menu_item_bool( GtkWidget **wid, const gchar *text, GtkSignalFunc func, bool state );

		// Utlities
		void mutate( GtkWidget *sender );                      // Change view type
		virtual void reset_view( int type ) {}
		void draw_axis();                                                 // Draw axis

				
	public:
		glview( app_objs *appref, GtkWidget *box, GtkWidget *aframe, GtkWidget *tframe );
		virtual ~glview();		
		GtkWidget *shared() { return area; }                 // return shared area widget for other views
		virtual void pref_changed();                               // Preferences change notification

		// Refresh the view
		virtual void refresh();
		virtual void force_refresh();
		
		// Utilities
		ViewType get_type() { return type; }                    // Return the view type
     	void change_type( ViewType new_type );            // Change the view type
		void set_title( const char *title ) { tbar_str = (char*)title; tbar_redraw(); }       // Set the view title
		void Hide();                                                            // Hide the view ( when other is maximized )
		void Show();		                                                      // Show the view
		void MaximizeRestore();                                        // Toggle maximize
		void RollUp();		                                                   // Toggle rollup		
		virtual void reset_home() {};                                 // Set Lookat to defaults ( 0,0,0 )
		bool project_point( float *point2d, float *point3d );		
		bool handle_base_key_press( GdkEventKey *ev );    // Common shortcuts for 2d & 3d views handling function
		
		virtual void save( ofstream & file ) {}                                                    // Save ( in scene file )
		virtual bool load( ifstream & file, char *tag ) { return false; }               // Load
		void save_basics( ofstream & file );                                                      // Save 2d & 3d common params
		bool load_basics( ifstream & file, char *type );                                      // Load commons
		virtual void clear( ViewType cltype );                                                  // Reset defaults
		
		void select() { tbar_focus = true; tbar_redraw(); }                                                         // View focus
		void unselect() { if ( ! tbar_focus ) return; tbar_focus = false; tbar_redraw(); }            // View unfocus
		
		GdkGLDrawable *get_drawable() { return gtk_widget_get_gl_drawable( area ); }
		GdkGLContext *get_context() { return gtk_widget_get_gl_context( area ); }
};


#endif
