FIRE-30873: build new UI control for trackpad

and tidy up
master
Angeldark Raymaker 2024-09-11 23:45:29 +01:00
parent 55aab0a164
commit 31ac69435e
7 changed files with 419 additions and 85 deletions

View File

@ -169,6 +169,7 @@ set(viewer_SOURCE_FILES
fsscriptlibrary.cpp
fsscrolllistctrl.cpp
fsslurlcommand.cpp
fsvirtualtrackpad.cpp
fsworldmapmessage.cpp
lggbeamcolormapfloater.cpp
lggbeammapfloater.cpp

View File

@ -31,7 +31,7 @@
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llsdserialize.h"
#include "llvirtualtrackball.h"
#include "fsvirtualtrackpad.h"
#include "llfloater.h"
#include "llviewercontrol.h"
#include "llcontrolavatar.h"
@ -124,10 +124,7 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
mCommitCallbackRegistrar.add("Poser.TrackBallMove", boost::bind(&FSFloaterPoser::onLimbTrackballChanged, this)); // so I can debug
}
FSFloaterPoser::~FSFloaterPoser()
{
clearRecentlySetRotations();
}
FSFloaterPoser::~FSFloaterPoser() {}
bool FSFloaterPoser::postBuild()
{
@ -741,25 +738,12 @@ void FSFloaterPoser::onToggleSympatheticChange()
void FSFloaterPoser::onUndoLastRotation()
{
auto size = _lastSetRotations.size();
if (size < 2)
FSVirtualTrackpad *trackBall = getChild<FSVirtualTrackpad>(POSER_AVATAR_TRACKBALL_NAME);
if (!trackBall)
return;
_lastSetRotations.pop();
LLVector3 lastRotation = _lastSetRotations.top();
setSelectedJointsRotation(lastRotation.mV[VX], lastRotation.mV[VY], lastRotation.mV[VZ]);
}
void FSFloaterPoser::clearRecentlySetRotations()
{
while (!_lastSetRotations.empty())
_lastSetRotations.pop();
}
void FSFloaterPoser::addRotationToRecentlySet(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians)
{
_lastSetRotations.push(LLVector3(yawInRadians, pitchInRadians, rollInRadians));
trackBall->undoLastValue();
onLimbTrackballChanged();
}
void FSFloaterPoser::onToggleAdvancedPanel()
@ -934,44 +918,31 @@ void FSFloaterPoser::onAvatarPositionSet()
/// </summary>
void FSFloaterPoser::onLimbTrackballChanged()
{
LLVirtualTrackball *trackBall = getChild<LLVirtualTrackball>(POSER_AVATAR_TRACKBALL_NAME);
FSVirtualTrackpad *trackBall = getChild<FSVirtualTrackpad>(POSER_AVATAR_TRACKBALL_NAME);
if (!trackBall)
return;
LLVector2 trackPadPos;
LLSD position = trackBall->getValue();
if (position.isArray() && position.size() == 2)
trackPadPos.setValue(position);
else
return;
LLSliderCtrl *pitchSlider = getChild<LLSliderCtrl>(POSER_AVATAR_SLIDER_PITCH_NAME); // up/down
LLSliderCtrl *yawSlider = getChild<LLSliderCtrl>(POSER_AVATAR_SLIDER_YAW_NAME); // left right
LLSliderCtrl *rollSlider = getChild<LLSliderCtrl>(POSER_AVATAR_SLIDER_ROLL_NAME);
if (!yawSlider || !pitchSlider || !rollSlider)
return;
LLQuaternion trackBallQuat = trackBall->getRotation();
// Convert the quaternion to a cartesian (x,y,z) point on a unit-sphere
LLVector3 cartesionPoint = VectorZero * trackBallQuat; // VX is +up/-down screen; VY is +right/-left screen; VZ is +in/-out; all are ranged 1..-1
F32 yaw, pitch, roll;
if (cartesionPoint.mV[VZ] >= 0) // the sun is in front of the trackball, easy math
{
yaw = cartesionPoint.mV[VX] * F_PI_BY_TWO;
pitch = cartesionPoint.mV[VY] * F_PI_BY_TWO;
}
else // when the sun is behind the trackball (VZ < 0), we want to keep increasing the angle
{
// this is a first pass, and does not consider sensitivity changes around the edges.
// it could be worth disallowing VZ < 0, or only allowing as an advanced feature.
if (cartesionPoint.mV[VX] >= 0) // sun is in top hemisphere
yaw = F_PI_BY_TWO * (2 - cartesionPoint.mV[VX]);
else
yaw = -1 * F_PI_BY_TWO - F_PI_BY_TWO * (1 + cartesionPoint.mV[VX]);
yaw = trackPadPos.mV[VX];
pitch = trackPadPos.mV[VY];
if (cartesionPoint.mV[VY] >= 0) // sun is in screen-right hemisphere
pitch = F_PI_BY_TWO * (2 - cartesionPoint.mV[VY]);
else
pitch = -1 * F_PI_BY_TWO - F_PI_BY_TWO * (1 + cartesionPoint.mV[VY]);
}
roll = rollSlider->getValue().asReal(); // roll comes from the slider
yaw *= F_PI;
pitch *= F_PI;
roll = rollSlider->getValue().asReal(); // roll comes from its own slider
roll *= DEG_TO_RAD;
setSelectedJointsRotation(yaw, pitch, roll);
@ -997,22 +968,16 @@ void FSFloaterPoser::onLimbYawPitchRollChanged()
yaw *= DEG_TO_RAD;
pitch *= DEG_TO_RAD;
roll *= DEG_TO_RAD;
setSelectedJointsRotation(yaw, pitch, roll);
yaw *= F_PI;
pitch *= F_PI;
roll *= F_PI; // roll needs to be recalculated from unit sphere based on ranges of yaw and roll
LLVector3 vec3 = LLVector3(yaw, pitch, roll);
LLQuaternion quat;
quat.unpackFromVector3(vec3);
quat.setAngleAxis(pitch, 0, 1, 0);
LLVirtualTrackball *trackBall = getChild<LLVirtualTrackball>(POSER_AVATAR_TRACKBALL_NAME);
FSVirtualTrackpad *trackBall = getChild<FSVirtualTrackpad>(POSER_AVATAR_TRACKBALL_NAME);
if (!trackBall)
return;
trackBall->setRotation(quat);
yaw /= F_PI;
pitch /= F_PI;
trackBall->setValue(yaw, pitch);
}
void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z)
@ -1040,8 +1005,6 @@ void FSFloaterPoser::setSelectedJointsRotation(F32 yawInRadians, F32 pitchInRadi
if (!_poserAnimator.isPosingAvatar(avatar))
return;
addRotationToRecentlySet(yawInRadians, pitchInRadians, rollInRadians);
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
LLVector3 vec3 = LLVector3(yawInRadians, pitchInRadians, rollInRadians);
@ -1078,26 +1041,10 @@ void FSFloaterPoser::onJointSelect()
if (!_poserAnimator.isPosingAvatar(avatar))
return;
clearRecentlySetRotations();
LLVector3 rotation = _poserAnimator.getJointRotation(avatar, *selectedJoints.front());
F32 yaw = rotation.mV[VX];
F32 pitch = rotation.mV[VY];
F32 roll = rotation.mV[VZ];
if (is_approx_zero(pitch))
pitch = F_APPROXIMATELY_ZERO;
LLQuaternion quat;
quat.setAngleAxis(-pitch, 0, 1, 0);
LLQuaternion az_quat;
az_quat.setAngleAxis(F_TWO_PI - yaw, 0, 0, 1);
quat *= az_quat;
LLVirtualTrackball *trackBall = getChild<LLVirtualTrackball>(POSER_AVATAR_TRACKBALL_NAME);
if (!trackBall)
return;
trackBall->setRotation(quat);
F32 yaw = rotation.mV[VX];
F32 pitch = rotation.mV[VY];
F32 roll = rotation.mV[VZ];
LLSliderCtrl *yawSlider = getChild<LLSliderCtrl>(POSER_AVATAR_SLIDER_YAW_NAME);
LLSliderCtrl *pitchSlider = getChild<LLSliderCtrl>(POSER_AVATAR_SLIDER_PITCH_NAME);
@ -1108,6 +1055,10 @@ void FSFloaterPoser::onJointSelect()
yawSlider->setValue(yaw *= RAD_TO_DEG);
pitchSlider->setValue(pitch *= RAD_TO_DEG);
rollSlider->setValue(roll *= RAD_TO_DEG);
FSVirtualTrackpad *trackBall = getChild<FSVirtualTrackpad>(POSER_AVATAR_TRACKBALL_NAME);
if (trackBall)
trackBall->setValue(yaw /= 180, pitch /= 180);
}
/// <summary>

