//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// interface.cc
//
// 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.  */ 
//*******************************************************************************************
#include <iostream>
#include "config.h"
#include "include/interface.h"
#include "include/pyscriptdb.h"
#include "include/tvio.h"


//***************************************************************************
// Constants 
//***************************************************************************

// Menu bar / toolbar definitions
// Normal Items
static const GtkActionEntry entries[] = {
  { "FileMenu", NULL, N_("_File") },
  { "EditMenu", NULL, N_("_Edit") },
  { "RenderMenu", NULL, N_("_Render") },
  { "ViewMenu", NULL, N_("_View") },
  { "ScriptMenu", NULL, N_("_Script") },
  { "HelpMenu", NULL, N_("_Help") },
  { "ExportMenu", GTK_STOCK_CONVERT, N_("Ex_port") },
  { "RecentMenu", GTK_STOCK_OPEN, N_("Recent files") },

  { "New", GTK_STOCK_NEW, N_("_New scene"), "<control>N", N_("Create new scene"), G_CALLBACK(interf_sign_menu_new) },
  { "Open", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a file"), G_CALLBACK(interf_sign_menu_open) },
  { "Save", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save to a file"), G_CALLBACK(interf_sign_menu_save) },
  { "Saveas", GTK_STOCK_SAVE_AS, N_("Save _as..."), "<shift><control>S", N_("Save to a file"), G_CALLBACK(interf_sign_menu_saveas) },
  { "Loadobj", GTK_STOCK_OPEN, N_("Open o_bject..."), "<control>B", N_("Open object file"), G_CALLBACK(interf_sign_menu_loadobj) },
  { "Saveobj", GTK_STOCK_OPEN, N_("Save ob_ject..."), "<control>J", N_("Save object file"), G_CALLBACK(interf_sign_menu_saveobj)},
  { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "<control>Q", N_("Exit the program"), G_CALLBACK(interf_sign_menu_exit) },

  { "ExportPov", NULL, N_("Povray scene..."), NULL, N_("Export to povray scene and ini files"), G_CALLBACK(interf_sign_menu_exportpov) },
  { "ExportPack", NULL, N_("Scene pack..."), NULL, N_("Export as povray scene pack"), G_CALLBACK(interf_sign_menu_exportpack) },

  { "Undo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z", N_("Undo last actions"), G_CALLBACK(interf_sign_menu_undo) },
  { "Redo", GTK_STOCK_REDO, N_("_Redo"), "<control>R", N_("Redo canceled actions"), G_CALLBACK(interf_sign_menu_redo) },
  { "Cut", GTK_STOCK_CUT, N_("_Cut"), "<control>X", N_("Cut selected object"), G_CALLBACK(interf_sign_menu_cut) },
  { "Copy", GTK_STOCK_COPY, N_("C_opy"), "<control>C", N_("Copy selected object"), G_CALLBACK(interf_sign_menu_copy) },
  { "Paste", GTK_STOCK_PASTE, N_("_Paste"), "<control>V", N_("Paste object from clipboard"), G_CALLBACK(interf_sign_menu_paste) },
  { "Preferences", GTK_STOCK_PREFERENCES, N_("Pre_ferences"), "<control>F", N_("Edit preferences"), G_CALLBACK(interf_sign_menu_prefs) },

  { "Render", GTK_STOCK_EXECUTE, N_("_Render"), "F11", N_("Render the scene"), G_CALLBACK(interf_sign_menu_render) },
  { "Stop", GTK_STOCK_STOP, N_("_Stop"), "F12", N_("Stop the render"), G_CALLBACK(interf_sign_menu_stop) },
  { "FrontEnd", GTK_STOCK_EXECUTE, N_("Povray _front end..."), NULL, N_("Raise the povray front end"), G_CALLBACK(interf_sign_menu_frontend) },
  { "RenderOptions", GTK_STOCK_EDIT, N_("Render _options..."), NULL, N_("Edit render options"), G_CALLBACK(interf_sign_menu_options) },

  { "Fullscreen", NULL, N_("_Fullscreen"), "F10", NULL, G_CALLBACK(interf_sign_menu_fullscreen) },
  { "Matedit", NULL, N_("_Material editor"), NULL, N_("Raise material editor"), G_CALLBACK(interf_sign_menu_matedit) },
  { "Matlib", NULL, N_("Material _library"), NULL, N_("Raise the material library"), G_CALLBACK(interf_sign_menu_matlib) },

 #ifdef HAVE_TV_PYTHON   
  { "Exescript", GTK_STOCK_EXECUTE, N_("_Execute python script"), NULL, N_("Execute python script"), G_CALLBACK(interf_sign_menu_script) },
#endif
  
  { "Index", GTK_STOCK_HELP, N_("_Help index..."), "F1", N_("Help index"), G_CALLBACK(interf_sign_menu_help) },
  { "Helpon", GTK_STOCK_HELP, N_("_Help on..."), NULL, N_("Help about current object"), G_CALLBACK(interf_sign_menu_helpon) },
  { "Web", GTK_STOCK_HELP, N_("_Truevision web site..."), NULL, N_("Truevision web site"), G_CALLBACK(interf_sign_menu_website) },
  { "About", GTK_STOCK_ABOUT, N_("_About..."), NULL, N_("About Truevision"), G_CALLBACK(interf_sign_menu_about) },

};

// Radio items
static const GtkToggleActionEntry toggle_entries[] = {
  { "Trackball", "tv-trackball", N_("_Trackball"), NULL, N_("Trackball"), G_CALLBACK(interf_sign_toolbar_pointer), FALSE },
  { "Select", "tv-select", N_("_Select"), NULL, N_("Select"), G_CALLBACK(interf_sign_toolbar_pointer), FALSE },
  { "Scale", "tv-scale", N_("_Scale"), NULL, N_("Scale"), G_CALLBACK(interf_sign_toolbar_pointer), FALSE },
  { "Rotate", "tv-rotate", N_("_Rotate"), NULL, N_("Rotate"), G_CALLBACK(interf_sign_toolbar_pointer), FALSE },
  { "Move", "tv-move", N_("_Move"), NULL, N_("Move"), G_CALLBACK(interf_sign_toolbar_pointer), FALSE },
};

static const char *ui_description =
"<ui>"
"  <menubar name='MainMenu'>"
"    <menu action='FileMenu'>"
"      <menuitem action='New'/>"
"      <menuitem action='Open'/>"
"      <menu action='RecentMenu'>"
"      <menuitem action='Open'/>"
"      <separator/>"
"      </menu>"
"      <menuitem action='Save'/>"
"      <menuitem action='Saveas'/>"
"      <menu action='ExportMenu'>"
"          <menuitem action='ExportPov'/>"
"          <menuitem action='ExportPack'/>"
"      </menu>"
"      <separator/>"
"      <menuitem action='Loadobj'/>"
"      <menuitem action='Saveobj'/>"
"      <separator/>"
"      <menuitem action='Exit'/>"
"    </menu>"

"    <menu action='EditMenu'>"
"      <menuitem action='Undo'/>"
"      <menuitem action='Redo'/>"
"      <separator/>"
"      <menuitem action='Cut'/>"
"      <menuitem action='Copy'/>"
"      <menuitem action='Paste'/>"
"      <separator/>"
"      <menuitem action='Preferences'/>"
"    </menu>"

"    <menu action='RenderMenu'>"
"      <menuitem action='Render'/>"
"      <menuitem action='Stop'/>"
"      <separator/>"
"      <menuitem action='RenderOptions'/>"
"      <menuitem action='FrontEnd'/>"
"    </menu>"

"    <menu action='ViewMenu'>"
"      <menuitem action='Fullscreen'/>"
"      <separator/>"
"      <menuitem action='Matedit'/>"
"      <menuitem action='Matlib'/>"
"    </menu>"

#ifdef HAVE_TV_PYTHON   
"    <menu action='ScriptMenu'>"
"      <menuitem action='Exescript'/>"
"      <separator/>"
"    </menu>"
#endif

"    <menu action='HelpMenu'>"
"      <menuitem action='Index'/>"
"      <menuitem action='Helpon'/>"
"      <menuitem action='Web'/>"
"      <menuitem action='About'/>"
"    </menu>"
"  </menubar>"

"  <toolbar name='MainToolbar'>"
"      <toolitem action='Exit'/>"
"      <toolitem action='New'/>"
"      <toolitem action='Open'/>"
"      <toolitem action='Save'/>"
"      <separator/>"
"      <toolitem action='Undo'/>"
"      <toolitem action='Redo'/>"
"      <separator/>"
"      <toolitem action='RenderOptions'/>"
"      <toolitem action='FrontEnd'/>"
"      <separator/>"
"      <toolitem action='Trackball'/>"
"      <toolitem action='Select'/>"
"      <toolitem action='Scale'/>"
"      <toolitem action='Rotate'/>"
"      <toolitem action='Move'/>"
"      <separator/>"
"      <toolitem action='Index'/>"
"  </toolbar>"
"</ui>";


//***************************************************
// Constructeur
//***************************************************
Interface::Interface( app_objs *appref )
{
	app_ref = appref;
	app_ref->interf = (app_object*)this;
	PREF_DEF
	fullscreen = false;	
	
	// register stock icons
	register_tv_stock_icons();

	// App gnome
	win = gnome_app_new( PACKAGE, APP_NAME );
	gtk_signal_connect( GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(app_exit), NULL );
	gtk_signal_connect( GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(app_destroy), NULL );
	GtkWidget *mbox = gtk_vbox_new( FALSE, 1 );
	gnome_app_set_contents( GNOME_APP(win), mbox );
	gtk_container_set_border_width( GTK_CONTAINER(win), 1 );
	gtk_container_set_border_width( GTK_CONTAINER(mbox), 0 );
	
	// Menu gtkaction
	GtkActionGroup *action_group = gtk_action_group_new ("MenuActions");
	gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), this);
	gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), this );

	GtkUIManager *ui_manager = gtk_ui_manager_new ();
	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);

	GtkAccelGroup *accel_group = gtk_ui_manager_get_accel_group (ui_manager);
	gtk_window_add_accel_group (GTK_WINDOW (win), accel_group);

	GError *error = NULL;
	if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error)) {
    	app_warning ("building menus failed: s", error->message);
    	g_error_free (error);
    	exit (EXIT_FAILURE);
  	}

	// Menu
	GtkWidget *menu = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
	gtk_box_pack_start (GTK_BOX (mbox), menu, FALSE, FALSE, 0);

	// Toolbar
	toolbar = gtk_ui_manager_get_widget (ui_manager, "/MainToolbar");
	gtk_box_pack_start (GTK_BOX (mbox), toolbar, FALSE, FALSE, 0);
	gtk_toolbar_set_style( GTK_TOOLBAR(toolbar), pref->toolbar_text->value() ? GTK_TOOLBAR_BOTH : GTK_TOOLBAR_ICONS );
	gtk_toolbar_set_tooltips( GTK_TOOLBAR(toolbar), pref->tooltips->value() );
	
	// Paned views
	vbox = gtk_hbox_new( FALSE, 1 );
	gtk_box_pack_start( GTK_BOX(mbox), vbox, TRUE, TRUE, 0 );
	paned = gtk_hpaned_new();
	gtk_box_pack_start( GTK_BOX(vbox), paned, TRUE, TRUE, 0 );

	// Set application icon - for windows decorations
	gchar *fname = tv_get_pixmap( "gnome-truevision.png" );
	GdkPixbuf *buffer = gdk_pixbuf_new_from_file( fname, NULL );
	gtk_window_set_default_icon( buffer );
	g_free( fname );
	
	// Accelerators
	accels = gtk_accel_group_new();
	gtk_window_add_accel_group( GTK_WINDOW(win), accels );
	gtk_widget_realize( win );

	SCENE_DEF
	scene->set_win_title();

	// Preferences
	if ( pref->save_geo->value() ) {
		if ( pref->win_xpos->value() < 0 ) 
			pref->win_xpos->set(0);
		if ( pref->win_ypos->value() < 0 ) 
			pref->win_ypos->set(0);	
		gtk_widget_set_uposition( win, pref->win_xpos->value(), pref->win_ypos->value() );
		gtk_window_resize( GTK_WINDOW(win), pref->win_xsize->value(), pref->win_ysize->value() );
		gtk_paned_set_position( GTK_PANED(paned), pref->pan_pos->value() );
	}
	
	// 3D Views
	vmanager = new ViewManager( app_ref, paned, ui_manager );
	
	// Side bar
	GtkWidget *box = gtk_vbox_new( FALSE, 0 );
	gtk_paned_add2( GTK_PANED(paned), box );
	hide_button = gtk_button_new();
	gtk_box_pack_start( GTK_BOX(box), hide_button, FALSE, TRUE, 0 );
	gtk_signal_connect( GTK_OBJECT(hide_button), "clicked", GTK_SIGNAL_FUNC(sign_interf_hide_panel), this );
	side_panel_box = gtk_vbox_new( FALSE, 1 );
	gtk_box_pack_start( GTK_BOX(box), side_panel_box, TRUE, TRUE, 0 );

	// PropertiesEditor
	panel = new PropPanel( app_ref, side_panel_box );
	
	// App bar
	GtkWidget *sbox = gtk_hbox_new( FALSE, 2 );
	gtk_box_pack_start( GTK_BOX(side_panel_box), sbox, FALSE, TRUE, 0 );
	progress_bar = gtk_progress_bar_new();
	gtk_box_pack_start( GTK_BOX(sbox), progress_bar, FALSE, TRUE, 0 );
	status = gtk_label_new( NULL );
	gtk_box_pack_start( GTK_BOX(sbox), status, TRUE, TRUE, 0 );
	
	gtk_widget_show_all( win );

	// Set recent files submenu
	recent_files = GTK_MENU_ITEM(gtk_ui_manager_get_widget( ui_manager, "/MainMenu/FileMenu/RecentMenu" ) );
	set_recent_files();	

	// Set scripts
	PyScriptDB *psdb = (PyScriptDB*)appref->pyscript_db;
	psdb->create_menu_structure(ui_manager);
	
	// Set File/save action
	GtkAction *action = gtk_ui_manager_get_action( ui_manager, "/MainMenu/FileMenu/Save" );
	gtk_action_set_sensitive( action, false );
	scene->set_save_menu_action( action );
	
	// set undo/redo actions
	UNDO_DEF
	GtkAction *act1 = gtk_ui_manager_get_action( ui_manager, "/MainMenu/EditMenu/Undo" );
	GtkAction *act2 = gtk_ui_manager_get_action( ui_manager, "/MainMenu/EditMenu/Redo" );
	undoman->set_undo_actions( act1, act2 );

	// Set Help on... menu item
	OBJLIST_DEF
	GtkWidget *item = gtk_ui_manager_get_widget( ui_manager, "/MainMenu/HelpMenu/Helpon" );
	objlist->set_help_on_wid( item );
	
	POVFE_DEF
	act1 = gtk_ui_manager_get_action( ui_manager, "/MainMenu/RenderMenu/Render" );
	act2 = gtk_ui_manager_get_action( ui_manager, "/MainMenu/RenderMenu/Stop" );
	gtk_action_set_sensitive( act2, FALSE );
	povfe->set_menu_actions( act1, act2 );
	
