summaryrefslogtreecommitdiff
path: root/indra/llui/llmultislider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llmultislider.cpp')
-rw-r--r--indra/llui/llmultislider.cpp438
1 files changed, 349 insertions, 89 deletions
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index 0aa3e17075..acfe4a0cba 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -54,13 +54,18 @@ LLMultiSlider::SliderParams::SliderParams()
LLMultiSlider::Params::Params()
: max_sliders("max_sliders", 1),
allow_overlap("allow_overlap", false),
+ loop_overlap("loop_overlap", false),
+ orientation("orientation"),
+ overlap_threshold("overlap_threshold", 0),
draw_track("draw_track", true),
use_triangle("use_triangle", false),
track_color("track_color"),
thumb_disabled_color("thumb_disabled_color"),
+ thumb_highlight_color("thumb_highlight_color"),
thumb_outline_color("thumb_outline_color"),
thumb_center_color("thumb_center_color"),
thumb_center_selected_color("thumb_center_selected_color"),
+ thumb_image("thumb_image"),
triangle_color("triangle_color"),
mouse_down_callback("mouse_down_callback"),
mouse_up_callback("mouse_up_callback"),
@@ -71,9 +76,9 @@ LLMultiSlider::Params::Params()
LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
: LLF32UICtrl(p),
mMouseOffset( 0 ),
- 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()),
@@ -83,12 +88,22 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
mDisabledThumbColor(p.thumb_disabled_color()),
mTriangleColor(p.triangle_color()),
mThumbWidth(p.thumb_width),
+ mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL)
{
mValue.emptyMap();
mCurSlider = LLStringUtil::null;
-
+
+ if (mOrientation == HORIZONTAL)
+ {
+ mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0);
+ }
+ else
+ {
+ mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0);
+ }
+
if (p.mouse_down_callback.isProvided())
{
setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
@@ -98,6 +113,15 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
}
+ if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement)
+ {
+ mOverlapThreshold = p.overlap_threshold - mIncrement;
+ }
+ else
+ {
+ mOverlapThreshold = 0;
+ }
+
for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin();
it != p.sliders.end();
++it)
@@ -111,6 +135,12 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
addSlider(it->value);
}
}
+
+ if (p.thumb_image.isProvided())
+ {
+ mThumbImagep = LLUI::getUIImage(p.thumb_image());
+ }
+ mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor());
}
LLMultiSlider::~LLMultiSlider()
@@ -119,6 +149,16 @@ LLMultiSlider::~LLMultiSlider()
delete mMouseUpSignal;
}
+F32 LLMultiSlider::getNearestIncrement(F32 value) const
+{
+ value = llclamp(value, mMinValue, mMaxValue);
+
+ // Round to nearest increment (bias towards rounding down)
+ value -= mMinValue;
+ value += mIncrement / 2.0001f;
+ value -= fmod(value, mIncrement);
+ return mMinValue + value;
+}
void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event)
{
@@ -127,13 +167,7 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from
return;
}
- value = llclamp( value, mMinValue, mMaxValue );
-
- // Round to nearest increment (bias towards rounding down)
- value -= mMinValue;
- value += mIncrement/2.0001f;
- value -= fmod(value, mIncrement);
- F32 newValue = mMinValue + value;
+ F32 newValue = getNearestIncrement(value);
// now, make sure no overlap
// if we want that
@@ -143,14 +177,40 @@ 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();
- for(;mIt != mValue.endMap(); mIt++) {
-
- F32 testVal = (F32)mIt->second.asReal() - newValue;
- if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD &&
- mIt->first != name) {
+
+ // 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) : mMinValue - 1.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) : mMaxValue + 1.0f;
+
+ for(;mIt != mValue.endMap(); mIt++)
+ {
+ F32 locationVal = (F32)mIt->second.asReal();
+ // Check nearby values
+ F32 testVal = locationVal - newValue;
+ if (testVal > -threshold
+ && testVal < threshold
+ && mIt->first != name)
+ {
hit = true;
break;
}
+ if (mLoopOverlap)
+ {
+ // Check edge overlap values
+ if (locationVal < loop_up_check)
+ {
+ hit = true;
+ break;
+ }
+ if (locationVal > loop_down_check)
+ {
+ hit = true;
+ break;
+ }
+ }
}
// if none found, stop
@@ -170,13 +230,26 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from
}
F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
+ if (mOrientation == HORIZONTAL)
+ {
+ S32 left_edge = mThumbWidth/2;
+ S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
- S32 left_edge = mThumbWidth/2;
- S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
+ S32 x = left_edge + S32( t * (right_edge - left_edge) );
- S32 x = left_edge + S32( t * (right_edge - left_edge) );
- mThumbRects[name].mLeft = x - (mThumbWidth/2);
- mThumbRects[name].mRight = x + (mThumbWidth/2);
+ mThumbRects[name].mLeft = x - (mThumbWidth / 2);
+ mThumbRects[name].mRight = x + (mThumbWidth / 2);
+ }
+ else
+ {
+ S32 bottom_edge = mThumbWidth/2;
+ S32 top_edge = getRect().getHeight() - (mThumbWidth/2);
+
+ S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) );
+
+ mThumbRects[name].mTop = x + (mThumbWidth / 2);
+ mThumbRects[name].mBottom = x - (mThumbWidth / 2);
+ }
}
void LLMultiSlider::setValue(const LLSD& value)
@@ -196,7 +269,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 +283,62 @@ void LLMultiSlider::setCurSlider(const std::string& name)
}
}
+F32 LLMultiSlider::getSliderValueFromPos(S32 xpos, S32 ypos) const
+{
+ F32 t = 0;
+ if (mOrientation == HORIZONTAL)
+ {
+ S32 left_edge = mThumbWidth / 2;
+ S32 right_edge = getRect().getWidth() - (mThumbWidth / 2);
+
+ xpos += mMouseOffset;
+ xpos = llclamp(xpos, left_edge, right_edge);
+
+ t = F32(xpos - left_edge) / (right_edge - left_edge);
+ }
+ else
+ {
+ S32 bottom_edge = mThumbWidth / 2;
+ S32 top_edge = getRect().getHeight() - (mThumbWidth / 2);
+
+ ypos += mMouseOffset;
+ ypos = llclamp(ypos, bottom_edge, top_edge);
+
+ t = F32(ypos - bottom_edge) / (top_edge - bottom_edge);
+ }
+
+ return((t * (mMaxValue - mMinValue)) + mMinValue);
+}
+
+
+LLRect LLMultiSlider::getSliderThumbRect(const std::string& name) const
+{
+ auto it = mThumbRects.find(name);
+ if (it != mThumbRects.end())
+ return (*it).second;
+ return LLRect();
+}
+
+void LLMultiSlider::setSliderThumbImage(const std::string &name)
+{
+ if (!name.empty())
+ {
+ mThumbImagep = LLUI::getUIImage(name);
+ }
+ else
+ clearSliderThumbImage();
+}
+
+void LLMultiSlider::clearSliderThumbImage()
+{
+ mThumbImagep = NULL;
+}
+
+void LLMultiSlider::resetCurSlider()
+{
+ mCurSlider = LLStringUtil::null;
+}
+
const std::string& LLMultiSlider::addSlider()
{
return addSlider(mInitialValue);
@@ -230,7 +363,14 @@ const std::string& LLMultiSlider::addSlider(F32 val)
}
// add a new thumb rect
- mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 );
+ if (mOrientation == HORIZONTAL)
+ {
+ mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0);
+ }
+ else
+ {
+ mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0);
+ }
// add the value and set the current slider to this one
mValue.insert(newName.str(), initVal);
@@ -242,21 +382,28 @@ const std::string& LLMultiSlider::addSlider(F32 val)
return mCurSlider;
}
-void LLMultiSlider::addSlider(F32 val, const std::string& name)
+bool LLMultiSlider::addSlider(F32 val, const std::string& name)
{
F32 initVal = val;
if(mValue.size() >= mMaxNumSliders) {
- return;
+ return false;
}
bool foundOne = findUnusedValue(initVal);
if(!foundOne) {
- return;
+ return false;
}
// add a new thumb rect
- mThumbRects[name] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 );
+ if (mOrientation == HORIZONTAL)
+ {
+ mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0);
+ }
+ else
+ {
+ mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0);
+ }
// add the value and set the current slider to this one
mValue.insert(name, initVal);
@@ -264,6 +411,8 @@ void LLMultiSlider::addSlider(F32 val, const std::string& name)
// move the slider
setSliderValue(mCurSlider, initVal, TRUE);
+
+ return true;
}
bool LLMultiSlider::findUnusedValue(F32& initVal)
@@ -278,11 +427,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 +485,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 +501,7 @@ 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 );
+ setCurSliderValue(getSliderValueFromPos(x, y));
onCommit();
getWindow()->setCursor(UI_CURSOR_ARROW);
@@ -360,6 +509,24 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
}
else
{
+ if (getEnabled())
+ {
+ mHoverSlider.clear();
+ std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin();
+ for (; mIt != mThumbRects.end(); mIt++)
+ {
+ if (mIt->second.pointInRect(x, y))
+ {
+ mHoverSlider = mIt->first;
+ break;
+ }
+ }
+ }
+ else
+ {
+ mHoverSlider.clear();
+ }
+
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;
}
@@ -416,20 +583,30 @@ 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))
+ {
+ if (mOrientation == HORIZONTAL)
+ {
+ mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x;
+ }
+ else
+ {
+ mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y;
+ }
+ }
+ 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");
@@ -462,6 +639,13 @@ BOOL LLMultiSlider::handleKeyHere(KEY key, MASK mask)
return handled;
}
+/*virtual*/
+void LLMultiSlider::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ mHoverSlider.clear();
+ LLF32UICtrl::onMouseLeave(x, y, mask);
+}
+
void LLMultiSlider::draw()
{
static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0);
@@ -470,6 +654,7 @@ void LLMultiSlider::draw()
std::map<std::string, LLRect>::iterator mIt;
std::map<std::string, LLRect>::iterator curSldrIt;
+ std::map<std::string, LLRect>::iterator hoverSldrIt;
// Draw background and thumb.
@@ -483,9 +668,18 @@ void LLMultiSlider::draw()
// Track
LLUIImagePtr thumb_imagep = LLUI::getUIImage("Rounded_Square");
- static LLUICachedControl<S32> multi_track_height ("UIMultiTrackHeight", 0);
- S32 height_offset = (getRect().getHeight() - multi_track_height) / 2;
- LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset );
+ static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0);
+ S32 height_offset = 0;
+ S32 width_offset = 0;
+ if (mOrientation == HORIZONTAL)
+ {
+ height_offset = (getRect().getHeight() - multi_track_height_width) / 2;
+ }
+ else
+ {
+ width_offset = (getRect().getWidth() - multi_track_height_width) / 2;
+ }
+ LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset);
if(mDrawTrack)
@@ -510,10 +704,11 @@ void LLMultiSlider::draw()
mTriangleColor.get() % opacity, TRUE);
}
}
- else if (!thumb_imagep)
+ else if (!thumb_imagep && !mThumbImagep)
{
// draw all the thumbs
curSldrIt = mThumbRects.end();
+ hoverSldrIt = mThumbRects.end();
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
// choose the color
@@ -522,15 +717,21 @@ void LLMultiSlider::draw()
curSldrIt = mIt;
continue;
- //curThumbColor = mThumbCenterSelectedColor;
+ }
+ if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this)
+ {
+ // draw last, after current one
+ hoverSldrIt = mIt;
+ continue;
}
// the draw command
gl_rect_2d(mIt->second, curThumbColor, TRUE);
}
- // now draw the current slider
- if(curSldrIt != mThumbRects.end()) {
+ // now draw the current and hover sliders
+ if(curSldrIt != mThumbRects.end())
+ {
gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE);
}
@@ -539,20 +740,57 @@ void LLMultiSlider::draw()
{
gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE);
}
+ else if (hoverSldrIt != mThumbRects.end())
+ {
+ gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), TRUE);
+ }
}
- else if( gFocusMgr.getMouseCapture() == this )
+ else
{
- // draw drag start
- thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
+ LLMouseHandler* capture = gFocusMgr.getMouseCapture();
+ if (capture == this)
+ {
+ // draw drag start (ghost)
+ if (mThumbImagep)
+ {
+ mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
+ }
+ else
+ {
+ thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
+ }
+ }
// draw the highlight
if (hasFocus())
{
- thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
+ if (!mCurSlider.empty())
+ {
+ if (mThumbImagep)
+ {
+ mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth());
+ }
+ else
+ {
+ thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
+ }
+ }
}
+ if (!mHoverSlider.empty())
+ {
+ if (mThumbImagep)
+ {
+ mThumbImagep->drawBorder(mThumbRects[mHoverSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth());
+ }
+ else
+ {
+ thumb_imagep->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
+ }
+ }
// draw the thumbs
curSldrIt = mThumbRects.end();
+ hoverSldrIt = mThumbRects.end();
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++)
{
// choose the color
@@ -563,46 +801,68 @@ void LLMultiSlider::draw()
curSldrIt = mIt;
continue;
}
+ if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this)
+ {
+ // don't draw now, draw last, after current one
+ hoverSldrIt = mIt;
+ continue;
+ }
// the draw command
- thumb_imagep->drawSolid(mIt->second, curThumbColor);
+ if (mThumbImagep)
+ {
+ if (getEnabled())
+ {
+ mThumbImagep->draw(mIt->second);
+ }
+ else
+ {
+ mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f);
+ }
+ }
+ else if (capture == this)
+ {
+ thumb_imagep->drawSolid(mIt->second, curThumbColor);
+ }
+ else
+ {
+ thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity);
+ }
}
- // draw cur slider last
+ // draw cur and hover slider last
if(curSldrIt != mThumbRects.end())
{
- thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get());
- }
-
- }
- else
- {
- // draw highlight
- if (hasFocus())
- {
- thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
- }
-
- // draw thumbs
- curSldrIt = mThumbRects.end();
- for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++)
- {
-
- // choose the color
- curThumbColor = mThumbCenterColor.get();
- if(mIt->first == mCurSlider)
+ if (mThumbImagep)
{
- curSldrIt = mIt;
- continue;
- //curThumbColor = mThumbCenterSelectedColor;
- }
-
- thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity);
+ if (getEnabled())
+ {
+ mThumbImagep->draw(curSldrIt->second);
+ }
+ else
+ {
+ mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f);
+ }
+ }
+ else if (capture == this)
+ {
+ thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get());
+ }
+ else
+ {
+ thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity);
+ }
}
-
- if(curSldrIt != mThumbRects.end())
+ if(hoverSldrIt != mThumbRects.end())
{
- thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity);
+ if (mThumbImagep)
+ {
+ mThumbImagep->draw(hoverSldrIt->second);
+ }
+ else
+ {
+ thumb_imagep->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get());
+ }
}
}