FIRE-30873: Add redo buttons to advanced areas

master
Angeldark Raymaker 2024-10-08 23:24:38 +01:00
parent d0465c9e6e
commit aebd67f10d
6 changed files with 317 additions and 25 deletions

View File

@ -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<LLButton>(POSER_AVATAR_BUTTON_REDO);

View File

@ -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();

View File

@ -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;

View File

@ -270,6 +270,13 @@ public:
/// <param name="joint">The joint with the position to undo.</param>
void undoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style);
/// <summary>
/// Undoes the last applied scale to the supplied PoserJoint.
/// </summary>
/// <param name="avatar">The avatar having the joint to which we refer.</param>
/// <param name="joint">The joint with the scale to undo.</param>
void undoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style);
/// <summary>
/// Resets the position of the supplied PoserJoint.
/// </summary>
@ -299,6 +306,20 @@ public:
/// <param name="joint">The joint with the rotation to redo.</param>
void redoLastJointRotation(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style);
/// <summary>
/// Re-does the last undone position to the supplied PoserJoint.
/// </summary>
/// <param name="avatar">The avatar having the joint to which we refer.</param>
/// <param name="joint">The joint with the position to redo.</param>
void redoLastJointPosition(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style);
/// <summary>
/// Re-does the last undone scale to the supplied PoserJoint.
/// </summary>
/// <param name="avatar">The avatar having the joint to which we refer.</param>
/// <param name="joint">The joint with the scale to redo.</param>
void redoLastJointScale(LLVOAvatar* avatar, FSPoserJoint joint, E_BoneDeflectionStyles style);
/// <summary>
/// Gets the position of a joint for the supplied avatar.
/// </summary>

View File

@ -85,6 +85,8 @@ public:
LLVector3 _targetScale;
LLVector3 _beginningScale;
std::deque<LLVector3> _lastSetScales;
size_t _undoneScaleIndex = 0;
std::chrono::system_clock::time_point _timeLastUpdatedScale = std::chrono::system_clock::now();
/// <summary>
/// Adds a last position to the deque.
@ -124,6 +126,34 @@ public:
_lastSetRotations.pop_back();
}
/// <summary>
/// Adds a last rotation to the deque.
/// </summary>
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:
/// <summary>
/// Gets the name of the joint.
@ -217,7 +247,7 @@ public:
_targetPosition.set(_lastSetPositions[_undonePositionIndex]);
if (_undonePositionIndex == 0)
_lastSetRotations.pop_front();
_lastSetPositions.pop_front();
}
/// <summary>
@ -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);
}
/// <summary>
@ -289,12 +351,8 @@ public:
/// </summary>
void revertJointScale()
{
LLJoint* joint = _jointState->getJoint();
if (!joint)
return;
_targetScale = _beginningScale;
joint->setScale(_beginningScale);
_targetScale.set(_beginningScale);
setScale(_beginningScale);
}
/// <summary>

View File

@ -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">
<button.commit_callback
function="Poser.RedoLastPosition"/>
</button>
<button
height="21"
follows="left|top"
layout="topleft"
label="Reset Position"
image_overlay="Inv_TrashOpen"
image_overlay_alignment="left"
image_unselected="Toolbar_Middle_Off"
name="undo_position_change"
tool_tip="Reset position back to original"
tool_tip="Double click to reset position back to original"
width="110"
top_delta="0"
left_pad="4">
@ -1316,15 +1332,47 @@ width="565">
height="21"
follows="left|top"
layout="topleft"
label="Reset Scale Change"
image_overlay="Inv_TrashOpen"
label="Undo Scale Change"
image_overlay="Script_Undo"
image_overlay_alignment="left"
image_unselected="Toolbar_Middle_Off"
name="reset_scale_change"
tool_tip="Reset the scale of the selected body part(s) to normal"
name="undo_position_change"
tool_tip="Undo the last scale change"
width="150"
top_pad="2"
left_delta="0">
<button.commit_callback
function="Poser.UndoLastScale"/>
</button>
<button
height="21"
follows="left|top"
layout="topleft"
label="Redo Scale"
image_overlay="Script_Redo"
image_overlay_alignment="left"
image_unselected="Toolbar_Middle_Off"
name="redo_scale_change"
tool_tip="Redo the last scale change"
width="110"
top_delta="0"
left_pad="4">
<button.commit_callback
function="Poser.RedoLastScale"/>
</button>
<button
height="21"
follows="left|top"
layout="topleft"
label="Reset Scale"
image_overlay="Inv_TrashOpen"
image_overlay_alignment="left"
image_unselected="Toolbar_Middle_Off"
name="undo_scale_change"
tool_tip="Double click to reset scale back to original"
width="110"
top_delta="0"
left_pad="4">
<button.commit_callback
function="Poser.ResetScale"/>
</button>