X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fmap.cpp;h=de6c6d135400a5ace17060c17ba1428e4599b7f6;hb=e3af470d9d19e105c9a9c6228931ee2645d09371;hp=fae78de3692376068e22060520195a0cdf1a3ad5;hpb=3c73487420fde8d4a3b5360d8b99e48132517900;p=xonotic%2Fnetradiant.git diff --git a/radiant/map.cpp b/radiant/map.cpp index fae78de3..de6c6d13 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -21,10 +21,14 @@ #include "map.h" +#include + #include "debugging/debugging.h" #include "imap.h" + MapModules& ReferenceAPI_getMapModules(); + #include "iselection.h" #include "iundo.h" #include "ibrush.h" @@ -35,21 +39,15 @@ MapModules& ReferenceAPI_getMapModules(); #include "irender.h" #include "ientity.h" #include "editable.h" +#include "iarchive.h" #include "ifilesystem.h" #include "namespace.h" #include "moduleobserver.h" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include "uilib/uilib.h" #include "scenelib.h" #include "transformlib.h" @@ -61,6 +59,7 @@ MapModules& ReferenceAPI_getMapModules(); #include "cmdlib.h" #include "stream/textfilestream.h" #include "os/path.h" +#include "os/file.h" #include "uniquenames.h" #include "modulesystem/singletonmodule.h" #include "modulesystem/moduleregistry.h" @@ -80,6 +79,7 @@ MapModules& ReferenceAPI_getMapModules(); #include "xywindow.h" #include "mainframe.h" #include "preferences.h" +#include "preferencesystem.h" #include "referencecache.h" #include "mru.h" #include "commands.h" @@ -87,6 +87,8 @@ MapModules& ReferenceAPI_getMapModules(); #include "brushmodule.h" #include "brush.h" +bool g_writeMapComments = true; + class NameObserver { UniqueNames& m_names; @@ -98,6 +100,7 @@ void construct(){ m_names.insert( name_read( c_str() ) ); } } + void destroy(){ if ( !empty() ) { //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n"; @@ -106,6 +109,7 @@ void destroy(){ } NameObserver& operator=( const NameObserver& other ); + public: NameObserver( UniqueNames& names ) : m_names( names ){ construct(); @@ -113,21 +117,26 @@ NameObserver( UniqueNames& names ) : m_names( names ){ NameObserver( const NameObserver& other ) : m_names( other.m_names ), m_name( other.m_name ){ construct(); } + ~NameObserver(){ destroy(); } + bool empty() const { return string_empty( c_str() ); } + const char* c_str() const { return m_name.c_str(); } + void nameChanged( const char* name ){ destroy(); m_name = name; construct(); } -typedef MemberCaller1 NameChangedCaller; + +typedef MemberCaller NameChangedCaller; }; class BasicNamespace : public Namespace @@ -139,12 +148,14 @@ public: ~BasicNamespace(){ ASSERT_MESSAGE( m_names.empty(), "namespace: names still registered at shutdown" ); } + void attach( const NameCallback& setName, const NameCallbackCallback& attachObserver ){ std::pair result = m_names.insert( Names::value_type( setName, m_uniqueNames ) ); ASSERT_MESSAGE( result.second, "cannot attach name" ); attachObserver( NameObserver::NameChangedCaller( ( *result.first ).second ) ); //globalOutputStream() << "attach: " << reinterpret_cast(setName) << "\n"; } + void detach( const NameCallback& setName, const NameCallbackCallback& detachObserver ){ Names::iterator i = m_names.find( setName ); ASSERT_MESSAGE( i != m_names.end(), "cannot detach name" ); @@ -199,11 +210,13 @@ class NamespaceAPI Namespace* m_namespace; public: typedef Namespace Type; + STRING_CONSTANT( Name, "*" ); NamespaceAPI(){ m_namespace = &g_defaultNamespace; } + Namespace* getTable(){ return m_namespace; } @@ -261,6 +274,7 @@ public: WorldNode() : m_node( 0 ){ } + void set( scene::Node* node ){ if ( m_node != 0 ) { m_node->DecRef(); @@ -270,6 +284,7 @@ void set( scene::Node* node ){ m_node->IncRef(); } } + scene::Node* get() const { return m_node; } @@ -277,7 +292,9 @@ scene::Node* get() const { class Map; void Map_SetValid( Map& map, bool valid ); + void Map_UpdateTitle( const Map& map ); + void Map_SetWorldspawn( Map& map, scene::Node* node ); @@ -289,6 +306,7 @@ Resource* m_resource; bool m_valid; bool m_modified; + void ( *m_modified_changed )( const Map& ); Signal0 m_mapValidCallbacks; @@ -319,6 +337,7 @@ void realise(){ Map_SetValid( g_map, true ); } } + void unrealise(){ if ( m_resource != 0 ) { Map_SetValid( g_map, false ); @@ -386,7 +405,6 @@ void Map_UpdateTitle( const Map& map ){ } - scene::Node* Map_GetWorldspawn( const Map& map ){ return map.m_world_node.get(); } @@ -402,6 +420,7 @@ float g_MaxWorldCoord = 64 * 1024; float g_MinWorldCoord = -64 * 1024; void AddRegionBrushes( void ); + void RemoveRegionBrushes( void ); @@ -432,6 +451,7 @@ public: EntityFindByClassname( const char* name, Entity*& entity ) : m_name( name ), m_entity( entity ){ m_entity = 0; } + bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( m_entity == 0 ) { Entity* entity = Node_getEntity( path.top() ); @@ -541,6 +561,7 @@ UnsortedNodeSet& m_nodes; public: CollectAllWalker( scene::Node& root, UnsortedNodeSet& nodes ) : m_root( root ), m_nodes( nodes ){ } + bool pre( scene::Node& node ) const { m_nodes.insert( NodeSmartReference( node ) ); Node_getTraversable( m_root )->erase( node ); @@ -584,12 +605,14 @@ public: MapMergeAll( const scene::Path& root ) : m_path( root ){ } + bool pre( scene::Node& node ) const { Node_getTraversable( m_path.top() )->insert( node ); m_path.push( makeReference( node ) ); selectPath( m_path, true ); return false; } + void post( scene::Node& node ) const { m_path.pop(); } @@ -602,6 +625,7 @@ public: MapMergeEntities( const scene::Path& root ) : m_path( root ){ } + bool pre( scene::Node& node ) const { if ( node_is_worldspawn( node ) ) { scene::Node* world_node = Map_FindWorldspawn( g_map ); @@ -631,6 +655,7 @@ bool pre( scene::Node& node ) const { } return false; } + void post( scene::Node& node ) const { m_path.pop(); } @@ -645,6 +670,7 @@ public: TypeCasts(){ NodeContainedCast::install( m_casts ); } + NodeTypeCastTable& get(){ return m_casts; } @@ -662,9 +688,11 @@ scene::Traversable& get( NullType){ BasicContainer() : m_node( this, this, StaticTypeCasts::instance().get() ){ } + void release(){ delete this; } + scene::Node& node(){ return m_node; } @@ -674,6 +702,7 @@ scene::Node& node(){ void MergeMap( scene::Node& node ){ Node_getTraversable( node )->traverse( MapMergeEntities( scene::Path( makeReference( GlobalSceneGraph().root() ) ) ) ); } + void Map_ImportSelected( TextInputStream& in, const MapFormat& format ){ NodeSmartReference node( ( new BasicContainer )->node() ); format.readGraph( node, in, GlobalEntityCreator() ); @@ -702,6 +731,7 @@ public: CloneAll( scene::Node& root ) : m_path( makeReference( root ) ){ } + bool pre( scene::Node& node ) const { if ( node.isRoot() ) { return false; @@ -712,6 +742,7 @@ bool pre( scene::Node& node ) const { return true; } + void post( scene::Node& node ) const { if ( node.isRoot() ) { return; @@ -743,14 +774,17 @@ public: EntityBreakdownWalker( EntityBreakdown& entitymap ) : m_entitymap( entitymap ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { Entity* entity = Node_getEntity( path.top() ); if ( entity != 0 ) { const EntityClass& eclass = entity->getEntityClass(); if ( m_entitymap.find( eclass.name() ) == m_entitymap.end() ) { m_entitymap[eclass.name()] = 1; + } else + { + ++m_entitymap[eclass.name()]; } - else{ ++m_entitymap[eclass.name()]; } } return true; } @@ -765,106 +799,98 @@ WindowPosition g_posMapInfoWnd( c_default_window_pos ); void DoMapInfo(){ ModalDialog dialog; - GtkEntry* brushes_entry; - GtkEntry* entities_entry; - GtkListStore* EntityBreakdownWalker; + ui::Entry brushes_entry{ui::null}; + ui::Entry entities_entry{ui::null}; + ui::ListStore EntityBreakdownWalker{ui::null}; - GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Map Info", G_CALLBACK( dialog_delete_callback ), &dialog ); + ui::Window window = MainFrame_getWindow().create_dialog_window("Map Info", G_CALLBACK(dialog_delete_callback ), &dialog ); window_set_position( window, g_posMapInfoWnd ); { - GtkVBox* vbox = create_dialog_vbox( 4, 4 ); - gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) ); + auto vbox = create_dialog_vbox( 4, 4 ); + window.add(vbox); { - GtkHBox* hbox = create_dialog_hbox( 4 ); - gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 ); + auto hbox = create_dialog_hbox( 4 ); + vbox.pack_start( hbox, FALSE, TRUE, 0 ); { - GtkTable* table = create_dialog_table( 2, 2, 4, 4 ); - gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 ); + auto table = create_dialog_table( 2, 2, 4, 4 ); + hbox.pack_start( table, TRUE, TRUE, 0 ); { - GtkEntry* entry = GTK_ENTRY( gtk_entry_new() ); - gtk_widget_show( GTK_WIDGET( entry ) ); - gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( entry, FALSE ); + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + gtk_editable_set_editable( GTK_EDITABLE(entry), FALSE ); brushes_entry = entry; } { - GtkEntry* entry = GTK_ENTRY( gtk_entry_new() ); - gtk_widget_show( GTK_WIDGET( entry ) ); - gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2, - (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_entry_set_editable( entry, FALSE ); + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); + gtk_editable_set_editable( GTK_EDITABLE(entry), FALSE ); entities_entry = entry; } { - GtkWidget* label = gtk_label_new( "Total Brushes" ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + ui::Widget label = ui::Label( "Total Brushes" ); + label.show(); + table.attach(label, {0, 1, 0, 1}, {GTK_FILL, 0}); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); } { - GtkWidget* label = gtk_label_new( "Total Entities" ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, - (GtkAttachOptions) ( GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + ui::Widget label = ui::Label( "Total Entities" ); + label.show(); + table.attach(label, {0, 1, 1, 2}, {GTK_FILL, 0}); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); } } { - GtkVBox* vbox2 = create_dialog_vbox( 4 ); - gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( vbox2 ), FALSE, FALSE, 0 ); + auto vbox2 = create_dialog_vbox( 4 ); + hbox.pack_start( vbox2, FALSE, FALSE, 0 ); { - GtkButton* button = create_dialog_button( "Close", G_CALLBACK( dialog_button_ok ), &dialog ); - gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( button ), FALSE, FALSE, 0 ); + auto button = create_dialog_button( "Close", G_CALLBACK( dialog_button_ok ), &dialog ); + vbox2.pack_start( button, FALSE, FALSE, 0 ); } } } { - GtkWidget* label = gtk_label_new( "Entity breakdown" ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( label ), FALSE, TRUE, 0 ); + ui::Widget label = ui::Label( "Entity breakdown" ); + label.show(); + vbox.pack_start( label, FALSE, TRUE, 0 ); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); } { - GtkScrolledWindow* scr = create_scrolled_window( GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4 ); - gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( scr ), TRUE, TRUE, 0 ); + auto scr = create_scrolled_window( ui::Policy::NEVER, ui::Policy::AUTOMATIC, 4 ); + vbox.pack_start( scr, TRUE, TRUE, 0 ); { - GtkListStore* store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_STRING ); + auto store = ui::ListStore::from(gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_STRING )); - GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) ); - gtk_tree_view_set_headers_clickable( GTK_TREE_VIEW( view ), TRUE ); + auto view = ui::TreeView(ui::TreeModel::from(store._handle)); + gtk_tree_view_set_headers_clickable(view, TRUE ); { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "Entity", renderer, "text", 0, 0 ); - gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); + auto renderer = ui::CellRendererText(ui::New); + auto column = ui::TreeViewColumn( "Entity", renderer, {{"text", 0}} ); + gtk_tree_view_append_column(view, column ); gtk_tree_view_column_set_sort_column_id( column, 0 ); } { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "Count", renderer, "text", 1, 0 ); - gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); + auto renderer = ui::CellRendererText(ui::New); + auto column = ui::TreeViewColumn( "Count", renderer, {{"text", 1}} ); + gtk_tree_view_append_column(view, column ); gtk_tree_view_column_set_sort_column_id( column, 1 ); } - gtk_widget_show( view ); + view.show(); - gtk_container_add( GTK_CONTAINER( scr ), view ); + scr.add(view); EntityBreakdownWalker = store; } @@ -881,26 +907,24 @@ void DoMapInfo(){ { char tmp[16]; sprintf( tmp, "%u", Unsigned( ( *i ).second ) ); - GtkTreeIter iter; - gtk_list_store_append( GTK_LIST_STORE( EntityBreakdownWalker ), &iter ); - gtk_list_store_set( GTK_LIST_STORE( EntityBreakdownWalker ), &iter, 0, ( *i ).first.c_str(), 1, tmp, -1 ); + EntityBreakdownWalker.append(0, (*i).first.c_str(), 1, tmp); } } - g_object_unref( G_OBJECT( EntityBreakdownWalker ) ); + EntityBreakdownWalker.unref(); char tmp[16]; sprintf( tmp, "%u", Unsigned( g_brushCount.get() ) ); - gtk_entry_set_text( GTK_ENTRY( brushes_entry ), tmp ); + brushes_entry.text(tmp); sprintf( tmp, "%u", Unsigned( g_entityCount.get() ) ); - gtk_entry_set_text( GTK_ENTRY( entities_entry ), tmp ); + entities_entry.text(tmp); modal_dialog_show( window, dialog ); // save before exit window_get_position( window, g_posMapInfoWnd ); - gtk_widget_destroy( GTK_WIDGET( window ) ); + window.destroy(); } @@ -914,12 +938,15 @@ ScopeTimer( const char* message ) : m_message( message ){ m_timer.start(); } + ~ScopeTimer(){ double elapsed_time = m_timer.elapsed_msec() / 1000.f; globalOutputStream() << m_message << " timer: " << FloatFormat( elapsed_time, 5, 2 ) << " second(s) elapsed\n"; } }; +CopiedString g_strLastMapFolder = ""; + /* ================ Map_LoadFile @@ -927,9 +954,18 @@ ScopeTimer( const char* message ) */ void Map_LoadFile( const char *filename ){ + g_map.m_name = filename; + + // refresh VFS to apply new pak filtering based on mapname + // needed for daemon DPK VFS + VFS_Refresh(); + globalOutputStream() << "Loading map from " << filename << "\n"; ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Map" ); + MRU_AddFile( filename ); + g_strLastMapFolder = g_path_get_dirname( filename ); + { ScopeTimer timer( "map load" ); @@ -945,8 +981,8 @@ void Map_LoadFile( const char *filename ){ Map_Free(); } Brush_toggleFormat( i ); - g_map.m_name = filename; Map_UpdateTitle( g_map ); + g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); if ( format ) { format->wrongFormat = false; @@ -993,6 +1029,7 @@ public: ExcludeWalker( const scene::Traversable::Walker& walker, const Excluder& exclude ) : m_walker( walker ), m_exclude( &exclude ), m_skip( false ){ } + bool pre( scene::Node& node ) const { if ( m_exclude->excluded( node ) || node.isRoot() ) { m_skip = true; @@ -1004,6 +1041,7 @@ bool pre( scene::Node& node ) const { } return true; } + void post( scene::Node& node ) const { if ( m_skip ) { m_skip = false; @@ -1022,6 +1060,7 @@ public: AnyInstanceSelected( bool& selected ) : m_selected( selected ){ m_selected = false; } + void visit( scene::Instance& instance ) const { Selectable* selectable = Instance_getSelectable( instance ); if ( selectable != 0 @@ -1083,10 +1122,12 @@ mutable bool m_skip; bool selectedParent() const { return m_selected != 0; } + public: IncludeSelectedWalker( const scene::Traversable::Walker& walker ) : m_walker( walker ), m_selected( 0 ), m_skip( false ){ } + bool pre( scene::Node& node ) const { // include node if: // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected ) @@ -1103,6 +1144,7 @@ bool pre( scene::Node& node ) const { return false; } } + void post( scene::Node& node ) const { if ( m_skip ) { m_skip = false; @@ -1129,7 +1171,7 @@ void Map_Traverse_Selected( scene::Node& root, const scene::Traversable::Walker& } void Map_ExportSelected( TextOutputStream& out, const MapFormat& format ){ - format.writeGraph( GlobalSceneGraph().root(), Map_Traverse_Selected, out ); + format.writeGraph( GlobalSceneGraph().root(), Map_Traverse_Selected, out, g_writeMapComments ); } void Map_Traverse( scene::Node& root, const scene::Traversable::Walker& walker ){ @@ -1184,6 +1226,9 @@ void Map_RenameAbsolute( const char* absolute ){ Map_UpdateTitle( g_map ); g_map.m_resource->attach( g_map ); + // refresh VFS to apply new pak filtering based on mapname + // needed for daemon DPK VFS + VFS_Refresh(); } void Map_Rename( const char* filename ){ @@ -1231,6 +1276,10 @@ void Map_New(){ FocusViews( g_vector3_identity, 0 ); g_currentMap = &g_map; + + // restart VFS to apply new pak filtering based on mapname + // needed for daemon DPK VFS + VFS_Restart(); } extern void ConstructRegionBrushes( scene::Node * brushes[6], const Vector3 ®ion_mins, const Vector3 ®ion_maxs ); @@ -1321,6 +1370,7 @@ public: ExcludeAllWalker( bool exclude ) : m_exclude( exclude ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { exclude_node( path.top(), m_exclude ); @@ -1344,6 +1394,7 @@ public: ExcludeSelectedWalker( bool exclude ) : m_exclude( exclude ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { exclude_node( path.top(), ( instance.isSelected() || instance.childSelected() || instance.parentSelected() ) == m_exclude ); return true; @@ -1361,6 +1412,7 @@ public: ExcludeRegionedWalker( bool exclude ) : m_exclude( exclude ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { exclude_node( path.top(), @@ -1478,6 +1530,8 @@ void Map_RegionBrush( void ){ bool Map_ImportFile( const char* filename ){ ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Map" ); + g_strLastMapFolder = g_path_get_dirname( filename ); + bool success = false; if ( extension_equal( path_get_extension( filename ), "bsp" ) ) { @@ -1521,20 +1575,41 @@ bool Map_ImportFile( const char* filename ){ tryDecompile: - const char *type = GlobalRadiant().getRequiredGameDescriptionKeyValue( "q3map2_type" ); + const char *type = GlobalRadiant().getGameDescriptionKeyValue( "q3map2_type" ); int n = string_length( path_get_extension( filename ) ); if ( n && ( extension_equal( path_get_extension( filename ), "bsp" ) || extension_equal( path_get_extension( filename ), "map" ) ) ) { StringBuffer output; output.push_string( AppPath_get() ); - output.push_string( "q3map2." ); - output.push_string( RADIANT_EXECUTABLE ); + output.push_string( "q3map2" ); + output.push_string( GDEF_OS_EXE_EXT ); + output.push_string( " -v -game " ); output.push_string( ( type && *type ) ? type : "quake3" ); output.push_string( " -fs_basepath \"" ); output.push_string( EnginePath_get() ); output.push_string( "\" -fs_homepath \"" ); output.push_string( g_qeglobals.m_userEnginePath.c_str() ); - output.push_string( "\" -fs_game " ); + output.push_string( "\"" ); + + // extra pakpaths + for ( int i = 0; i < g_pakPathCount; i++ ) { + if ( g_strcmp0( g_strPakPath[i].c_str(), "") ) { + output.push_string( " -fs_pakpath \"" ); + output.push_string( g_strPakPath[i].c_str() ); + output.push_string( "\"" ); + } + } + + // extra switches + if ( g_disableEnginePath ) { + output.push_string( " -fs_nobasepath " ); + } + + if ( g_disableHomePath ) { + output.push_string( " -fs_nohomepath " ); + } + + output.push_string( " -fs_game " ); output.push_string( gamename_get() ); output.push_string( " -convert -format " ); output.push_string( Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map" ); @@ -1581,7 +1656,13 @@ tryDecompile: */ bool Map_SaveFile( const char* filename ){ ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Saving Map" ); - return MapResource_saveFile( MapFormat_forFile( filename ), GlobalSceneGraph().root(), Map_Traverse, filename ); + bool success = MapResource_saveFile( MapFormat_forFile( filename ), GlobalSceneGraph().root(), Map_Traverse, filename ); + if ( success ) { + // refresh VFS to apply new pak filtering based on mapname + // needed for daemon DPK VFS + VFS_Refresh(); + } + return success; } // @@ -1602,6 +1683,7 @@ scene::Node& m_parent; public: ParentSelectedBrushesToEntityWalker( scene::Node& parent ) : m_parent( parent ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( path.top().get_pointer() != &m_parent && Node_isPrimitive( path.top() ) ) { @@ -1614,6 +1696,7 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { } return true; } + void post( const scene::Path& path, scene::Instance& instance ) const { if ( path.top().get_pointer() != &m_parent && Node_isPrimitive( path.top() ) ) { @@ -1644,6 +1727,7 @@ public: CountSelectedBrushes( std::size_t& count ) : m_count( count ), m_depth( 0 ){ m_count = 0; } + bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( ++m_depth != 1 && path.top().get().isRoot() ) { return false; @@ -1656,6 +1740,7 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { } return true; } + void post( const scene::Path& path, scene::Instance& instance ) const { --m_depth; } @@ -1742,6 +1827,7 @@ void Scene_parentSelected(){ public: ParentSelectedBrushesToEntityWalker( const scene::Path& parent ) : m_parent( parent ){ } + void visit( scene::Instance& instance ) const { if ( &m_parent != &instance.path() ) { Path_parent( m_parent, instance.path() ); @@ -1759,7 +1845,6 @@ public: } - void NewMap(){ if ( ConfirmModified( "New Map" ) ) { Map_RegionOff(); @@ -1774,16 +1859,32 @@ const char* getMapsPath(){ return g_mapsPath.c_str(); } +const char* getLastMapFolderPath(){ + if (g_strLastMapFolder.empty()) { + GlobalPreferenceSystem().registerPreference( "LastMapFolder", make_property_string( g_strLastMapFolder ) ); + if (g_strLastMapFolder.empty()) { + StringOutputStream buffer( 1024 ); + buffer << getMapsPath(); + if ( !file_readable( buffer.c_str() ) ) { + buffer.clear(); + buffer << g_qeglobals.m_userGamePath.c_str() << "/"; + } + g_strLastMapFolder = buffer.c_str(); + } + } + return g_strLastMapFolder.c_str(); +} + const char* map_open( const char* title ){ - return file_dialog( GTK_WIDGET( MainFrame_getWindow() ), TRUE, title, getMapsPath(), MapFormat::Name(), true, false, false ); + return MainFrame_getWindow().file_dialog( TRUE, title, getLastMapFolderPath(), MapFormat::Name(), true, false, false ); } const char* map_import( const char* title ){ - return file_dialog( GTK_WIDGET( MainFrame_getWindow() ), TRUE, title, getMapsPath(), MapFormat::Name(), false, true, false ); + return MainFrame_getWindow().file_dialog( TRUE, title, getLastMapFolderPath(), MapFormat::Name(), false, true, false ); } const char* map_save( const char* title ){ - return file_dialog( GTK_WIDGET( MainFrame_getWindow() ), FALSE, title, getMapsPath(), MapFormat::Name(), false, false, true ); + return MainFrame_getWindow().file_dialog( FALSE, title, getLastMapFolderPath(), MapFormat::Name(), false, false, true ); } void OpenMap(){ @@ -1793,7 +1894,7 @@ void OpenMap(){ const char* filename = map_open( "Open Map" ); - if ( filename != 0 ) { + if ( filename != NULL ) { MRU_AddFile( filename ); Map_RegionOff(); Map_Free(); @@ -1804,7 +1905,7 @@ void OpenMap(){ void ImportMap(){ const char* filename = map_import( "Import Map" ); - if ( filename != 0 ) { + if ( filename != NULL ) { UndoableCommand undo( "mapImport" ); Map_ImportFile( filename ); } @@ -1813,7 +1914,8 @@ void ImportMap(){ bool Map_SaveAs(){ const char* filename = map_save( "Save Map" ); - if ( filename != 0 ) { + if ( filename != NULL ) { + g_strLastMapFolder = g_path_get_dirname( filename ); MRU_AddFile( filename ); Map_Rename( filename ); return Map_Save(); @@ -1837,7 +1939,8 @@ void SaveMap(){ void ExportMap(){ const char* filename = map_save( "Export Selection" ); - if ( filename != 0 ) { + if ( filename != NULL ) { + g_strLastMapFolder = g_path_get_dirname( filename ); Map_SaveSelected( filename ); } } @@ -1845,7 +1948,8 @@ void ExportMap(){ void SaveRegion(){ const char* filename = map_save( "Export Region" ); - if ( filename != 0 ) { + if ( filename != NULL ) { + g_strLastMapFolder = g_path_get_dirname( filename ); Map_SaveRegion( filename ); } } @@ -1888,6 +1992,7 @@ public: BrushFindByIndexWalker( std::size_t index, scene::Path& path ) : m_index( index ), m_path( path ){ } + bool pre( scene::Node& node ) const { if ( Node_isPrimitive( node ) && m_index-- == 0 ) { m_path.push( makeReference( node ) ); @@ -1904,6 +2009,7 @@ public: EntityFindByIndexWalker( std::size_t index, scene::Path& path ) : m_index( index ), m_path( path ){ } + bool pre( scene::Node& node ) const { if ( Node_isEntity( node ) && m_index-- == 0 ) { m_path.push( makeReference( node ) ); @@ -1952,6 +2058,7 @@ public: BrushFindIndexWalker( const scene::Node& node, std::size_t& count ) : m_node( &node ), m_count( count ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( Node_isPrimitive( path.top() ) ) { if ( m_node == path.top().get_pointer() ) { @@ -1973,6 +2080,7 @@ public: EntityFindIndexWalker( const scene::Node& node, std::size_t& count ) : m_node( &node ), m_count( count ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( Node_isEntity( path.top() ) ) { if ( m_node == path.top().get_pointer() ) { @@ -2001,66 +2109,58 @@ static void GetSelectionIndex( int *ent, int *brush ){ void DoFind(){ ModalDialog dialog; - GtkEntry* entity; - GtkEntry* brush; + ui::Entry entity{ui::null}; + ui::Entry brush{ui::null}; - GtkWindow* window = create_dialog_window( MainFrame_getWindow(), "Find Brush", G_CALLBACK( dialog_delete_callback ), &dialog ); + ui::Window window = MainFrame_getWindow().create_dialog_window("Find Brush", G_CALLBACK(dialog_delete_callback ), &dialog ); - GtkAccelGroup* accel = gtk_accel_group_new(); - gtk_window_add_accel_group( window, accel ); + auto accel = ui::AccelGroup(ui::New); + window.add_accel_group( accel ); { - GtkVBox* vbox = create_dialog_vbox( 4, 4 ); - gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) ); + auto vbox = create_dialog_vbox( 4, 4 ); + window.add(vbox); { - GtkTable* table = create_dialog_table( 2, 2, 4, 4 ); - gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), TRUE, TRUE, 0 ); + auto table = create_dialog_table( 2, 2, 4, 4 ); + vbox.pack_start( table, TRUE, TRUE, 0 ); { - GtkWidget* label = gtk_label_new( "Entity number" ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + ui::Widget label = ui::Label( "Entity number" ); + label.show(); + (table).attach(label, {0, 1, 0, 1}, {0, 0}); } { - GtkWidget* label = gtk_label_new( "Brush number" ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, - (GtkAttachOptions) ( 0 ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + ui::Widget label = ui::Label( "Brush number" ); + label.show(); + (table).attach(label, {0, 1, 1, 2}, {0, 0}); } { - GtkEntry* entry = GTK_ENTRY( gtk_entry_new() ); - gtk_widget_show( GTK_WIDGET( entry ) ); - gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 0, 1, - (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_widget_grab_focus( GTK_WIDGET( entry ) ); + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + gtk_widget_grab_focus( entry ); entity = entry; } { - GtkEntry* entry = GTK_ENTRY( gtk_entry_new() ); - gtk_widget_show( GTK_WIDGET( entry ) ); - gtk_table_attach( table, GTK_WIDGET( entry ), 1, 2, 1, 2, - (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), - (GtkAttachOptions) ( 0 ), 0, 0 ); + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); brush = entry; } } { - GtkHBox* hbox = create_dialog_hbox( 4 ); - gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), TRUE, TRUE, 0 ); + auto hbox = create_dialog_hbox( 4 ); + vbox.pack_start( hbox, TRUE, TRUE, 0 ); { - GtkButton* button = create_dialog_button( "Find", G_CALLBACK( dialog_button_ok ), &dialog ); - gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 ); - widget_make_default( GTK_WIDGET( button ) ); - gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0 ); + auto button = create_dialog_button( "Find", G_CALLBACK( dialog_button_ok ), &dialog ); + hbox.pack_start( button, FALSE, FALSE, 0 ); + widget_make_default( button ); + gtk_widget_add_accelerator( button , "clicked", accel, GDK_KEY_Return, (GdkModifierType)0, (GtkAccelFlags)0 ); } { - GtkButton* button = create_dialog_button( "Close", G_CALLBACK( dialog_button_cancel ), &dialog ); - gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( button ), FALSE, FALSE, 0 ); - gtk_widget_add_accelerator( GTK_WIDGET( button ), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0 ); + auto button = create_dialog_button( "Close", G_CALLBACK( dialog_button_cancel ), &dialog ); + hbox.pack_start( button, FALSE, FALSE, 0 ); + gtk_widget_add_accelerator( button , "clicked", accel, GDK_KEY_Escape, (GdkModifierType)0, (GtkAccelFlags)0 ); } } } @@ -2071,9 +2171,9 @@ void DoFind(){ GetSelectionIndex( &ent, &br ); sprintf( buf, "%i", ent ); - gtk_entry_set_text( entity, buf ); + entity.text(buf); sprintf( buf, "%i", br ); - gtk_entry_set_text( brush, buf ); + brush.text(buf); if ( modal_dialog_show( window, dialog ) == eIDOK ) { const char *entstr = gtk_entry_get_text( entity ); @@ -2081,11 +2181,12 @@ void DoFind(){ SelectBrush( atoi( entstr ), atoi( brushstr ) ); } - gtk_widget_destroy( GTK_WIDGET( window ) ); + window.destroy(); } void Map_constructPreferences( PreferencesPage& page ){ - page.appendCheckBox( "", "Load last map on open", g_bLoadLastMap ); + page.appendCheckBox( "", "Load last map at startup", g_bLoadLastMap ); + page.appendCheckBox( "", "Add entity and brush number comments on map write", g_writeMapComments ); } @@ -2095,6 +2196,7 @@ std::size_t m_unrealised; public: MapEntityClasses() : m_unrealised( 1 ){ } + void realise(){ if ( --m_unrealised == 0 ) { if ( g_map.m_resource != 0 ) { @@ -2103,6 +2205,7 @@ void realise(){ } } } + void unrealise(){ if ( ++m_unrealised == 1 ) { if ( g_map.m_resource != 0 ) { @@ -2122,6 +2225,7 @@ std::size_t m_unrealised; public: MapModuleObserver() : m_unrealised( 1 ){ } + void realise(){ if ( --m_unrealised == 0 ) { ASSERT_MESSAGE( !string_empty( g_qeglobals.m_userGamePath.c_str() ), "maps_directory: user-game-path is empty" ); @@ -2131,6 +2235,7 @@ void realise(){ g_mapsPath = buffer.c_str(); } } + void unrealise(){ if ( ++m_unrealised == 1 ) { g_mapsPath = ""; @@ -2140,22 +2245,21 @@ void unrealise(){ MapModuleObserver g_MapModuleObserver; -#include "preferencesystem.h" - CopiedString g_strLastMap; bool g_bLoadLastMap = false; void Map_Construct(){ - GlobalCommands_insert( "RegionOff", FreeCaller() ); - GlobalCommands_insert( "RegionSetXY", FreeCaller() ); - GlobalCommands_insert( "RegionSetBrush", FreeCaller() ); - GlobalCommands_insert( "RegionSetSelection", FreeCaller(), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); + GlobalCommands_insert( "RegionOff", makeCallbackF(RegionOff) ); + GlobalCommands_insert( "RegionSetXY", makeCallbackF(RegionXY) ); + GlobalCommands_insert( "RegionSetBrush", makeCallbackF(RegionBrush) ); + GlobalCommands_insert( "RegionSetSelection", makeCallbackF(RegionSelected), Accelerator( 'R', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); - GlobalPreferenceSystem().registerPreference( "LastMap", CopiedStringImportStringCaller( g_strLastMap ), CopiedStringExportStringCaller( g_strLastMap ) ); - GlobalPreferenceSystem().registerPreference( "LoadLastMap", BoolImportStringCaller( g_bLoadLastMap ), BoolExportStringCaller( g_bLoadLastMap ) ); - GlobalPreferenceSystem().registerPreference( "MapInfoDlg", WindowPositionImportStringCaller( g_posMapInfoWnd ), WindowPositionExportStringCaller( g_posMapInfoWnd ) ); + GlobalPreferenceSystem().registerPreference( "LastMap", make_property_string( g_strLastMap ) ); + GlobalPreferenceSystem().registerPreference( "LoadLastMap", make_property_string( g_bLoadLastMap ) ); + GlobalPreferenceSystem().registerPreference( "MapInfoDlg", make_property( g_posMapInfoWnd ) ); + GlobalPreferenceSystem().registerPreference( "WriteMapComments", make_property_string( g_writeMapComments ) ); - PreferencesDialog_addSettingsPreferences( FreeCaller1() ); + PreferencesDialog_addSettingsPreferences( makeCallbackF(Map_constructPreferences) ); GlobalEntityClassManager().attach( g_MapEntityClasses ); Radiant_attachHomePathsObserver( g_MapModuleObserver );