From 76f69a0ee7645b4c5204187ce850368533fc7eaa Mon Sep 17 00:00:00 2001 From: Mattia Basaglia Date: Thu, 23 Jul 2015 14:14:42 +0200 Subject: [PATCH] Allow deselecting primitives in a fully selected entity --- libs/scenelib.h | 4 + radiant/brush.h | 6 ++ radiant/map.cpp | 16 ++-- radiant/select.cpp | 182 +++++++++++++++++++----------------------- radiant/selection.cpp | 7 +- 5 files changed, 103 insertions(+), 112 deletions(-) diff --git a/libs/scenelib.h b/libs/scenelib.h index 29402065..57ccd0b2 100644 --- a/libs/scenelib.h +++ b/libs/scenelib.h @@ -739,6 +739,10 @@ bool parentSelected() const { } return m_parentSelected; } +Instance* parent() const +{ + return m_parent; +} }; } diff --git a/radiant/brush.h b/radiant/brush.h index 46c820bd..030db483 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -3197,6 +3197,12 @@ bool isSelected() const { } void setSelected( bool select ){ m_selectable.setSelected( select ); + if ( !select && parent() ) + { + Selectable* sel_parent = Instance_getSelectable(*parent()); + if ( sel_parent && sel_parent->isSelected() ) + sel_parent->setSelected(false); + } } void update_selected() const { diff --git a/radiant/map.cpp b/radiant/map.cpp index 7493c088..36308f88 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -1765,15 +1765,15 @@ void Scene_parentSelected(){ if ( GlobalSelectionSystem().countSelected() > 1 ) { class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor { - const scene::Path& m_parent; -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() ); + const scene::Path& m_parent; + 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() ); + } } - } }; ParentSelectedBrushesToEntityWalker visitor( GlobalSelectionSystem().ultimateSelected().path() ); diff --git a/radiant/select.cpp b/radiant/select.cpp index 5d34645a..4a0c9b41 100644 --- a/radiant/select.cpp +++ b/radiant/select.cpp @@ -60,36 +60,24 @@ select_workzone_t g_select_workzone; */ class CollectSelectedBrushesBounds : public SelectionSystem::Visitor { -AABB* m_bounds; // array of AABBs -Unsigned m_max; // max AABB-elements in array -Unsigned& m_count; // count of valid AABBs stored in array + std::vector& m_bounds; // array of AABBs public: -CollectSelectedBrushesBounds( AABB* bounds, Unsigned max, Unsigned& count ) - : m_bounds( bounds ), - m_max( max ), - m_count( count ){ - m_count = 0; -} - -void visit( scene::Instance& instance ) const { - ASSERT_MESSAGE( m_count <= m_max, "Invalid m_count in CollectSelectedBrushesBounds" ); - - // stop if the array is already full - if ( m_count == m_max ) { - return; + CollectSelectedBrushesBounds( std::vector& bounds ) + : m_bounds( bounds ) + { + m_bounds.clear(); } - Selectable* selectable = Instance_getSelectable( instance ); - if ( ( selectable != 0 ) - && instance.isSelected() ) { - // brushes only - if ( Instance_getBrush( instance ) != 0 ) { - m_bounds[m_count] = instance.worldAABB(); - ++m_count; + void visit( scene::Instance& instance ) const { + Selectable* selectable = Instance_getSelectable( instance ); + if ( selectable && instance.isSelected() ) { + // brushes only + if ( Instance_getBrush( instance ) ) { + m_bounds.push_back(instance.worldAABB()); + } } } -} }; /** @@ -99,76 +87,66 @@ void visit( scene::Instance& instance ) const { template class SelectByBounds : public scene::Graph::Walker { -AABB* m_aabbs; // selection aabbs -Unsigned m_count; // number of aabbs in m_aabbs -TSelectionPolicy policy; // type that contains a custom intersection method aabb<->aabb + std::vector m_aabbs; // selection aabbs + TSelectionPolicy policy; // type that contains a custom intersection method aabb<->aabb public: -SelectByBounds( AABB* aabbs, Unsigned count ) - : m_aabbs( aabbs ), - m_count( count ){ -} + SelectByBounds( const std::vector& aabbs ) + : m_aabbs( aabbs ) + {} -bool pre( const scene::Path& path, scene::Instance& instance ) const { - Selectable* selectable = Instance_getSelectable( instance ); + bool pre( const scene::Path& path, scene::Instance& instance ) const { + Selectable* selectable = Instance_getSelectable( instance ); - // ignore worldspawn - Entity* entity = Node_getEntity( path.top() ); - if ( entity ) { - if ( string_equal( entity->getKeyValue( "classname" ), "worldspawn" ) ) { + // ignore worldspawn + Entity* entity = Node_getEntity( path.top() ); + if ( entity && string_equal( entity->getKeyValue( "classname" ), "worldspawn" ) ) { return true; } - } - if ( ( path.size() > 1 ) && - ( !path.top().get().isRoot() ) && - ( selectable != 0 ) - ) { - for ( Unsigned i = 0; i < m_count; ++i ) + if ( ( path.size() > 1 ) && ( !path.top().get().isRoot() ) && selectable ) { - if ( policy.Evaluate( m_aabbs[i], instance ) ) { - selectable->setSelected( true ); + for ( const AABB& aabb : m_aabbs ) + { + if ( policy.Evaluate( aabb, instance ) ) { + selectable->setSelected( true ); + } } } - } - return true; -} + return true; + } -/** - Performs selection operation on the global scenegraph. - If delete_bounds_src is true, then the objects which were - used as source for the selection aabbs will be deleted. - */ -static void DoSelection( bool delete_bounds_src = true ){ - if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) { - // we may not need all AABBs since not all selected objects have to be brushes - const Unsigned max = (Unsigned)GlobalSelectionSystem().countSelected(); - AABB* aabbs = new AABB[max]; - - Unsigned count; - CollectSelectedBrushesBounds collector( aabbs, max, count ); - GlobalSelectionSystem().foreachSelected( collector ); - - // nothing usable in selection - if ( !count ) { - delete[] aabbs; - return; - } + /** + Performs selection operation on the global scenegraph. + If delete_bounds_src is true, then the objects which were + used as source for the selection aabbs will be deleted. + */ + static void DoSelection( bool delete_bounds_src = true ){ + if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) { + // we may not need all AABBs since not all selected objects have to be brushes + const Unsigned max = (Unsigned)GlobalSelectionSystem().countSelected(); + std::vector aabbs(max); + CollectSelectedBrushesBounds collector( aabbs ); + GlobalSelectionSystem().foreachSelected( collector ); + + // nothing usable in selection + if ( aabbs.empty() ) { + return; + } - // delete selected objects - if ( delete_bounds_src ) { // see deleteSelection - UndoableCommand undo( "deleteSelected" ); - Select_Delete(); - } + // delete selected objects + if ( delete_bounds_src ) { // see deleteSelection + UndoableCommand undo( "deleteSelected" ); + Select_Delete(); + } - // select objects with bounds - GlobalSceneGraph().traverse( SelectByBounds( aabbs, count ) ); + // select objects with bounds + GlobalSceneGraph().traverse( SelectByBounds( aabbs ) ); - SceneChangeNotify(); - delete[] aabbs; + SceneChangeNotify(); + } } -} }; /** @@ -311,36 +289,38 @@ void Select_Invert(){ class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker { -mutable std::size_t m_depth; -NodeSmartReference worldspawn; + mutable std::size_t m_depth; + NodeSmartReference worldspawn; public: -ExpandSelectionToEntitiesWalker() : m_depth( 0 ), worldspawn( Map_FindOrInsertWorldspawn( g_map ) ){ -} -bool pre( const scene::Path& path, scene::Instance& instance ) const { - ++m_depth; - - // ignore worldspawn - NodeSmartReference me( path.top().get() ); - if ( me == worldspawn ) { - return false; + ExpandSelectionToEntitiesWalker() + : m_depth( 0 ), + worldspawn( Map_FindOrInsertWorldspawn( g_map ) ){ } + bool pre( const scene::Path& path, scene::Instance& instance ) const { + ++m_depth; - if ( m_depth == 2 ) { // entity depth - // traverse and select children if any one is selected - if ( instance.childSelected() ) { + // ignore worldspawn + NodeSmartReference me( path.top().get() ); + if ( me == worldspawn ) { + return false; + } + + if ( m_depth == 2 ) { // entity depth + // traverse and select children if any one is selected + if ( instance.childSelected() ) { + Instance_setSelected( instance, true ); + } + return Node_getEntity( path.top() )->isContainer() && instance.isSelected(); + } + else if ( m_depth == 3 ) { // primitive depth Instance_setSelected( instance, true ); + return false; } - return Node_getEntity( path.top() )->isContainer() && instance.isSelected(); + return true; } - else if ( m_depth == 3 ) { // primitive depth - Instance_setSelected( instance, true ); - return false; + void post( const scene::Path& path, scene::Instance& instance ) const { + --m_depth; } - return true; -} -void post( const scene::Path& path, scene::Instance& instance ) const { - --m_depth; -} }; void Scene_ExpandSelectionToEntities(){ diff --git a/radiant/selection.cpp b/radiant/selection.cpp index 2e481b40..d39703a3 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -2804,11 +2804,12 @@ void SelectPoint( const View& view, const float device_point[2], const float dev { SelectableSortedSet::iterator best = selector.begin(); // toggle selection of the object with least depth - if ( ( *best ).second->isSelected() ) { - ( *best ).second->setSelected( false ); + if ( best->second->isSelected() ) { + best->second->setSelected( false ); } else{ - ( *best ).second->setSelected( true ); + best->second->setSelected( true ); + /// \todo Might be cool to select the whole entity if all the children are selected } } break; -- 2.39.2