// Set panel state
	if ( pref->pan_hidden->value() ) {
		pref->pan_hidden->set( false );
		hide_panel();
	}
}


//***********************************************************
// Register Truevision stock icons
//
// Register some pixmaps as stock items
//***********************************************************
void Interface::register_tv_stock_icons()
{
	const int n_stock_icons = 5;
	const char *filename[n_stock_icons] = {
		"trackball_icon.png", "select_icon.png", "scale_icon.png",
		"rotate_icon.png", "move_icon.png" };
	const char *stock_id[n_stock_icons] = {
		"tv-trackball", "tv-select", "tv-scale",
		"tv-rotate", "tv-move" };
	
	GtkIconFactory *icon_factory = gtk_icon_factory_new ();
	GtkIconSet *icon_set; 
	GtkIconSource *icon_source;

	for ( int i = 0; i < n_stock_icons; i++ ) {
		icon_set = gtk_icon_set_new( );
		icon_source = gtk_icon_source_new( );
		gtk_icon_source_set_filename( icon_source, tv_get_pixmap( (char*)filename[i] ) );
		gtk_icon_set_add_source( icon_set, icon_source );
		gtk_icon_source_free( icon_source );
		gtk_icon_factory_add( icon_factory,  stock_id[i], icon_set );
		gtk_icon_set_unref( icon_set );
	}

	gtk_icon_factory_add_default (icon_factory); 
	g_object_unref (icon_factory);
}



