//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // interface.cc // // Vincent LE PRINCE // 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 #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"), "N", N_("Create new scene"), G_CALLBACK(interf_sign_menu_new) }, { "Open", GTK_STOCK_OPEN, N_("_Open..."), "O", N_("Open a file"), G_CALLBACK(interf_sign_menu_open) }, { "Save", GTK_STOCK_SAVE, N_("_Save"), "S", N_("Save to a file"), G_CALLBACK(interf_sign_menu_save) }, { "Saveas", GTK_STOCK_SAVE_AS, N_("Save _as..."), "S", N_("Save to a file"), G_CALLBACK(interf_sign_menu_saveas) }, { "Loadobj", GTK_STOCK_OPEN, N_("Open o_bject..."), "B", N_("Open object file"), G_CALLBACK(interf_sign_menu_loadobj) }, { "Saveobj", GTK_STOCK_OPEN, N_("Save ob_ject..."), "J", N_("Save object file"), G_CALLBACK(interf_sign_menu_saveobj)}, { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "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"), "Z", N_("Undo last actions"), G_CALLBACK(interf_sign_menu_undo) }, { "Redo", GTK_STOCK_REDO, N_("_Redo"), "R", N_("Redo canceled actions"), G_CALLBACK(interf_sign_menu_redo) }, { "Cut", GTK_STOCK_CUT, N_("_Cut"), "X", N_("Cut selected object"), G_CALLBACK(interf_sign_menu_cut) }, { "Copy", GTK_STOCK_COPY, N_("C_opy"), "C", N_("Copy selected object"), G_CALLBACK(interf_sign_menu_copy) }, { "Paste", GTK_STOCK_PASTE, N_("_Paste"), "V", N_("Paste object from clipboard"), G_CALLBACK(interf_sign_menu_paste) }, { "Preferences", GTK_STOCK_PREFERENCES, N_("Pre_ferences"), "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 = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " #ifdef HAVE_TV_PYTHON " " " " " " " " #endif " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; //*************************************************** // 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(); } }