/** * @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 { Optional border; Optional image_moon_back, image_moon_front, image_sphere, image_sun_back, image_sun_front; Optional pinch_mode; Optional infinite_scroll_mode; Params(); }; virtual ~FSVirtualTrackpad(); 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 handleRightMouseUp(S32 x, S32 y, MASK mask); virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask); virtual bool handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void draw(); virtual void setValue(const LLSD& value); /// /// Sets the position of the cursor. /// /// The x-axis (left/right) position to set; expected range -1..1; left= -1 /// The y-axis (top/bottom) position to set; expected range 1..-1; top = 1 /// The z-axis position to set; expected range 1..-1; top = 1 void setValue(F32 x, F32 y, F32 z); /// /// Sets the position of the second cursor. /// /// The normalized x-axis value (ordinarily screen left-right), expected left-to-right range -1..1. /// The normalized y-axis value (ordinarily screen up-down), expected top-to-bottom range 1..-1 /// The normalized z-axis value, expected top-to-bottom range 1..-1 void setPinchValue(F32 x, F32 y, F32 z); /// /// Gets the current position of the first 3-axis cursor. /// virtual LLSD getValue() const; /// /// Gets the most recent delta of position of the first 3-axis cursor. /// virtual LLSD getValueDelta(); /// /// Gets the current position of the second 3-axis cursor. /// virtual LLSD getPinchValue(); /// /// Gets the most recent delta of position of the second 3-axis cursor. /// virtual LLSD getPinchValueDelta(); protected: friend class LLUICtrlFactory; FSVirtualTrackpad(const Params&); protected: LLPanel* mTouchArea{ nullptr }; LLViewBorder* mBorder{ nullptr }; private: const F32 ThirdAxisQuantization = 0.001f; // To avoid quantizing the third axis as we add integer wheel clicks, use this to preserve some precision as int. const S32 WheelClickQuanta = 10; // each click of the wheel moves the third axis by this normalized amount. void drawThumb(bool isPinchThumb); bool isPointInTouchArea(S32 x, S32 y) const; void wrapOrClipCursorPosition(S32* x, S32* y) const; void determineThumbClickError(S32 x, S32 y); void updateClickErrorIfInfiniteScrolling(); void determineThumbClickErrorForPinch(S32 x, S32 y); void updateClickErrorIfInfiniteScrollingForPinch(); void convertNormalizedToPixelPos(F32 x, F32 y, F32 z, S32* valX, S32* valY, S32* valZ); LLVector3 normalizePixelPos(S32 x, S32 y, S32 z) const; LLVector3 normalizeDelta(S32 x, S32 y, S32 z) const; void getHoverMovementDeltas(S32 x, S32 y, MASK mask, S32* deltaX, S32* deltaY, S32* deltaZ); void applyHoverMovementDeltas(S32 deltaX, S32 deltaY, MASK mask); void applyDeltasToValues(S32 deltaX, S32 deltaY, MASK mask); void applyDeltasToDeltaValues(S32 deltaX, S32 deltaY, S32 deltaZ, MASK mask); LLUIImage* mImgMoonBack{ nullptr }; LLUIImage* mImgMoonFront{ nullptr }; LLUIImage* mImgSunBack{ nullptr }; LLUIImage* mImgSunFront{ nullptr }; LLUIImage* mImgSphere{ nullptr }; /// /// Whether we allow the second cursor to appear. /// bool mAllowPinchMode{ false }; /// /// Whether we should be moving the pinch cursor now /// bool mDoingPinchMode{ false }; /// /// Whether to allow the cursor(s) to 'wrap'. /// /// /// When false, the cursor is constrained to the control-area. /// When true, the cursor 'disappears' out the top, and starts from the bottom, /// effectively allowing infinite scrolling. /// bool mInfiniteScrollMode{ false }; bool mHeldDownControlBefore{ false }; /// /// The values the owner will get and set. /// S32 mWheelClicksSinceLastDelta{ 0 }; /// /// The values the owner will get and set. /// S32 mValueX{ 0 }; S32 mValueY{ 0 }; S32 mValueZ{ 0 }; S32 mPinchValueX{ 0 }; S32 mPinchValueY{ 0 }; S32 mPinchValueZ{ 0 }; /// /// The delta values the owner will get and set. /// S32 mValueDeltaX{ 0 }; S32 mValueDeltaY{ 0 }; S32 mValueDeltaZ{ 0 }; S32 mPinchValueDeltaX{ 0 }; S32 mPinchValueDeltaY{ 0 }; S32 mPinchValueDeltaZ{ 0 }; /// /// The various values placing the cursors and documenting behaviours. /// Where relevant, all are scaled in pixels. /// S32 mCursorValueX{ 0 }; S32 mCursorValueY{ 0 }; S32 mCursorValueZ{ 0 }; S32 mPinchCursorValueX{ 0 }; S32 mPinchCursorValueY{ 0 }; S32 mPinchCursorValueZ{ 0 }; // if one clicks on or about the thumb, we don't move it, instead we calculate the click-position error and factor it out S32 mThumbClickOffsetX{ 0 }; S32 mThumbClickOffsetY{ 0 }; S32 mPinchThumbClickOffsetX{ 0 }; S32 mPinchThumbClickOffsetY{ 0 }; S32 mPosXwhenCtrlDown{ 0 }; S32 mPosYwhenCtrlDown{ 0 }; }; #endif