//***********************************************************
// Toggle fullscreen
//
// Set fullscreen mode on / off
//***********************************************************
void Interface::toggle_fullscreen( )
{
	if ( fullscreen ) {
		gtk_window_unfullscreen( GTK_WINDOW(win) );
		fullscreen = false;
	} else {
		gtk_window_fullscreen( GTK_WINDOW(win) );
		fullscreen = true;
	}
}


//***********************************************************
// Hide panel
//
// Hide / Show side panel
//***********************************************************
void Interface::hide_panel( bool change )
{
	PREF_DEF
	bool panel_hidden = pref->pan_hidden->value();
	int panel_size = pref->pan_pos->value();
	if ( panel_hidden ) {
		gtk_widget_show_all( side_panel_box );
		gtk_paned_set_position( GTK_PANED(paned), panel_size );
		gtk_widget_set_usize( hide_button, -1, 8 );
	} else {
		int hei = side_panel_box->allocation.height;
		panel_size = gtk_paned_get_position( GTK_PANED(paned) );
		gtk_widget_hide_all( side_panel_box );
		gtk_paned_set_position( GTK_PANED(paned), win->allocation.width-16 );
		gtk_widget_set_usize( hide_button, 8, hei );
	}
	if ( change ) 
		pref->pan_hidden->set( ! panel_hidden );
	pref->pan_pos->set( panel_size );
}


