From aeff001658517569a36e5b16870f6cfe46b38463 Mon Sep 17 00:00:00 2001 From: codereader Date: Thu, 23 Sep 2021 06:24:49 +0200 Subject: [PATCH] #5746: Implement handling of UnselectSelectionRequests in TextureToolSelectionSystem. --- include/itexturetoolmodel.h | 6 ++ .../textool/TextureToolSelectionSystem.cpp | 86 +++++++++++++++++- .../textool/TextureToolSelectionSystem.h | 11 +++ test/TextureTool.cpp | 88 +++++++++++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) diff --git a/include/itexturetoolmodel.h b/include/itexturetoolmodel.h index cb3bdb5f21..3c51d0a689 100644 --- a/include/itexturetoolmodel.h +++ b/include/itexturetoolmodel.h @@ -160,6 +160,12 @@ class ITextureToolSelectionSystem : // Collection should not be modified during iteration virtual void foreachSelectedComponentNode(const std::function& functor) = 0; + virtual std::size_t countSelected() = 0; + virtual std::size_t countSelectedComponentNodes() = 0; + + virtual void clearSelection() = 0; + virtual void clearComponentSelection() = 0; + virtual SelectionMode getMode() const = 0; virtual void setMode(SelectionMode mode) = 0; virtual sigc::signal& signal_selectionModeChanged() = 0; diff --git a/radiantcore/selection/textool/TextureToolSelectionSystem.cpp b/radiantcore/selection/textool/TextureToolSelectionSystem.cpp index 2dbe19f91f..10f0f1792d 100644 --- a/radiantcore/selection/textool/TextureToolSelectionSystem.cpp +++ b/radiantcore/selection/textool/TextureToolSelectionSystem.cpp @@ -1,6 +1,7 @@ #include "TextureToolSelectionSystem.h" #include "itextstream.h" +#include "iradiant.h" #include "module/StaticModule.h" #include "../textool/TextureToolRotateManipulator.h" #include "../textool/TextureToolDragManipulator.h" @@ -18,7 +19,8 @@ const std::string& TextureToolSelectionSystem::getName() const const StringSet& TextureToolSelectionSystem::getDependencies() const { - static StringSet _dependencies{ MODULE_TEXTOOL_SCENEGRAPH, MODULE_COMMANDSYSTEM }; + static StringSet _dependencies{ MODULE_TEXTOOL_SCENEGRAPH, + MODULE_COMMANDSYSTEM, MODULE_RADIANT_CORE }; return _dependencies; } @@ -41,10 +43,17 @@ void TextureToolSelectionSystem::initialiseModule(const IApplicationContext& ctx GlobalCommandSystem().addCommand("ToggleTextureToolSelectionMode", std::bind(&TextureToolSelectionSystem::toggleSelectionModeCmd, this, std::placeholders::_1), { cmd::ARGTYPE_STRING }); + + _unselectListener = GlobalRadiantCore().getMessageBus().addListener( + radiant::IMessage::Type::UnselectSelectionRequest, + radiant::TypeListener( + sigc::mem_fun(this, &TextureToolSelectionSystem::handleUnselectRequest))); } void TextureToolSelectionSystem::shutdownModule() { + GlobalRadiantCore().getMessageBus().removeListener(_unselectListener); + _sigSelectionModeChanged.clear(); _sigActiveManipulatorChanged.clear(); _manipulators.clear(); @@ -173,6 +182,81 @@ void TextureToolSelectionSystem::foreachSelectedNodeOfAnyType(const std::functio } } +std::size_t TextureToolSelectionSystem::countSelected() +{ + std::size_t count = 0; + + foreachSelectedNode([&](const INode::Ptr& node) + { + ++count; + return true; + }); + + return count; +} + +std::size_t TextureToolSelectionSystem::countSelectedComponentNodes() +{ + std::size_t count = 0; + + foreachSelectedComponentNode([&](const INode::Ptr& node) + { + ++count; + return true; + }); + + return count; +} + +void TextureToolSelectionSystem::clearSelection() +{ + foreachSelectedNode([&](const INode::Ptr& node) + { + node->setSelected(false); + return true; + }); +} + +void TextureToolSelectionSystem::clearComponentSelection() +{ + foreachSelectedComponentNode([&](const INode::Ptr& node) + { + auto componentSelectable = std::dynamic_pointer_cast(node); + + if (componentSelectable) + { + componentSelectable->clearComponentSelection(); + } + + return true; + }); +} + +void TextureToolSelectionSystem::handleUnselectRequest(selection::UnselectSelectionRequest& request) +{ + if (getMode() == SelectionMode::Vertex) + { + if (countSelectedComponentNodes() > 0) + { + clearComponentSelection(); + } + else // no selection, just switch modes + { + setMode(SelectionMode::Surface); + } + + request.setHandled(true); + } + else + { + if (countSelected() > 0) + { + clearSelection(); + request.setHandled(true); + } + } +} + std::size_t TextureToolSelectionSystem::registerManipulator(const selection::ITextureToolManipulator::Ptr& manipulator) { std::size_t newId = 1; diff --git a/radiantcore/selection/textool/TextureToolSelectionSystem.h b/radiantcore/selection/textool/TextureToolSelectionSystem.h index 614c0ed6b2..5e89e7debb 100644 --- a/radiantcore/selection/textool/TextureToolSelectionSystem.h +++ b/radiantcore/selection/textool/TextureToolSelectionSystem.h @@ -3,6 +3,7 @@ #include "itexturetoolmodel.h" #include "icommandsystem.h" #include "TextureToolManipulationPivot.h" +#include "messages/UnselectSelectionRequest.h" namespace textool { @@ -24,6 +25,8 @@ class TextureToolSelectionSystem : TextureToolManipulationPivot _manipulationPivot; + std::size_t _unselectListener; + public: const std::string& getName() const override; const StringSet& getDependencies() const override; @@ -37,6 +40,12 @@ class TextureToolSelectionSystem : void foreachSelectedNode(const std::function& functor) override; void foreachSelectedComponentNode(const std::function& functor) override; + std::size_t countSelected() override; + std::size_t countSelectedComponentNodes() override; + + void clearSelection() override; + void clearComponentSelection() override; + void selectPoint(SelectionTest& test, SelectionSystem::EModifier modifier) override; void selectArea(SelectionTest& test, SelectionSystem::EModifier modifier) override; @@ -58,6 +67,8 @@ class TextureToolSelectionSystem : void onManipulationCancelled() override; private: + void handleUnselectRequest(selection::UnselectSelectionRequest& request); + // Internally switches between the selection modes and iterates over the corresponding collection void foreachSelectedNodeOfAnyType(const std::function& functor); diff --git a/test/TextureTool.cpp b/test/TextureTool.cpp index ec887a4680..d2c79dc8fb 100644 --- a/test/TextureTool.cpp +++ b/test/TextureTool.cpp @@ -644,6 +644,94 @@ TEST_F(TextureToolTest, TestSelectPatchByArea) EXPECT_TRUE(std::dynamic_pointer_cast(selectedNodes.front())) << "Couldn't cast to special type"; } +TEST_F(TextureToolTest, ClearSelectionUsingCommand) +{ + auto worldspawn = GlobalMapModule().findOrInsertWorldspawn(); + auto brush1 = algorithm::createCubicBrush(worldspawn, Vector3(0, 0, 0), "textures/numbers/1"); + auto brush2 = algorithm::createCubicBrush(worldspawn, Vector3(0, 256, 256), "textures/numbers/1"); + auto patchNode = GlobalPatchModule().createPatch(patch::PatchDefType::Def2); + scene::addNodeToContainer(patchNode, worldspawn); + Node_getIPatch(patchNode)->setDims(3, 3); + Node_getIPatch(patchNode)->setShader("textures/numbers/1"); + + Node_setSelected(brush1, true); + Node_setSelected(brush2, true); + Node_setSelected(patchNode, true); + EXPECT_EQ(GlobalSelectionSystem().countSelected(), 3) << "3 items must be selected"; + + // We don't know how many tex tool nodes there are, but it should be more than 0 + EXPECT_GT(getTextureToolNodeCount(), 0) << "There should be some tex tool nodes now"; + + std::set selectedNodes; + std::size_t i = 0; + + // Select every single node + GlobalTextureToolSceneGraph().foreachNode([&](const textool::INode::Ptr& node) + { + node->setSelected(true); + selectedNodes.emplace(node); + return true; + }); + + // We should have a non-empty selection + EXPECT_GT(GlobalTextureToolSelectionSystem().countSelected(), 0) << "No nodes selected"; + + // Switch to vertex mode + GlobalTextureToolSelectionSystem().setMode(textool::SelectionMode::Vertex); + + // Get the texture space bounds of this patch + render::TextureToolView view; + auto bounds = getTextureSpaceBounds(*Node_getIPatch(patchNode)); + bounds.extents *= 1.2f; + view.constructFromTextureSpaceBounds(bounds, TEXTOOL_WIDTH, TEXTOOL_HEIGHT); + + // Select patch vertices + foreachPatchVertex(*Node_getIPatch(patchNode), [&](const PatchControl& control) + { + performPointSelection(control.texcoord, view); + }); + + // Select face vertices + auto faceUp = algorithm::findBrushFaceWithNormal(Node_getIBrush(brush1), Vector3(0, 0, 1)); + + // Get the texture space bounds of this face + bounds = getTextureSpaceBounds(*faceUp); + bounds.extents *= 1.2f; + view.constructFromTextureSpaceBounds(bounds, TEXTOOL_WIDTH, TEXTOOL_HEIGHT); + + for (const auto& vertex : faceUp->getWinding()) + { + performPointSelection(vertex.texcoord, view); + } + + // We should have two selected component nodes + EXPECT_GT(GlobalTextureToolSelectionSystem().countSelectedComponentNodes(), 0) << "No components selected"; + EXPECT_GT(GlobalSelectionSystem().countSelected(), 0) << "Scene selection count should be > 0"; + + // Hitting ESC once will deselect the components + GlobalCommandSystem().executeCommand("UnSelectSelection"); + + EXPECT_EQ(GlobalTextureToolSelectionSystem().countSelectedComponentNodes(), 0) << "Component selection should be gone"; + EXPECT_GT(GlobalTextureToolSelectionSystem().countSelected(), 0) << "Surface selection should not have been touched"; + EXPECT_GT(GlobalSelectionSystem().countSelected(), 0) << "Scene selection count should still be > 0"; + EXPECT_EQ(GlobalTextureToolSelectionSystem().getMode(), textool::SelectionMode::Vertex) << "We should still be in vertex mode"; + + // Next deselection will exit vertex mode + GlobalCommandSystem().executeCommand("UnSelectSelection"); + EXPECT_EQ(GlobalTextureToolSelectionSystem().getMode(), textool::SelectionMode::Surface) << "We should be in Surface mode now"; + EXPECT_GT(GlobalTextureToolSelectionSystem().countSelected(), 0) << "Surface selection should not have been touched"; + EXPECT_GT(GlobalSelectionSystem().countSelected(), 0) << "Scene selection count should still be > 0"; + + // Next will de-select the regular selection + GlobalCommandSystem().executeCommand("UnSelectSelection"); + EXPECT_EQ(GlobalTextureToolSelectionSystem().countSelected(), 0) << "Surface selection should be gone now"; + EXPECT_GT(GlobalSelectionSystem().countSelected(), 0) << "Scene selection count should still be > 0"; + + // Now that the tex tool selection is gone, we should affect the scene selection + GlobalCommandSystem().executeCommand("UnSelectSelection"); + EXPECT_EQ(GlobalSelectionSystem().countSelected(), 0) << "Scene selection should be gone now"; +} + inline std::vector getTexcoords(const IFace* face) { std::vector uvs;