From aebd67f10d426d554bcc7bdc8a38693105ff43e1 Mon Sep 17 00:00:00 2001 From: Angeldark Raymaker Date: Tue, 8 Oct 2024 23:24:38 +0100 Subject: [PATCH] FIRE-30873: Add redo buttons to advanced areas --- indra/newview/fsfloaterposer.cpp | 98 +++++++++++++++++-- indra/newview/fsfloaterposer.h | 3 + indra/newview/fsposeranimator.cpp | 84 ++++++++++++++++ indra/newview/fsposeranimator.h | 21 ++++ indra/newview/fsposingmotion.h | 78 +++++++++++++-- .../skins/default/xui/en/floater_poser.xml | 58 ++++++++++- 6 files changed, 317 insertions(+), 25 deletions(-) diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp index 9145a618b1..87191dd625 100644 --- a/indra/newview/fsfloaterposer.cpp +++ b/indra/newview/fsfloaterposer.cpp @@ -130,8 +130,11 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key) mCommitCallbackRegistrar.add("Poser.Advanced.RotationSet", boost::bind(&FSFloaterPoser::onAdvancedRotationSet, this)); mCommitCallbackRegistrar.add("Poser.Advanced.ScaleSet", boost::bind(&FSFloaterPoser::onAdvancedScaleSet, this)); mCommitCallbackRegistrar.add("Poser.UndoLastPosition", boost::bind(&FSFloaterPoser::onUndoLastPosition, this)); + mCommitCallbackRegistrar.add("Poser.RedoLastPosition", boost::bind(&FSFloaterPoser::onRedoLastPosition, this)); mCommitCallbackRegistrar.add("Poser.ResetPosition", boost::bind(&FSFloaterPoser::onResetPosition, this)); mCommitCallbackRegistrar.add("Poser.ResetScale", boost::bind(&FSFloaterPoser::onResetScale, this)); + mCommitCallbackRegistrar.add("Poser.UndoLastScale", boost::bind(&FSFloaterPoser::onUndoLastScale, this)); + mCommitCallbackRegistrar.add("Poser.RedoLastScale", boost::bind(&FSFloaterPoser::onRedoLastScale, this)); mCommitCallbackRegistrar.add("Poser.Save", boost::bind(&FSFloaterPoser::onClickPoseSave, this)); mCommitCallbackRegistrar.add("Pose.Menu", boost::bind(&FSFloaterPoser::onPoseMenuAction, this, _2)); @@ -979,14 +982,11 @@ void FSFloaterPoser::onUndoLastRotation() if (selectedJoints.size() < 1) return; - bool shouldEnableRedoButton = false; for (auto item : selectedJoints) { bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); if (currentlyPosing) _poserAnimator.undoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle()); - - shouldEnableRedoButton |= _poserAnimator.canRedoJointRotation(avatar, *item); } enableOrDisableRedoButton(); @@ -1007,7 +1007,6 @@ void FSFloaterPoser::onUndoLastPosition() if (selectedJoints.size() < 1) return; - bool shouldEnableRedoButton = false; for (auto item : selectedJoints) { bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); @@ -1016,9 +1015,10 @@ void FSFloaterPoser::onUndoLastPosition() } refreshAdvancedPositionSliders(); + refreshAvatarPositionSliders(); } -void FSFloaterPoser::onResetPosition() +void FSFloaterPoser::onUndoLastScale() { LLVOAvatar* avatar = getUiSelectedAvatar(); if (!avatar) @@ -1031,7 +1031,35 @@ void FSFloaterPoser::onResetPosition() if (selectedJoints.size() < 1) return; - bool shouldEnableRedoButton = false; + for (auto item : selectedJoints) + { + bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); + if (currentlyPosing) + _poserAnimator.undoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle()); + } + + refreshAdvancedScaleSliders(); +} + +void FSFloaterPoser::onResetPosition() +{ + // This is a double-click function: it needs to run twice within some amount of time to complete. + auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - _timeLastClickedJointReset; + _timeLastClickedJointReset = std::chrono::system_clock::now(); + if (timeIntervalSinceLastClick > _doubleClickInterval) + return; + + LLVOAvatar* avatar = getUiSelectedAvatar(); + if (!avatar) + return; + + if (!_poserAnimator.isPosingAvatar(avatar)) + return; + + auto selectedJoints = getUiSelectedPoserJoints(); + if (selectedJoints.size() < 1) + return; + for (auto item : selectedJoints) { bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); @@ -1040,10 +1068,17 @@ void FSFloaterPoser::onResetPosition() } refreshAdvancedPositionSliders(); + refreshAvatarPositionSliders(); } void FSFloaterPoser::onResetScale() { + // This is a double-click function: it needs to run twice within some amount of time to complete. + auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - _timeLastClickedJointReset; + _timeLastClickedJointReset = std::chrono::system_clock::now(); + if (timeIntervalSinceLastClick > _doubleClickInterval) + return; + LLVOAvatar* avatar = getUiSelectedAvatar(); if (!avatar) return; @@ -1055,7 +1090,6 @@ void FSFloaterPoser::onResetScale() if (selectedJoints.size() < 1) return; - bool shouldEnableRedoButton = false; for (auto item : selectedJoints) { bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); @@ -1079,14 +1113,11 @@ void FSFloaterPoser::onRedoLastRotation() if (selectedJoints.size() < 1) return; - bool shouldEnableRedoButton = false; for (auto item : selectedJoints) { bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); if (currentlyPosing) _poserAnimator.redoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle()); - - shouldEnableRedoButton |= _poserAnimator.canRedoJointRotation(avatar, *item); } enableOrDisableRedoButton(); @@ -1094,6 +1125,53 @@ void FSFloaterPoser::onRedoLastRotation() refreshTrackpadCursor(); } +void FSFloaterPoser::onRedoLastPosition() +{ + LLVOAvatar* avatar = getUiSelectedAvatar(); + if (!avatar) + return; + + if (!_poserAnimator.isPosingAvatar(avatar)) + return; + + auto selectedJoints = getUiSelectedPoserJoints(); + if (selectedJoints.size() < 1) + return; + + for (auto item : selectedJoints) + { + bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); + if (currentlyPosing) + _poserAnimator.redoLastJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle()); + } + + refreshAdvancedPositionSliders(); + refreshAvatarPositionSliders(); +} + +void FSFloaterPoser::onRedoLastScale() +{ + LLVOAvatar* avatar = getUiSelectedAvatar(); + if (!avatar) + return; + + if (!_poserAnimator.isPosingAvatar(avatar)) + return; + + auto selectedJoints = getUiSelectedPoserJoints(); + if (selectedJoints.size() < 1) + return; + + for (auto item : selectedJoints) + { + bool currentlyPosing = _poserAnimator.isPosingAvatarJoint(avatar, *item); + if (currentlyPosing) + _poserAnimator.redoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle()); + } + + refreshAdvancedScaleSliders(); +} + void FSFloaterPoser::enableOrDisableRedoButton() { LLButton* redoButton = getChild(POSER_AVATAR_BUTTON_REDO); diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h index f5574d1109..f459586c41 100644 --- a/indra/newview/fsfloaterposer.h +++ b/indra/newview/fsfloaterposer.h @@ -215,6 +215,9 @@ class FSFloaterPoser : public LLFloater void onUndoLastRotation(); void onRedoLastRotation(); void onUndoLastPosition(); + void onRedoLastPosition(); + void onUndoLastScale(); + void onRedoLastScale(); void onResetPosition(); void onResetScale(); void enableOrDisableRedoButton(); diff --git a/indra/newview/fsposeranimator.cpp b/indra/newview/fsposeranimator.cpp index 7abe4abb99..b539966198 100644 --- a/indra/newview/fsposeranimator.cpp +++ b/indra/newview/fsposeranimator.cpp @@ -154,6 +154,34 @@ void FSPoserAnimator::undoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joi oppositeJointPose->undoLastPositionSet(); } +void FSPoserAnimator::undoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style) +{ + if (!isAvatarSafeToUse(avatar)) + return; + + FSPosingMotion* posingMotion = getPosingMotion(avatar); + if (!posingMotion) + return; + + if (posingMotion->isStopped()) + return; + + FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + if (!jointPose) + return; + + jointPose->undoLastScaleSet(); + + if (style == NONE) + return; + + FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + if (!oppositeJointPose) + return; + + oppositeJointPose->undoLastScaleSet(); +} + void FSPoserAnimator::resetJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style) { if (!isAvatarSafeToUse(avatar)) @@ -257,6 +285,62 @@ void FSPoserAnimator::redoLastJointRotation(LLVOAvatar* avatar, FSPoserJoint joi oppositeJointPose->redoLastRotationSet(); } +void FSPoserAnimator::redoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style) +{ + if (!isAvatarSafeToUse(avatar)) + return; + + FSPosingMotion* posingMotion = getPosingMotion(avatar); + if (!posingMotion) + return; + + if (posingMotion->isStopped()) + return; + + FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + if (!jointPose) + return; + + jointPose->redoLastPositionSet(); + + if (style == NONE) + return; + + FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + if (!oppositeJointPose) + return; + + oppositeJointPose->redoLastPositionSet(); +} + +void FSPoserAnimator::redoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style) +{ + if (!isAvatarSafeToUse(avatar)) + return; + + FSPosingMotion* posingMotion = getPosingMotion(avatar); + if (!posingMotion) + return; + + if (posingMotion->isStopped()) + return; + + FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + if (!jointPose) + return; + + jointPose->redoLastScaleSet(); + + if (style == NONE) + return; + + FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + if (!oppositeJointPose) + return; + + oppositeJointPose->redoLastScaleSet(); +} + LLVector3 FSPoserAnimator::getJointPosition(LLVOAvatar *avatar, FSPoserJoint joint) { LLVector3 pos; diff --git a/indra/newview/fsposeranimator.h b/indra/newview/fsposeranimator.h index ef04e7480a..70118d27bd 100644 --- a/indra/newview/fsposeranimator.h +++ b/indra/newview/fsposeranimator.h @@ -270,6 +270,13 @@ public: /// The joint with the position to undo. void undoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style); + /// + /// Undoes the last applied scale to the supplied PoserJoint. + /// + /// The avatar having the joint to which we refer. + /// The joint with the scale to undo. + void undoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style); + /// /// Resets the position of the supplied PoserJoint. /// @@ -299,6 +306,20 @@ public: /// The joint with the rotation to redo. void redoLastJointRotation(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style); + /// + /// Re-does the last undone position to the supplied PoserJoint. + /// + /// The avatar having the joint to which we refer. + /// The joint with the position to redo. + void redoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style); + + /// + /// Re-does the last undone scale to the supplied PoserJoint. + /// + /// The avatar having the joint to which we refer. + /// The joint with the scale to redo. + void redoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style); + /// /// Gets the position of a joint for the supplied avatar. /// diff --git a/indra/newview/fsposingmotion.h b/indra/newview/fsposingmotion.h index f9a940f4d9..ecbc183d2a 100644 --- a/indra/newview/fsposingmotion.h +++ b/indra/newview/fsposingmotion.h @@ -85,6 +85,8 @@ public: LLVector3 _targetScale; LLVector3 _beginningScale; std::deque _lastSetScales; + size_t _undoneScaleIndex = 0; + std::chrono::system_clock::time_point _timeLastUpdatedScale = std::chrono::system_clock::now(); /// /// Adds a last position to the deque. @@ -124,6 +126,34 @@ public: _lastSetRotations.pop_back(); } + /// + /// Adds a last rotation to the deque. + /// + void addLastScaleToUndo() + { + if (_undoneScaleIndex > 0) + { + for (int i = 0; i < _undoneScaleIndex; i++) + _lastSetScales.pop_front(); + + _undoneScaleIndex = 0; + } + + _lastSetScales.push_front(_targetScale); + + while (_lastSetScales.size() > MaximumUndoQueueLength) + _lastSetScales.pop_back(); + } + + void setScale(LLVector3 scale) + { + LLJoint* joint = _jointState->getJoint(); + if (!joint) + return; + + joint->setScale(scale); + } + public: /// /// Gets the name of the joint. @@ -217,7 +247,7 @@ public: _targetPosition.set(_lastSetPositions[_undonePositionIndex]); if (_undonePositionIndex == 0) - _lastSetRotations.pop_front(); + _lastSetPositions.pop_front(); } /// @@ -276,12 +306,44 @@ public: LLVector3 getJointScale() const { return _targetScale; } void setJointScale(LLVector3 scale) { + auto timeIntervalSinceLastScaleChange = std::chrono::system_clock::now() - _timeLastUpdatedScale; + if (timeIntervalSinceLastScaleChange > _undoUpdateInterval) + addLastScaleToUndo(); + + _timeLastUpdatedScale = std::chrono::system_clock::now(); + _targetScale.set(scale); - LLJoint* joint = _jointState->getJoint(); - if (!joint) + setScale(_targetScale); + } + + void undoLastScaleSet() + { + if (_lastSetScales.empty()) return; - joint->setScale(_targetScale); + if (_undoneScaleIndex == 0) // at the top of the queue add the current + addLastScaleToUndo(); + + _undoneScaleIndex++; + _undoneScaleIndex = llclamp(_undoneScaleIndex, 0, _lastSetScales.size() - 1); + _targetScale.set(_lastSetScales[_undoneScaleIndex]); + + setScale(_targetScale); + } + + void redoLastScaleSet() + { + if (_lastSetScales.empty()) + return; + + _undoneScaleIndex--; + _undoneScaleIndex = llclamp(_undoneScaleIndex, 0, _lastSetScales.size() - 1); + + _targetScale.set(_lastSetScales[_undoneScaleIndex]); + if (_undoneScaleIndex == 0) + _lastSetScales.pop_front(); + + setScale(_targetScale); } /// @@ -289,12 +351,8 @@ public: /// void revertJointScale() { - LLJoint* joint = _jointState->getJoint(); - if (!joint) - return; - - _targetScale = _beginningScale; - joint->setScale(_beginningScale); + _targetScale.set(_beginningScale); + setScale(_beginningScale); } /// diff --git a/indra/newview/skins/default/xui/en/floater_poser.xml b/indra/newview/skins/default/xui/en/floater_poser.xml index 230fa3310c..c7c89d7e91 100644 --- a/indra/newview/skins/default/xui/en/floater_poser.xml +++ b/indra/newview/skins/default/xui/en/floater_poser.xml @@ -1229,12 +1229,28 @@ width="565"> height="21" follows="left|top" layout="topleft" + label="Redo Position" + image_overlay="Script_Redo" + image_overlay_alignment="left" + image_unselected="Toolbar_Middle_Off" + name="redo_position_change" + tool_tip="Redo the last position change" + width="110" + top_delta="0" + left_pad="4"> + + + + +