// TEMP - Jitter
// Used to bypass a refresh bug
/*void Interface::jitter()
{
int size = gtk_paned_get_position( GTK_PANED(paned) );
gtk_paned_set_position( GTK_PANED(paned), size-1 );
while ( gtk_events_pending() ) gtk_main_iteration();
gtk_paned_set_position( GTK_PANED(paned), size );	
}*/

//*******************************************************
// Flush preferences & Change callback
//*******************************************************
void Interface::flush_pref()
{
	PREF_DEF
	gint x,y;
	gdk_window_get_root_origin( win->window, &x, &y );
	pref->win_xpos->set( x );
	pref->win_ypos->set( y );
	pref->win_xsize->set( win->allocation.width );
	pref->win_ysize->set( win->allocation.height );
	if ( ! pref->pan_hidden->value() ) 
		pref->pan_pos->set( gtk_paned_get_position( GTK_PANED(paned) ) );
}

void Interface::pref_changed()
{
	PREF_DEF
	gtk_toolbar_set_style( GTK_TOOLBAR(toolbar), pref->toolbar_text->value() ? GTK_TOOLBAR_BOTH : GTK_TOOLBAR_ICONS );
	gtk_toolbar_set_tooltips( GTK_TOOLBAR(toolbar), pref->tooltips->value() );
}


