/* Copyright 2005 Nicholas Bishop * * This file is part of SharpConstruct. * * SharpConstruct 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. * * SharpConstruct 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 SharpConstruct; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Brush.h" #include "Create.hh" #include "MainWindow.hh" #include "MeshHistory.h" #include "Preferences.h" #include "config.h" #include "prefix.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using SharpConstruct::GInterface::MainWindow; MainWindow::MainWindow() { const std::string path( BR_DATADIR( "/interface/" ) ); Gtk::IconTheme::get_default()->append_search_path( path + "pixmaps/" ); glade_ = Gnome::Glade::Xml::create( path + "SharpConstruct.glade" ); // Put the editor into the interface Gtk::Frame* modelframe; glade_->get_widget( "ModelFrame", modelframe ); modelframe->remove(); modelframe->add( editor_ ); // Must go before signals are connected! const int gm( Editor::DisplayOptionsData::VBO ); if( Preferences::Instance().Get( "GraphicsMode", gm ) == Editor::DisplayOptionsData::VAR ) { Gtk::RadioButton* rb; glade_->get_widget( "VAR", rb ); rb->set_active( true ); } icon_factory_ = Gtk::IconFactory::create(); init_actions_(); connect_handlers_(); init_brushes_(); } void MainWindow::Run( Gtk::Main& kit ) { Gtk::Window* mainwindow( 0 ); glade_->get_widget( "MainWindow", mainwindow ); initialize_(); create_model_(); kit.run( *mainwindow ); } void MainWindow::add_stock_item_( const std::string& filepath, const Glib::ustring& id, const Glib::ustring& label, const Gdk::ModifierType mod, const unsigned key ) { Gtk::IconSource source; try { source.set_pixbuf( Gdk::Pixbuf::create_from_file(filepath) ); } catch( const Glib::Exception& ex ) { std::cout << ex.what() << std::endl; } source.set_size( Gtk::ICON_SIZE_SMALL_TOOLBAR ); source.set_size_wildcarded(); //Icon may be scaled. Gtk::IconSet icon_set; icon_set.add_source( source ); //More than one source per set is allowed. const Gtk::StockID stock_id( id ); icon_factory_->add( stock_id, icon_set ); if( key == '\0' ) Gtk::Stock::add( Gtk::StockItem( stock_id, label ) ); else Gtk::Stock::add( Gtk::StockItem( stock_id, label, mod, key ) ); } void MainWindow::add_stock_item_( const std::string& filepath, const Glib::ustring& id, const Glib::ustring& label ) { add_stock_item_( filepath, id, label, Gdk::ModifierType(), '\0' ); } void MainWindow::init_actions_() { using sigc::mem_fun; Gtk::AboutDialog* ad; Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); glade_->get_widget( "AboutDialog", ad ); // Create new stock items { const std::string path( BR_DATADIR( "/interface/" ) ); add_stock_item_( path + "wire.png", "SC_WIRE", "_Wire", Gdk::CONTROL_MASK, 'w' ); add_stock_item_( path + "smoothed.png", "SC_SMOOTH", "_Smooth" ); add_stock_item_( path + "double.png", "SC_DOUBLE", "_Double" ); add_stock_item_( path + "speed.png", "SC_SPEED", "S_peed" ); add_stock_item_( path + "center.png", "SC_CENTER", "_Center", Gdk::CONTROL_MASK, 'c' ); icon_factory_->add_default(); } action_group_ = Gtk::ActionGroup::create(); action_group_->add( Gtk::Action::create( "MenuFile", "_File" ) ); action_group_->add( Gtk::Action::create( "New", Gtk::Stock::NEW, "", "Create new model" ), mem_fun( *this, &MainWindow::new_model_ ) ); action_group_->add( Gtk::Action::create( "Open", Gtk::Stock::OPEN, "", "Open model" ), mem_fun( *this, &MainWindow::open_model_ ) ); action_group_->add( Gtk::Action::create( "Save", Gtk::Stock::SAVE, "", "Save model" ), mem_fun( *this, &MainWindow::save_model_ ) ); action_group_->add( Gtk::Action::create( "SaveAs", Gtk::Stock::SAVE_AS, "", "Save model under new name" ), mem_fun( *this, &MainWindow::save_model_as_ ) ); action_group_->add( Gtk::Action::create( "Quit", Gtk::Stock::QUIT ), mem_fun( *this, &MainWindow::on_quit_ ) ); action_group_->add( Gtk::Action::create( "MenuEdit", "_Edit" ) ); action_group_->add( Gtk::Action::create( "Undo", Gtk::Stock::UNDO ), Gtk::AccelKey( "z", "//Undo" ), mem_fun( *this, &MainWindow::on_undo_clicked_ ) ); action_group_->add( Gtk::Action::create( "Redo", Gtk::Stock::REDO ), Gtk::AccelKey( "z", "//Redo" ), mem_fun( *this, &MainWindow::on_redo_clicked_ ) ); action_group_->add( Gtk::Action::create( "MenuBrush", "_Brush" ) ); action_group_->add( Gtk::Action::create( "IncreaseSize", "_Increase Size" ), Gtk::AccelKey( "f", "//IncreaseSize" ), mem_fun( *this, &MainWindow::on_increase_size_clicked_ ) ); action_group_->add( Gtk::Action::create( "DecreaseSize", "_Decrease Size" ), Gtk::AccelKey( "d", "//DecreaseSize" ), mem_fun( *this, &MainWindow::on_decrease_size_clicked_ ) ); action_group_->add( Gtk::Action::create( "MenuView", "_View" ) ); action_group_->add( Gtk::ToggleAction::create( "ShowSidebar", "Show Side_bar" ), mem_fun( *this, &MainWindow::on_sidebar_toggled_ ) ); action_group_->add( Gtk::ToggleAction::create( "Wireframe", Gtk::StockID( "SC_WIRE" ), "", "Overlay polygon wireframe" ), mem_fun( editor_.DisplayOptions(), &Editor::DisplayOptionsData::ToggleWireframe ) ); action_group_->add( Gtk::ToggleAction::create( "Smooth", Gtk::StockID( "SC_SMOOTH" ), "", "Smooth polygon edges" ), mem_fun( editor_.DisplayOptions(), &Editor::DisplayOptionsData::ToggleSmoothed ) ); action_group_->add( Gtk::ToggleAction::create( "Double", Gtk::StockID( "SC_DOUBLE" ), "", "Draw back side of polygons" ), mem_fun( editor_.DisplayOptions(), &Editor::DisplayOptionsData::ToggleDoubleSided ) ); action_group_->add( Gtk::ToggleAction::create( "Speed", Gtk::StockID( "SC_SPEED" ),"", "Restrict model redraw to increase speed, may cause redraw artifacts" ), mem_fun( editor_.DisplayOptions(), &Editor::DisplayOptionsData::ToggleSpeed ) ); action_group_->add( Gtk::Action::create( "Center", Gtk::StockID( "SC_CENTER" ) ), mem_fun( editor_, &Editor::ResetView ) ); action_group_->add( Gtk::Action::create( "MenuDeformations", "_Deformations" ) ); action_group_->add( Gtk::Action::create( "Subdivide", "_Subdivide" ), Gtk::AccelKey( "s", "//Subdivide" ), mem_fun( deformations_, &Deformations::Subdivide ) ); action_group_->add( Gtk::Action::create( "FlipNormals", "_Flip Normals" ), mem_fun( deformations_, &Deformations::FlipNormals ) ); action_group_->add( Gtk::Action::create( "Unify", "_Unify" ), Gtk::AccelKey( "u", "//Unify" ), mem_fun( deformations_, &Deformations::Unify ) ); action_group_->add( Gtk::Action::create( "ToTriangles", "_To Triangles" ), mem_fun( deformations_, &Deformations::ToTriangles ) ); action_group_->add( Gtk::Action::create( "MenuHelp", "_Help" ) ); action_group_->add( Gtk::Action::create( "About", Gtk::Stock::ABOUT ), mem_fun( *ad, &Gtk::AboutDialog::show ) ); // Configure actions Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( action_group_->get_action( "ShowSidebar" ) )->set_active( true ); Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( action_group_->get_action( "Smooth" ) )->set_active( true ); Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( action_group_->get_action( "Double" ) )->set_active( true ); ui_manager_ = Gtk::UIManager::create(); ui_manager_->insert_action_group( action_group_ ); mainwindow->add_accel_group( ui_manager_->get_accel_group() ); ui_manager_->add_ui_from_string ( "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "" ); Gtk::VBox* vb; glade_->get_widget( "MainVBox", vb ); vb->pack_start( *ui_manager_->get_widget( "/MenuBar" ), Gtk::PACK_SHRINK ); vb->pack_start( *ui_manager_->get_widget( "/ToolBar" ), Gtk::PACK_SHRINK ); vb->reorder_child( *ui_manager_->get_widget( "/ToolBar" ), 0 ); vb->reorder_child( *ui_manager_->get_widget( "/MenuBar" ), 0 ); } void MainWindow::connect_handlers_() { using sigc::mem_fun; Gtk::ColorButton* cb; Gtk::HScale* hs; Gtk::TreeView* iv; Gtk::RadioButton* rb; Gtk::SpinButton* sb; Gtk::ToggleButton* tgb; MeshHistory::Instance().Changed(). connect( sigc::hide< -1 > ( sigc::hide< -1 >( mem_fun( *this, &MainWindow:: on_history_changed_ ) ) ) ); Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); mainwindow->signal_delete_event().connect( mem_fun( *this, &MainWindow::on_delete_event_ ) ); // Connect brush modifiers // Type glade_->get_widget( "BrushDraw", rb ); rb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "BrushGrab", rb ); rb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "BrushPinch", rb ); rb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "BrushSmooth", rb ); rb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); // Stroke glade_->get_widget( "Layer", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "Dot", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "Radius", hs ); hs->signal_value_changed().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->connect_clicked( "SizePressure", mem_fun( *this, &MainWindow::update_input_settings_ ) ); glade_->get_widget( "Strength", hs ); hs->signal_value_changed().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->connect_clicked( "StrengthPressure", mem_fun( *this, &MainWindow::update_input_settings_ ) ); glade_->get_widget( "Intensity", hs ); hs->signal_value_changed().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->connect_clicked( "IntensityPressure", mem_fun( *this, &MainWindow::update_input_settings_ ) ); glade_->get_widget( "BrushAdd", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::on_brush_add_ ) ); glade_->get_widget( "BrushSub", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::on_brush_sub_ ) ); glade_->get_widget( "BrushRGB", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "BrushColor", cb ); cb->signal_color_set().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "SymmetryX", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "SymmetryY", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "SymmetryZ", tgb ); tgb->signal_toggled().connect( mem_fun( *this, &MainWindow::update_brush_ ) ); glade_->get_widget( "BrushShapes", iv ); iv->get_selection()->signal_changed().connect( mem_fun( *this, &MainWindow::update_brush_shape_ ) ); glade_->connect_clicked( "BrushShapeAdd", mem_fun( *this, &MainWindow::on_brush_shape_add_clicked_ ) ); glade_->connect_clicked( "BrushShapeRemove", mem_fun( *this, &MainWindow::on_brush_shape_remove_clicked_ ) ); // Connect settings glade_->get_widget( "BackgroundColor", cb ); cb->signal_color_set().connect( mem_fun( *this, &MainWindow::on_background_color_set_ ) ); glade_->get_widget( "UndoSteps", sb ); sb->signal_value_changed().connect( mem_fun( *this, &MainWindow::on_undo_steps_value_changed_ ) ); glade_->get_widget( "VBO", rb ); glade_->connect_clicked( "VBO", mem_fun( *this, &MainWindow::update_graphics_mode_settings_ ) ); glade_->connect_clicked( "SpeedTest", mem_fun( *this, &MainWindow::on_speed_test_clicked_ ) ); glade_->connect_clicked( "InputDevices", mem_fun( input_dialog_, &InputDialog::Show ) ); } void MainWindow::initialize_() { Gtk::AboutDialog* ad; Gtk::ColorButton* cb; Gtk::ToggleButton* tgb; Gtk::Window* mainwindow; Gtk::SpinButton* sb; glade_->get_widget( "AboutDialog", ad ); ad->set_version( GetVersion() ); input_dialog_.Initialize(); deformations_.Initialize( glade_ ); glade_->get_widget( "BrushColor", cb ); cb->set_color( Gdk::Color( "White" ) ); { glade_->get_widget( "BackgroundColor", cb ); Gdk::Color c; c.set_rgb_p( Preferences::Instance().Get( "VIEW_COLOR_R", 0.3 ), Preferences::Instance().Get( "VIEW_COLOR_G", 0.3 ), Preferences::Instance().Get( "VIEW_COLOR_B", 0.3 ) ); cb->set_color( c ); } glade_->get_widget( "UndoSteps", sb ); sb->set_value( Preferences::Instance().Get( "UNDO_STEPS", 3 ) ); glade_->get_widget( "MainWindow", mainwindow ); if( !Preferences::Instance().Get( "Maximized", false ) ) { mainwindow->resize( Preferences::Instance().Get( "W", 800 ), Preferences::Instance().Get( "H", 600 ) ); } else mainwindow->maximize(); mainwindow->set_icon_from_file( BR_DATADIR( "/interface/icon.png" ) ); { const std::string path( BR_DATADIR( "/interface/" ) ); add_stock_item_( path + "pressure.png", "SC_PRESSURE", "" ); glade_->get_widget( "SizePressure", tgb ); tgb->set_label( "SC_PRESSURE" ); tgb->set_use_stock( true ); glade_->get_widget( "StrengthPressure", tgb ); tgb->set_label( "SC_PRESSURE" ); tgb->set_use_stock( true ); glade_->get_widget( "IntensityPressure", tgb ); tgb->set_label( "SC_PRESSURE" ); tgb->set_use_stock( true ); } } void MainWindow::update_model_info_() { Gtk::Label* l; glade_->get_widget( "ModelLabel", l ); const Mesh& mesh( MeshHistory::Instance().GetCurrentMesh() ); std::string file( Glib::filename_display_basename( mesh.FileName() ) ); if( file == "." ) file = "untitled"; l->set_text( file + ": " + mesh.GetModelStatisticsString() ); } void MainWindow::init_brushes_() { update_brush_(); Gtk::TreeView* iv; glade_->get_widget( "BrushShapes", iv ); brush_shape_model_ = Gtk::ListStore::create( brush_shape_columns_ ); brush_shape_model_->clear(); std::string def_path; #ifdef ENABLE_BINRELOC def_path = BR_DATADIR( "/brushes/" ); #else def_path = "/usr/X11R6/share/sharpconstruct/brushes/"; if( !FileDialog::FileExists( def_path ) ) { def_path = "/usr/local/share/sharpconstruct/brushes/"; if( !FileDialog::FileExists( def_path ) ) return; } #endif iv->set_model( brush_shape_model_ ); { Gtk::TreeView::Column* pColumn = Gtk::manage( new Gtk::TreeView::Column( "" ) ); pColumn->pack_start( brush_shape_columns_.Icon, false ); pColumn->pack_start( brush_shape_columns_.Name ); iv->append_column( *pColumn ); } Glib::Dir dir( def_path ); std::string name( dir.read_name() ); Gtk::TreeModel::iterator def; while( !name.empty() ) { if( name[ 0 ] != '.' ) { const std::string path( Glib::build_filename( def_path, name ) ); Glib::ustring display_name ( Glib::filename_to_utf8( name ) ); Gtk::TreeModel::iterator iter; try { iter = brush_shape_model_->append(); Gtk::TreeModel::Row row = *iter; const unsigned extdot( display_name.find( "." ) ); if( extdot != std::string::npos ) display_name = display_name.substr( 0, extdot ); if( display_name == "Default" ) def = iter; row[ brush_shape_columns_.Name ] = display_name; row[ brush_shape_columns_.Icon ] = Gdk::Pixbuf::create_from_file( path )-> scale_simple( 32, 32, Gdk::INTERP_BILINEAR ); row[ brush_shape_columns_.Shape ] = Gdk::Pixbuf::create_from_file( path ); } catch( const Gdk::PixbufError& ) { brush_shape_model_->erase( iter ); } } name = dir.read_name(); } brush_shape_model_->move( def, brush_shape_model_->children().begin() ); iv->get_selection()->set_mode( Gtk::SELECTION_BROWSE ); iv->get_selection()->select( brush_shape_model_->get_path( def ) ); } void MainWindow::create_model_() { Gtk::Notebook* mdltype; glade_->get_widget( "ModelType", mdltype ); const Glib::ustring type( mdltype->get_current()->get_tab_label_text() ); MeshHistory::Instance().Clear(); Mesh& mesh( MeshHistory::Instance().GetCurrentMesh() ); Gtk::SpinButton* sb; if( type == "Cube" ) { glade_->get_widget( "CubeX", sb ); const unsigned x( sb->get_value_as_int() + 1 ); glade_->get_widget( "CubeY", sb ); const unsigned y( sb->get_value_as_int() + 1 ); glade_->get_widget( "CubeZ", sb ); const unsigned z( sb->get_value_as_int() + 1 ); mesh.Create( Create::Cube( x, y, z ) ); } else if( type == "Plane" ) { glade_->get_widget( "PlaneX", sb ); const unsigned x( sb->get_value_as_int() + 1 ); glade_->get_widget( "PlaneY", sb ); const unsigned y( sb->get_value_as_int() + 1 ); mesh.Create( Create::Plane( x, y ) ); } else if( type == "Sphere" ) { glade_->get_widget( "SphereDiv", sb ); const unsigned div( sb->get_value_as_int() + 1 ); mesh.Create( Create::Sphere( div ) ); } on_history_changed_(); // For save btn editor_.Refresh( true, true ); } bool MainWindow::is_mesh_data_safe_() { const bool SAFE = true; const bool UNSAFE = false; if( MeshHistory::Instance().Saved() ) return SAFE; else { Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); Gtk::MessageDialog md( "Save changes to model before closing? ", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE ); md.set_title( "" ); md.set_secondary_text( "If you don't save the model, unsaved changes will be lost." ); md.set_transient_for( *mainwindow ); md.add_button( "Discard", Gtk::RESPONSE_NO ); md.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); md.add_button( Gtk::Stock::SAVE, Gtk::RESPONSE_YES ); const int rsp( md.run() ); if( rsp == Gtk::RESPONSE_NO ) return SAFE; else if( rsp == Gtk::RESPONSE_CANCEL ) return UNSAFE; else if( rsp == Gtk::RESPONSE_YES ) { save_model_(); if( MeshHistory::Instance().Saved() ) return SAFE; else return UNSAFE; } else return UNSAFE; } } void MainWindow::on_background_color_set_() { Gtk::ColorButton* cb; glade_->get_widget( "BackgroundColor", cb ); const Gdk::Color c( cb->get_color() ); editor_.DisplayOptions().SetBackgroundColor( Color( c.get_red_p(), c.get_green_p(), c.get_blue_p() ) ); } void MainWindow::on_brush_add_() { Gtk::ToggleButton* add, * sub; glade_->get_widget( "BrushAdd", add ); glade_->get_widget( "BrushSub", sub ); if( add->get_active() ) sub->set_active( false ); update_brush_(); } void MainWindow::on_brush_sub_() { Gtk::ToggleButton* add, * sub; glade_->get_widget( "BrushAdd", add ); glade_->get_widget( "BrushSub", sub ); if( sub->get_active() ) add->set_active( false ); update_brush_(); } void MainWindow::on_brush_shape_add_clicked_() { Gtk::TreeView* tv; glade_->get_widget( "BrushShapes", tv ); Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); Gtk::FileChooserDialog fd( "Add Brush Shape" ); fd.set_transient_for( *mainwindow ); fd.set_select_multiple( true ); fd.set_action( Gtk::FILE_CHOOSER_ACTION_OPEN ); fd.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); fd.add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_OK ); Gtk::FileFilter filter_text; filter_text.set_name( "Portable Network Graphics (*.png)" ); filter_text.add_pattern( "*.png" ); fd.add_filter( filter_text ); Gtk::FileFilter filter_any; filter_any.set_name( "All files" ); filter_any.add_pattern( "*" ); fd.add_filter( filter_any ); const int result( fd.run() ); if( result == Gtk::RESPONSE_OK ) { Glib::SListHandle< Glib::ustring > files( fd.get_filenames() ); Glib::ustring name; for( Glib::SListHandle< Glib::ustring >::iterator i = files.begin(); i != files.end(); ++i ) { Gtk::ListStore::iterator cur( tv->get_selection()->get_selected() ), iter; iter = brush_shape_model_->insert_after( cur ); try { Gtk::TreeModel::Row row = *iter; name = path_get_basename( *i ); const unsigned extdot( name.find( "." ) ); if( extdot != std::string::npos ) name = name.substr( 0, extdot ); row[ brush_shape_columns_.Name ] = name; Glib::RefPtr< Gdk::Pixbuf > input( Gdk::Pixbuf::create_from_file( *i ) ); if( input->get_width() != input->get_height() ) { input = input->scale_simple( input->get_width(), input->get_width(), Gdk::INTERP_BILINEAR ); } row[ brush_shape_columns_.Icon ] = input->scale_simple( 32, 32, Gdk::INTERP_BILINEAR ); row[ brush_shape_columns_.Shape ] = input; } catch( const Gdk::PixbufError& ) { brush_shape_model_->erase( iter ); } } } } void MainWindow::on_brush_shape_remove_clicked_() { Gtk::TreeView* tv; glade_->get_widget( "BrushShapes", tv ); if( brush_shape_model_->children().size() > 1 ) { Gtk::ListStore::iterator iter( tv->get_selection()->get_selected() ), after( iter ), before( iter ); after++; if( iter != brush_shape_model_->children().begin() ) before--; brush_shape_model_->erase( iter++ ); if( after != brush_shape_model_->children().end() ) tv->get_selection()->select( after ); else tv->get_selection()->select( before ); } } void MainWindow::on_decrease_size_clicked_() { Gtk::HScale* hs; glade_->get_widget( "Radius", hs ); hs->set_value( hs->get_value() - 2 ); } bool MainWindow::on_delete_event_( GdkEventAny* ) { if( is_mesh_data_safe_() ) { Gtk::SpinButton* sb; Gtk::Window* mw; glade_->get_widget( "UndoSteps", sb ); Preferences::Instance().Set( "UNDO_STEPS", (int)sb->get_value() ); glade_->get_widget( "MainWindow", mw ); Preferences::Instance().Set( "W", mw->get_width() ); Preferences::Instance().Set( "H", mw->get_height() ); const Gdk::WindowState ws( mw->get_window()->get_state() ); if( ws & Gdk::WINDOW_STATE_MAXIMIZED ) Preferences::Instance().Set( "Maximized", true ); else Preferences::Instance().Set( "Maximized", false ); return false; } else return true; } void MainWindow::on_history_changed_() { action_group_->get_action( "Save" )->set_sensitive( !MeshHistory::Instance().Saved() ); action_group_->get_action( "Undo" )->set_sensitive( MeshHistory::Instance().UndoPossible() ); action_group_->get_action( "Redo" )->set_sensitive( MeshHistory::Instance().RedoPossible() ); update_model_info_(); } void MainWindow::on_increase_size_clicked_() { Gtk::HScale* hs; glade_->get_widget( "Radius", hs ); hs->set_value( hs->get_value() + 2 ); } void MainWindow::on_undo_clicked_() { MeshHistory::Instance().Undo(); editor_.Refresh( true, true ); } void MainWindow::on_redo_clicked_() { MeshHistory::Instance().Redo(); editor_.Refresh( true, true ); } void MainWindow::on_quit_() { if( is_mesh_data_safe_() ) { Gtk::Window* mw; glade_->get_widget( "MainWindow", mw ); mw->hide(); } } void MainWindow::on_sidebar_toggled_() { Gtk::Notebook* nb; glade_->get_widget( "Sidebar", nb ); const bool v( Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( action_group_->get_action( "ShowSidebar" ) )->get_active() ); if( v ) nb->show(); else nb->hide(); } void MainWindow::on_speed_test_clicked_() { const int test( 0 ); Gtk::Window* mw; glade_->get_widget( "MainWindow", mw ); if( test == 0 ) { const unsigned runs( 10 ); Gtk::Statusbar* sb; glade_->get_widget( "Statusbar", sb ); std::vector< double > times; std::string output; double adder( 0 ); for( unsigned i = 0; i < runs; ++i ) { MeshHistory::Instance().AddMesh( true, false, false ); Glib::Timer timer; MeshHistory::Instance().GetCurrentMesh().PerformanceTest( "" ); timer.stop(); times.push_back( timer.elapsed() ); output += ToString( times[ i ] ) + " seconds\n"; adder += times[ i ]; } Gtk::MessageDialog::MessageDialog( *mw, "Times:\n" + output + "\nAverage: " + ToString( adder / runs ) + " seconds" ).run(); } else if( test == 1 ) { GdkEventButton click; //GdkEventMotion em; int x( editor_.get_width() / 2 + editor_.get_allocation().get_x() ); int y( editor_.get_height() / 2 + editor_.get_allocation().get_y() ); click.type = GDK_BUTTON_PRESS; click.window = editor_.get_window()->gobj(); click.x = x; click.y = y; click.button = 1; click.device = ( *editor_.get_display()->list_devices().begin() )->gobj(); const unsigned runs( 100 ); Glib::Timer timer; for( unsigned i = 0; i < runs; ++i ) editor_.event( (GdkEvent*)( &click ) ); timer.stop(); Gtk::MessageDialog::MessageDialog( *mw, ToString( timer.elapsed() ) + " seconds" ).run(); /*em.type = GDK_MOTION_NOTIFY; em.window = editor_.get_window()->gobj(); em.x = 200; em.y = 200; em.device = ( *editor_.get_display()->list_devices().begin() )->gobj(); editor_.event( (GdkEvent*)( &em ) );*/ } } void MainWindow::on_undo_steps_value_changed_() { Gtk::SpinButton* sb; glade_->get_widget( "UndoSteps", sb ); MeshHistory::Instance().SetMaximum( lround( sb->get_value() + 1 ) ); } void MainWindow::new_model_() { if( !is_mesh_data_safe_() ) return; Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); Gtk::Dialog* nd; glade_->get_widget( "NewDialog", nd ); nd->set_transient_for( *mainwindow ); const int result( nd->run() ); if( result == Gtk::RESPONSE_OK ) { create_model_(); } nd->hide(); } void MainWindow::open_model_() { Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); Gtk::FileChooserDialog fd( "Open Model" ); fd.set_transient_for( *mainwindow ); fd.set_action( Gtk::FILE_CHOOSER_ACTION_OPEN ); fd.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); fd.add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_OK ); Gtk::FileFilter filter_text; filter_text.set_name( "Wavefront (*.obj)" ); filter_text.add_pattern( "*.obj" ); fd.add_filter( filter_text ); Gtk::FileFilter filter_any; filter_any.set_name( "All files" ); filter_any.add_pattern( "*" ); fd.add_filter( filter_any ); const int result( fd.run() ); if( result == Gtk::RESPONSE_OK ) { const std::string filename( fd.get_filename() ); MeshHistory::Instance().Clear(); MeshHistory::Instance().GetCurrentMesh().Create( Create::File( filename ) ); editor_.Refresh( true, true ); } } void MainWindow::save_model_() { if( MeshHistory::Instance().GetCurrentMesh().FileName().length() ) { MeshHistory::Instance().GetCurrentMesh().Save ( MeshHistory::Instance().GetCurrentMesh().FileName() ); } else { save_model_as_(); } on_history_changed_(); } void MainWindow::save_model_as_() { Mesh& mesh( MeshHistory::Instance().GetCurrentMesh() ); Gtk::Window* mainwindow; glade_->get_widget( "MainWindow", mainwindow ); Gtk::FileChooserDialog fd( "Save Model" ); fd.set_transient_for( *mainwindow ); fd.set_action( Gtk::FILE_CHOOSER_ACTION_SAVE ); fd.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); fd.add_button( Gtk::Stock::SAVE, Gtk::RESPONSE_OK ); Gtk::FileFilter filter_obj; filter_obj.set_name( "Wavefront (*.obj)" ); filter_obj.add_pattern( "*.obj" ); fd.add_filter( filter_obj ); Gtk::FileFilter filter_vrml; filter_vrml.set_name( "VRML (*.wrl)" ); filter_vrml.add_pattern( "*.wrl" ); fd.add_filter( filter_vrml ); Gtk::FileFilter filter_any; filter_any.set_name( "All files" ); filter_any.add_pattern( "*" ); fd.add_filter( filter_any ); fd.set_filename( mesh.FileName() ); fd.set_do_overwrite_confirmation( true ); const int result( fd.run() ); if( result == Gtk::RESPONSE_OK ) { const std::string filename( fd.get_filename() ); mesh.Save( filename ); } on_history_changed_(); } void MainWindow::update_brush_() { Brush& brush( Mesh::CurrentBrush() ); Gtk::ColorButton* cb; Gtk::HScale* hs; Gtk::RadioButton* rb; Gtk::ToggleButton* tgb, * add, * sub, * sx, * sy, * sz; glade_->get_widget( "BrushDraw", rb ); if( rb->get_active() ) brush.SetMode( Brush::DISPLACE ); else { glade_->get_widget( "BrushGrab", rb ); if( rb->get_active() ) brush.SetMode( Brush::GRAB ); else { glade_->get_widget( "BrushPinch", rb ); if( rb->get_active() ) brush.SetMode( Brush::PINCH ); else { glade_->get_widget( "BrushSmooth", rb ); if( rb->get_active() ) brush.SetMode( Brush::SMOOTH ); } } } glade_->get_widget( "Layer", tgb ); brush.SetOnce( tgb->get_active() ); glade_->get_widget( "Dot", tgb ); brush.SetDot( tgb->get_active() ); glade_->get_widget( "Radius", hs ); brush.SetRadius( hs->get_value() ); glade_->get_widget( "Strength", hs ); brush.SetStrength( hs->get_value() / 1000.0f ); glade_->get_widget( "Intensity", hs ); brush.SetIntensity( hs->get_value() / 100 ); glade_->get_widget( "BrushAdd", add ); glade_->get_widget( "BrushSub", sub ); if( add->get_active() ) brush.SetPositionEdit( Brush::ADD ); else if( sub->get_active() ) brush.SetPositionEdit( Brush::SUB ); else brush.SetPositionEdit( Brush::OFF ); glade_->get_widget( "BrushRGB", tgb ); brush.SetColorEdit( tgb->get_active() ); glade_->get_widget( "BrushColor", cb ); brush.SetColor( Color( cb->get_color().get_red_p(), cb->get_color().get_green_p(), cb->get_color().get_blue_p() ) ); glade_->get_widget( "SymmetryX", sx ); glade_->get_widget( "SymmetryY", sy ); glade_->get_widget( "SymmetryZ", sz ); brush.SetSymmetry( SymmetryData( sx->get_active(), sy->get_active(), sz->get_active() ) ); update_brush_sensitivities_(); editor_.Refresh( false, false ); } void MainWindow::update_brush_preview_() { Gtk::Image* img; glade_->get_widget( "BrushShapePreview", img ); const int sz( 72 ); img->set( brush_shape_->scale_simple( sz, sz, Gdk::INTERP_BILINEAR ) ); } void MainWindow::update_brush_sensitivities_() { const Brush& brush( Mesh::CurrentBrush() ); Gtk::ColorButton* cb; Gtk::HScale* strength, * intensity; Gtk::Label* strength_label, * intensity_label; Gtk::ToggleButton* layer, * dot, * strength_pressure, * intensity_pressure, * add, * sub, * rgb; glade_->get_widget( "StrengthLabel", strength_label ); glade_->get_widget( "Strength", strength ); glade_->get_widget( "StrengthPressure", strength_pressure ); glade_->get_widget( "IntensityLabel", intensity_label ); glade_->get_widget( "Intensity", intensity ); glade_->get_widget( "IntensityPressure", intensity_pressure ); glade_->get_widget( "Layer", layer ); glade_->get_widget( "Dot", dot ); glade_->get_widget( "BrushAdd", add ); glade_->get_widget( "BrushSub", sub ); glade_->get_widget( "BrushRGB", rgb ); glade_->get_widget( "BrushColor", cb ); if( brush.Mode() == Brush::DISPLACE ) { strength_label->set_sensitive( true ); strength->set_sensitive( true ); strength_pressure->set_sensitive( true ); intensity_label->set_sensitive( true ); intensity->set_sensitive( true ); intensity_pressure->set_sensitive( true ); layer->set_sensitive( true ); dot->set_sensitive( true ); add->set_sensitive( true ); sub->set_sensitive( true ); rgb->set_sensitive( true ); cb->set_sensitive( true ); } else if( brush.Mode() == Brush::GRAB ) { strength_label->set_sensitive( false ); strength->set_sensitive( false ); strength_pressure->set_sensitive( false ); intensity_label->set_sensitive( false ); intensity->set_sensitive( false ); intensity_pressure->set_sensitive( false ); layer->set_sensitive( false ); dot->set_sensitive( false ); add->set_sensitive( false ); sub->set_sensitive( false ); rgb->set_sensitive( false ); cb->set_sensitive( false ); } else if( brush.Mode() == Brush::PINCH ) { strength_label->set_sensitive( true ); strength->set_sensitive( true ); strength_pressure->set_sensitive( true ); intensity_label->set_sensitive( false ); intensity->set_sensitive( false ); intensity_pressure->set_sensitive( false ); layer->set_sensitive( false ); dot->set_sensitive( false ); add->set_sensitive( true ); sub->set_sensitive( true ); rgb->set_sensitive( false ); cb->set_sensitive( false ); } else if( brush.Mode() == Brush::SMOOTH ) { strength_label->set_sensitive( true ); strength->set_sensitive( true ); strength_pressure->set_sensitive( true ); intensity_label->set_sensitive( true ); intensity->set_sensitive( true ); intensity_pressure->set_sensitive( true ); layer->set_sensitive( false ); dot->set_sensitive( false ); add->set_sensitive( false ); sub->set_sensitive( false ); rgb->set_sensitive( true ); cb->set_sensitive( false ); } } void MainWindow::update_brush_shape_() { Gtk::TreeView* tv; glade_->get_widget( "BrushShapes", tv ); Gtk::Image* img; glade_->get_widget( "BrushShapePreview", img ); Gtk::ListStore::iterator iter( tv->get_selection()->get_selected() ); if( iter ) { Gtk::TreeModel::Row row = *iter; brush_shape_ = row[ brush_shape_columns_.Shape ]; Mesh::CurrentBrush().SetShape( brush_shape_ ); update_brush_preview_(); } } void MainWindow::update_graphics_mode_settings_() { Gtk::RadioButton* rb; glade_->get_widget( "VBO", rb ); if( rb->get_active() ) editor_.DisplayOptions().SetGraphicsMode( Editor::DisplayOptionsData::VBO ); glade_->get_widget( "VAR", rb ); if( rb->get_active() ) editor_.DisplayOptions().SetGraphicsMode( Editor::DisplayOptionsData::VAR ); } void MainWindow::update_input_settings_() { Gtk::ToggleButton* tgb; glade_->get_widget( "SizePressure", tgb ); Mesh::CurrentBrush().SetRadiusPressure( tgb->get_active() ); glade_->get_widget( "StrengthPressure", tgb ); Mesh::CurrentBrush().SetStrengthPressure( tgb->get_active() ); glade_->get_widget( "IntensityPressure", tgb ); Mesh::CurrentBrush().SetIntensityPressure( tgb->get_active() ); }