View File

@ -77,8 +77,7 @@ class FSFloaterPoser : public LLFloater
std::vector<FSPoserAnimator::FSPoserJoint *> getUiSelectedPoserJoints();
LLVOAvatar *getUiSelectedAvatar();
E_BoneDeflectionStyles getUiSelectedBoneDeflectionStyle();
void addRotationToRecentlySet(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians);
void clearRecentlySetRotations();
void setSelectedJointsRotation(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians);
void setSelectedJointsPosition(F32 x, F32 y, F32 z);
void setSelectedJointsScale(F32 x, F32 y, F32 z);
@ -124,7 +123,6 @@ class FSFloaterPoser : public LLFloater
private:
FSPoserAnimator _poserAnimator;
std::stack<LLVector3> _lastSetRotations;
};
#endif

View File

@ -0,0 +1,243 @@
/**
* @file irtualTrackpad.cpp
* @author Angeldark Raymaker; derived from llVirtualTrackball by Andrey Lihatskiy
* @brief Header file for FSVirtualTrackpad
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2018, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// A two dimensional slider control with optional pinch-mode.
#include "fsvirtualtrackpad.h"
#include "llrect.h"
#include "lluictrlfactory.h"
// Globals
static LLDefaultChildRegistry::Register<FSVirtualTrackpad> register_virtual_trackball("fs_virtual_trackpad");
FSVirtualTrackpad::Params::Params()
: border("border"),
image_moon_back("image_moon_back"),
image_moon_front("image_moon_front"),
image_sphere("image_sphere"),
image_sun_back("image_sun_back"),
image_sun_front("image_sun_front"),
pinch_mode("pinch_mode")
{
}
FSVirtualTrackpad::FSVirtualTrackpad(const FSVirtualTrackpad::Params &p)
: LLUICtrl(p),
mImgMoonBack(p.image_moon_back),
mImgMoonFront(p.image_moon_front),
mImgSunBack(p.image_sun_back),
mImgSunFront(p.image_sun_front),
mImgSphere(p.image_sphere),
mAllowPinchMode(p.pinch_mode)
{
LLRect border_rect = getLocalRect();
S32 centerX = border_rect.getCenterX();
S32 centerY = border_rect.getCenterY();
mValue.set(centerX, centerY);
mPinchValue.set(centerX, centerY);
mLastValue.set(centerX, centerY);
mLastPinchValue.set(centerX, centerY);
LLViewBorder::Params border = p.border;
border.rect(border_rect);
mBorder = LLUICtrlFactory::create<LLViewBorder>(border);
addChild(mBorder);
LLPanel::Params touch_area;
touch_area.rect = LLRect(border_rect);
mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area);
addChild(mTouchArea);
}
FSVirtualTrackpad::~FSVirtualTrackpad() {}
bool FSVirtualTrackpad::postBuild()
{
return true;
}
void FSVirtualTrackpad::drawThumb(const LLVector2 vec, bool isPinchThumb)
{
LLUIImage *thumb = isPinchThumb ? mImgSunFront : mImgMoonFront;
thumb->draw(LLRect(vec.mV[VX] - thumb->getWidth() / 2,
vec.mV[VY] + thumb->getHeight() / 2,
vec.mV[VX] + thumb->getWidth() / 2,
vec.mV[VY] - thumb->getHeight() / 2));
}
bool FSVirtualTrackpad::isPointInTouchArea(S32 x, S32 y) const
{
if (!mTouchArea)
return false;
return mTouchArea->getRect().localPointInRect(x, y);
}
void FSVirtualTrackpad::draw()
{
mImgSphere->draw(mTouchArea->getRect(), UI_VERTEX_COLOR);
if (mAllowPinchMode)
drawThumb(mPinchValue, true);
drawThumb(mValue, false);
LLView::draw();
}
void FSVirtualTrackpad::setValue(const LLSD& value)
{
if (value.isArray() && value.size() == 2)
mValue.setValue(value);
}
void FSVirtualTrackpad::setValue(F32 x, F32 y) { mValue = convertNormalizedToPixelPos(x, y); }
void FSVirtualTrackpad::setPinchValue(F32 x, F32 y) { mPinchValue = convertNormalizedToPixelPos(x, y); }
void FSVirtualTrackpad::undoLastValue() { setValueAndCommit(mLastValue); }
void FSVirtualTrackpad::undoLastSetPinchValue() { setPinchValueAndCommit(mLastValue); }
void FSVirtualTrackpad::setValueAndCommit(const LLVector2 vec)
{
mValue.set(vec);
onCommit();
}
void FSVirtualTrackpad::setPinchValueAndCommit(const LLVector2 vec)
{
mPinchValue.set(vec);
onCommit();
}
LLSD FSVirtualTrackpad::getValue() const { return normalizePixelPosToCenter(mValue).getValue(); }
LLSD FSVirtualTrackpad::getPinchValue() const { return normalizePixelPosToCenter(mPinchValue).getValue(); }
bool FSVirtualTrackpad::handleHover(S32 x, S32 y, MASK mask)
{
if (!hasMouseCapture())
return true;
bool slowMode = mask == MASK_CONTROL;
LLRect rect = mTouchArea->getRect();
rect.clampPointToRect(x, y);
if (doingPinchMode)
mPinchValue.set(x, y);
else
mValue.set(x, y);
onCommit();
return true;
}
LLVector2 FSVirtualTrackpad::normalizePixelPosToCenter(LLVector2 pixelPos) const
{
LLVector2 result;
if (!mTouchArea)
return result;
LLRect rect = mTouchArea->getRect();
S32 centerX = rect.getCenterX();
S32 centerY = rect.getCenterY();
S32 width = rect.getWidth();
S32 height = rect.getHeight();
result.mV[VX] = (pixelPos.mV[VX] - centerX) / width * 2;
result.mV[VY] = (pixelPos.mV[VY] - centerY) / height * 2;
return result;
}
LLVector2 FSVirtualTrackpad::convertNormalizedToPixelPos(F32 x, F32 y)
{
LLVector2 result;
if (!mTouchArea)
return result;
LLRect rect = mTouchArea->getRect();
S32 centerX = rect.getCenterX();
S32 centerY = rect.getCenterY();
S32 width = rect.getWidth();
S32 height = rect.getHeight();
result.mV[VX] = (centerX + x * width / 2);
result.mV[VY] = (centerY + y * height / 2);
return result;
}
bool FSVirtualTrackpad::handleMouseUp(S32 x, S32 y, MASK mask)
{
if (hasMouseCapture())
{
doingPinchMode = false;
gFocusMgr.setMouseCapture(NULL);
make_ui_sound("UISndClickRelease");
}
return LLView::handleMouseUp(x, y, mask);
}
bool FSVirtualTrackpad::handleMouseDown(S32 x, S32 y, MASK mask)
{
if (isPointInTouchArea(x, y))
{
mLastValue.set(mValue);
gFocusMgr.setMouseCapture(this);
make_ui_sound("UISndClick");
}
return LLView::handleMouseDown(x, y, mask);
}
// move pinch cursor
bool FSVirtualTrackpad::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
if (!mAllowPinchMode)
return LLView::handleRightMouseDown(x, y, mask);
if (isPointInTouchArea(x, y))
{
mLastPinchValue.set(mPinchValue);
doingPinchMode = true;
gFocusMgr.setMouseCapture(this);
make_ui_sound("UISndClick");
}
return LLView::handleRightMouseDown(x, y, mask);
}

View File

@ -0,0 +1,123 @@
/**
* @file fsvirtualtrackpad.h
* @author Angeldark Raymaker; derived from llVirtualTrackball by Andrey Lihatskiy
* @brief Header file for FSVirtualTrackpad
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2018, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// A two dimensional slider control with optional pinch-mode.
#ifndef LL_FSVIRTUALTRACKPAD_H
#define LL_FSVIRTUALTRACKPAD_H
#include "lluictrl.h"
#include "llpanel.h"
class FSVirtualTrackpad
: public LLUICtrl
{
public:
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<LLViewBorder::Params> border;
Optional<LLUIImage *> image_moon_back, image_moon_front, image_sphere, image_sun_back, image_sun_front;
Optional<bool> pinch_mode;
Optional<bool> allow_drag_outside;
Params();
};
virtual ~FSVirtualTrackpad();
/*virtual*/ bool postBuild();
virtual bool handleHover(S32 x, S32 y, MASK mask);
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual void draw();
virtual void setValue(const LLSD& value);
/// <summary>
/// Sets the position of the cursor.
/// </summary>
/// <param name="x">The x-axis (left/right) position to set; expected range -1..1; left= -1</param>
/// <param name="y">The y-axis (top/bottom) position to set; expected range 1..-1; top = 1</param>
void setValue(F32 x, F32 y);
void undoLastValue();
void undoLastSetPinchValue();
/// <summary>
/// Sets the position of the second cursor.
/// </summary>
/// <param name="x">The normalized x-axis value (ordinarily screen left-right), expected left-to-right range -1..1.</param>
/// <param name="y">The normalized y-axis value (ordinarily screen up-down), expected top-to-bottom range 1..-1</param>
void setPinchValue(F32 x, F32 y);
virtual LLSD getValue() const;
virtual LLSD getPinchValue() const;
protected:
friend class LLUICtrlFactory;
FSVirtualTrackpad(const Params&);
protected:
LLPanel* mTouchArea;
LLViewBorder* mBorder;
private:
void setValueAndCommit(const LLVector2 vec);
void setPinchValueAndCommit(const LLVector2 vec);
void drawThumb(LLVector2 vec, bool isPinchThumb);
bool isPointInTouchArea(S32 x, S32 y) const;
LLVector2 normalizePixelPosToCenter(LLVector2 vec) const;
LLVector2 convertNormalizedToPixelPos(F32 x, F32 y);
LLUIImage* mImgMoonBack;
LLUIImage* mImgMoonFront;
LLUIImage* mImgSunBack;
LLUIImage* mImgSunFront;
LLUIImage* mImgSphere;
/// <summary>
/// Whether we allow the second cursor to appear.
/// </summary>
bool mAllowPinchMode = false;
/// <summary>
/// Whether we should be moving the pinch cursor now
/// </summary>
bool doingPinchMode = false;
LLVector2 mValue;
LLVector2 mPinchValue;
LLVector2 mLastValue;
LLVector2 mLastPinchValue;
};
#endif

View File

@ -510,13 +510,13 @@ width="565">
left="5"
top="2"
width="105">Rotation:</text>
<sun_moon_trackball name="limb_rotation"
<fs_virtual_trackpad name="limb_rotation"
follows="left|top"
left_delta="0"
top_delta="15"
height="153"
width="153"
tool_tip="Change the rotation of the currently selected joint(s). Hold CTRL/CMD while changing for easy-rolling"
tool_tip="Change the rotation of the currently selected joint(s). Hold CTRL/CMD while changing for slow-motion"
thumb_mode="sun"/>
<panel
follows="left|top|bottom"

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<fs_virtual_trackball
name="virtualtrackpad"
width="150"
height="150"
pinch_mode="false"
user_resize="false"
image_sphere="VirtualTrackball_Sphere"
image_moon_back="VirtualTrackball_Moon_Back"
image_moon_front="VirtualTrackball_Moon_Front"
image_sun_back="VirtualTrackball_Sun_Back"
image_sun_front="VirtualTrackball_Sun_Front">
<fs_virtual_trackball.border
visible="true"/>
</fs_virtual_trackball>