//********************************************************
// Save
//
// Save interface parameters to a povray scene file
//********************************************************
void Interface::save( ofstream & file )
{
	file << "\nINTERFACE{";
	vmanager->save( file );
	file << "\n}";
}




//********************************************************
// Load
//
// Load interface parameters from a povray scene file
//********************************************************
bool Interface::load( ifstream & file, char * ltag )
{
	if ( strcmp( ltag, "INTERFACE" ) ) 
		return false;

	char * tag = NULL;
	do {
		tag = tvio_get_next_tag( file );
		if ( tag == NULL ) 
			break;
		if ( vmanager->load( file, tag ) ) 
			continue;
		tvio_skip_section(file );
	} while ( tag != NULL );
	return true;
}


//******************************************************
// Recent Files list management
//******************************************************

// Set recent files submenu content
void Interface::set_recent_files()
{
	PREF_DEF
	gtk_menu_item_remove_submenu( recent_files );
	GtkMenu *menu = (GtkMenu*)gtk_menu_new();
	gtk_menu_item_set_submenu( recent_files, (GtkWidget*)menu );
	int size = pref->recent_files->get_size();
	for ( register int i = 0 ; i < size ; i++ ) {
		char *str = pref->recent_files->value(i);
		if ( str == NULL ) 
			break;
		recent_files_widgets[i] = gtk_menu_item_new_with_label( str );
		gtk_signal_connect( GTK_OBJECT(recent_files_widgets[i]), "activate", GTK_SIGNAL_FUNC(sign_interface_recent_file), this );
		gtk_menu_append( menu,  recent_files_widgets[i] );
	}
	gtk_widget_show_all( (GtkWidget*)menu );
}

// Push a new recent file in list
void Interface::recent_file_push( char *filename )
{
	PREF_DEF
	pref->recent_files->push_string_unique( filename );
	set_recent_files();
}

// Pop a file out of the recent files list
void Interface::recent_file_pop( char *filename )
{
	PREF_DEF
	if ( pref->recent_files->pop_string( filename ) )
		set_recent_files();
}

// Load recent files list from preferences file
void Interface::load_recent_file( GtkWidget *wid )
{
	int num = -1;
	for ( int i = 0 ; i < 10 ; i++ ) 
		if ( wid == recent_files_widgets[i] ) { 
			num = i; 
			break; 
		}
	SCENE_DEF
	PREF_DEF
	if ( num != -1 ) {
		scene->load( pref->recent_files->value( num ) );
		pref->recent_files->reput_on_top( num );
		set_recent_files();
	}
}


//****************************************************************
// Set Hourglass
//
// Set hourglass pointer on / off for al interface
//***************************************************************
void Interface::set_hourglass( bool set )
{
	if ( set == true ) {
		GdkCursor *pointeur = gdk_cursor_new( GDK_WATCH );
		gdk_window_set_cursor( win->window, pointeur );
		gdk_cursor_destroy( pointeur );
		vmanager->unset_cursor();
	} else {
		gdk_window_set_cursor( win->window, NULL );
		vmanager->set_pointer_mode();
	}
}
