diff --git a/CHANGELOG.md b/CHANGELOG.md index 97941564a31..ceb9894539c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -290,6 +290,7 @@ Task #7182: FFMpeg 5.1.1+ support Task #7394: Drop support for --fs-strict Task #7720: Drop 360-degree screenshot support + Task #8141: Merge Instance Drop Modes Task #8214: Drop script blacklisting functionality 0.48.0 diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 3dcc5194016..f0af163bf21 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -336,10 +336,7 @@ void CSMPrefs::State::declare() declareShortcut(mValues->mKeyBindings.mSceneSelectTertiary, "Tertiary Select"); declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier"); declareShortcut(mValues->mKeyBindings.mSceneDelete, "Delete Instance"); - declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrain, "Drop to Terrain Level"); - declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollision, "Drop to Collision"); - declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrainSeparately, "Drop to Terrain Level Separately"); - declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollisionSeparately, "Drop to Collision Separately"); + declareShortcut(mValues->mKeyBindings.mSceneInstanceDrop, "Drop to Collision"); declareShortcut(mValues->mKeyBindings.mSceneLoadCamCell, "Load Camera Cell"); declareShortcut(mValues->mKeyBindings.mSceneLoadCamEastcell, "Load East Cell"); declareShortcut(mValues->mKeyBindings.mSceneLoadCamNorthcell, "Load North Cell"); diff --git a/apps/opencs/model/prefs/values.hpp b/apps/opencs/model/prefs/values.hpp index c4b7010aaf9..1339fa62ed7 100644 --- a/apps/opencs/model/prefs/values.hpp +++ b/apps/opencs/model/prefs/values.hpp @@ -447,14 +447,7 @@ namespace CSMPrefs Settings::SettingValue mSceneSelectTertiary{ mIndex, sName, "scene-select-tertiary", "Shift+LMB" }; Settings::SettingValue mSceneSpeedModifier{ mIndex, sName, "scene-speed-modifier", "Shift" }; Settings::SettingValue mSceneDelete{ mIndex, sName, "scene-delete", "Delete" }; - Settings::SettingValue mSceneInstanceDropTerrain{ mIndex, sName, "scene-instance-drop-terrain", - "B" }; - Settings::SettingValue mSceneInstanceDropCollision{ mIndex, sName, "scene-instance-drop-collision", - "H" }; - Settings::SettingValue mSceneInstanceDropTerrainSeparately{ mIndex, sName, - "scene-instance-drop-terrain-separately", "" }; - Settings::SettingValue mSceneInstanceDropCollisionSeparately{ mIndex, sName, - "scene-instance-drop-collision-separately", "" }; + Settings::SettingValue mSceneInstanceDrop{ mIndex, sName, "scene-instance-drop", "F" }; Settings::SettingValue mSceneDuplicate{ mIndex, sName, "scene-duplicate", "Shift+C" }; Settings::SettingValue mSceneLoadCamCell{ mIndex, sName, "scene-load-cam-cell", "Keypad+5" }; Settings::SettingValue mSceneLoadCamEastcell{ mIndex, sName, "scene-load-cam-eastcell", @@ -505,14 +498,14 @@ namespace CSMPrefs Settings::SettingValue mFreeRight{ mIndex, sName, "free-right", "D" }; Settings::SettingValue mFreeRollLeft{ mIndex, sName, "free-roll-left", "Q" }; Settings::SettingValue mFreeRollRight{ mIndex, sName, "free-roll-right", "E" }; - Settings::SettingValue mFreeSpeedMode{ mIndex, sName, "free-speed-mode", "F" }; + Settings::SettingValue mFreeSpeedMode{ mIndex, sName, "free-speed-mode", "" }; Settings::SettingValue mOrbitUp{ mIndex, sName, "orbit-up", "W" }; Settings::SettingValue mOrbitDown{ mIndex, sName, "orbit-down", "S" }; Settings::SettingValue mOrbitLeft{ mIndex, sName, "orbit-left", "A" }; Settings::SettingValue mOrbitRight{ mIndex, sName, "orbit-right", "D" }; Settings::SettingValue mOrbitRollLeft{ mIndex, sName, "orbit-roll-left", "Q" }; Settings::SettingValue mOrbitRollRight{ mIndex, sName, "orbit-roll-right", "E" }; - Settings::SettingValue mOrbitSpeedMode{ mIndex, sName, "orbit-speed-mode", "F" }; + Settings::SettingValue mOrbitSpeedMode{ mIndex, sName, "orbit-speed-mode", "" }; Settings::SettingValue mOrbitCenterSelection{ mIndex, sName, "orbit-center-selection", "C" }; Settings::SettingValue mScriptEditorComment{ mIndex, sName, "script-editor-comment", "" }; Settings::SettingValue mScriptEditorUncomment{ mIndex, sName, "script-editor-uncomment", "" }; diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 58513110355..7a59222eff8 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -60,6 +60,24 @@ #include "pagedworldspacewidget.hpp" #include "worldspacewidget.hpp" +namespace +{ + constexpr std::string_view sInstanceModeTooltip = R"( + Instance editing +
  • Use {scene-select-primary} and {scene-select-secondary} to select and unselect instances
  • +
  • Use {scene-edit-primary} to manipulate instances
  • +
  • Use {scene-select-tertiary} to select a reference object and then {scene-edit-secondary} to snap + selection relative to the reference object
  • +
  • Use {scene-submode-move}, {scene-submode-rotate}, {scene-submode-scale} to change to move, rotate, and + scale modes respectively
  • +
  • Use {scene-axis-x}, {scene-axis-y}, and {scene-axis-z} to lock changes to X, Y, and Z axes + respectively
  • +
  • Use {scene-delete} to delete currently selected objects
  • +
  • Use {scene-duplicate} to duplicate instances
  • +
  • Use {scene-instance-drop} to drop instances
