diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/CMakeLists.txt | 4 | ||||
-rw-r--r-- | indra/llui/llmultislider.cpp | 121 | ||||
-rw-r--r-- | indra/llui/llmultislider.h | 7 | ||||
-rw-r--r-- | indra/llui/llmultisliderctrl.cpp | 12 | ||||
-rw-r--r-- | indra/llui/llmultisliderctrl.h | 8 | ||||
-rw-r--r-- | indra/llui/llslider.cpp | 5 | ||||
-rw-r--r-- | indra/llui/llui.h | 5 | ||||
-rw-r--r-- | indra/llui/llvirtualtrackball.cpp | 449 | ||||
-rw-r--r-- | indra/llui/llvirtualtrackball.h | 155 | ||||
-rw-r--r-- | indra/llui/llxyvector.cpp | 306 | ||||
-rw-r--r-- | indra/llui/llxyvector.h | 118 |
11 files changed, 1157 insertions, 33 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 8054eb3619..54e4d296ab 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -133,8 +133,10 @@ set(llui_SOURCE_FILES llview.cpp llviewquery.cpp llviewereventrecorder.cpp + llvirtualtrackball.cpp llwindowshade.cpp llxuiparser.cpp + llxyvector.cpp ) set(llui_HEADER_FILES @@ -249,8 +251,10 @@ set(llui_HEADER_FILES llview.h llviewereventrecorder.h llviewquery.h + llvirtualtrackball.h llwindowshade.h llxuiparser.h + llxyvector.h ) set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 0aa3e17075..725f1e8f65 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -54,6 +54,8 @@ LLMultiSlider::SliderParams::SliderParams() LLMultiSlider::Params::Params() : max_sliders("max_sliders", 1), allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + overlap_threshold("overlap_threshold", 0), draw_track("draw_track", true), use_triangle("use_triangle", false), track_color("track_color"), @@ -74,6 +76,7 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) mDragStartThumbRect( 0, getRect().getHeight(), p.thumb_width, 0 ), mMaxNumSliders(p.max_sliders), mAllowOverlap(p.allow_overlap), + mLoopOverlap(p.loop_overlap), mDrawTrack(p.draw_track), mUseTriangle(p.use_triangle), mTrackColor(p.track_color()), @@ -98,6 +101,15 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); } + if (p.overlap_threshold.isProvided()) + { + mOverlapThreshold = p.overlap_threshold; + } + else + { + mOverlapThreshold = 0; + } + for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin(); it != p.sliders.end(); ++it) @@ -143,11 +155,33 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from // look at the current spot // and see if anything is there LLSD::map_iterator mIt = mValue.beginMap(); + + // increment is our distance between points, use to eliminate round error + F32 threshold = mOverlapThreshold + (mIncrement / 4); + // If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower) + F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : 0.0f; + // If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper) + F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : 0.0f; + for(;mIt != mValue.endMap(); mIt++) { F32 testVal = (F32)mIt->second.asReal() - newValue; - if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD && - mIt->first != name) { + if (testVal > -threshold + && testVal < threshold + && mIt->first != name) + { + hit = true; + break; + } + if (loop_up_check != 0 + && testVal < loop_up_check) + { + hit = true; + break; + } + if (loop_down_check != 0 + && testVal > loop_down_check) + { hit = true; break; } @@ -196,7 +230,11 @@ void LLMultiSlider::setValue(const LLSD& value) F32 LLMultiSlider::getSliderValue(const std::string& name) const { - return (F32)mValue[name].asReal(); + if (mValue.has(name)) + { + return (F32)mValue[name].asReal(); + } + return 0; } void LLMultiSlider::setCurSlider(const std::string& name) @@ -206,6 +244,24 @@ void LLMultiSlider::setCurSlider(const std::string& name) } } +F32 LLMultiSlider::getSliderValueFromX(S32 xpos) const +{ + S32 left_edge = mThumbWidth / 2; + S32 right_edge = getRect().getWidth() - (mThumbWidth / 2); + + xpos += mMouseOffset; + xpos = llclamp(xpos, left_edge, right_edge); + + F32 t = F32(xpos - left_edge) / (right_edge - left_edge); + + return((t * (mMaxValue - mMinValue)) + mMinValue); +} + +void LLMultiSlider::resetCurSlider() +{ + mCurSlider = LLStringUtil::null; +} + const std::string& LLMultiSlider::addSlider() { return addSlider(mInitialValue); @@ -278,11 +334,13 @@ bool LLMultiSlider::findUnusedValue(F32& initVal) // look at the current spot // and see if anything is there + F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4); LLSD::map_iterator mIt = mValue.beginMap(); for(;mIt != mValue.endMap(); mIt++) { F32 testVal = (F32)mIt->second.asReal() - initVal; - if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD) { + if(testVal > -threshold && testVal < threshold) + { hit = true; break; } @@ -334,10 +392,15 @@ void LLMultiSlider::deleteSlider(const std::string& name) void LLMultiSlider::clear() { - while(mThumbRects.size() > 0) { + while(mThumbRects.size() > 0 && mValue.size() > 0) { deleteCurSlider(); } + if (mThumbRects.size() > 0 || mValue.size() > 0) + { + LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL; + } + LLF32UICtrl::clear(); } @@ -345,14 +408,15 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) { if( gFocusMgr.getMouseCapture() == this ) { - S32 left_edge = mThumbWidth/2; - S32 right_edge = getRect().getWidth() - (mThumbWidth/2); - - x += mMouseOffset; - x = llclamp( x, left_edge, right_edge ); - - F32 t = F32(x - left_edge) / (right_edge - left_edge); - setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue ); +// S32 left_edge = mThumbWidth/2; +// S32 right_edge = getRect().getWidth() - (mThumbWidth/2); +// +// x += mMouseOffset; +// x = llclamp( x, left_edge, right_edge ); +// +// F32 t = F32(x - left_edge) / (right_edge - left_edge); +// setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue ); + setCurSliderValue(getSliderValueFromX(x)); onCommit(); getWindow()->setCursor(UI_CURSOR_ARROW); @@ -416,20 +480,23 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask) } } - // Find the offset of the actual mouse location from the center of the thumb. - if (mThumbRects[mCurSlider].pointInRect(x,y)) + if (!mCurSlider.empty()) { - mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x; - } - else - { - mMouseOffset = 0; - } + // Find the offset of the actual mouse location from the center of the thumb. + if (mThumbRects[mCurSlider].pointInRect(x,y)) + { + mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x; + } + else + { + mMouseOffset = 0; + } - // Start dragging the thumb - // No handler needed for focus lost since this class has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - mDragStartThumbRect = mThumbRects[mCurSlider]; + // Start dragging the thumb + // No handler needed for focus lost since this class has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + mDragStartThumbRect = mThumbRects[mCurSlider]; + } } make_ui_sound("UISndClick"); @@ -546,7 +613,7 @@ void LLMultiSlider::draw() thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); // draw the highlight - if (hasFocus()) + if (hasFocus() && !mCurSlider.empty()) { thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); } @@ -578,7 +645,7 @@ void LLMultiSlider::draw() else { // draw highlight - if (hasFocus()) + if (hasFocus() && !mCurSlider.empty()) { thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); } diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index 2b422e89c9..eff0c7d2d7 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -47,9 +47,12 @@ public: Optional<S32> max_sliders; Optional<bool> allow_overlap, + loop_overlap, draw_track, use_triangle; + Optional<F32> overlap_threshold; + Optional<LLUIColor> track_color, thumb_disabled_color, thumb_outline_color, @@ -72,10 +75,12 @@ public: virtual ~LLMultiSlider(); void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE); F32 getSliderValue(const std::string& name) const; + F32 getSliderValueFromX(S32 xpos) const; const std::string& getCurSlider() const { return mCurSlider; } F32 getCurSliderValue() const { return getSliderValue(mCurSlider); } void setCurSlider(const std::string& name); + void resetCurSlider(); void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); } /*virtual*/ void setValue(const LLSD& value); @@ -105,6 +110,8 @@ protected: S32 mMaxNumSliders; BOOL mAllowOverlap; + BOOL mLoopOverlap; + F32 mOverlapThreshold; BOOL mDrawTrack; BOOL mUseTriangle; /// hacked in toggle to use a triangle diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index c460a08afc..4c2936eb69 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -53,6 +53,8 @@ LLMultiSliderCtrl::Params::Params() can_edit_text("can_edit_text", false), max_sliders("max_sliders", 1), allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + overlap_threshold("overlap_threshold", 0), draw_track("draw_track", true), use_triangle("use_triangle", false), decimal_digits("decimal_digits", 3), @@ -167,6 +169,11 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.increment(p.increment); params.max_sliders(p.max_sliders); params.allow_overlap(p.allow_overlap); + params.loop_overlap(p.loop_overlap); + if (p.overlap_threshold.isProvided()) + { + params.overlap_threshold = p.overlap_threshold; + } params.draw_track(p.draw_track); params.use_triangle(p.use_triangle); params.control_name(p.control_name); @@ -213,6 +220,11 @@ void LLMultiSliderCtrl::setCurSlider(const std::string& name) mCurValue = mMultiSlider->getCurSliderValue(); } +void LLMultiSliderCtrl::resetCurSlider() +{ + mMultiSlider->resetCurSlider(); +} + BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) { BOOL res = FALSE; diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index b6a3542376..0ce21c0612 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -54,9 +54,12 @@ public: Optional<S32> decimal_digits; Optional<S32> max_sliders; Optional<bool> allow_overlap, + loop_overlap, draw_track, use_triangle; + Optional<F32> overlap_threshold; + Optional<LLUIColor> text_color, text_disabled_color; @@ -74,7 +77,7 @@ protected: public: virtual ~LLMultiSliderCtrl(); - F32 getSliderValue(const std::string& name) const; + F32 getSliderValue(const std::string& name) const { return mMultiSlider->getSliderValue(name); } void setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE); virtual void setValue(const LLSD& value ); @@ -84,6 +87,7 @@ public: const std::string& getCurSlider() const { return mMultiSlider->getCurSlider(); } F32 getCurSliderValue() const { return mCurValue; } void setCurSlider(const std::string& name); + void resetCurSlider(); void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); } virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } @@ -98,6 +102,8 @@ public: void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);} void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);} + F32 getSliderValueFromX(S32 x) const { return mMultiSlider->getSliderValueFromX(x); } + /// for adding and deleting sliders const std::string& addSlider(); const std::string& addSlider(F32 val); diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index ebbb951ee6..6925c0a130 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -331,8 +331,9 @@ void LLSlider::draw() highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom); } - trackImage->draw(track_rect, LLColor4::white % alpha); - trackHighlightImage->draw(highlight_rect, LLColor4::white % alpha); + LLColor4 color = isInEnabledChain() ? LLColor4::white % alpha : LLColor4::white % (0.6f * alpha); + trackImage->draw(track_rect, color); + trackHighlightImage->draw(highlight_rect, color); // Thumb if (hasFocus()) diff --git a/indra/llui/llui.h b/indra/llui/llui.h index d7151dbee9..59fc1ddcef 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -33,7 +33,6 @@ #include "llcontrol.h" #include "llcoord.h" #include "llcontrol.h" -#include "llglslshader.h" #include "llinitparam.h" #include "llregistry.h" #include "llrender2dutils.h" @@ -49,7 +48,6 @@ // for initparam specialization #include "llfontgl.h" - class LLUUID; class LLWindow; class LLView; @@ -77,7 +75,8 @@ enum EDragAndDropType DAD_MESH = 15, DAD_WIDGET = 16, DAD_PERSON = 17, - DAD_COUNT = 18, // number of types in this enum + DAD_SETTINGS = 18, + DAD_COUNT = 19, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/llui/llvirtualtrackball.cpp b/indra/llui/llvirtualtrackball.cpp new file mode 100644 index 0000000000..e73bba57bb --- /dev/null +++ b/indra/llui/llvirtualtrackball.cpp @@ -0,0 +1,449 @@ +/** +* @file LLVirtualTrackball.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLVirtualTrackball +* +* $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 control for positioning the sun and the moon in the celestial sphere. + +#include "linden_common.h" +#include "llvirtualtrackball.h" +#include "llstring.h" +#include "llrect.h" +#include "lluictrlfactory.h" +#include "llrender.h" + +// Globals +static LLDefaultChildRegistry::Register<LLVirtualTrackball> register_virtual_trackball("sun_moon_trackball"); + +const LLVector3 VectorZero(1.0f, 0.0f, 0.0f); + +LLVirtualTrackball::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"), + btn_rotate_top("button_rotate_top"), + btn_rotate_bottom("button_rotate_bottom"), + btn_rotate_left("button_rotate_left"), + btn_rotate_right("button_rotate_right"), + thumb_mode("thumb_mode"), + lbl_N("labelN"), + lbl_S("labelS"), + lbl_W("labelW"), + lbl_E("labelE"), + increment_angle_mouse("increment_angle_mouse", 0.5f), + increment_angle_btn("increment_angle_btn", 3.0f) +{ +} + +LLVirtualTrackball::LLVirtualTrackball(const LLVirtualTrackball::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), + mThumbMode(p.thumb_mode() == "moon" ? ThumbMode::MOON : ThumbMode::SUN), + mIncrementMouse(DEG_TO_RAD * p.increment_angle_mouse()), + mIncrementBtn(DEG_TO_RAD * p.increment_angle_btn()) +{ + LLRect border_rect = getLocalRect(); + S32 centerX = border_rect.getCenterX(); + S32 centerY = border_rect.getCenterY(); + U32 btn_size = 32; // width & height + U32 axis_offset_lt = 16; // offset from the axis for left/top sides + U32 axis_offset_rb = btn_size - axis_offset_lt; // and for right/bottom + + LLViewBorder::Params border = p.border; + border.rect(border_rect); + mBorder = LLUICtrlFactory::create<LLViewBorder>(border); + addChild(mBorder); + + + LLButton::Params btn_rt = p.btn_rotate_top; + btn_rt.rect(LLRect(centerX - axis_offset_lt, border_rect.mTop, centerX + axis_offset_rb, border_rect.mTop - btn_size)); + btn_rt.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); + btn_rt.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); + mBtnRotateTop = LLUICtrlFactory::create<LLButton>(btn_rt); + addChild(mBtnRotateTop); + + LLTextBox::Params lbl_N = p.lbl_N; + LLRect rect_N = btn_rt.rect; + //rect_N.translate(btn_rt.rect().getWidth(), 0); + lbl_N.rect = rect_N; + lbl_N.initial_value(lbl_N.label()); + mLabelN = LLUICtrlFactory::create<LLTextBox>(lbl_N); + addChild(mLabelN); + + + LLButton::Params btn_rr = p.btn_rotate_right; + btn_rr.rect(LLRect(border_rect.mRight - btn_size, centerY + axis_offset_lt, border_rect.mRight, centerY - axis_offset_rb)); + btn_rr.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); + btn_rr.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightClick, this)); + mBtnRotateRight = LLUICtrlFactory::create<LLButton>(btn_rr); + addChild(mBtnRotateRight); + + LLTextBox::Params lbl_E = p.lbl_E; + LLRect rect_E = btn_rr.rect; + //rect_E.translate(0, -1 * btn_rr.rect().getHeight()); + lbl_E.rect = rect_E; + lbl_E.initial_value(lbl_E.label()); + mLabelE = LLUICtrlFactory::create<LLTextBox>(lbl_E); + addChild(mLabelE); + + + LLButton::Params btn_rb = p.btn_rotate_bottom; + btn_rb.rect(LLRect(centerX - axis_offset_lt, border_rect.mBottom + btn_size, centerX + axis_offset_rb, border_rect.mBottom)); + btn_rb.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); + btn_rb.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomClick, this)); + mBtnRotateBottom = LLUICtrlFactory::create<LLButton>(btn_rb); + addChild(mBtnRotateBottom); + + LLTextBox::Params lbl_S = p.lbl_S; + LLRect rect_S = btn_rb.rect; + //rect_S.translate(btn_rb.rect().getWidth(), 0); + lbl_S.rect = rect_S; + lbl_S.initial_value(lbl_S.label()); + mLabelS = LLUICtrlFactory::create<LLTextBox>(lbl_S); + addChild(mLabelS); + + + LLButton::Params btn_rl = p.btn_rotate_left; + btn_rl.rect(LLRect(border_rect.mLeft, centerY + axis_offset_lt, border_rect.mLeft + btn_size, centerY - axis_offset_rb)); + btn_rl.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); + btn_rl.mouse_held_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftClick, this)); + mBtnRotateLeft = LLUICtrlFactory::create<LLButton>(btn_rl); + addChild(mBtnRotateLeft); + + LLTextBox::Params lbl_W = p.lbl_W; + LLRect rect_W = btn_rl.rect; + //rect_W.translate(0, -1* btn_rl.rect().getHeight()); + lbl_W.rect = rect_W; + lbl_W.initial_value(lbl_W.label()); + mLabelW = LLUICtrlFactory::create<LLTextBox>(lbl_W); + addChild(mLabelW); + + + LLPanel::Params touch_area; + touch_area.rect = LLRect(centerX - mImgSphere->getWidth() / 2, + centerY + mImgSphere->getHeight() / 2, + centerX + mImgSphere->getWidth() / 2, + centerY - mImgSphere->getHeight() / 2); + mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); + addChild(mTouchArea); +} + +LLVirtualTrackball::~LLVirtualTrackball() +{ +} + +BOOL LLVirtualTrackball::postBuild() +{ + return TRUE; +} + + +void LLVirtualTrackball::drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi) +{ + LLUIImage* thumb; + if (mode == ThumbMode::SUN) + { + if (upperHemi) + { + thumb = mImgSunFront; + } + else + { + thumb = mImgSunBack; + } + } + else + { + if (upperHemi) + { + thumb = mImgMoonFront; + } + else + { + thumb = mImgMoonBack; + } + } + thumb->draw(LLRect(x - thumb->getWidth() / 2, + y + thumb->getHeight() / 2, + x + thumb->getWidth() / 2, + y - thumb->getHeight() / 2)); +} + +bool LLVirtualTrackball::pointInTouchCircle(S32 x, S32 y) const +{ + S32 centerX = mTouchArea->getRect().getCenterX(); + S32 centerY = mTouchArea->getRect().getCenterY(); + + bool in_circle = pow(x - centerX, 2) + pow(y - centerY, 2) <= pow(mTouchArea->getRect().getWidth() / 2, 2); + return in_circle; +} + +void LLVirtualTrackball::draw() +{ + LLVector3 draw_point = VectorZero * mValue; + + S32 halfwidth = mTouchArea->getRect().getWidth() / 2; + S32 halfheight = mTouchArea->getRect().getHeight() / 2; + draw_point.mV[VX] = (draw_point.mV[VX] + 1.0) * halfwidth + mTouchArea->getRect().mLeft; + draw_point.mV[VY] = (draw_point.mV[VY] + 1.0) * halfheight + mTouchArea->getRect().mBottom; + bool upper_hemisphere = (draw_point.mV[VZ] >= 0.f); + + mImgSphere->draw(mTouchArea->getRect(), upper_hemisphere ? UI_VERTEX_COLOR : UI_VERTEX_COLOR % 0.5f); + drawThumb(draw_point.mV[VX], draw_point.mV[VY], mThumbMode, upper_hemisphere); + + + if (LLView::sDebugRects) + { + gGL.color4fv(LLColor4::red.mV); + gl_circle_2d(mTouchArea->getRect().getCenterX(), mTouchArea->getRect().getCenterY(), mImgSphere->getWidth() / 2, 60, false); + gl_circle_2d(draw_point.mV[VX], draw_point.mV[VY], mImgSunFront->getWidth() / 2, 12, false); + } + + LLView::draw(); +} + +void LLVirtualTrackball::onRotateTopClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 1, 0, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateBottomClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, -1, 0, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateLeftClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 0, 1, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::onRotateRightClick() +{ + if (getEnabled()) + { + LLQuaternion delta; + delta.setAngleAxis(mIncrementBtn, 0, -1, 0); + mValue *= delta; + setValueAndCommit(mValue); + + make_ui_sound("UISndClick"); + } +} + +void LLVirtualTrackball::setValue(const LLSD& value) +{ + if (value.isArray() && value.size() == 4) + { + mValue.setValue(value); + } +} + +void LLVirtualTrackball::setRotation(const LLQuaternion &value) +{ + mValue = value; +} + +void LLVirtualTrackball::setValue(F32 x, F32 y, F32 z, F32 w) +{ + mValue.set(x, y, z, w); +} + +void LLVirtualTrackball::setValueAndCommit(const LLQuaternion &value) +{ + mValue = value; + onCommit(); +} + +LLSD LLVirtualTrackball::getValue() const +{ + return mValue.getValue(); +} + +LLQuaternion LLVirtualTrackball::getRotation() const +{ + return mValue; +} + +BOOL LLVirtualTrackball::handleHover(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + if (mDragMode == DRAG_SCROLL) + { // trackball (move to roll) mode + LLQuaternion delta; + + F32 rotX = x - mPrevX; + F32 rotY = y - mPrevY; + + if (abs(rotX) > 1) + { + F32 direction = (rotX < 0) ? -1 : 1; + delta.setAngleAxis(mIncrementMouse * abs(rotX), 0, direction, 0); // changing X - rotate around Y axis + mValue *= delta; + } + + if (abs(rotY) > 1) + { + F32 direction = (rotY < 0) ? 1 : -1; // reverse for Y (value increases from bottom to top) + delta.setAngleAxis(mIncrementMouse * abs(rotY), direction, 0, 0); // changing Y - rotate around X axis + mValue *= delta; + } + } + else + { // set on click mode + if (!pointInTouchCircle(x, y)) + { + return TRUE; // don't drag outside the circle + } + + F32 radius = mTouchArea->getRect().getWidth() / 2; + F32 xx = x - mTouchArea->getRect().getCenterX(); + F32 yy = y - mTouchArea->getRect().getCenterY(); + F32 dist = sqrt(pow(xx, 2) + pow(yy, 2)); + + F32 azimuth = llclamp(acosf(xx / dist), 0.0f, F_PI); + F32 altitude = llclamp(acosf(dist / radius), 0.0f, F_PI_BY_TWO); + + if (yy < 0) + { + azimuth = F_TWO_PI - azimuth; + } + + LLVector3 draw_point = VectorZero * mValue; + if (draw_point.mV[VZ] >= 0.f) + { + if (is_approx_zero(altitude)) // don't change the hemisphere + { + altitude = F_APPROXIMATELY_ZERO; + } + altitude *= -1; + } + + mValue.setAngleAxis(altitude, 0, 1, 0); + LLQuaternion az_quat; + az_quat.setAngleAxis(azimuth, 0, 0, 1); + mValue *= az_quat; + } + + mPrevX = x; + mPrevY = y; + onCommit(); + } + return TRUE; +} + +BOOL LLVirtualTrackball::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + mPrevX = 0; + mPrevY = 0; + gFocusMgr.setMouseCapture(NULL); + make_ui_sound("UISndClickRelease"); + } + return LLView::handleMouseUp(x, y, mask); +} + +BOOL LLVirtualTrackball::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (pointInTouchCircle(x, y)) + { + mPrevX = x; + mPrevY = y; + gFocusMgr.setMouseCapture(this); + mDragMode = (mask == MASK_CONTROL) ? DRAG_SCROLL : DRAG_SET; + make_ui_sound("UISndClick"); + } + return LLView::handleMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (pointInTouchCircle(x, y)) + { + + //make_ui_sound("UISndClick"); + } + return LLView::handleRightMouseDown(x, y, mask); +} + +BOOL LLVirtualTrackball::handleKeyHere(KEY key, MASK mask) +{ + BOOL handled = FALSE; + switch (key) + { + case KEY_DOWN: + onRotateTopClick(); + handled = TRUE; + break; + case KEY_LEFT: + onRotateRightClick(); + handled = TRUE; + break; + case KEY_UP: + onRotateBottomClick(); + handled = TRUE; + break; + case KEY_RIGHT: + onRotateLeftClick(); + handled = TRUE; + break; + default: + break; + } + return handled; +} + diff --git a/indra/llui/llvirtualtrackball.h b/indra/llui/llvirtualtrackball.h new file mode 100644 index 0000000000..48ddb7f4d9 --- /dev/null +++ b/indra/llui/llvirtualtrackball.h @@ -0,0 +1,155 @@ +/** +* @file virtualtrackball.h +* @author Andrey Lihatskiy +* @brief Header file for LLVirtualTrackball +* +* $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 control for positioning the sun and the moon in the celestial sphere. + +#ifndef LL_LLVIRTUALTRACKBALL_H +#define LL_LLVIRTUALTRACKBALL_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "llbutton.h" + +class LLVirtualTrackball + : public LLUICtrl +{ +public: + enum ThumbMode + { + SUN, + MOON + }; + enum DragMode + { + DRAG_SET, + DRAG_SCROLL + }; + + 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<std::string> thumb_mode; + Optional<F32> increment_angle_mouse, + increment_angle_btn; + + Optional<LLTextBox::Params> lbl_N, + lbl_S, + lbl_W, + lbl_E; + + Optional<LLButton::Params> btn_rotate_top, + btn_rotate_bottom, + btn_rotate_left, + btn_rotate_right; + + Params(); + }; + + + virtual ~LLVirtualTrackball(); + /*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 BOOL handleKeyHere(KEY key, MASK mask); + + virtual void draw(); + + virtual void setValue(const LLSD& value); + void setValue(F32 x, F32 y, F32 z, F32 w); + virtual LLSD getValue() const; + + void setRotation(const LLQuaternion &value); + LLQuaternion getRotation() const; + +protected: + friend class LLUICtrlFactory; + LLVirtualTrackball(const Params&); + void onEditChange(); + +protected: + LLTextBox* mNLabel; + LLTextBox* mELabel; + LLTextBox* mSLabel; + LLTextBox* mWLabel; + + LLButton* mBtnRotateTop; + LLButton* mBtnRotateBottom; + LLButton* mBtnRotateLeft; + LLButton* mBtnRotateRight; + + LLTextBox* mLabelN; + LLTextBox* mLabelS; + LLTextBox* mLabelW; + LLTextBox* mLabelE; + + LLPanel* mTouchArea; + LLViewBorder* mBorder; + +private: + void setValueAndCommit(const LLQuaternion &value); + void drawThumb(S32 x, S32 y, ThumbMode mode, bool upperHemi = true); + bool pointInTouchCircle(S32 x, S32 y) const; + + void onRotateTopClick(); + void onRotateBottomClick(); + void onRotateLeftClick(); + void onRotateRightClick(); + + S32 mPrevX; + S32 mPrevY; + + LLUIImage* mImgMoonBack; + LLUIImage* mImgMoonFront; + LLUIImage* mImgSunBack; + LLUIImage* mImgSunFront; + LLUIImage* mImgBtnRotTop; + LLUIImage* mImgBtnRotLeft; + LLUIImage* mImgBtnRotRight; + LLUIImage* mImgBtnRotBottom; + LLUIImage* mImgSphere; + + LLQuaternion mValue; + ThumbMode mThumbMode; + DragMode mDragMode; + + F32 mIncrementMouse; + F32 mIncrementBtn; +}; + +#endif + diff --git a/indra/llui/llxyvector.cpp b/indra/llui/llxyvector.cpp new file mode 100644 index 0000000000..48f38b8a92 --- /dev/null +++ b/indra/llui/llxyvector.cpp @@ -0,0 +1,306 @@ +/** +* @file llxyvector.cpp +* @author Andrey Lihatskiy +* @brief Implementation for LLXYVector +* +* $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 control that allows to set two related vector magnitudes by manipulating a single vector on a plane. + +#include "linden_common.h" + +#include "llxyvector.h" + +#include "llstring.h" +#include "llrect.h" + +#include "lluictrlfactory.h" +#include "llrender.h" + +// Globals +static LLDefaultChildRegistry::Register<LLXYVector> register_xy_vector("xy_vector"); + + +const F32 CENTER_CIRCLE_RADIUS = 2; +const S32 ARROW_ANGLE = 30; +const S32 ARROW_LENGTH_LONG = 10; +const S32 ARROW_LENGTH_SHORT = 6; + +LLXYVector::Params::Params() + : x_entry("x_entry"), + y_entry("y_entry"), + touch_area("touch_area"), + border("border"), + edit_bar_height("edit_bar_height", 18), + padding("padding", 4), + min_val_x("min_val_x", -1.0f), + max_val_x("max_val_x", 1.0f), + increment_x("increment_x", 0.05f), + min_val_y("min_val_y", -1.0f), + max_val_y("max_val_y", 1.0f), + increment_y("increment_y", 0.05f), + label_width("label_width", 16), + arrow_color("arrow_color", LLColor4::white), + ghost_color("ghost_color"), + area_color("area_color", LLColor4::grey4), + grid_color("grid_color", LLColor4::grey % 0.25f) +{ +} + +LLXYVector::LLXYVector(const LLXYVector::Params& p) + : LLUICtrl(p), + mArrowColor(p.arrow_color()), + mAreaColor(p.area_color), + mGridColor(p.grid_color), + mMinValueX(p.min_val_x), + mMaxValueX(p.max_val_x), + mIncrementX(p.increment_x), + mMinValueY(p.min_val_y), + mMaxValueY(p.max_val_y), + mIncrementY(p.increment_y) +{ + mGhostColor = p.ghost_color.isProvided() ? p.ghost_color() % 0.3f : p.arrow_color() % 0.3f; + + LLRect border_rect = getLocalRect(); + LLViewBorder::Params params = p.border; + params.rect(border_rect); + mBorder = LLUICtrlFactory::create<LLViewBorder>(params); + addChild(mBorder); + + LLTextBox::Params x_label_params; + x_label_params.initial_value(p.x_entry.label()); + x_label_params.rect = LLRect(p.padding, + border_rect.mTop - p.padding, + p.label_width, + border_rect.getHeight() - p.edit_bar_height); + mXLabel = LLUICtrlFactory::create<LLTextBox>(x_label_params); + addChild(mXLabel); + LLLineEditor::Params x_params = p.x_entry; + x_params.rect = LLRect(p.padding + p.label_width, + border_rect.mTop - p.padding, + border_rect.getCenterX(), + border_rect.getHeight() - p.edit_bar_height); + x_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); + mXEntry = LLUICtrlFactory::create<LLLineEditor>(x_params); + mXEntry->setPrevalidateInput(LLTextValidate::validateFloat); + addChild(mXEntry); + + LLTextBox::Params y_label_params; + y_label_params.initial_value(p.y_entry.label()); + y_label_params.rect = LLRect(border_rect.getCenterX() + p.padding, + border_rect.mTop - p.padding, + border_rect.getCenterX() + p.label_width, + border_rect.getHeight() - p.edit_bar_height); + mYLabel = LLUICtrlFactory::create<LLTextBox>(y_label_params); + addChild(mYLabel); + LLLineEditor::Params y_params = p.y_entry; + y_params.rect = LLRect(border_rect.getCenterX() + p.padding + p.label_width, + border_rect.getHeight() - p.padding, + border_rect.getWidth() - p.padding, + border_rect.getHeight() - p.edit_bar_height); + y_params.commit_callback.function(boost::bind(&LLXYVector::onEditChange, this)); + mYEntry = LLUICtrlFactory::create<LLLineEditor>(y_params); + mYEntry->setPrevalidateInput(LLTextValidate::validateFloat); + addChild(mYEntry); + + LLPanel::Params touch_area = p.touch_area; + touch_area.rect = LLRect(p.padding, + border_rect.mTop - p.edit_bar_height - p.padding, + border_rect.getWidth() - p.padding, + p.padding); + mTouchArea = LLUICtrlFactory::create<LLPanel>(touch_area); + addChild(mTouchArea); +} + +LLXYVector::~LLXYVector() +{ +} + +BOOL LLXYVector::postBuild() +{ + return TRUE; +} + +void drawArrow(S32 tailX, S32 tailY, S32 tipX, S32 tipY, LLColor4 color) +{ + gl_line_2d(tailX, tailY, tipX, tipY, color); + + S32 dx = tipX - tailX; + S32 dy = tipY - tailY; + + S32 arrowLength = (abs(dx) < ARROW_LENGTH_LONG && abs(dy) < ARROW_LENGTH_LONG) ? ARROW_LENGTH_SHORT : ARROW_LENGTH_LONG; + + F32 theta = std::atan2(dy, dx); + + F32 rad = ARROW_ANGLE * std::atan(1) * 4 / 180; + F32 x = tipX - arrowLength * cos(theta + rad); + F32 y = tipY - arrowLength * sin(theta + rad); + F32 rad2 = -1 * ARROW_ANGLE * std::atan(1) * 4 / 180; + F32 x2 = tipX - arrowLength * cos(theta + rad2); + F32 y2 = tipY - arrowLength * sin(theta + rad2); + gl_triangle_2d(tipX, tipY, x, y, x2, y2, color, true); +} + +void LLXYVector::draw() +{ + S32 centerX = mTouchArea->getRect().getCenterX(); + S32 centerY = mTouchArea->getRect().getCenterY(); + + S32 pointX = centerX + (mValueX * mTouchArea->getRect().getWidth() / (2 * mMaxValueX)); + S32 pointY = centerY + (mValueY * mTouchArea->getRect().getHeight() / (2 * mMaxValueY)); + + // fill + gl_rect_2d(mTouchArea->getRect(), mAreaColor, true); + + // draw grid + gl_line_2d(centerX, mTouchArea->getRect().mTop, centerX, mTouchArea->getRect().mBottom, mGridColor); + gl_line_2d(mTouchArea->getRect().mLeft, centerY, mTouchArea->getRect().mRight, centerY, mGridColor); + + // draw ghost + if (hasMouseCapture()) + { + drawArrow(centerX, centerY, mGhostX, mGhostY, mGhostColor); + } + else + { + mGhostX = pointX; + mGhostY = pointY; + } + + if (abs(mValueX) >= mIncrementX || abs(mValueY) >= mIncrementY) + { + // draw the vector arrow + drawArrow(centerX, centerY, pointX, pointY, mArrowColor); + } + else + { + // skip the arrow, set color for center circle + gGL.color4fv(mArrowColor.get().mV); + } + + // draw center circle + gl_circle_2d(centerX, centerY, CENTER_CIRCLE_RADIUS, 12, true); + + LLView::draw(); +} + +void LLXYVector::onEditChange() +{ + if (getEnabled()) + { + setValueAndCommit(mXEntry->getValue().asReal(), mYEntry->getValue().asReal()); + } +} + +void LLXYVector::setValue(const LLSD& value) +{ + if (value.isArray()) + { + setValue(value[0].asReal(), value[1].asReal()); + } +} + +void LLXYVector::setValue(F32 x, F32 y) +{ + x = llclamp(x, mMinValueX, mMaxValueX); + y = llclamp(y, mMinValueY, mMaxValueY); + + // Round the values to nearest increments + x -= mMinValueX; + x += mIncrementX / 2.0001f; + x -= fmod(x, mIncrementX); + x += mMinValueX; + + y -= mMinValueY; + y += mIncrementY / 2.0001f; + y -= fmod(y, mIncrementY); + y += mMinValueY; + + mValueX = x; + mValueY = y; + + update(); +} + +void LLXYVector::setValueAndCommit(F32 x, F32 y) +{ + if (mValueX != x || mValueY != y) + { + setValue(x, y); + onCommit(); + } +} + +LLSD LLXYVector::getValue() const +{ + LLSD value; + value.append(mValueX); + value.append(mValueY); + return value; +} + +void LLXYVector::update() +{ + mXEntry->setValue(mValueX); + mYEntry->setValue(mValueY); +} + +BOOL LLXYVector::handleHover(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + F32 valueX = F32(x - mTouchArea->getRect().getCenterX()) / mTouchArea->getRect().getWidth(); + F32 valueY = F32(y - mTouchArea->getRect().getCenterY()) / mTouchArea->getRect().getHeight(); + + valueX *= 2 * mMaxValueX; + valueY *= 2 * mMaxValueY; + + setValueAndCommit(valueX, valueY); + } + + return TRUE; +} + +BOOL LLXYVector::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + gFocusMgr.setMouseCapture(NULL); + make_ui_sound("UISndClickRelease"); + } + + return TRUE; +} + +BOOL LLXYVector::handleMouseDown(S32 x, S32 y, MASK mask) +{ + + if (mTouchArea->getRect().pointInRect(x, y)) + { + gFocusMgr.setMouseCapture(this); + make_ui_sound("UISndClick"); + } + + return TRUE; +} + diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h new file mode 100644 index 0000000000..4d67db3251 --- /dev/null +++ b/indra/llui/llxyvector.h @@ -0,0 +1,118 @@ +/** +* @file llxyvector.h +* @author Andrey Lihatskiy +* @brief Header file for LLXYVector +* +* $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 control that allows to set two related vector magnitudes by manipulating a single vector on a plane. + +#ifndef LL_LLXYVECTOR_H +#define LL_LLXYVECTOR_H + +#include "lluictrl.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "lllineeditor.h" + +class LLXYVector + : public LLUICtrl +{ +public: + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLLineEditor::Params> x_entry; + Optional<LLLineEditor::Params> y_entry; + Optional<LLPanel::Params> touch_area; + Optional<LLViewBorder::Params> border; + Optional<S32> edit_bar_height; + Optional<S32> padding; + Optional<S32> label_width; + Optional<F32> min_val_x; + Optional<F32> max_val_x; + Optional<F32> increment_x; + Optional<F32> min_val_y; + Optional<F32> max_val_y; + Optional<F32> increment_y; + Optional<LLUIColor> arrow_color; + Optional<LLUIColor> ghost_color; + Optional<LLUIColor> area_color; + Optional<LLUIColor> grid_color; + + Params(); + }; + + + virtual ~LLXYVector(); + /*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 void draw(); + + virtual void setValue(const LLSD& value); + void setValue(F32 x, F32 y); + virtual LLSD getValue() const; + +protected: + friend class LLUICtrlFactory; + LLXYVector(const Params&); + void onEditChange(); + +protected: + LLTextBox* mXLabel; + LLTextBox* mYLabel; + LLLineEditor* mXEntry; + LLLineEditor* mYEntry; + LLPanel* mTouchArea; + LLViewBorder* mBorder; + +private: + void update(); + void setValueAndCommit(F32 x, F32 y); + + F32 mValueX; + F32 mValueY; + + F32 mMinValueX; + F32 mMaxValueX; + F32 mIncrementX; + F32 mMinValueY; + F32 mMaxValueY; + F32 mIncrementY; + + U32 mGhostX; + U32 mGhostY; + + LLUIColor mArrowColor; + LLUIColor mGhostColor; + LLUIColor mAreaColor; + LLUIColor mGridColor; + +}; + +#endif + |