diff --git a/libs/SelectableNode.h b/libs/SelectableNode.h deleted file mode 100644 index b8789ca238..0000000000 --- a/libs/SelectableNode.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once - -#include "scene/Node.h" -#include "iselectiongroup.h" -#include "iselection.h" -#include - -namespace scene -{ - -/** - * \brief - * Subclass of scene::Node which implements the Selectable interface. - * - * The GlobalSelectionSystem will be notified of selection changes. - */ -class SelectableNode : - public scene::Node, - public IGroupSelectable -{ -private: - // Current selection state - bool _selected; - - // The groups this node is a member of. The last value in the list - // represents the group this node has been added to most recently - GroupIds _groups; - -public: - SelectableNode() : - _selected(false) - {} - - SelectableNode(const SelectableNode& other) : - scene::Node(other), - _selected(false) - {} - - virtual ~SelectableNode() - { - setSelected(false); - } - - virtual void onInsertIntoScene(IMapRootNode& root) override - { - Node::onInsertIntoScene(root); - - // If the group ID set is not empty, this node was likely removed while - // it was still member of one or more groups. - // Try to add ourselves to any groups we were assigned to, if the group - // is not there anymore, we don't do anything. - for (std::size_t id : _groups) - { - selection::ISelectionGroupPtr group = GlobalSelectionGroupManager().getSelectionGroup(id); - - if (group) - { - group->addNode(getSelf()); - } - } - } - - // override scene::Inode::onRemoveFromScene to de-select self - virtual void onRemoveFromScene(IMapRootNode& root) override - { - setSelected(false); - - // When a node is removed from the scene with a non-empty group assignment - // we do notify the SelectionGroup to remove ourselves, but we keep the ID list - // That way we can re-add ourselves when being inserted into the scene again - - if (!_groups.empty()) - { - // Copy the group IDs, as calling removeNode() will alter the group ID list - GroupIds copy(_groups); - - // Remove ourselves from all groups - while (!_groups.empty()) - { - std::size_t id = _groups.front(); - - selection::ISelectionGroupPtr group = GlobalSelectionGroupManager().getSelectionGroup(id); - - if (group) - { - group->removeNode(getSelf()); - } - } - - // Now copy the values back in for later use - _groups.swap(copy); - } - - Node::onRemoveFromScene(root); - } - - /** - * \brief - * Set the selection state. - */ - virtual void setSelected(bool select) override - { - // Set selection status and notify group members if applicable - setSelected(select, false); - } - - virtual void addToGroup(std::size_t groupId) override - { - if (std::find(_groups.begin(), _groups.end(), groupId) == _groups.end()) - { - _groups.push_back(groupId); - } - } - - virtual void removeFromGroup(std::size_t groupId) override - { - std::vector::iterator i = std::find(_groups.begin(), _groups.end(), groupId); - - if (i != _groups.end()) - { - _groups.erase(i); - } - } - - virtual bool isGroupMember() override - { - return !_groups.empty(); - } - - virtual std::size_t getMostRecentGroupId() override - { - if (_groups.empty()) throw std::runtime_error("This node is not a member of any group."); - - return _groups.back(); - } - - virtual const GroupIds& getGroupIds() override - { - return _groups; - } - - virtual void setSelected(bool select, bool changeGroupStatus) override - { - // Change state and invoke callback only if the new state is different - // from the current state - if (select ^ _selected) - { - _selected = select; - - onSelectionStatusChange(changeGroupStatus); - } - } - - virtual bool isSelected() const override - { - return _selected; - } - -protected: - /** - * \brief - * Invoked when the selection status changes. - */ - virtual void onSelectionStatusChange(bool changeGroupStatus) - { - bool selected = isSelected(); - - // Update the flag to render selected nodes regardless of their hidden status - setForcedVisibility(selected, true); - - GlobalSelectionSystem().onSelectedChanged(Node::getSelf(), *this); - - // Check if this node is member of a group - if (changeGroupStatus && !_groups.empty()) - { - std::size_t mostRecentGroupId = _groups.back(); - - // Propagate the selection status of this node to all members of the topmost group - GlobalSelectionGroupManager().setGroupSelected(mostRecentGroupId, selected); - } - } -}; - -} // namespace diff --git a/libs/scene/SelectableNode.cpp b/libs/scene/SelectableNode.cpp new file mode 100644 index 0000000000..5fff8dec49 --- /dev/null +++ b/libs/scene/SelectableNode.cpp @@ -0,0 +1,152 @@ +#include "SelectableNode.h" + +#include "iselection.h" +#include + +namespace scene +{ + +SelectableNode::SelectableNode() : + _selected(false) +{} + +SelectableNode::SelectableNode(const SelectableNode& other) : + scene::Node(other), + _selected(false) +{} + +SelectableNode::~SelectableNode() +{ + setSelected(false); +} + +void SelectableNode::onInsertIntoScene(IMapRootNode& root) +{ + Node::onInsertIntoScene(root); + + // If the group ID set is not empty, this node was likely removed while + // it was still member of one or more groups. + // Try to add ourselves to any groups we were assigned to, if the group + // is not there anymore, we don't do anything. + for (std::size_t id : _groups) + { + selection::ISelectionGroupPtr group = GlobalSelectionGroupManager().getSelectionGroup(id); + + if (group) + { + group->addNode(getSelf()); + } + } +} + +void SelectableNode::onRemoveFromScene(IMapRootNode& root) +{ + setSelected(false); + + // When a node is removed from the scene with a non-empty group assignment + // we do notify the SelectionGroup to remove ourselves, but we keep the ID list + // That way we can re-add ourselves when being inserted into the scene again + + if (!_groups.empty()) + { + // Copy the group IDs, as calling removeNode() will alter the group ID list + GroupIds copy(_groups); + + // Remove ourselves from all groups + while (!_groups.empty()) + { + std::size_t id = _groups.front(); + + selection::ISelectionGroupPtr group = GlobalSelectionGroupManager().getSelectionGroup(id); + + if (group) + { + group->removeNode(getSelf()); + } + } + + // Now copy the values back in for later use + _groups.swap(copy); + } + + Node::onRemoveFromScene(root); +} + +void SelectableNode::setSelected(bool select) +{ + // Set selection status and notify group members if applicable + setSelected(select, false); +} + +void SelectableNode::addToGroup(std::size_t groupId) +{ + if (std::find(_groups.begin(), _groups.end(), groupId) == _groups.end()) + { + _groups.push_back(groupId); + } +} + +void SelectableNode::removeFromGroup(std::size_t groupId) +{ + std::vector::iterator i = std::find(_groups.begin(), _groups.end(), groupId); + + if (i != _groups.end()) + { + _groups.erase(i); + } +} + +bool SelectableNode::isGroupMember() +{ + return !_groups.empty(); +} + +std::size_t SelectableNode::getMostRecentGroupId() +{ + if (_groups.empty()) throw std::runtime_error("This node is not a member of any group."); + + return _groups.back(); +} + +const SelectableNode::GroupIds& SelectableNode::getGroupIds() +{ + return _groups; +} + +void SelectableNode::setSelected(bool select, bool changeGroupStatus) +{ + // Change state and invoke callback only if the new state is different + // from the current state + if (select ^ _selected) + { + _selected = select; + + onSelectionStatusChange(changeGroupStatus); + } +} + +bool SelectableNode::isSelected() const +{ + return _selected; +} + +void SelectableNode::onSelectionStatusChange(bool changeGroupStatus) +{ + bool selected = isSelected(); + + // Update the flag to render selected nodes regardless of their hidden status + setForcedVisibility(selected, true); + + GlobalSelectionSystem().onSelectedChanged(Node::getSelf(), *this); + + // Check if this node is member of a group + if (changeGroupStatus && !_groups.empty()) + { + std::size_t mostRecentGroupId = _groups.back(); + + // Propagate the selection status of this node to all members of the topmost group + GlobalSelectionGroupManager().setGroupSelected(mostRecentGroupId, selected); + } +} + +} // namespace diff --git a/libs/scene/SelectableNode.h b/libs/scene/SelectableNode.h new file mode 100644 index 0000000000..b74243198d --- /dev/null +++ b/libs/scene/SelectableNode.h @@ -0,0 +1,62 @@ +#pragma once + +#include "scene/Node.h" +#include "iselectiongroup.h" + +namespace scene +{ + +/** + * \brief + * Subclass of scene::Node which implements the Selectable interface. + * + * The GlobalSelectionSystem will be notified of selection changes. + */ +class SelectableNode : + public scene::Node, + public IGroupSelectable +{ +private: + // Current selection state + bool _selected; + + // The groups this node is a member of. The last value in the list + // represents the group this node has been added to most recently + GroupIds _groups; + +public: + SelectableNode(); + + SelectableNode(const SelectableNode& other); + + virtual ~SelectableNode(); + + virtual void onInsertIntoScene(IMapRootNode& root) override; + + // override scene::Inode::onRemoveFromScene to de-select self + virtual void onRemoveFromScene(IMapRootNode& root) override; + + /** + * \brief + * Set the selection state. + */ + virtual void setSelected(bool select) override; + + virtual void addToGroup(std::size_t groupId) override; + virtual void removeFromGroup(std::size_t groupId) override; + + virtual bool isGroupMember() override; + virtual std::size_t getMostRecentGroupId() override; + virtual const GroupIds& getGroupIds() override; + virtual void setSelected(bool select, bool changeGroupStatus) override; + virtual bool isSelected() const override; + +protected: + /** + * \brief + * Invoked when the selection status changes. + */ + virtual void onSelectionStatusChange(bool changeGroupStatus); +}; + +} // namespace diff --git a/plugins/entity/EntityNode.h b/plugins/entity/EntityNode.h index 103ed65f1c..716e34befd 100644 --- a/plugins/entity/EntityNode.h +++ b/plugins/entity/EntityNode.h @@ -4,7 +4,7 @@ #include "inamespace.h" #include "Bounded.h" -#include "SelectableNode.h" +#include "scene/SelectableNode.h" #include "transformlib.h" #include "NamespaceManager.h" diff --git a/radiant/brush/BrushNode.h b/radiant/brush/BrushNode.h index 60745d843e..c681a885c9 100644 --- a/radiant/brush/BrushNode.h +++ b/radiant/brush/BrushNode.h @@ -6,7 +6,7 @@ #include "iscenegraph.h" #include "Brush.h" -#include "SelectableNode.h" +#include "scene/SelectableNode.h" #include "FaceInstance.h" #include "EdgeInstance.h" #include "VertexInstance.h" diff --git a/radiant/patch/PatchNode.h b/radiant/patch/PatchNode.h index 0ab9682b41..44bc88fc0d 100644 --- a/radiant/patch/PatchNode.h +++ b/radiant/patch/PatchNode.h @@ -5,7 +5,7 @@ #include "itraceable.h" #include "imap.h" #include "Patch.h" -#include "SelectableNode.h" +#include "scene/SelectableNode.h" #include "PatchControlInstance.h" #include "dragplanes.h" diff --git a/radiant/selection/algorithm/Group.cpp b/radiant/selection/algorithm/Group.cpp index 8e3abdb07b..29524ebc8d 100644 --- a/radiant/selection/algorithm/Group.cpp +++ b/radiant/selection/algorithm/Group.cpp @@ -9,7 +9,7 @@ #include "selectionlib.h" #include "entitylib.h" #include "map/Map.h" -#include "SelectableNode.h" +#include "scene/SelectableNode.h" #include "wxutil/dialog/MessageBox.h" #include "selection/algorithm/Entity.h" diff --git a/radiant/selection/group/SelectionGroupManager.cpp b/radiant/selection/group/SelectionGroupManager.cpp index e572d006e7..e5f55ef2e3 100644 --- a/radiant/selection/group/SelectionGroupManager.cpp +++ b/radiant/selection/group/SelectionGroupManager.cpp @@ -15,7 +15,7 @@ #include "wxutil/dialog/MessageBox.h" #include "selectionlib.h" #include "SelectionGroup.h" -#include "SelectableNode.h" +#include "scene/SelectableNode.h" #include "SelectionGroupInfoFileModule.h" #include "wxutil/menu/MenuItem.h" #include "wxutil/menu/IconTextMenuItem.h" diff --git a/tools/msvc2015/libs.vcxproj b/tools/msvc2015/libs.vcxproj index 67241df8b3..f575d072ea 100644 --- a/tools/msvc2015/libs.vcxproj +++ b/tools/msvc2015/libs.vcxproj @@ -190,7 +190,6 @@ - diff --git a/tools/msvc2015/libs.vcxproj.filters b/tools/msvc2015/libs.vcxproj.filters index de10c1ad0b..8a19ffcd3b 100644 --- a/tools/msvc2015/libs.vcxproj.filters +++ b/tools/msvc2015/libs.vcxproj.filters @@ -135,7 +135,6 @@ - stream diff --git a/tools/msvc2015/scenelib.vcxproj b/tools/msvc2015/scenelib.vcxproj index cc2d6cf919..f41b3c03cf 100644 --- a/tools/msvc2015/scenelib.vcxproj +++ b/tools/msvc2015/scenelib.vcxproj @@ -135,6 +135,7 @@ + @@ -142,6 +143,7 @@ + diff --git a/tools/msvc2015/scenelib.vcxproj.filters b/tools/msvc2015/scenelib.vcxproj.filters index c4e1f0235c..74bfe91d3e 100644 --- a/tools/msvc2015/scenelib.vcxproj.filters +++ b/tools/msvc2015/scenelib.vcxproj.filters @@ -15,6 +15,9 @@ scene + + scene + @@ -34,5 +37,8 @@ scene + + scene + \ No newline at end of file