+)"; +} + int CSVRender::InstanceMode::getSubModeFromId(const std::string& id) const { return id == "move" ? 0 : (id == "rotate" ? 1 : 2); @@ -297,7 +315,7 @@ void CSVRender::InstanceMode::setDragAxis(const char axis) CSVRender::InstanceMode::InstanceMode( WorldspaceWidget* worldspaceWidget, osg::ref_ptr parentNode, QWidget* parent) : EditMode(worldspaceWidget, Misc::ScalableIcon::load(":scenetoolbar/editing-instance"), - Mask_Reference | Mask_Terrain, "Instance editing", parent) + Mask_Reference | Mask_Terrain, sInstanceModeTooltip.data(), parent) , mSubMode(nullptr) , mSubModeId("move") , mSelectionMode(nullptr) @@ -320,26 +338,8 @@ CSVRender::InstanceMode::InstanceMode( connect( duplicateShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, &InstanceMode::cloneSelectedInstances); - // Following classes could be simplified by using QSignalMapper, which is obsolete in Qt5.10, but not in Qt4.8 and - // Qt5.14 - CSMPrefs::Shortcut* dropToCollisionShortcut - = new CSMPrefs::Shortcut("scene-instance-drop-collision", worldspaceWidget); - - connect(dropToCollisionShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, - &InstanceMode::dropSelectedInstancesToCollision); - - CSMPrefs::Shortcut* dropToTerrainLevelShortcut - = new CSMPrefs::Shortcut("scene-instance-drop-terrain", worldspaceWidget); - connect(dropToTerrainLevelShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, - &InstanceMode::dropSelectedInstancesToTerrain); - CSMPrefs::Shortcut* dropToCollisionShortcut2 - = new CSMPrefs::Shortcut("scene-instance-drop-collision-separately", worldspaceWidget); - connect(dropToCollisionShortcut2, qOverload<>(&CSMPrefs::Shortcut::activated), this, - &InstanceMode::dropSelectedInstancesToCollisionSeparately); - CSMPrefs::Shortcut* dropToTerrainLevelShortcut2 - = new CSMPrefs::Shortcut("scene-instance-drop-terrain-separately", worldspaceWidget); - connect(dropToTerrainLevelShortcut2, qOverload<>(&CSMPrefs::Shortcut::activated), this, - &InstanceMode::dropSelectedInstancesToTerrainSeparately); + connect(new CSMPrefs::Shortcut("scene-instance-drop", worldspaceWidget), + qOverload<>(&CSMPrefs::Shortcut::activated), this, &InstanceMode::dropToCollision); for (short i = 0; i <= 9; i++) { @@ -1254,7 +1254,7 @@ void CSVRender::InstanceMode::dropInstance(CSVRender::Object* object, float drop object->setPosition(position.pos); } -float CSVRender::InstanceMode::calculateDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight) +float CSVRender::InstanceMode::calculateDropHeight(CSVRender::Object* object, float objectHeight) { osg::Vec3d point = object->getPosition().asVec3(); @@ -1268,10 +1268,7 @@ float CSVRender::InstanceMode::calculateDropHeight(DropMode dropMode, CSVRender: intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); osgUtil::IntersectionVisitor visitor(intersector); - if (dropMode & Terrain) - visitor.setTraversalMask(Mask_Terrain); - if (dropMode & Collision) - visitor.setTraversalMask(Mask_Terrain | Mask_Reference); + visitor.setTraversalMask(Mask_Terrain | Mask_Reference); mParentNode->accept(visitor); @@ -1286,27 +1283,7 @@ float CSVRender::InstanceMode::calculateDropHeight(DropMode dropMode, CSVRender: return 0.0f; } -void CSVRender::InstanceMode::dropSelectedInstancesToCollision() -{ - handleDropMethod(Collision, "Drop instances to next collision"); -} - -void CSVRender::InstanceMode::dropSelectedInstancesToTerrain() -{ - handleDropMethod(Terrain, "Drop instances to terrain level"); -} - -void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately() -{ - handleDropMethod(CollisionSep, "Drop instances to next collision level separately"); -} - -void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately() -{ - handleDropMethod(TerrainSep, "Drop instances to terrain level separately"); -} - -void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString commandMsg) +void CSVRender::InstanceMode::dropToCollision() { std::vector> selection = getWorldspaceWidget().getSelection(Mask_Reference); if (selection.empty()) @@ -1315,43 +1292,19 @@ void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString comman CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); - CSMWorld::CommandMacro macro(undoStack, commandMsg); + CSMWorld::CommandMacro macro(undoStack, "Drop objects to collision"); DropObjectHeightHandler dropObjectDataHandler(&getWorldspaceWidget()); - if (dropMode & Separate) - { - int counter = 0; - for (osg::ref_ptr tag : selection) - if (CSVRender::ObjectTag* objectTag = dynamic_cast(tag.get())) - { - float objectHeight = dropObjectDataHandler.mObjectHeights[counter]; - float dropHeight = calculateDropHeight(dropMode, objectTag->mObject, objectHeight); - dropInstance(objectTag->mObject, dropHeight); - objectTag->mObject->apply(macro); - counter++; - } - } - else - { - float smallestDropHeight = std::numeric_limits::max(); - int counter = 0; - for (osg::ref_ptr tag : selection) - if (CSVRender::ObjectTag* objectTag = dynamic_cast(tag.get())) - { - float objectHeight = dropObjectDataHandler.mObjectHeights[counter]; - float thisDrop = calculateDropHeight(dropMode, objectTag->mObject, objectHeight); - if (thisDrop < smallestDropHeight) - smallestDropHeight = thisDrop; - counter++; - } - for (osg::ref_ptr tag : selection) - if (CSVRender::ObjectTag* objectTag = dynamic_cast(tag.get())) - { - dropInstance(objectTag->mObject, smallestDropHeight); - objectTag->mObject->apply(macro); - } - } + int counter = 0; + for (osg::ref_ptr tag : selection) + if (CSVRender::ObjectTag* objectTag = dynamic_cast(tag.get())) + { + float objectHeight = dropObjectDataHandler.mObjectHeights[counter++]; + float dropHeight = calculateDropHeight(objectTag->mObject, objectHeight); + dropInstance(objectTag->mObject, dropHeight); + objectTag->mObject->apply(macro); + } } CSVRender::DropObjectHeightHandler::DropObjectHeightHandler(WorldspaceWidget* worldspacewidget) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 45d7c2b6fd1..193423efd5c 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -41,17 +41,6 @@ namespace CSVRender { Q_OBJECT - enum DropMode - { - Separate = 0b1, - - Collision = 0b10, - Terrain = 0b100, - - CollisionSep = Collision | Separate, - TerrainSep = Terrain | Separate, - }; - CSVWidget::SceneToolMode* mSubMode; std::string mSubModeId; InstanceSelectionMode* mSelectionMode; @@ -77,7 +66,7 @@ namespace CSVRender osg::Vec3 getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart); void handleSelectDrag(const QPoint& pos); void dropInstance(CSVRender::Object* object, float dropHeight); - float calculateDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight); + float calculateDropHeight(CSVRender::Object* object, float objectHeight); osg::Vec3 calculateSnapPositionRelativeToTarget(osg::Vec3 initalPosition, osg::Vec3 targetPosition, osg::Vec3 targetRotation, osg::Vec3 translation, double snap) const; @@ -139,11 +128,7 @@ namespace CSVRender void cloneSelectedInstances(); void getSelectionGroup(const int group); void saveSelectionGroup(const int group); - void dropSelectedInstancesToCollision(); - void dropSelectedInstancesToTerrain(); - void dropSelectedInstancesToCollisionSeparately(); - void dropSelectedInstancesToTerrainSeparately(); - void handleDropMethod(DropMode dropMode, QString commandMsg); + void dropToCollision(); }; /// \brief Helper class to handle object mask data in safe way