summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt8
-rw-r--r--indra/llui/llaccordionctrl.cpp34
-rw-r--r--indra/llui/llaccordionctrl.h5
-rw-r--r--indra/llui/llaccordionctrltab.cpp31
-rw-r--r--indra/llui/llaccordionctrltab.h1
-rw-r--r--indra/llui/llbadgeowner.cpp8
-rw-r--r--indra/llui/llbadgeowner.h1
-rw-r--r--indra/llui/llbutton.cpp47
-rw-r--r--indra/llui/llbutton.h1
-rw-r--r--indra/llui/llchat.h6
-rw-r--r--indra/llui/llchatentry.cpp4
-rw-r--r--indra/llui/llcheckboxctrl.cpp94
-rw-r--r--indra/llui/llcheckboxctrl.h17
-rw-r--r--indra/llui/llcombobox.cpp12
-rw-r--r--indra/llui/llcombobox.h2
-rw-r--r--indra/llui/llconsole.cpp10
-rw-r--r--indra/llui/llconsole.h2
-rw-r--r--indra/llui/llflashtimer.cpp4
-rw-r--r--indra/llui/llfloater.cpp129
-rw-r--r--indra/llui/llfloater.h19
-rw-r--r--indra/llui/llfloaterreg.cpp10
-rw-r--r--indra/llui/llfloaterreg.h1
-rw-r--r--indra/llui/llfocusmgr.cpp4
-rw-r--r--indra/llui/llfolderview.cpp42
-rw-r--r--indra/llui/llfolderview.h11
-rw-r--r--indra/llui/llfolderviewitem.cpp90
-rw-r--r--indra/llui/llfolderviewitem.h12
-rw-r--r--indra/llui/llfolderviewmodel.cpp5
-rw-r--r--indra/llui/llfolderviewmodel.h16
-rw-r--r--indra/llui/lllayoutstack.cpp10
-rw-r--r--indra/llui/lllineeditor.cpp96
-rw-r--r--indra/llui/lllineeditor.h10
-rw-r--r--indra/llui/llmenugl.cpp95
-rw-r--r--indra/llui/llmenugl.h23
-rw-r--r--indra/llui/llmodaldialog.cpp12
-rw-r--r--indra/llui/llmultislider.cpp443
-rw-r--r--indra/llui/llmultislider.h53
-rw-r--r--indra/llui/llmultisliderctrl.cpp36
-rw-r--r--indra/llui/llmultisliderctrl.h28
-rw-r--r--indra/llui/llnotificationptr.h3
-rw-r--r--indra/llui/llnotifications.cpp65
-rw-r--r--indra/llui/llnotifications.h54
-rw-r--r--indra/llui/llnotificationslistener.cpp8
-rw-r--r--indra/llui/llpanel.cpp4
-rw-r--r--indra/llui/llresmgr.cpp3
-rw-r--r--indra/llui/llrngwriter.cpp7
-rw-r--r--indra/llui/llscrollbar.cpp16
-rw-r--r--indra/llui/llscrollbar.h1
-rw-r--r--indra/llui/llscrollcontainer.cpp19
-rw-r--r--indra/llui/llscrollcontainer.h1
-rw-r--r--indra/llui/llscrolllistcell.cpp149
-rw-r--r--indra/llui/llscrolllistcell.h31
-rw-r--r--indra/llui/llscrolllistcolumn.cpp4
-rw-r--r--indra/llui/llscrolllistctrl.cpp274
-rw-r--r--indra/llui/llscrolllistctrl.h33
-rw-r--r--indra/llui/llscrolllistitem.cpp56
-rw-r--r--indra/llui/llscrolllistitem.h21
-rw-r--r--indra/llui/llsearcheditor.cpp22
-rw-r--r--indra/llui/llsearcheditor.h20
-rw-r--r--indra/llui/llslider.cpp7
-rw-r--r--indra/llui/llslider.h4
-rw-r--r--indra/llui/llsliderctrl.cpp42
-rw-r--r--indra/llui/llsliderctrl.h4
-rw-r--r--indra/llui/llspellcheck.cpp39
-rw-r--r--indra/llui/llspellcheck.h22
-rw-r--r--indra/llui/llspinctrl.cpp3
-rw-r--r--indra/llui/llstatview.cpp4
-rw-r--r--indra/llui/lltabcontainer.cpp16
-rw-r--r--indra/llui/lltabcontainer.h8
-rw-r--r--indra/llui/lltextbase.cpp58
-rw-r--r--indra/llui/lltextbase.h11
-rw-r--r--indra/llui/lltextbox.cpp6
-rw-r--r--indra/llui/lltextbox.h2
-rw-r--r--indra/llui/lltexteditor.cpp16
-rw-r--r--indra/llui/lltextutil.cpp2
-rw-r--r--indra/llui/lltoggleablemenu.cpp2
-rw-r--r--indra/llui/lltoolbar.cpp6
-rw-r--r--indra/llui/lltooltip.cpp24
-rw-r--r--indra/llui/llui.cpp151
-rw-r--r--indra/llui/llui.h126
-rw-r--r--indra/llui/lluictrl.cpp62
-rw-r--r--indra/llui/lluictrl.h7
-rw-r--r--indra/llui/lluictrlfactory.h14
-rw-r--r--indra/llui/lluiusage.cpp146
-rw-r--r--indra/llui/lluiusage.h57
-rw-r--r--indra/llui/llurlentry.cpp113
-rw-r--r--indra/llui/llurlentry.h37
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/llui/llview.cpp73
-rw-r--r--indra/llui/llview.h8
-rw-r--r--indra/llui/llviewereventrecorder.cpp6
-rw-r--r--indra/llui/llviewinject.h2
-rw-r--r--indra/llui/llvirtualtrackball.cpp520
-rw-r--r--indra/llui/llvirtualtrackball.h163
-rw-r--r--indra/llui/llxyvector.cpp337
-rw-r--r--indra/llui/llxyvector.h122
-rw-r--r--indra/llui/tests/llurlentry_test.cpp44
97 files changed, 3741 insertions, 747 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index e44f57fa9f..f781ff4110 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -122,6 +122,7 @@ set(llui_SOURCE_FILES
lluictrl.cpp
lluictrlfactory.cpp
lluistring.cpp
+ lluiusage.cpp
llundo.cpp
llurlaction.cpp
llurlentry.cpp
@@ -133,8 +134,10 @@ set(llui_SOURCE_FILES
llview.cpp
llviewquery.cpp
llviewereventrecorder.cpp
+ llvirtualtrackball.cpp
llwindowshade.cpp
llxuiparser.cpp
+ llxyvector.cpp
)
set(llui_HEADER_FILES
@@ -239,6 +242,7 @@ set(llui_HEADER_FILES
llui.h
lluicolor.h
lluistring.h
+ lluiusage.h
llundo.h
llurlaction.h
llurlentry.h
@@ -250,8 +254,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}
@@ -299,7 +305,7 @@ if(LL_TESTS)
set(test_libs llui llmessage llcorehttp llcommon
${HUNSPELL_LIBRARY}
${LLCOMMON_LIBRARIES}
- ${BOOST_COROUTINE_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
+ ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY}
${WINDOWS_LIBRARIES})
if(NOT LINUX)
LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 623f570cef..809d72208f 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -55,6 +55,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
, mTabComparator( NULL )
, mNoVisibleTabsHelpText(NULL)
, mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString())
+ , mSkipScrollToChild(false)
{
initNoTabsWidget(params.no_matched_tabs_text);
@@ -338,7 +339,7 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
addChild(accordion_tab);
mAccordionTabs.push_back(accordion_tab);
- accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
+ accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) );
arrange();
}
@@ -655,6 +656,37 @@ void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
{
updateLayout(getRect().getWidth(),getRect().getHeight());
}
+
+// virtual
+void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl)
+{
+ if (mScrollbar && mScrollbar->getVisible() && !mSkipScrollToChild)
+ {
+ // same as scrollToShowRect
+ LLRect rect;
+ cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this);
+
+ // Translate to parent coordinatess to check if we are in visible rectangle
+ rect.translate(getRect().mLeft, getRect().mBottom);
+
+ if (!getRect().contains(rect))
+ {
+ // for accordition's scroll, height is in pixels
+ // Back to local coords and calculate position for scroller
+ S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom;
+ S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop;
+
+ S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
+ bottom, // min vertical scroll
+ top); // max vertical scroll
+
+ mScrollbar->setDocPos(scroll_pos);
+ }
+ }
+
+ LLUICtrl::onUpdateScrollToChild(cntrl);
+}
+
void LLAccordionCtrl::onOpen (const LLSD& key)
{
for(size_t i=0;i<mAccordionTabs.size();++i)
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 1fe64c472e..2828254472 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -111,6 +111,7 @@ public:
void draw();
void onScrollPosChangeCallback(S32, LLScrollbar*);
+ virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
void onOpen (const LLSD& key);
S32 notifyParent(const LLSD& info);
@@ -137,6 +138,8 @@ public:
bool getFitParent() const {return mFitParent;}
+ void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; }
+
private:
void initNoTabsWidget(const LLTextBox::Params& tb_params);
void updateNoTabsHelpTextVisibility();
@@ -182,6 +185,8 @@ private:
F32 mAutoScrollRate;
LLTextBox* mNoVisibleTabsHelpText;
+ bool mSkipScrollToChild;
+
std::string mNoMatchedTabsOrigString;
std::string mNoVisibleTabsOrigString;
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index eaf1284237..04485c6262 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -452,6 +452,35 @@ void LLAccordionCtrlTab::onVisibilityChange(BOOL new_visibility)
notifyParent(LLSD().with("child_visibility_change", new_visibility));
}
+// virtual
+void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl)
+{
+ if (mScrollbar && mScrollbar->getVisible())
+ {
+ LLRect rect;
+ cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this);
+
+ // Translate to parent coordinatess to check if we are in visible rectangle
+ rect.translate(getRect().mLeft, getRect().mBottom);
+
+ if (!getRect().contains(rect))
+ {
+ // for accordition's scroll, height is in pixels
+ // Back to local coords and calculate position for scroller
+ S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom;
+ S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop;
+
+ S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
+ bottom, // min vertical scroll
+ top); // max vertical scroll
+
+ mScrollbar->setDocPos(scroll_pos);
+ }
+ }
+
+ LLUICtrl::onUpdateScrollToChild(cntrl);
+}
+
BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
{
if(mCollapsible && mHeaderVisible && mCanOpenClose)
@@ -977,7 +1006,7 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)
LLRect screen_rect;
localRectToScreen(child->getRect(),&screen_rect);
- if ( root_rect.overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect))
+ if ( root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect))
{
gGL.matrixMode(LLRender::MM_MODELVIEW);
LLUI::pushMatrix();
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index 0263bce4be..2c72e8c036 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -159,6 +159,7 @@ public:
* Raises notifyParent event with "child_visibility_change" = new_visibility
*/
void onVisibilityChange(BOOL new_visibility);
+ virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
// Changes expand/collapse state and triggers expand/collapse callbacks
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp
index 0557cd4375..5f11c383ef 100644
--- a/indra/llui/llbadgeowner.cpp
+++ b/indra/llui/llbadgeowner.cpp
@@ -56,6 +56,14 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p)
}
}
+void LLBadgeOwner::reshapeBadge(const LLRect& new_rect)
+{
+ if (mBadge)
+ {
+ mBadge->setShape(new_rect);
+ }
+}
+
void LLBadgeOwner::setBadgeVisibility(bool visible)
{
if (mBadge)
diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h
index 01ed95f3a3..4ce208fa0d 100644
--- a/indra/llui/llbadgeowner.h
+++ b/indra/llui/llbadgeowner.h
@@ -46,6 +46,7 @@ public:
bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; };
void setBadgeVisibility(bool visible);
void setDrawBadgeAtTop(bool draw_at_top);
+ void reshapeBadge(const LLRect& new_rect);
private:
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 6b7a8a8b86..0e59fdf519 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -47,6 +47,7 @@
#include "llnotificationsutil.h"
#include "llrender.h"
#include "lluictrlfactory.h"
+#include "lluiusage.h"
#include "llhelp.h"
#include "lldockablefloater.h"
#include "llviewereventrecorder.h"
@@ -90,8 +91,8 @@ LLButton::Params::Params()
image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
flash_color("flash_color"),
- pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
- pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
+ pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
+ pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
pad_bottom("pad_bottom"),
click_callback("click_callback"),
mouse_down_callback("mouse_down_callback"),
@@ -437,6 +438,13 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
setFocus(TRUE);
}
+ if (!mFunctionName.empty())
+ {
+ LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL;
+ LLUIUsage::instance().logCommand(mFunctionName);
+ LLUIUsage::instance().logControl(getPathname());
+ }
+
/*
* ATTENTION! This call fires another mouse down callback.
* If you wish to remove this call emit that signal directly
@@ -614,7 +622,7 @@ void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height)
// virtual
void LLButton::draw()
{
- static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);
+ static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true);
F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool pressed_by_keyboard = FALSE;
@@ -628,7 +636,7 @@ void LLButton::draw()
{
S32 local_mouse_x ;
S32 local_mouse_y;
- LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
+ LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y);
}
@@ -643,7 +651,8 @@ void LLButton::draw()
LLColor4 highlighting_color = LLColor4::white;
LLColor4 glow_color = LLColor4::white;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
- LLUIImage* imagep = NULL;
+ LLUIImage* imagep = NULL;
+ LLUIImage* image_glow = NULL;
// Cancel sticking of color, if the button is pressed,
// or when a flashing of the previously selected button is ended
@@ -710,17 +719,18 @@ void LLButton::draw()
imagep = mImageDisabled;
}
+ image_glow = imagep;
+
if (mFlashing)
{
- // if button should flash and we have icon for flashing, use it as image for button
- if(flash && mImageFlash)
+ if (flash && mImageFlash)
{
- // setting flash to false to avoid its further influence on glow
- flash = false;
- imagep = mImageFlash;
+ // if button should flash and we have icon for flashing, use it as image for button
+ image_glow = mImageFlash;
}
- // else use usual flashing via flash_color
- else if (mFlashingTimer)
+
+ // provide fade-in and fade-out via flash_color
+ if (mFlashingTimer)
{
LLColor4 flash_color = mFlashBgColor.get();
use_glow_effect = TRUE;
@@ -734,6 +744,11 @@ void LLButton::draw()
{
glow_color = highlighting_color;
}
+ else
+ {
+ // will fade from highlight color
+ glow_color = flash_color;
+ }
}
}
@@ -806,7 +821,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
- imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
+ image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
@@ -817,7 +832,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
- imagep->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
+ image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
@@ -1261,10 +1276,10 @@ void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname)
// search back through the button's parents for a panel
// with a help_topic string defined
std::string help_topic;
- if (LLUI::sHelpImpl &&
+ if (LLUI::getInstance()->mHelpImpl &&
ctrl->findHelpTopic(help_topic))
{
- LLUI::sHelpImpl->showTopic(help_topic);
+ LLUI::getInstance()->mHelpImpl->showTopic(help_topic);
return; // success
}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 7629ed1fea..572d36996c 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -205,6 +205,7 @@ public:
void setFlashing( bool b, bool force_flashing = false );
BOOL getFlashing() const { return mFlashing; }
LLFlashTimer* getFlashTimer() {return mFlashingTimer;}
+ void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; };
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
LLFontGL::HAlign getHAlign() const { return mHAlign; }
diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h
index f5b242fdfc..c39e44200c 100644
--- a/indra/llui/llchat.h
+++ b/indra/llui/llchat.h
@@ -37,7 +37,8 @@ typedef enum e_chat_source_type
CHAT_SOURCE_SYSTEM = 0,
CHAT_SOURCE_AGENT = 1,
CHAT_SOURCE_OBJECT = 2,
- CHAT_SOURCE_UNKNOWN = 3
+ CHAT_SOURCE_TELEPORT = 3,
+ CHAT_SOURCE_UNKNOWN = 4
} EChatSourceType;
typedef enum e_chat_type
@@ -64,7 +65,8 @@ typedef enum e_chat_style
{
CHAT_STYLE_NORMAL,
CHAT_STYLE_IRC,
- CHAT_STYLE_HISTORY
+ CHAT_STYLE_HISTORY,
+ CHAT_STYLE_TELEPORT_SEP
}EChatStyle;
// A piece of chat
diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp
index dac001afab..c506576126 100644
--- a/indra/llui/llchatentry.cpp
+++ b/indra/llui/llchatentry.cpp
@@ -201,7 +201,7 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
@@ -225,7 +225,7 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index eee6339caf..08da599ef2 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -47,10 +47,18 @@ static LLDefaultChildRegistry::Register<LLCheckBoxCtrl> r("check_box");
template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(
const std::string& name, BOOL recurse) const;
+void LLCheckBoxCtrl::WordWrap::declareValues()
+{
+ declare("none", EWordWrap::WRAP_NONE);
+ declare("down", EWordWrap::WRAP_DOWN);
+ declare("up", EWordWrap::WRAP_UP);
+}
+
LLCheckBoxCtrl::Params::Params()
: initial_value("initial_value", false),
label_text("label_text"),
check_button("check_button"),
+ word_wrap("word_wrap", EWordWrap::WRAP_NONE),
radio_style("radio_style")
{}
@@ -59,14 +67,14 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
: LLUICtrl(p),
mTextEnabledColor(p.label_text.text_color()),
mTextDisabledColor(p.label_text.text_readonly_color()),
- mFont(p.font())
+ mFont(p.font()),
+ mWordWrap(p.word_wrap)
{
mViewModel->setValue(LLSD(p.initial_value));
mViewModel->resetDirty();
static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0);
static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0);
static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0);
- static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0);
// must be big enough to hold all children
setUseBoundingRect(TRUE);
@@ -85,20 +93,47 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
{
tbparams.font(p.font);
}
- mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);
+
+ mLabel = LLUICtrlFactory::create<LLTextBox>(tbparams);
+ if (mWordWrap != WRAP_NONE)
+ {
+ // Not setWordWrap(mWordWrap != WRAP_NONE) because there might be some old lurking code that sets it manually
+ mLabel->setWordWrap(true);
+ S32 new_width = getRect().getWidth() - p.check_button.rect().getWidth() - llcheckboxctrl_hpad;
+ LLRect label_rect = mLabel->getRect();
+ label_rect.mRight = label_rect.mLeft + new_width;
+ mLabel->setRect(label_rect);
+ }
mLabel->reshapeToFitText();
- addChild(mLabel);
LLRect label_rect = mLabel->getRect();
+ if (mLabel->getLineCount() > 1)
+ {
+ if (mWordWrap == WRAP_DOWN)
+ {
+ // reshapeToFitText uses LLView::reshape() which always reshapes
+ // from bottom to top, but we want to extend the bottom
+ // Note: might be better idea to use getRect().mTop of LLCheckBoxCtrl (+pad) as top point of new rect
+ S32 delta = ll_round((F32)mLabel->getFont()->getLineHeight() * mLabel->getLineSpacingMult()) - label_rect.getHeight();
+ label_rect.translate(0, delta);
+ mLabel->setRect(label_rect);
+ }
+ // else
+ // WRAP_UP is essentially done by reshapeToFitText() (extends from bottom to top)
+ // howhever it doesn't respect rect of checkbox
+ // todo: this should be fixed, but there are at least couple checkboxes that use this feature as is.
+ }
+
+ addChild(mLabel);
// Button
- // Note: button cover the label by extending all the way to the right.
+ // Note: button cover the label by extending all the way to the right and down.
LLRect btn_rect = p.check_button.rect();
btn_rect.setOriginAndSize(
btn_rect.mLeft,
- btn_rect.mBottom,
+ llmin(btn_rect.mBottom, label_rect.mBottom),
llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft),
- llmax( label_rect.getHeight(), btn_rect.mTop));
+ llmax(label_rect.getHeight(), btn_rect.mTop));
std::string active_true_id, active_false_id;
std::string inactive_true_id, inactive_false_id;
@@ -152,20 +187,53 @@ void LLCheckBoxCtrl::clear()
void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
{
-
- mLabel->reshapeToFitText();
-
- LLRect label_rect = mLabel->getRect();
+ LLRect rect = getRect();
+ S32 delta_width = width - rect.getWidth();
+ S32 delta_height = height - rect.getHeight();
+
+ if (delta_width || delta_height)
+ {
+ // adjust our rectangle
+ rect.mRight = getRect().mLeft + width;
+ rect.mTop = getRect().mBottom + height;
+ setRect(rect);
+ }
+
+ // reshapeToFitText reshapes label to minimal size according to last bounding box
+ // it will work fine in case of decrease of space, but if we get more space or text
+ // becomes longer, label will fail to grow so reinit label's dimentions.
+
+ static LLUICachedControl<S32> llcheckboxctrl_hpad("UICheckboxctrlHPad", 0);
+ LLRect label_rect = mLabel->getRect();
+ S32 new_width = getRect().getWidth() - label_rect.mLeft - llcheckboxctrl_hpad;
+ label_rect.mRight = label_rect.mLeft + new_width;
+ mLabel->setRect(label_rect);
+
+ S32 label_top = label_rect.mTop;
+ mLabel->reshapeToFitText(TRUE);
+
+ label_rect = mLabel->getRect();
+ if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN)
+ {
+ // reshapeToFitText uses LLView::reshape() which always reshapes
+ // from bottom to top, but we want to extend the bottom so
+ // reposition control
+ S32 delta = label_top - label_rect.mTop;
+ label_rect.translate(0, delta);
+ mLabel->setRect(label_rect);
+ }
// Button
- // Note: button cover the label by extending all the way to the right.
+ // Note: button cover the label by extending all the way to the right and down.
LLRect btn_rect = mButton->getRect();
btn_rect.setOriginAndSize(
btn_rect.mLeft,
- btn_rect.mBottom,
+ llmin(btn_rect.mBottom, label_rect.mBottom),
llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft),
llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight()));
mButton->setShape(btn_rect);
+
+ updateBoundingRect();
}
//virtual
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index 07ae9c3b18..eb5bd5b6da 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -50,6 +50,19 @@ class LLCheckBoxCtrl
, public ll::ui::SearchableControl
{
public:
+
+ enum EWordWrap
+ {
+ WRAP_NONE,
+ WRAP_UP,
+ WRAP_DOWN
+ };
+
+ struct WordWrap : public LLInitParam::TypeValuesHelper<EWordWrap, WordWrap>
+ {
+ static void declareValues();
+ };
+
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
@@ -58,6 +71,8 @@ public:
Optional<LLTextBox::Params> label_text;
Optional<LLButton::Params> check_button;
+ Optional<EWordWrap, WordWrap> word_wrap;
+
Ignored radio_style;
Params();
@@ -129,6 +144,8 @@ protected:
LLUIColor mTextEnabledColor;
LLUIColor mTextDisabledColor;
+
+ EWordWrap mWordWrap; // off, shifts text up, shifts text down
};
// Build time optimization, generate once in .cpp file
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index b2ad38bddf..52dc908655 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -514,6 +514,14 @@ S32 LLComboBox::getCurrentIndex() const
return -1;
}
+void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled)
+{
+ LLScrollListItem *found = mList->getItem(value);
+ if (found)
+ {
+ found->setEnabled(enabled);
+ }
+}
void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
@@ -668,7 +676,7 @@ void LLComboBox::showList()
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
- LLUI::addPopup(this);
+ LLUI::getInstance()->addPopup(this);
setUseBoundingRect(TRUE);
// updateBoundingRect();
@@ -694,7 +702,7 @@ void LLComboBox::hideList()
mList->mouseOverHighlightNthItem(-1);
setUseBoundingRect(FALSE);
- LLUI::removePopup(this);
+ LLUI::getInstance()->removePopup(this);
// updateBoundingRect();
}
}
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 7d38c051a5..4af3313162 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -158,6 +158,8 @@ public:
BOOL setCurrentByIndex( S32 index );
S32 getCurrentIndex() const;
+ void setEnabledByValue(const LLSD& value, BOOL enabled);
+
void createLineEditor(const Params&);
//========================================================================
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 26ae31cac6..8fc2978bdd 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -68,7 +68,7 @@ LLConsole::LLConsole(const LLConsole::Params& p)
setFontSize(p.font_size_index);
}
mFadeTime = mLinePersistTime - FADE_DURATION;
- setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines"));
+ setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines"));
}
void LLConsole::setLinePersistTime(F32 seconds)
@@ -180,7 +180,9 @@ void LLConsole::draw()
LLUIImagePtr imagep = LLUI::getUIImage("transparent");
- F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
+ static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f);
+ F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f);
+
LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground");
color.mV[VALPHA] *= console_opacity;
@@ -369,9 +371,9 @@ LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_t
// static
void LLConsole::updateClass()
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ for (auto& con : instance_snapshot())
{
- it->update();
+ con.update();
}
}
diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h
index 5ff05698b0..04f5e71609 100644
--- a/indra/llui/llconsole.h
+++ b/indra/llui/llconsole.h
@@ -51,7 +51,7 @@ public:
Optional<F32> persist_time;
Optional<S32> font_size_index;
Params()
- : max_lines("max_lines", LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")),
+ : max_lines("max_lines", LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")),
persist_time("persist_time", 0.f), // forever
font_size_index("font_size_index")
{
diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp
index 6d9c429b08..39793316f4 100644
--- a/indra/llui/llflashtimer.cpp
+++ b/indra/llui/llflashtimer.cpp
@@ -40,10 +40,10 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period)
// By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
// Due to Timer is implemented as derived class from EventTimer it is impossible to change period
// in runtime. So, both settings are made as required restart.
- mFlashCount = 2 * ((count > 0) ? count : LLUI::sSettingGroups["config"]->getS32("FlashCount"));
+ mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount"));
if (mPeriod <= 0)
{
- mPeriod = LLUI::sSettingGroups["config"]->getF32("FlashPeriod");
+ mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod");
}
}
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index a245dd8f78..0e42922543 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1,5 +1,4 @@
/**
-
* @file llfloater.cpp
* @brief LLFloater base class
*
@@ -37,6 +36,7 @@
#include "lluictrlfactory.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
+#include "llcriticaldamp.h" // LLSmoothInterpolation
#include "lldir.h"
#include "lldraghandle.h"
#include "llfloaterreg.h"
@@ -58,12 +58,17 @@
#include "llhelp.h"
#include "llmultifloater.h"
#include "llsdutil.h"
+#include "lluiusage.h"
#include <boost/foreach.hpp>
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
+const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f;
+const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f;
+
namespace LLInitParam
{
void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
@@ -194,7 +199,9 @@ LLFloater::Params::Params()
help_pressed_image("help_pressed_image"),
open_callback("open_callback"),
close_callback("close_callback"),
- follows("follows")
+ follows("follows"),
+ rel_x("rel_x", 0),
+ rel_y("rel_y", 0)
{
changeDefault(visible, false);
}
@@ -215,14 +222,14 @@ void LLFloater::initClass()
sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
}
- LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
+ LLControlVariable* ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
if (ctrl)
{
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
updateActiveFloaterTransparency();
}
- ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
+ ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
if (ctrl)
{
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
@@ -263,6 +270,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mHasBeenDraggedWhileMinimized(FALSE),
mPreviousMinimizedBottom(0),
mPreviousMinimizedLeft(0),
+ mDefaultRelativeX(p.rel_x),
+ mDefaultRelativeY(p.rel_y),
mMinimizeSignal(NULL)
// mNotificationContext(NULL)
{
@@ -299,12 +308,10 @@ void LLFloater::initFloater(const Params& p)
mButtonsEnabled[BUTTON_CLOSE] = TRUE;
}
- // Help button: '?'
- if ( !mHelpTopic.empty() )
- {
- mButtonsEnabled[BUTTON_HELP] = TRUE;
- }
-
+ // Help button: '?'
+ //SL-14050 Disable all Help question marks
+ mButtonsEnabled[BUTTON_HELP] = FALSE;
+
// Minimize button only for top draggers
if ( !mDragOnLeft && mCanMinimize )
{
@@ -374,13 +381,15 @@ void LLFloater::layoutDragHandle()
// static
void LLFloater::updateActiveFloaterTransparency()
{
- sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
+ static LLCachedControl<F32> active_transparency(*LLUI::getInstance()->mSettingGroups["config"], "ActiveFloaterTransparency", 1.f);
+ sActiveControlTransparency = active_transparency;
}
// static
void LLFloater::updateInactiveFloaterTransparency()
{
- sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
+ static LLCachedControl<F32> inactive_transparency(*LLUI::getInstance()->mSettingGroups["config"], "InactiveFloaterTransparency", 0.95f);
+ sInactiveControlTransparency = inactive_transparency;
}
void LLFloater::addResizeCtrls()
@@ -503,7 +512,12 @@ void LLFloater::destroy()
// virtual
LLFloater::~LLFloater()
{
- LLFloaterReg::removeInstance(mInstanceName, mKey);
+ if (!isDead())
+ {
+ // If it's dead, instance is supposed to be already removed, and
+ // in case of single instance we can remove new one by accident
+ LLFloaterReg::removeInstance(mInstanceName, mKey);
+ }
if( gFocusMgr.childHasKeyboardFocus(this))
{
@@ -579,7 +593,7 @@ std::string LLFloater::getControlName(const std::string& name, const LLSD& key)
LLControlGroup* LLFloater::getControlGroup()
{
// Floater size, position, visibility, etc are saved in per-account settings.
- return LLUI::sSettingGroups["account"];
+ return LLUI::getInstance()->mSettingGroups["account"];
}
void LLFloater::setVisible( BOOL visible )
@@ -592,7 +606,7 @@ void LLFloater::setVisible( BOOL visible )
if( !visible )
{
- LLUI::removePopup(this);
+ LLUI::getInstance()->removePopup(this);
if( gFocusMgr.childHasMouseCapture( this ) )
{
@@ -818,7 +832,7 @@ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
void LLFloater::releaseFocus()
{
- LLUI::removePopup(this);
+ LLUI::getInstance()->removePopup(this);
setFocus(FALSE);
@@ -932,6 +946,15 @@ bool LLFloater::applyRectControl()
saved_rect = true;
}
+ else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0))
+ {
+ mPosition.mX = mDefaultRelativeX;
+ mPosition.mY = mDefaultRelativeY;
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ applyRelativePosition();
+
+ saved_rect = true;
+ }
// remember updated position
if (rect_specified)
@@ -1629,6 +1652,7 @@ void LLFloater::bringToFront( S32 x, S32 y )
// virtual
void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)
{
+ LLUIUsage::instance().logFloater(getInstanceName());
LLMultiFloater* hostp = getHost();
if (hostp)
{
@@ -1771,13 +1795,13 @@ void LLFloater::onClickDock(LLFloater* self)
// static
void LLFloater::onClickHelp( LLFloater* self )
{
- if (self && LLUI::sHelpImpl)
+ if (self && LLUI::getInstance()->mHelpImpl)
{
// find the current help context for this floater
std::string help_topic;
if (self->findHelpTopic(help_topic))
{
- LLUI::sHelpImpl->showTopic(help_topic);
+ LLUI::getInstance()->mHelpImpl->showTopic(help_topic);
}
}
}
@@ -2116,6 +2140,70 @@ void LLFloater::updateTitleButtons()
}
}
+void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
+ F32 max_cone_opacity,
+ LLView *owner_view,
+ F32 fade_time,
+ F32 contex_cone_in_alpha,
+ F32 contex_cone_out_alpha)
+{
+ if (owner_view
+ && owner_view->isInVisibleChain()
+ && hasFocus()
+ && context_cone_opacity > 0.001f
+ && gFocusMgr.childHasKeyboardFocus(this))
+ {
+ // draw cone of context pointing back to owner (e.x. texture swatch)
+ LLRect owner_rect;
+ owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this);
+ LLRect local_rect = getLocalRect();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable(GL_CULL_FACE);
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ }
+ gGL.end();
+ }
+
+ if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+ {
+ context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time));
+ }
+ else
+ {
+ context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time));
+ }
+}
+
void LLFloater::buildButtons(const Params& floater_params)
{
static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
@@ -2931,7 +3019,7 @@ void LLFloaterView::syncFloaterTabOrder()
if (modal_dialog)
{
// If we have a visible modal dialog, make sure that it has focus
- LLUI::addPopup(modal_dialog);
+ LLUI::getInstance()->addPopup(modal_dialog);
if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) )
{
@@ -3132,6 +3220,9 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
mSingleInstance = p.single_instance;
mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance;
+ mDefaultRelativeX = p.rel_x;
+ mDefaultRelativeY = p.rel_y;
+
mPositioning = p.positioning;
mSaveRect = p.save_rect;
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 165f67499b..2672d600c6 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -172,6 +172,9 @@ public:
Optional<S32> header_height,
legacy_header_height; // HACK see initFromXML()
+ Optional<F32> rel_x,
+ rel_y;
+
// Images for top-right controls
Optional<LLUIImage*> close_image,
restore_image,
@@ -395,6 +398,15 @@ protected:
virtual void updateTitleButtons();
+ // Draws a cone from this floater to parent floater or view (owner)
+ // Modifies context_cone_opacity (interpolates according to fade time and returns new value)
+ void drawConeToOwner(F32 &context_cone_opacity,
+ F32 max_cone_opacity,
+ LLView *owner_view,
+ F32 context_fade_time = CONTEXT_CONE_FADE_TIME,
+ F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA,
+ F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA);
+
private:
void setForeground(BOOL b); // called only by floaterview
void cleanupHandles(); // remove handles to dead floaters
@@ -424,6 +436,10 @@ private:
void updateTransparency(LLView* view, ETypeTransparency transparency_type);
public:
+ static const F32 CONTEXT_CONE_IN_ALPHA;
+ static const F32 CONTEXT_CONE_OUT_ALPHA;
+ static const F32 CONTEXT_CONE_FADE_TIME;
+
// Called when floater is opened, passes mKey
// Public so external views or floaters can watch for this floater opening
commit_signal_t mOpenSignal;
@@ -508,6 +524,9 @@ private:
BOOL mHasBeenDraggedWhileMinimized;
S32 mPreviousMinimizedBottom;
S32 mPreviousMinimizedLeft;
+
+ F32 mDefaultRelativeX;
+ F32 mDefaultRelativeY;
};
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 9ef290abc0..36a0cb0fd0 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -32,6 +32,7 @@
#include "llfloater.h"
#include "llmultifloater.h"
#include "llfloaterreglistener.h"
+#include "lluiusage.h"
//*******************************************************
@@ -57,6 +58,12 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con
}
//static
+bool LLFloaterReg::isRegistered(const std::string& name)
+{
+ return sBuildMap.find(name) != sBuildMap.end();
+}
+
+//static
LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
{
const std::string& groupname = sGroupMap[name];
@@ -445,7 +452,7 @@ void LLFloaterReg::registerControlVariables()
}
}
- const LLSD& exclude_list = LLUI::sSettingGroups["config"]->getLLSD("always_showable_floaters");
+ const LLSD& exclude_list = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("always_showable_floaters");
for (LLSD::array_const_iterator iter = exclude_list.beginArray();
iter != exclude_list.endArray();
iter++)
@@ -472,7 +479,6 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD&
std::string name = sdname.asString();
LLFloater* instance = getInstance(name, key);
-
if (!instance)
{
LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL;
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index e3b17dcb4f..a457a15673 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -85,6 +85,7 @@ public:
static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func,
const std::string& groupname = LLStringUtil::null);
+ static bool isRegistered(const std::string& name);
// Helpers
static LLFloater* getLastFloaterInGroup(const std::string& name);
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 1b213c3418..7b0a6cbdae 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -183,7 +183,7 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
}
}
- LLUI::removePopup(view);
+ LLUI::getInstance()->removePopup(view);
}
void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only)
@@ -481,7 +481,7 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
// release focus from "top ctrl"s, which generally hides them
if (!focus)
{
- LLUI::clearPopups();
+ LLUI::getInstance()->clearPopups();
}
mAppHasFocus = focus;
}
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 895753aeae..622c9edba7 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -148,7 +148,9 @@ LLFolderView::Params::Params()
: title("title"),
use_label_suffix("use_label_suffix"),
allow_multiselect("allow_multiselect", true),
+ allow_drag("allow_drag", true),
show_empty_message("show_empty_message", true),
+ suppress_folder_menu("suppress_folder_menu", false),
use_ellipses("use_ellipses", false),
options_menu("options_menu", "")
{
@@ -162,11 +164,13 @@ LLFolderView::LLFolderView(const Params& p)
mScrollContainer( NULL ),
mPopupMenuHandle(),
mAllowMultiSelect(p.allow_multiselect),
+ mAllowDrag(p.allow_drag),
mShowEmptyMessage(p.show_empty_message),
mShowFolderHierarchy(FALSE),
mRenameItem( NULL ),
mNeedsScroll( FALSE ),
mUseLabelSuffix(p.use_label_suffix),
+ mSuppressFolderMenu(p.suppress_folder_menu),
mPinningSelectedItem(FALSE),
mNeedsAutoSelect( FALSE ),
mAutoSelectOverride(FALSE),
@@ -338,7 +342,9 @@ static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View");
void LLFolderView::filter( LLFolderViewFilter& filter )
{
LL_RECORD_BLOCK_TIME(FTM_FILTER);
- filter.resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32(mParentPanel.get()->getVisible() ? "FilterItemsMaxTimePerFrameVisible" : "FilterItemsMaxTimePerFrameUnvisible"), 1, 100));
+ static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
+ static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
+ filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
@@ -657,7 +663,8 @@ void LLFolderView::draw()
closeAutoOpenedFolders();
}
- if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout") || !mSearchString.size())
+ static LLCachedControl<F32> type_ahead_timeout(*LLUI::getInstance()->mSettingGroups["config"], "TypeAheadTimeout", 1.5f);
+ if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size())
{
mSearchString.clear();
}
@@ -733,7 +740,7 @@ void LLFolderView::closeRenamer( void )
if (mRenamer && mRenamer->getVisible())
{
// Triggers onRenamerLost() that actually closes the renamer.
- LLUI::removePopup(mRenamer);
+ LLUI::getInstance()->removePopup(mRenamer);
}
}
@@ -1064,7 +1071,7 @@ void LLFolderView::startRenamingSelectedItem( void )
// set focus will fail unless item is visible
mRenamer->setFocus( TRUE );
mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this));
- LLUI::addPopup(mRenamer);
+ LLUI::getInstance()->addPopup(mRenamer);
}
}
@@ -1321,7 +1328,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char)
}
//do text search
- if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout"))
+ if (mSearchTimer.getElapsedTimeF32() > LLUI::getInstance()->mSettingGroups["config"]->getF32("TypeAheadTimeout"))
{
mSearchString.clear();
}
@@ -1432,10 +1439,13 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;
S32 count = mSelectedItems.size();
+
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
- if ( handled
+ bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected();
+ if ((handled
&& ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible
- && menu )
+ && menu ) &&
+ !hide_folder_menu)
{
if (mCallbackRegistrar)
{
@@ -1449,7 +1459,7 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
if (mCallbackRegistrar)
{
mCallbackRegistrar->popScope();
- }
+ }
}
else
{
@@ -1803,7 +1813,7 @@ void LLFolderView::updateRenamerPosition()
screenPointToLocal( x, y, &x, &y );
mRenamer->setOrigin( x, y );
- LLRect scroller_rect(0, 0, (S32)LLUI::getWindowSize().mV[VX], 0);
+ LLRect scroller_rect(0, 0, (S32)LLUI::getInstance()->getWindowSize().mV[VX], 0);
if (mScrollContainer)
{
scroller_rect = mScrollContainer->getContentWindowRect();
@@ -1862,6 +1872,20 @@ void LLFolderView::updateMenu()
}
}
+bool LLFolderView::isFolderSelected()
+{
+ selected_items_t::iterator item_iter;
+ for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter)
+ {
+ LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*item_iter);
+ if (folder != NULL)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
bool LLFolderView::selectFirstItem()
{
for (folders_t::iterator iter = mFolders.begin();
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 2926e160d0..6bb5e6c02e 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -90,9 +90,11 @@ public:
Optional<std::string> title;
Optional<bool> use_label_suffix,
allow_multiselect,
+ allow_drag,
show_empty_message,
use_ellipses,
- show_item_link_overlays;
+ show_item_link_overlays,
+ suppress_folder_menu;
Mandatory<LLFolderViewModelInterface*> view_model;
Optional<LLFolderViewGroupedItemModel*> grouped_item_model;
Mandatory<std::string> options_menu;
@@ -123,6 +125,7 @@ public:
void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }
bool getAllowMultiSelect() { return mAllowMultiSelect; }
+ bool getAllowDrag() { return mAllowDrag; }
// Close all folders in the view
void closeAllFolders();
@@ -259,6 +262,8 @@ protected:
void closeRenamer( void );
+ bool isFolderSelected();
+
bool selectFirstItem();
bool selectLastItem();
@@ -271,6 +276,7 @@ protected:
selected_items_t mSelectedItems;
bool mKeyboardSelection,
mAllowMultiSelect,
+ mAllowDrag,
mShowEmptyMessage,
mShowFolderHierarchy,
mNeedsScroll,
@@ -282,7 +288,8 @@ protected:
mDragAndDropThisFrame,
mShowItemLinkOverlays,
mShowSelectionContext,
- mShowSingleSelection;
+ mShowSingleSelection,
+ mSuppressFolderMenu;
// Renaming variables and methods
LLFolderViewItem* mRenameItem; // The item currently being renamed
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 0c1c3c40ec..835d3b781d 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -122,6 +122,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
: LLView(p),
mLabelWidth(0),
mLabelWidthDirty(false),
+ mSuffixNeedsRefresh(false),
mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT),
mParentFolder( NULL ),
mIsSelected( FALSE ),
@@ -181,11 +182,25 @@ LLFolderViewItem::~LLFolderViewItem()
BOOL LLFolderViewItem::postBuild()
{
- refresh();
+ LLFolderViewModelItem& vmi = *getViewModelItem();
+ // getDisplayName() is expensive (due to internal getLabelSuffix() and name building)
+ // it also sets search strings so it requires a filter reset
+ mLabel = vmi.getDisplayName();
+ setToolTip(vmi.getName());
+
+ // Dirty the filter flag of the model from the view (CHUI-849)
+ vmi.dirtyFilter();
+
+ // Don't do full refresh on constructor if it is possible to avoid
+ // it significantly slows down bulk view creation.
+ // Todo: Ideally we need to move getDisplayName() out of constructor as well.
+ // Like: make a logic that will let filter update search string,
+ // while LLFolderViewItem::arrange() updates visual part
+ mSuffixNeedsRefresh = true;
+ mLabelWidthDirty = true;
return TRUE;
}
-
LLFolderView* LLFolderViewItem::getRoot()
{
return mRoot;
@@ -280,24 +295,51 @@ BOOL LLFolderViewItem::isPotentiallyVisible(S32 filter_generation)
void LLFolderViewItem::refresh()
{
- LLFolderViewModelItem& vmi = *getViewModelItem();
+ LLFolderViewModelItem& vmi = *getViewModelItem();
- mLabel = vmi.getDisplayName();
+ mLabel = vmi.getDisplayName();
+ setToolTip(vmi.getName());
+ // icons are slightly expensive to get, can be optimized
+ // see LLInventoryIcon::getIcon()
+ mIcon = vmi.getIcon();
+ mIconOpen = vmi.getIconOpen();
+ mIconOverlay = vmi.getIconOverlay();
- setToolTip(vmi.getName());
- mIcon = vmi.getIcon();
- mIconOpen = vmi.getIconOpen();
- mIconOverlay = vmi.getIconOverlay();
+ if (mRoot->useLabelSuffix())
+ {
+ // Very Expensive!
+ // Can do a number of expensive checks, like checking active motions, wearables or friend list
+ mLabelStyle = vmi.getLabelStyle();
+ mLabelSuffix = vmi.getLabelSuffix();
+ }
+
+ // Dirty the filter flag of the model from the view (CHUI-849)
+ vmi.dirtyFilter();
+
+ mLabelWidthDirty = true;
+ mSuffixNeedsRefresh = false;
+}
+
+void LLFolderViewItem::refreshSuffix()
+{
+ LLFolderViewModelItem const* vmi = getViewModelItem();
+
+ // icons are slightly expensive to get, can be optimized
+ // see LLInventoryIcon::getIcon()
+ mIcon = vmi->getIcon();
+ mIconOpen = vmi->getIconOpen();
+ mIconOverlay = vmi->getIconOverlay();
if (mRoot->useLabelSuffix())
{
- mLabelStyle = vmi.getLabelStyle();
- mLabelSuffix = vmi.getLabelSuffix();
+ // Very Expensive!
+ // Can do a number of expensive checks, like checking active motions, wearables or friend list
+ mLabelStyle = vmi->getLabelStyle();
+ mLabelSuffix = vmi->getLabelSuffix();
}
- mLabelWidthDirty = true;
- // Dirty the filter flag of the model from the view (CHUI-849)
- vmi.dirtyFilter();
+ mLabelWidthDirty = true;
+ mSuffixNeedsRefresh = false;
}
// Utility function for LLFolderView
@@ -348,6 +390,12 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
: 0;
if (mLabelWidthDirty)
{
+ if (mSuffixNeedsRefresh)
+ {
+ // Expensive. But despite refreshing label,
+ // it is purely visual, so it is fine to do at our laisure
+ refreshSuffix();
+ }
mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
mLabelWidthDirty = false;
}
@@ -548,7 +596,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
{
- static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::sSettingGroups["config"],"DragAndDropDistanceThreshold", 3);
+ static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3);
mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight));
@@ -557,6 +605,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
LLFolderView* root = getRoot();
if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()
+ && root->getAllowDrag()
&& root->getCurSelectedItem()
&& root->startDrag())
{
@@ -913,9 +962,10 @@ void LLFolderViewItem::draw()
//
if (filter_string_length > 0)
{
- F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mViewModelItem->getFilterStringOffset());
+ S32 filter_offset = mViewModelItem->getFilterStringOffset();
+ F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
- font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy,
+ font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
filter_string_length, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE );
}
@@ -1558,7 +1608,7 @@ void LLFolderViewFolder::destroyView()
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
-void LLFolderViewFolder::extractItem( LLFolderViewItem* item )
+void LLFolderViewFolder::extractItem( LLFolderViewItem* item, bool deparent_model )
{
if (item->isSelected())
getRoot()->clearSelection();
@@ -1581,7 +1631,11 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item )
mItems.erase(it);
}
//item has been removed, need to update filter
- getViewModelItem()->removeChild(item->getViewModelItem());
+ if (deparent_model)
+ {
+ // in some cases model does not belong to parent view, is shared between views
+ getViewModelItem()->removeChild(item->getViewModelItem());
+ }
//because an item is going away regardless of filter status, force rearrange
requestArrange();
removeChild(item);
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 61c39e0175..616d2e7d86 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -95,6 +95,7 @@ protected:
LLPointer<LLFolderViewModelItem> mViewModelItem;
LLFontGL::StyleFlags mLabelStyle;
std::string mLabelSuffix;
+ bool mSuffixNeedsRefresh; //suffix and icons
LLUIImagePtr mIcon,
mIconOpen,
mIconOverlay;
@@ -266,8 +267,13 @@ public:
virtual BOOL passedFilter(S32 filter_generation = -1);
virtual BOOL isPotentiallyVisible(S32 filter_generation = -1);
- // refresh information from the object being viewed.
- virtual void refresh();
+ // refresh information from the object being viewed.
+ // refreshes label, suffixes and sets icons. Expensive!
+ // Causes filter update
+ virtual void refresh();
+ // refreshes suffixes and sets icons. Expensive!
+ // Does not need filter update
+ virtual void refreshSuffix();
// LLView functionality
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
@@ -381,7 +387,7 @@ public:
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
- virtual void extractItem( LLFolderViewItem* item );
+ virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true);
// This function is called by a child that needs to be resorted.
void resort(LLFolderViewItem* item);
diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp
index 3363dc5316..93122503d1 100644
--- a/indra/llui/llfolderviewmodel.cpp
+++ b/indra/llui/llfolderviewmodel.cpp
@@ -48,8 +48,9 @@ std::string LLFolderViewModelCommon::getStatusText()
void LLFolderViewModelCommon::filter()
{
- getFilter().resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsMaxTimePerFrameVisible"), 1, 100));
- mFolderView->getViewModelItem()->filter(getFilter());
+ static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
+ getFilter().resetTime(llclamp(max_time(), 1, 100));
+ mFolderView->getViewModelItem()->filter(getFilter());
}
bool LLFolderViewModelItemCommon::hasFilterStringMatch()
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index f71a88c56e..e62b2779dd 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -204,6 +204,7 @@ public:
virtual bool hasChildren() const = 0;
virtual void addChild(LLFolderViewModelItem* child) = 0;
virtual void removeChild(LLFolderViewModelItem* child) = 0;
+ virtual void clearChildren() = 0;
// This method will be called to determine if a drop can be
// performed, and will set drop to TRUE if a drop is
@@ -286,16 +287,6 @@ public:
virtual void addChild(LLFolderViewModelItem* child)
{
- // Avoid duplicates: bail out if that child is already present in the list
- // Note: this happens when models are created before views
- child_list_t::const_iterator iter;
- for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
- {
- if (child == *iter)
- {
- return;
- }
- }
mChildren.push_back(child);
child->setParent(this);
dirtyFilter();
@@ -311,9 +302,8 @@ public:
virtual void clearChildren()
{
- // As this is cleaning the whole list of children wholesale, we do need to delete the pointed objects
- // This is different and not equivalent to calling removeChild() on each child
- std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
+ // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest
+ std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); });
mChildren.clear();
dirtyDescendantsFilter();
dirtyFilter();
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 955e7089f4..29a156e933 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -166,7 +166,7 @@ void LLLayoutPanel::setVisible( BOOL visible )
void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ )
{
- if (width == getRect().getWidth() && height == getRect().getHeight()) return;
+ if (width == getRect().getWidth() && height == getRect().getHeight() && !LLView::sForceReshape) return;
if (!mIgnoreReshape && mAutoResize == false)
{
@@ -209,7 +209,7 @@ LLLayoutStack::Params::Params()
open_time_constant("open_time_constant", 0.02f),
close_time_constant("close_time_constant", 0.03f),
resize_bar_overlap("resize_bar_overlap", 1),
- border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)),
+ border_size("border_size", LLCachedControl<S32>(*LLUI::getInstance()->mSettingGroups["config"], "UIResizeBarHeight", 0)),
show_drag_handle("show_drag_handle", false),
drag_handle_first_indent("drag_handle_first_indent", 0),
drag_handle_second_indent("drag_handle_second_indent", 0),
@@ -636,10 +636,10 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
//static
void LLLayoutStack::updateClass()
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ for (auto& layout : instance_snapshot())
{
- it->updateLayout();
- it->mAnimatedThisFrame = false;
+ layout.updateLayout();
+ layout.mAnimatedThisFrame = false;
}
}
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index ff8bf30319..1badd54fca 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -96,6 +96,8 @@ LLLineEditor::Params::Params()
ignore_tab("ignore_tab", true),
is_password("is_password", false),
cursor_color("cursor_color"),
+ use_bg_color("use_bg_color", false),
+ bg_color("bg_color"),
text_color("text_color"),
text_readonly_color("text_readonly_color"),
text_tentative_color("text_tentative_color"),
@@ -150,10 +152,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mBgImageDisabled( p.background_image_disabled ),
mBgImageFocused( p.background_image_focused ),
mShowImageFocused( p.bg_image_always_focused ),
+ mUseBgColor(p.use_bg_color),
mHaveHistory(FALSE),
mReplaceNewlinesWithSpaces( TRUE ),
mLabel(p.label),
mCursorColor(p.cursor_color()),
+ mBgColor(p.bg_color()),
mFgColor(p.text_color()),
mReadOnlyFgColor(p.text_readonly_color()),
mTentativeFgColor(p.text_tentative_color()),
@@ -941,7 +945,7 @@ void LLLineEditor::removeChar()
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
@@ -992,7 +996,7 @@ void LLLineEditor::addChar(const llwchar uni_char)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
getWindow()->hideCursorUntilMouseMove();
@@ -1088,7 +1092,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
break;
@@ -1104,7 +1108,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
break;
@@ -1184,7 +1188,7 @@ void LLLineEditor::cut()
if( need_to_rollback )
{
rollback.doRollback( this );
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
else
{
@@ -1288,7 +1292,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
}
// Truncate the clean string at the limit of what will fit
clean_string = clean_string.substr(0, wchars_that_fit);
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
if (mMaxLengthChars)
@@ -1300,7 +1304,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
clean_string = clean_string.substr(0, available_chars);
}
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
mText.insert(getCursor(), clean_string);
@@ -1312,7 +1316,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
if( need_to_rollback )
{
rollback.doRollback( this );
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
else
{
@@ -1376,7 +1380,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
handled = TRUE;
@@ -1425,7 +1429,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
@@ -1452,7 +1456,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
@@ -1469,7 +1473,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
@@ -1486,7 +1490,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
handled = TRUE;
}
@@ -1567,7 +1571,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
{
rollback.doRollback(this);
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
// Notify owner if requested
@@ -1623,7 +1627,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
{
rollback.doRollback( this );
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
// Notify owner if requested
@@ -1674,7 +1678,7 @@ void LLLineEditor::doDelete()
if( need_to_rollback )
{
rollback.doRollback( this );
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
else
{
@@ -1688,37 +1692,42 @@ void LLLineEditor::doDelete()
void LLLineEditor::drawBackground()
{
- bool has_focus = hasFocus();
- LLUIImage* image;
- if ( mReadOnly )
- {
- image = mBgImageDisabled;
- }
- else if ( has_focus || mShowImageFocused)
+ F32 alpha = getCurrentTransparency();
+ if (mUseBgColor)
{
- image = mBgImageFocused;
+ gl_rect_2d(getLocalRect(), mBgColor % alpha, TRUE);
}
else
{
- image = mBgImage;
- }
-
- if (!image) return;
-
- F32 alpha = getCurrentTransparency();
+ bool has_focus = hasFocus();
+ LLUIImage* image;
+ if (mReadOnly)
+ {
+ image = mBgImageDisabled;
+ }
+ else if (has_focus || mShowImageFocused)
+ {
+ image = mBgImageFocused;
+ }
+ else
+ {
+ image = mBgImage;
+ }
- // optionally draw programmatic border
- if (has_focus)
- {
- LLColor4 tmp_color = gFocusMgr.getFocusColor();
+ if (!image) return;
+ // optionally draw programmatic border
+ if (has_focus)
+ {
+ LLColor4 tmp_color = gFocusMgr.getFocusColor();
+ tmp_color.setAlpha(alpha);
+ image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(),
+ tmp_color,
+ gFocusMgr.getFocusFlashWidth());
+ }
+ LLColor4 tmp_color = UI_VERTEX_COLOR;
tmp_color.setAlpha(alpha);
- image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(),
- tmp_color,
- gFocusMgr.getFocusFlashWidth());
+ image->draw(getLocalRect(), tmp_color);
}
- LLColor4 tmp_color = UI_VERTEX_COLOR;
- tmp_color.setAlpha(alpha);
- image->draw(getLocalRect(), tmp_color);
}
void LLLineEditor::draw()
@@ -2142,6 +2151,7 @@ void LLLineEditor::clear()
void LLLineEditor::onTabInto()
{
selectAll();
+ LLUICtrl::onTabInto();
}
//virtual
@@ -2478,7 +2488,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
{
LLRect control_rect_screen;
localRectToScreen(getRect(), &control_rect_screen);
- LLUI::screenRectToGL(control_rect_screen, control);
+ LLUI::getInstance()->screenRectToGL(control_rect_screen, control);
}
S32 preedit_left_column, preedit_right_column;
@@ -2508,7 +2518,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
S32 query_local = findPixelNearestPos(query - getCursor());
S32 query_screen_x, query_screen_y;
localPointToScreen(query_local, getRect().getHeight() / 2, &query_screen_x, &query_screen_y);
- LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
+ LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
}
if (bounds)
@@ -2524,7 +2534,7 @@ BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
LLRect preedit_rect_local(preedit_left_local, getRect().getHeight(), preedit_right_local, 0);
LLRect preedit_rect_screen;
localRectToScreen(preedit_rect_local, &preedit_rect_screen);
- LLUI::screenRectToGL(preedit_rect_screen, bounds);
+ LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds);
}
return TRUE;
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index f775d53e63..f84625bea7 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -91,10 +91,12 @@ public:
commit_on_focus_lost,
ignore_tab,
bg_image_always_focused,
- is_password;
+ is_password,
+ use_bg_color;
// colors
Optional<LLUIColor> cursor_color,
+ bg_color,
text_color,
text_readonly_color,
text_tentative_color,
@@ -281,6 +283,9 @@ public:
void resetContextMenu() { setContextMenu(NULL); };
+ void setBgImage(LLPointer<LLUIImage> image) { mBgImage = image; }
+ void setBgImageFocused(LLPointer<LLUIImage> image) { mBgImageFocused = image; }
+
private:
// private helper methods
@@ -368,6 +373,7 @@ protected:
LLTimer mTripleClickTimer;
LLUIColor mCursorColor;
+ LLUIColor mBgColor;
LLUIColor mFgColor;
LLUIColor mReadOnlyFgColor;
LLUIColor mTentativeFgColor;
@@ -388,6 +394,8 @@ protected:
BOOL mShowImageFocused;
+ bool mUseBgColor;
+
LLWString mPreeditWString;
LLWString mPreeditOverwrittenWString;
std::vector<S32> mPreeditPositions;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 92543b952e..cdaf03ebde 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -79,7 +79,7 @@ const U32 LEFT_PAD_PIXELS = 3;
const U32 LEFT_WIDTH_PIXELS = 15;
const U32 LEFT_PLAIN_PIXELS = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS;
-const U32 RIGHT_PAD_PIXELS = 2;
+const U32 RIGHT_PAD_PIXELS = 7;
const U32 RIGHT_WIDTH_PIXELS = 15;
const U32 RIGHT_PLAIN_PIXELS = RIGHT_PAD_PIXELS + RIGHT_WIDTH_PIXELS;
@@ -95,7 +95,7 @@ const std::string SEPARATOR_NAME("separator");
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
const std::string LLMenuGL::BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK
-const std::string LLMenuGL::BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE
+const std::string LLMenuGL::BRANCH_SUFFIX( "\xe2\x96\xb8" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE
const std::string LLMenuGL::ARROW_UP ("^^^^^^^");
const std::string LLMenuGL::ARROW_DOWN("vvvvvvv");
@@ -213,6 +213,12 @@ LLSD LLMenuItemGL::getValue() const
}
//virtual
+bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ return (mAcceleratorKey == key) && (mAcceleratorMask == mask);
+}
+
+//virtual
BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
{
if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
@@ -263,13 +269,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
-BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
+BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp)
{
- LLKeyBinding *accelerator = NULL;
+ LLMenuKeyboardBinding *accelerator = NULL;
if (mAcceleratorKey != KEY_NONE)
{
- std::list<LLKeyBinding*>::iterator list_it;
+ std::list<LLMenuKeyboardBinding*>::iterator list_it;
for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
{
accelerator = *list_it;
@@ -293,7 +299,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
}
if (!accelerator)
{
- accelerator = new LLKeyBinding;
+ accelerator = new LLMenuKeyboardBinding;
if (accelerator)
{
accelerator->mKey = mAcceleratorKey;
@@ -788,6 +794,12 @@ void LLMenuItemCallGL::initFromParams(const Params& p)
{
setEnabledControlVariable(control);
}
+ else
+ {
+ LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName()
+ << ": control " << p.on_enable.control_name()
+ << " does not exist." << LL_ENDL;
+ }
}
}
if (p.on_click.isProvided())
@@ -1011,6 +1023,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
return TRUE;
}
+bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ return getBranch() && getBranch()->hasAccelerator(key, mask);
+}
+
BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
{
return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
@@ -1018,7 +1035,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
-BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
+BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp)
{
LLMenuGL* branch = getBranch();
if (!branch)
@@ -2717,6 +2734,15 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible )
}
}
+
+void LLMenuGL::setItemLabel(const std::string &name, const std::string &label)
+{
+ LLMenuItemGL *item = getItem(name);
+
+ if (item)
+ item->setLabel(label);
+}
+
void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)
{
if (getVisible())
@@ -2761,6 +2787,19 @@ LLMenuItemGL* LLMenuGL::getItem(S32 number)
return NULL;
}
+LLMenuItemGL* LLMenuGL::getItem(std::string name)
+{
+ item_list_t::iterator item_iter;
+ for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+ {
+ if ((*item_iter)->getName() == name)
+ {
+ return (*item_iter);
+ }
+ }
+ return NULL;
+}
+
LLMenuItemGL* LLMenuGL::getHighlightedItem()
{
item_list_t::iterator item_iter;
@@ -2995,6 +3034,27 @@ void LLMenuGL::updateParent(LLView* parentp)
}
}
+bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ if (key == KEY_NONE)
+ {
+ return false;
+ }
+ // Note: checking this way because mAccelerators seems to be broken
+ // mAccelerators probably needs to be cleaned up or fixed
+ // It was used for dupplicate accelerator avoidance.
+ item_list_t::const_iterator item_iter;
+ for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+ {
+ LLMenuItemGL* itemp = *item_iter;
+ if (itemp->hasAccelerator(key, mask))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
{
// don't handle if not enabled
@@ -3216,7 +3276,7 @@ void hide_top_view( LLView* view )
// x and y are the desired location for the popup, in the spawning_view's
// coordinate frame, NOT necessarily the mouse location
// static
-void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
+void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x, S32 mouse_y)
{
const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size
const S32 CURSOR_WIDTH = 12;
@@ -3247,12 +3307,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
}
}
- // Save click point for detecting cursor moves before mouse-up.
- // Must be in local coords to compare with mouseUp events.
- // If the mouse doesn't move, the menu will stay open ala the Mac.
- // See also LLContextMenu::show()
- S32 mouse_x, mouse_y;
-
// Resetting scrolling position
if (menu->isScrollable() && menu->isScrollPositionOnShowReset())
{
@@ -3263,7 +3317,18 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
menu->needsArrange();
menu->arrangeAndClear();
- LLUI::getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y);
+ if ((mouse_x == 0) || (mouse_y == 0))
+
+ {
+ // Save click point for detecting cursor moves before mouse-up.
+ // Must be in local coords to compare with mouseUp events.
+ // If the mouse doesn't move, the menu will stay open ala the Mac.
+ // See also LLContextMenu::show()
+
+ LLUI::getInstance()->getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y);
+ }
+
+
LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y);
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getRect();
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 78f688642e..273bd789c4 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -42,6 +42,13 @@
extern S32 MENU_BAR_HEIGHT;
extern S32 MENU_BAR_WIDTH;
+class LLMenuKeyboardBinding
+{
+public:
+ KEY mKey;
+ MASK mMask;
+};
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemGL
//
@@ -91,6 +98,7 @@ public:
/*virtual*/ void setValue(const LLSD& value);
/*virtual*/ LLSD getValue() const;
+ virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }
@@ -109,7 +117,7 @@ public:
virtual void setBriefItem(BOOL brief);
virtual BOOL isBriefItem() const;
- virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp);
+ virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; }
BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; }
@@ -436,7 +444,8 @@ public:
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*virtual*/ void removeChild( LLView* ctrl);
/*virtual*/ BOOL postBuild();
-
+
+ virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const;
@@ -468,6 +477,8 @@ public:
void setEnabledSubMenus(BOOL enable);
void setItemVisible( const std::string& name, BOOL visible);
+
+ void setItemLabel(const std::string &name, const std::string &label);
// sets the left,bottom corner of menu, useful for popups
void setLeftAndBottom(S32 left, S32 bottom);
@@ -498,6 +509,7 @@ public:
void setItemLastSelected(LLMenuItemGL* item); // must be in menu
U32 getItemCount(); // number of menu items
LLMenuItemGL* getItem(S32 number); // 0 = first item
+ LLMenuItemGL* getItem(std::string name);
LLMenuItemGL* getHighlightedItem();
LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE);
@@ -507,7 +519,7 @@ public:
void createJumpKeys();
// Show popup at a specific location, in the spawn_view's coordinate frame
- static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y);
+ static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0);
// Whether to drop shadow menu bar
void setDropShadowed( const BOOL shadowed );
@@ -625,10 +637,11 @@ public:
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
// check if we've used these accelerators already
- virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp);
+ virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -794,7 +807,7 @@ private:
void checkMenuTrigger();
- std::list <LLKeyBinding*> mAccelerators;
+ std::list <LLMenuKeyboardBinding*> mAccelerators;
BOOL mAltKeyTrigger;
};
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 8cf88ad5eb..5cfa8ea973 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -105,7 +105,7 @@ void LLModalDialog::onOpen(const LLSD& key)
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( this );
- LLUI::addPopup(this);
+ LLUI::getInstance()->addPopup(this);
setFocus(TRUE);
sModalStack.push_front( this );
@@ -147,7 +147,7 @@ void LLModalDialog::setVisible( BOOL visible )
gFocusMgr.setMouseCapture( this );
// The dialog view is a root view
- LLUI::addPopup(this);
+ LLUI::getInstance()->addPopup(this);
setFocus( TRUE );
}
else
@@ -165,7 +165,7 @@ BOOL LLModalDialog::handleMouseDown(S32 x, S32 y, MASK mask)
if (popup_menu != NULL)
{
S32 mx, my;
- LLUI::getMousePositionScreen(&mx, &my);
+ LLUI::getInstance()->getMousePositionScreen(&mx, &my);
LLRect menu_screen_rc = popup_menu->calcScreenRect();
if(!menu_screen_rc.pointInRect(mx, my))
{
@@ -202,7 +202,7 @@ BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask)
if (popup_menu != NULL)
{
S32 mx, my;
- LLUI::getMousePositionScreen(&mx, &my);
+ LLUI::getInstance()->getMousePositionScreen(&mx, &my);
LLRect menu_screen_rc = popup_menu->calcScreenRect();
if(menu_screen_rc.pointInRect(mx, my))
{
@@ -286,7 +286,7 @@ void LLModalDialog::draw()
void LLModalDialog::centerOnScreen()
{
- LLVector2 window_size = LLUI::getWindowSize();
+ LLVector2 window_size = LLUI::getInstance()->getWindowSize();
centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY])));
}
@@ -316,7 +316,7 @@ void LLModalDialog::onAppFocusGained()
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( instance );
instance->setFocus(TRUE);
- LLUI::addPopup(instance);
+ LLUI::getInstance()->addPopup(instance);
instance->centerOnScreen();
}
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index 0aa3e17075..f89064d59a 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,13 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
addSlider(it->value);
}
}
+
+ mRoundedSquareImgp = LLUI::getUIImage("Rounded_Square");
+ 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 +150,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 +168,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 +178,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 +231,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 +270,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 +284,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 +364,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 +383,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 +412,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 +428,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 +486,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 +502,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 +510,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 +584,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))
- {
- mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x;
- }
- else
+ if (!mCurSlider.empty())
{
- 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 +640,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 +655,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.
@@ -481,17 +667,24 @@ void LLMultiSlider::draw()
F32 opacity = getEnabled() ? 1.f : 0.3f;
// 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)
{
track_rect.stretch(-1);
- thumb_imagep->draw(track_rect, mTrackColor.get() % opacity);
+ mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity);
}
// if we're supposed to use a drawn triangle
@@ -510,10 +703,11 @@ void LLMultiSlider::draw()
mTriangleColor.get() % opacity, TRUE);
}
}
- else if (!thumb_imagep)
+ else if (!mRoundedSquareImgp && !mThumbImagep)
{
// draw all the thumbs
curSldrIt = mThumbRects.end();
+ hoverSldrIt = mThumbRects.end();
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
// choose the color
@@ -522,15 +716,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 +739,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
+ {
+ mRoundedSquareImgp->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
+ {
+ mRoundedSquareImgp->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
+ }
+ }
}
+ if (!mHoverSlider.empty())
+ {
+ if (mThumbImagep)
+ {
+ mThumbImagep->drawBorder(mThumbRects[mHoverSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth());
+ }
+ else
+ {
+ mRoundedSquareImgp->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 +800,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)
+ {
+ mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor);
+ }
+ else
+ {
+ mRoundedSquareImgp->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)
+ {
+ mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get());
+ }
+ else
+ {
+ mRoundedSquareImgp->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
+ {
+ mRoundedSquareImgp->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get());
+ }
}
}
diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h
index 2b422e89c9..3cb4b760b0 100644
--- a/indra/llui/llmultislider.h
+++ b/indra/llui/llmultislider.h
@@ -47,16 +47,23 @@ 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_highlight_color,
thumb_outline_color,
thumb_center_color,
thumb_center_selected_color,
triangle_color;
+ Optional<std::string> orientation,
+ thumb_image;
+
Optional<CommitCallbackParam> mouse_down_callback,
mouse_up_callback;
Optional<S32> thumb_width;
@@ -70,16 +77,27 @@ protected:
friend class LLUICtrlFactory;
public:
virtual ~LLMultiSlider();
+
+ // Multi-slider rounds values to nearest increments (bias towards rounding down)
+ F32 getNearestIncrement(F32 value) const;
+
void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
F32 getSliderValue(const std::string& name) const;
+ F32 getSliderValueFromPos(S32 xpos, S32 ypos) const;
+ LLRect getSliderThumbRect(const std::string& name) const;
+
+ void setSliderThumbImage(const std::string &name);
+ void clearSliderThumbImage();
+
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);
- /*virtual*/ LLSD getValue() const { return mValue; }
+ /*virtual*/ void setValue(const LLSD& value) override;
+ /*virtual*/ LLSD getValue() const override { return mValue; }
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb );
@@ -87,24 +105,34 @@ public:
bool findUnusedValue(F32& initVal);
const std::string& addSlider();
const std::string& addSlider(F32 val);
- void addSlider(F32 val, const std::string& name);
+ bool addSlider(F32 val, const std::string& name);
void deleteSlider(const std::string& name);
void deleteCurSlider() { deleteSlider(mCurSlider); }
- void clear();
+ /*virtual*/ void clear() override;
+
+ /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override;
+ /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override;
+ /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override;
+ /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override;
+ /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override;
+ /*virtual*/ void draw() override;
+
+ S32 getMaxNumSliders() { return mMaxNumSliders; }
+ S32 getCurNumSliders() { return mValue.size(); }
+ F32 getOverlapThreshold() { return mOverlapThreshold; }
+ bool canAddSliders() { return mValue.size() < mMaxNumSliders; }
- /*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 handleKeyHere(KEY key, MASK mask);
- /*virtual*/ void draw();
protected:
LLSD mValue;
std::string mCurSlider;
+ std::string mHoverSlider;
static S32 mNameCounter;
S32 mMaxNumSliders;
BOOL mAllowOverlap;
+ BOOL mLoopOverlap;
+ F32 mOverlapThreshold;
BOOL mDrawTrack;
BOOL mUseTriangle; /// hacked in toggle to use a triangle
@@ -116,11 +144,16 @@ protected:
mThumbRects;
LLUIColor mTrackColor;
LLUIColor mThumbOutlineColor;
+ LLUIColor mThumbHighlightColor;
LLUIColor mThumbCenterColor;
LLUIColor mThumbCenterSelectedColor;
LLUIColor mDisabledThumbColor;
LLUIColor mTriangleColor;
-
+ LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support
+ LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support
+
+ const EOrientation mOrientation;
+
commit_signal_t* mMouseDownSignal;
commit_signal_t* mMouseUpSignal;
};
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index c460a08afc..b3df7c154b 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -53,6 +53,12 @@ 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),
+ orientation("orientation"),
+ thumb_image("thumb_image"),
+ thumb_width("thumb_width"),
+ thumb_highlight_color("thumb_highlight_color"),
+ overlap_threshold("overlap_threshold", 0),
draw_track("draw_track", true),
use_triangle("use_triangle", false),
decimal_digits("decimal_digits", 3),
@@ -167,6 +173,19 @@ 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.orientation(p.orientation);
+ params.thumb_image(p.thumb_image);
+ params.thumb_highlight_color(p.thumb_highlight_color);
+ if (p.thumb_width.isProvided())
+ {
+ // otherwise should be provided by template
+ params.thumb_width(p.thumb_width);
+ }
params.draw_track(p.draw_track);
params.use_triangle(p.use_triangle);
params.control_name(p.control_name);
@@ -213,6 +232,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;
@@ -269,6 +293,17 @@ const std::string& LLMultiSliderCtrl::addSlider(F32 val)
return name;
}
+bool LLMultiSliderCtrl::addSlider(F32 val, const std::string& name)
+{
+ bool res = mMultiSlider->addSlider(val, name);
+ if (res)
+ {
+ mCurValue = mMultiSlider->getCurSliderValue();
+ updateText();
+ }
+ return res;
+}
+
void LLMultiSliderCtrl::deleteSlider(const std::string& name)
{
mMultiSlider->deleteSlider(name);
@@ -474,6 +509,7 @@ void LLMultiSliderCtrl::onTabInto()
{
mEditor->onTabInto();
}
+ LLF32UICtrl::onTabInto();
}
void LLMultiSliderCtrl::reportInvalidData()
diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h
index b6a3542376..adb28676ec 100644
--- a/indra/llui/llmultisliderctrl.h
+++ b/indra/llui/llmultisliderctrl.h
@@ -51,14 +51,22 @@ public:
text_width;
Optional<bool> show_text,
can_edit_text;
- Optional<S32> decimal_digits;
+ Optional<S32> decimal_digits,
+ thumb_width;
Optional<S32> max_sliders;
Optional<bool> allow_overlap,
+ loop_overlap,
draw_track,
use_triangle;
+ Optional<std::string> orientation,
+ thumb_image;
+
+ Optional<F32> overlap_threshold;
+
Optional<LLUIColor> text_color,
- text_disabled_color;
+ text_disabled_color,
+ thumb_highlight_color;
Optional<CommitCallbackParam> mouse_down_callback,
mouse_up_callback;
@@ -74,7 +82,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 +92,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,15 +107,28 @@ public:
void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);}
void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);}
+ F32 getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); }
+ F32 getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); }
+ LLRect getSliderThumbRect(const std::string &name) const { return mMultiSlider->getSliderThumbRect(name); }
+
+ void setSliderThumbImage(const std::string &name) { mMultiSlider->setSliderThumbImage(name); }
+ void clearSliderThumbImage() { mMultiSlider->clearSliderThumbImage(); }
+
/// for adding and deleting sliders
const std::string& addSlider();
const std::string& addSlider(F32 val);
+ bool addSlider(F32 val, const std::string& name);
void deleteSlider(const std::string& name);
void deleteCurSlider() { deleteSlider(mMultiSlider->getCurSlider()); }
F32 getMinValue() const { return mMultiSlider->getMinValue(); }
F32 getMaxValue() const { return mMultiSlider->getMaxValue(); }
+ S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); }
+ S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); }
+ F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); }
+ bool canAddSliders() { return mMultiSlider->canAddSliders(); }
+
void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); }
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; }
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; }
diff --git a/indra/llui/llnotificationptr.h b/indra/llui/llnotificationptr.h
index acc047527f..580f353c7d 100644
--- a/indra/llui/llnotificationptr.h
+++ b/indra/llui/llnotificationptr.h
@@ -27,9 +27,8 @@
// Many classes just store a single LLNotificationPtr
// and llnotifications.h is very large, so define this ligher header.
-#include <boost/shared_ptr.hpp>
class LLNotification;
-typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
+typedef std::shared_ptr<LLNotification> LLNotificationPtr;
#endif
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 7bafd711cb..b791a19c2b 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore()
control("control"),
invert_control("invert_control", false),
save_option("save_option", false),
- session_only("session_only", false)
+ session_only("session_only", false),
+ checkbox_only("checkbox_only", false)
{}
LLNotificationForm::FormButton::FormButton()
@@ -76,6 +77,7 @@ LLNotificationForm::FormButton::FormButton()
text("text"),
ignore("ignore"),
is_default("default"),
+ width("width", 0),
type("type")
{
// set type here so it gets serialized
@@ -130,7 +132,7 @@ bool handleIgnoredNotification(const LLSD& payload)
response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
break;
case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
- response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
+ response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
break;
case LLNotificationForm::IGNORE_SHOW_AGAIN:
break;
@@ -195,9 +197,15 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
{
if (p.ignore.isProvided())
{
+ // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences
mIgnoreMsg = p.ignore.text;
- if (!p.ignore.save_option)
+ LLUI *ui_inst = LLUI::getInstance();
+ if (p.ignore.checkbox_only)
+ {
+ mIgnore = IGNORE_CHECKBOX_ONLY;
+ }
+ else if (!p.ignore.save_option)
{
mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE;
}
@@ -205,19 +213,19 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
{
// remember last option chosen by user and automatically respond with that in the future
mIgnore = IGNORE_WITH_LAST_RESPONSE;
- LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
+ ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
}
BOOL show_notification = TRUE;
if (p.ignore.control.isProvided())
{
- mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control);
+ mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control);
mInvertSetting = p.ignore.invert_control;
}
- else
+ else if (mIgnore > IGNORE_NO)
{
- LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT);
- mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
+ ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT);
+ mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name);
}
}
@@ -248,7 +256,7 @@ LLNotificationForm::LLNotificationForm(const LLSD& sd)
}
else
{
- LL_WARNS() << "Invalid form data " << sd << LL_ENDL;
+ LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL;
mFormData = LLSD::emptyArray();
}
}
@@ -388,13 +396,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
bool LLNotificationForm::getIgnored()
{
bool show = true;
- if (mIgnore != LLNotificationForm::IGNORE_NO
+ if (mIgnore > LLNotificationForm::IGNORE_NO
&& mIgnoreSetting)
{
show = mIgnoreSetting->getValue().asBoolean();
if (mInvertSetting) show = !show;
}
-
return !show;
}
@@ -432,7 +439,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
mSoundName("")
{
if (p.sound.isProvided()
- && LLUI::sSettingGroups["config"]->controlExists(p.sound))
+ && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound))
{
mSoundName = p.sound;
}
@@ -442,11 +449,11 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
mUniqueContext.push_back(context.value);
}
- LL_DEBUGS() << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL;
BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags)
{
- LL_DEBUGS() << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL;
+ LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL;
mTags.push_back(tag.value);
}
@@ -695,12 +702,12 @@ void LLNotification::respond(const LLSD& response)
mTemporaryResponder = false;
}
- if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+ if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)
{
mForm->setIgnored(mIgnored);
if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
{
- LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
+ LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
}
}
@@ -1392,8 +1399,14 @@ void LLNotifications::initSingleton()
createDefaultChannels();
}
+void LLNotifications::cleanupSingleton()
+{
+ clear();
+}
+
void LLNotifications::createDefaultChannels()
{
+ LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL;
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "",
@@ -1449,7 +1462,7 @@ void LLNotifications::forceResponse(const LLNotification::Params& params, S32 op
if (selected_item.isUndefined())
{
- LL_WARNS() << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL;
+ LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL;
return;
}
response[selected_item["name"].asString()] = true;
@@ -1483,12 +1496,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
if (found != replacements.end())
{
replacement = found->second;
- LL_DEBUGS() << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL;
+ LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL;
it->second->setValue(replacement);
}
else
{
- LL_WARNS() << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL;
+ LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL;
}
}
}
@@ -1527,7 +1540,7 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path
bool LLNotifications::loadTemplates()
{
- LL_INFOS() << "Reading notifications template" << LL_ENDL;
+ LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL;
// Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it
// output all relevant pathnames instead of just the ones from the most
// specific skin.
@@ -1598,7 +1611,7 @@ bool LLNotifications::loadTemplates()
mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification));
}
- LL_INFOS() << "...done" << LL_ENDL;
+ LL_INFOS("Notifications") << "...done" << LL_ENDL;
return true;
}
@@ -1826,7 +1839,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++)
{
// An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule.
- LL_DEBUGS()
+ LL_DEBUGS("Notifications")
<< "notification \"" << n->getName() << "\" "
<< "testing against " << ((*it)->mVisible?"show":"hide") << " rule, "
<< "name = \"" << (*it)->mName << "\" "
@@ -1871,7 +1884,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
if((*it)->mResponse.empty())
{
// Response property is empty. Cancel this notification.
- LL_DEBUGS() << "cancelling notification " << n->getName() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL;
cancel(n);
}
@@ -1882,7 +1895,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
// TODO: verify that the response template has an item with the correct name
response[(*it)->mResponse] = true;
- LL_DEBUGS() << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL;
+ LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL;
n->respond(response);
}
@@ -1894,7 +1907,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
break;
}
- LL_DEBUGS() << "allowing notification " << n->getName() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL;
return true;
}
@@ -1955,7 +1968,7 @@ void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
// from PE merge - we should figure out if this is the right thing to do
if (name.empty())
{
- LL_WARNS() << "Empty name received for Id: " << agent_id << LL_ENDL;
+ LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL;
name = SYSTEM_FROM;
}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 1509446920..b1123d27e5 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -85,7 +85,6 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
#include <boost/type_traits.hpp>
#include <boost/signals2.hpp>
#include <boost/range.hpp>
@@ -180,6 +179,7 @@ public:
Optional<std::string> control;
Optional<bool> invert_control;
Optional<bool> session_only;
+ Optional<bool> checkbox_only;
FormIgnore();
};
@@ -190,6 +190,7 @@ public:
Mandatory<std::string> text;
Optional<std::string> ignore;
Optional<bool> is_default;
+ Optional<S32> width;
Mandatory<std::string> type;
@@ -232,7 +233,8 @@ public:
typedef enum e_ignore_type
{
- IGNORE_NO,
+ IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only
+ IGNORE_NO = 0,
IGNORE_WITH_DEFAULT_RESPONSE,
IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY,
IGNORE_WITH_LAST_RESPONSE,
@@ -302,7 +304,7 @@ typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibility
*/
class LLNotification :
boost::noncopyable,
- public boost::enable_shared_from_this<LLNotification>
+ public std::enable_shared_from_this<LLNotification>
{
LOG_CLASS(LLNotification);
friend class LLNotifications;
@@ -741,45 +743,30 @@ public:
: mFilter(filter),
mItems()
{}
- virtual ~LLNotificationChannelBase() {}
+ virtual ~LLNotificationChannelBase()
+ {
+ mItems.clear();
+ }
// you can also connect to a Channel, so you can be notified of
// changes to this channel
- template <typename LISTENER>
- LLBoundListener connectChanged(const LISTENER& slot)
+ LLBoundListener connectChanged(const LLEventListener& slot)
{
- // Examine slot to see if it binds an LLEventTrackable subclass, or a
- // boost::shared_ptr to something, or a boost::weak_ptr to something.
// Call this->connectChangedImpl() to actually connect it.
- return LLEventDetail::visit_and_connect(slot,
- boost::bind(&LLNotificationChannelBase::connectChangedImpl,
- this,
- _1));
+ return connectChangedImpl(slot);
}
- template <typename LISTENER>
- LLBoundListener connectAtFrontChanged(const LISTENER& slot)
+ LLBoundListener connectAtFrontChanged(const LLEventListener& slot)
{
- return LLEventDetail::visit_and_connect(slot,
- boost::bind(&LLNotificationChannelBase::connectAtFrontChangedImpl,
- this,
- _1));
+ return connectAtFrontChangedImpl(slot);
}
- template <typename LISTENER>
- LLBoundListener connectPassedFilter(const LISTENER& slot)
+ LLBoundListener connectPassedFilter(const LLEventListener& slot)
{
// see comments in connectChanged()
- return LLEventDetail::visit_and_connect(slot,
- boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
- this,
- _1));
+ return connectPassedFilterImpl(slot);
}
- template <typename LISTENER>
- LLBoundListener connectFailedFilter(const LISTENER& slot)
+ LLBoundListener connectFailedFilter(const LLEventListener& slot)
{
// see comments in connectChanged()
- return LLEventDetail::visit_and_connect(slot,
- boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
- this,
- _1));
+ return connectFailedFilterImpl(slot);
}
// use this when items change or to add a new one
@@ -889,6 +876,7 @@ class LLNotifications :
{
LLSINGLETON(LLNotifications);
LOG_CLASS(LLNotifications);
+ virtual ~LLNotifications() {}
public:
@@ -973,6 +961,7 @@ public:
private:
/*virtual*/ void initSingleton();
+ /*virtual*/ void cleanupSingleton();
void loadPersistentNotifications();
@@ -1086,6 +1075,11 @@ public:
: LLNotificationChannel("Persistent", "Visible", &notificationFilter)
{}
+ virtual ~LLPersistentNotificationChannel()
+ {
+ mHistory.clear();
+ }
+
typedef std::vector<LLNotificationPtr> history_list_t;
history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); }
history_list_t::iterator endHistory() { return mHistory.end(); }
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index be26416cbb..e73ba1fbe9 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -127,18 +127,16 @@ void LLNotificationsListener::listChannels(const LLSD& params) const
{
LLReqID reqID(params);
LLSD response(reqID.makeResponse());
- for (LLNotificationChannel::instance_iter cmi(LLNotificationChannel::beginInstances()),
- cmend(LLNotificationChannel::endInstances());
- cmi != cmend; ++cmi)
+ for (auto& cm : LLNotificationChannel::instance_snapshot())
{
LLSD channelInfo, parents;
- BOOST_FOREACH(const std::string& parent, cmi->getParents())
+ for (const std::string& parent : cm.getParents())
{
parents.append(parent);
}
channelInfo["parents"] = parents;
channelInfo["parent"] = parents.size()? parents[0] : "";
- response[cmi->getName()] = channelInfo;
+ response[cm.getName()] = channelInfo;
}
LLEventPumps::instance().obtain(params["reply"]).post(response);
}
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index ee90574161..00da0f5fec 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -609,7 +609,7 @@ std::string LLPanel::getString(const std::string& name, const LLStringUtil::form
return formatted_string.getString();
}
std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
- if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
+ if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode"))
{
LL_ERRS() << err_str << LL_ENDL;
}
@@ -628,7 +628,7 @@ std::string LLPanel::getString(const std::string& name) const
return found_it->second;
}
std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
- if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
+ if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode"))
{
LL_ERRS() << err_str << LL_ENDL;
}
diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp
index 6e924c1f19..d65c220974 100644
--- a/indra/llui/llresmgr.cpp
+++ b/indra/llui/llresmgr.cpp
@@ -295,9 +295,6 @@ const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252");
#elif LL_DARWIN
const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLStringUtil::null;
const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1");
-#elif LL_SOLARIS
-const std::string LLLocale::USER_LOCALE("en_US.ISO8859-1");
-const std::string LLLocale::SYSTEM_LOCALE("C");
#else // LL_LINUX likes this
const std::string LLLocale::USER_LOCALE("en_US.utf8");
const std::string LLLocale::SYSTEM_LOCALE("C");
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index e4a31d6a79..4bd1561425 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -29,14 +29,7 @@
#include "llrngwriter.h"
#include "lluicolor.h"
-#if LL_DARWIN
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdelete-incomplete"
#include "lluictrlfactory.h"
-#pragma clang diagnostic pop
-#else
-#include "lluictrlfactory.h"
-#endif
#include "boost/bind.hpp"
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 76134144a0..fde6de4921 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -84,7 +84,7 @@ LLScrollbar::LLScrollbar(const Params & p)
mThumbImageH(p.thumb_image_horizontal),
mTrackImageV(p.track_image_vertical),
mTrackImageH(p.track_image_horizontal),
- mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize")),
+ mThickness(p.thickness.isProvided() ? p.thickness : LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize")),
mBGVisible(p.bg_visible),
mBGColor(p.bg_color)
{
@@ -408,6 +408,16 @@ BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks)
return handled;
}
+BOOL LLScrollbar::handleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ BOOL handled = FALSE;
+ if (LLScrollbar::HORIZONTAL == mOrientation)
+ {
+ handled = changeLine(clicks * mStepSize, TRUE);
+ }
+ return handled;
+}
+
BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg)
{
@@ -488,7 +498,7 @@ void LLScrollbar::draw()
S32 local_mouse_x;
S32 local_mouse_y;
- LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
+ LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this;
BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y));
if (hovered)
@@ -645,5 +655,5 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
void LLScrollbar::setThickness(S32 thickness)
{
- mThickness = thickness < 0 ? LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize") : thickness;
+ mThickness = thickness < 0 ? LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize") : thickness;
}
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index e2bf52c14b..5f2f490d81 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -88,6 +88,7 @@ public:
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg);
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 6135cc56ad..3db38bbfac 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -272,6 +272,25 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
return FALSE;
}
+BOOL LLScrollContainer::handleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ if (LLUICtrl::handleScrollHWheel(x,y,clicks))
+ {
+ return TRUE;
+ }
+
+ LLScrollbar* horizontal = mScrollbar[HORIZONTAL];
+ if (horizontal->getVisible()
+ && horizontal->getEnabled()
+ && horizontal->handleScrollHWheel( 0, 0, clicks ) )
+ {
+ updateScroll();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop,
EDragAndDropType cargo_type,
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index e6c7891397..c14099dbd5 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -107,6 +107,7 @@ public:
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleUnicodeCharHere(llwchar uni_char);
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+ virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks );
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 8000efad0e..13839da400 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
{
cell = new LLScrollListDate(cell_p);
}
+ else if (cell_p.type() == "icontext")
+ {
+ cell = new LLScrollListIconText(cell_p);
+ }
else // default is "text"
{
cell = new LLScrollListText(cell_p);
@@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0;
LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
- mText(p.value().asString()),
+ mText(p.label.isProvided() ? p.label() : p.value().asString()),
mFont(p.font),
mColor(p.color),
mUseColor(p.color.isProvided()),
@@ -192,7 +196,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
void LLScrollListText::highlightText(S32 offset, S32 num_chars)
{
mHighlightOffset = offset;
- mHighlightCount = num_chars;
+ mHighlightCount = llmax(0, num_chars);
}
//virtual
@@ -292,11 +296,12 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
if (mHighlightCount > 0)
{
+ // Highlight text
S32 left = 0;
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
+ left = mFont->getWidth(mText.getString(), 1, mHighlightOffset);
break;
case LLFontGL::RIGHT:
left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
@@ -319,7 +324,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- start_x = 0.f;
+ start_x = 1.f;
break;
case LLFontGL::RIGHT:
start_x = (F32)getWidth();
@@ -435,3 +440,139 @@ const LLSD LLScrollListDate::getValue() const
{
return mDate;
}
+
+//
+// LLScrollListIconText
+//
+LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p)
+ : LLScrollListText(p),
+ mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())),
+ mPad(4)
+{
+ mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+LLScrollListIconText::~LLScrollListIconText()
+{
+}
+
+const LLSD LLScrollListIconText::getValue() const
+{
+ if (mIcon.isNull())
+ {
+ return LLStringUtil::null;
+ }
+ return mIcon->getName();
+}
+
+void LLScrollListIconText::setValue(const LLSD& value)
+{
+ if (value.isUUID())
+ {
+ // don't use default image specified by LLUUID::null, use no image in that case
+ LLUUID image_id = value.asUUID();
+ mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL);
+ }
+ else
+ {
+ std::string value_string = value.asString();
+ if (LLUUID::validate(value_string))
+ {
+ setValue(LLUUID(value_string));
+ }
+ else if (!value_string.empty())
+ {
+ mIcon = LLUI::getUIImage(value.asString());
+ }
+ else
+ {
+ mIcon = NULL;
+ }
+ }
+}
+
+void LLScrollListIconText::setWidth(S32 width)
+{
+ LLScrollListCell::setWidth(width);
+ // Assume that iamge height and width is identical to font height and width
+ mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+
+void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const
+{
+ LLColor4 display_color;
+ if (mUseColor)
+ {
+ display_color = mColor;
+ }
+ else
+ {
+ display_color = color;
+ }
+
+ S32 icon_height = mFont->getLineHeight();
+ S32 icon_space = mIcon ? (icon_height + mPad) : 0;
+
+ if (mHighlightCount > 0)
+ {
+ S32 left = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset);
+ break;
+ case LLFontGL::RIGHT:
+ left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2;
+ break;
+ }
+ LLRect highlight_rect(left - 2,
+ mFont->getLineHeight() + 1,
+ left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
+ 1);
+ mRoundedRectImage->draw(highlight_rect, highlight_color);
+ }
+
+ // Try to draw the entire string
+ F32 right_x;
+ U32 string_chars = mText.length();
+ F32 start_text_x = 0.f;
+ S32 start_icon_x = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ start_text_x = icon_space + 1;
+ start_icon_x = 1;
+ break;
+ case LLFontGL::RIGHT:
+ start_text_x = (F32)getWidth();
+ start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ F32 center = (F32)getWidth()* 0.5f;
+ start_text_x = center + ((F32)icon_space * 0.5f);
+ start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f);
+ break;
+ }
+ mFont->render(mText.getWString(), 0,
+ start_text_x, 0.f,
+ display_color,
+ mFontAlignment,
+ LLFontGL::BOTTOM,
+ 0,
+ LLFontGL::NO_SHADOW,
+ string_chars,
+ getTextWidth(),
+ &right_x,
+ TRUE);
+
+ if (mIcon)
+ {
+ mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor);
+ }
+}
+
+
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index d625ebddcc..19576fb247 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -59,7 +59,8 @@ public:
visible;
Optional<void*> userdata;
- Optional<LLSD> value;
+ Optional<LLSD> value; // state of checkbox, icon id/name, date
+ Optional<std::string> label; // description or text
Optional<std::string> tool_tip;
Optional<const LLFontGL*> font;
@@ -75,6 +76,7 @@ public:
enabled("enabled", true),
visible("visible", true),
value("value"),
+ label("label"),
tool_tip("tool_tip", ""),
font("font", LLFontGL::getFontSansSerifSmall()),
font_color("font_color", LLColor4::black),
@@ -152,11 +154,12 @@ public:
void setText(const LLStringExplicit& text);
void setFontStyle(const U8 font_style);
-private:
+protected:
LLUIString mText;
S32 mTextWidth;
const LLFontGL* mFont;
LLColor4 mColor;
+ LLColor4 mHighlightColor;
U8 mUseColor;
LLFontGL::HAlign mFontAlignment;
BOOL mVisible;
@@ -169,7 +172,7 @@ private:
};
/*
- * Cell displaying an image.
+ * Cell displaying an image. AT the moment, this is specifically UI image
*/
class LLScrollListIcon : public LLScrollListCell
{
@@ -223,4 +226,26 @@ private:
LLDate mDate;
};
+/*
+* Cell displaying icon and text.
+*/
+
+class LLScrollListIconText : public LLScrollListText
+{
+public:
+ LLScrollListIconText(const LLScrollListCell::Params& p);
+ /*virtual*/ ~LLScrollListIconText();
+ /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const;
+ /*virtual*/ const LLSD getValue() const;
+ /*virtual*/ void setValue(const LLSD& value);
+
+
+ S32 getIconWidth() const;
+ /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/
+
+private:
+ LLPointer<LLUIImage> mIcon;
+ S32 mPad;
+};
+
#endif
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index cc9ff7a487..82b0415624 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -257,7 +257,7 @@ void LLScrollColumnHeader::updateResizeBars()
for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
{
LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
- if (columnp->mHeader && columnp->mHeader->canResize())
+ if (columnp && columnp->mHeader && columnp->mHeader->canResize())
{
num_resizable_columns++;
}
@@ -269,7 +269,7 @@ void LLScrollColumnHeader::updateResizeBars()
for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
{
LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
- if (!columnp->mHeader) continue;
+ if (!columnp || !columnp->mHeader) continue;
BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
columnp->mHeader->enableResizeBar(enable);
if (enable)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index f4028057e8..de644185fd 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -115,6 +115,13 @@ struct SortScrollListItem
// LLScrollListCtrl
//---------------------------------------------------------------------------
+void LLScrollListCtrl::SelectionTypeNames::declareValues()
+{
+ declare("row", LLScrollListCtrl::ROW);
+ declare("cell", LLScrollListCtrl::CELL);
+ declare("header", LLScrollListCtrl::HEADER);
+}
+
LLScrollListCtrl::Contents::Contents()
: columns("column"),
rows("row")
@@ -128,15 +135,19 @@ LLScrollListCtrl::Params::Params()
has_border("draw_border"),
draw_heading("draw_heading"),
search_column("search_column", 0),
+ selection_type("selection_type", ROW),
sort_column("sort_column", -1),
sort_ascending("sort_ascending", true),
+ can_sort("can_sort", true),
mouse_wheel_opaque("mouse_wheel_opaque", false),
commit_on_keyboard_movement("commit_on_keyboard_movement", true),
+ commit_on_selection_change("commit_on_selection_change", false),
heading_height("heading_height"),
page_lines("page_lines", 0),
background_visible("background_visible"),
draw_stripes("draw_stripes"),
column_padding("column_padding"),
+ row_padding("row_padding", 2),
fg_unselected_color("fg_unselected_color"),
fg_selected_color("fg_selected_color"),
bg_selected_color("bg_selected_color"),
@@ -161,10 +172,12 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mMaxSelectable(0),
mAllowKeyboardMovement(true),
mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
- mCommitOnSelectionChange(false),
+ mCommitOnSelectionChange(p.commit_on_selection_change),
mSelectionChanged(false),
+ mSelectionType(p.selection_type),
mNeedsScroll(false),
mCanSelect(true),
+ mCanSort(p.can_sort),
mColumnsDirty(false),
mMaxItemCount(INT_MAX),
mBorderThickness( 2 ),
@@ -199,6 +212,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mHoveredColor(p.hovered_color()),
mSearchColumn(p.search_column),
mColumnPadding(p.column_padding),
+ mRowPadding(p.row_padding),
mContextMenuType(MENU_NONE),
mIsFriendSignal(NULL)
{
@@ -685,8 +699,6 @@ bool LLScrollListCtrl::updateColumnWidths()
return width_changed;
}
-const S32 SCROLL_LIST_ROW_PAD = 2;
-
// Line height is the max height of all the cells in all the items.
void LLScrollListCtrl::updateLineHeight()
{
@@ -699,7 +711,7 @@ void LLScrollListCtrl::updateLineHeight()
S32 i = 0;
for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
{
- mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD );
+ mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding );
}
}
}
@@ -711,7 +723,7 @@ void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp)
S32 i = 0;
for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
{
- mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD );
+ mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding );
}
}
@@ -731,12 +743,12 @@ void LLScrollListCtrl::updateColumns(bool force_update)
LLScrollColumnHeader* last_header = NULL;
for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
{
- if ((*column_ordered_it)->getWidth() < 0)
+ LLScrollListColumn* column = *column_ordered_it;
+ if (!column || column->getWidth() < 0)
{
// skip hidden columns
continue;
}
- LLScrollListColumn* column = *column_ordered_it;
if (column->mHeader)
{
@@ -762,14 +774,20 @@ void LLScrollListCtrl::updateColumns(bool force_update)
}
}
+ bool header_changed_width = false;
// expand last column header we encountered to full list width
if (last_header)
{
+ S32 old_width = last_header->getColumn()->getWidth();
S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
last_header->reshape(new_width, last_header->getRect().getHeight());
last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
- last_header->getColumn()->setWidth(new_width);
- }
+ if (old_width != new_width)
+ {
+ last_header->getColumn()->setWidth(new_width);
+ header_changed_width = true;
+ }
+ }
// propagate column widths to individual cells
if (columns_changed_width || force_update)
@@ -788,6 +806,20 @@ void LLScrollListCtrl::updateColumns(bool force_update)
}
}
}
+ else if (header_changed_width)
+ {
+ item_list::iterator iter;
+ S32 index = last_header->getColumn()->mIndex; // Not always identical to last column!
+ for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListItem *itemp = *iter;
+ LLScrollListCell* cell = itemp->getColumn(index);
+ if (cell)
+ {
+ cell->setWidth(last_header->getColumn()->getWidth());
+ }
+ }
+ }
}
void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
@@ -819,7 +851,15 @@ BOOL LLScrollListCtrl::selectFirstItem()
{
if (!itemp->getSelected())
{
- selectItem(itemp);
+ switch (mSelectionType)
+ {
+ case CELL:
+ selectItem(itemp, 0);
+ break;
+ case HEADER:
+ case ROW:
+ selectItem(itemp, -1);
+ }
}
success = TRUE;
mOriginalSelection = 0;
@@ -878,7 +918,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
{
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ // TODO: support range selection for cells
+ selectItem(itemp, -1, FALSE);
success = TRUE;
}
}
@@ -1004,10 +1045,14 @@ void LLScrollListCtrl::clearHighlightedItems()
void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
{
- if (mHighlightedItem != target_index)
- {
- mHighlightedItem = target_index;
- }
+ if (mHighlightedItem != target_index)
+ {
+ if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size())
+ {
+ mItemList[mHighlightedItem]->setHoverCell(-1);
+ }
+ mHighlightedItem = target_index;
+ }
}
S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
@@ -1022,7 +1067,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
{
if (item->getEnabled() && (item->getUUID() == (*iditr)))
{
- selectItem(item,FALSE);
+ // TODO: support multiple selection for cells
+ selectItem(item, -1, FALSE);
++count;
break;
}
@@ -1095,7 +1141,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
{
if (prev_item)
{
- selectItem(prev_item, !extend_selection);
+ selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1139,7 +1185,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
{
if (next_item)
{
- selectItem(next_item, !extend_selection);
+ selectItem(next_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1210,7 +1256,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
bool found = NULL != item;
if(found)
{
- selectItem(item);
+ selectItem(item, -1);
}
if (mCommitOnSelectionChange)
@@ -1278,7 +1324,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1318,7 +1364,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
// find offset of matching text (might have leading whitespace)
S32 offset = item_label.find(target_trimmed);
cellp->highlightText(offset, target_trimmed.size());
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1380,18 +1426,34 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
LLScrollListItem* item = *iter;
- if (item->getEnabled() && (item->getValue().asString() == value.asString()))
- {
- if (selected)
- {
- selectItem(item);
- }
- else
- {
- deselectItem(item);
- }
- found = TRUE;
- break;
+ if (item->getEnabled())
+ {
+ if (value.isBinary())
+ {
+ if (item->getValue().isBinary())
+ {
+ LLSD::Binary data1 = value.asBinary();
+ LLSD::Binary data2 = item->getValue().asBinary();
+ found = std::equal(data1.begin(), data1.end(), data2.begin()) ? TRUE : FALSE;
+ }
+ }
+ else
+ {
+ found = item->getValue().asString() == value.asString() ? TRUE : FALSE;
+ }
+
+ if (found)
+ {
+ if (selected)
+ {
+ selectItem(item, -1);
+ }
+ else
+ {
+ deselectItem(item);
+ }
+ break;
+ }
}
}
@@ -1464,7 +1526,7 @@ void LLScrollListCtrl::drawItems()
S32 max_columns = 0;
- LLColor4 highlight_color = LLColor4::white;
+ LLColor4 highlight_color = LLColor4::white; // ex: text inside cells
static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f);
@@ -1490,7 +1552,8 @@ void LLScrollListCtrl::drawItems()
max_columns = llmax(max_columns, item->getNumColumns());
LLColor4 fg_color;
- LLColor4 bg_color(LLColor4::transparent);
+ LLColor4 hover_color(LLColor4::transparent);
+ LLColor4 select_color(LLColor4::transparent);
if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{
@@ -1499,44 +1562,44 @@ void LLScrollListCtrl::drawItems()
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+ select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just select-highlight it
{
- bg_color = mBgSelectedColor.get();
+ select_color = mBgSelectedColor.get();
}
fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
}
- else if (mHighlightedItem == line && mCanSelect)
+ if (mHighlightedItem == line && mCanSelect)
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+ hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just hover-highlight it
{
- bg_color = mHoveredColor.get();
+ hover_color = mHoveredColor.get();
}
}
else if (item->getHighlighted())
{
- bg_color = mHighlightedColor.get();
+ hover_color = mHighlightedColor.get();
}
else
{
if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
{
- bg_color = mBgStripeColor.get();
+ hover_color = mBgStripeColor.get();
}
}
if (!item->getEnabled())
{
- bg_color = mBgReadOnlyColor.get();
+ hover_color = mBgReadOnlyColor.get();
}
- item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
+ item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding);
cur_y -= mLineHeight;
}
@@ -1601,6 +1664,20 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
return handled;
}
+BOOL LLScrollListCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ BOOL handled = FALSE;
+ // Pretend the mouse is over the scrollbar
+ handled = mScrollbar->handleScrollHWheel( 0, 0, clicks );
+
+ if (mMouseWheelOpaque)
+ {
+ return TRUE;
+ }
+
+ return handled;
+}
+
// *NOTE: Requires a valid row_index and column_index
LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index)
{
@@ -1674,7 +1751,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if (mLastSelected == NULL)
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
else
{
@@ -1698,7 +1775,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
LLScrollListItem *item = *itor;
if (item == hit_item || item == lastSelected)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
selecting = !selecting;
if (hit_item == lastSelected)
{
@@ -1708,7 +1785,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
}
if (selecting)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
}
}
}
@@ -1723,7 +1800,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
{
- selectItem(hit_item, FALSE);
+ selectItem(hit_item, getColumnIndexFromOffset(x), FALSE);
}
else
{
@@ -1737,12 +1814,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
else
{
deselectAllItems(TRUE);
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
}
else
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
selection_changed = mSelectionChanged;
@@ -2110,8 +2187,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{
LLScrollListItem* item = hitItem(x, y);
if (item)
- {
- mouseOverHighlightNthItem(getItemIndex(item));
+ {
+ mouseOverHighlightNthItem(getItemIndex(item));
+ switch (mSelectionType)
+ {
+ case CELL:
+ item->setHoverCell(getColumnIndexFromOffset(x));
+ break;
+ case HEADER:
+ {
+ S32 cell = getColumnIndexFromOffset(x);
+ if (cell > 0)
+ {
+ item->setHoverCell(cell);
+ }
+ else
+ {
+ item->setHoverCell(-1);
+ }
+ break;
+ }
+ case ROW:
+ break;
+ }
}
else
{
@@ -2159,6 +2257,58 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
handled = TRUE;
}
break;
+ case KEY_LEFT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell < mColumns.size()) cell++;
+ break;
+ case HEADER:
+ if (cell == -1) cell = 1;
+ else if (cell > 1 && cell < mColumns.size()) cell++; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell >= 0) cell--;
+ break;
+ case HEADER:
+ if (cell > 1) cell--;
+ else if (cell == 1) cell = -1; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
case KEY_PAGE_UP:
if (mAllowKeyboardMovement || hasFocus())
{
@@ -2327,7 +2477,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
{
- selectItem(item);
+ selectItem(item, -1);
mNeedsScroll = true;
cellp->highlightText(0, 1);
mSearchTimer.reset();
@@ -2379,7 +2529,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
return TRUE;
}
-void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
+void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item)
{
if (!itemp) return;
@@ -2398,6 +2548,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
deselectAllItems(TRUE);
}
itemp->setSelected(TRUE);
+ switch (mSelectionType)
+ {
+ case CELL:
+ itemp->setSelectedCell(cell);
+ break;
+ case HEADER:
+ itemp->setSelectedCell(cell <= 0 ? -1 : cell);
+ break;
+ case ROW:
+ itemp->setSelectedCell(-1);
+ break;
+ }
mLastSelected = itemp;
mSelectionChanged = true;
}
@@ -2658,7 +2820,7 @@ void LLScrollListCtrl::selectAll()
LLScrollListItem *itemp = *iter;
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ selectItem(itemp, -1, FALSE);
}
}
@@ -2787,6 +2949,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
LLScrollListCtrl *parent = info->mParentCtrl;
if (!parent) return;
+ if (!parent->mCanSort) return;
+
S32 column_index = info->mIndex;
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index b35a8608e7..0cc481b113 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
public LLCtrlListInterface, public LLCtrlScrollInterface
{
public:
+ typedef enum e_selection_type
+ {
+ ROW, // default
+ CELL, // does not support multi-selection
+ HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select
+ } ESelectionType;
+
+ struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames>
+ {
+ static void declareValues();
+ };
+
struct Contents : public LLInitParam::Block<Contents>
{
Multiple<LLScrollListColumn::Params> columns;
@@ -97,8 +109,11 @@ public:
// behavioral flags
Optional<bool> multi_select,
commit_on_keyboard_movement,
+ commit_on_selection_change,
mouse_wheel_opaque;
+ Optional<ESelectionType, SelectionTypeNames> selection_type;
+
// display flags
Optional<bool> has_border,
draw_heading,
@@ -108,13 +123,15 @@ public:
// layout
Optional<S32> column_padding,
- page_lines,
+ row_padding,
+ page_lines,
heading_height;
// sort and search behavior
Optional<S32> search_column,
sort_column;
- Optional<bool> sort_ascending;
+ Optional<bool> sort_ascending,
+ can_sort; // whether user is allowed to sort
// colors
Optional<LLUIColor> fg_unselected_color,
@@ -283,8 +300,10 @@ public:
void setBackgroundVisible(BOOL b) { mBackgroundVisible = b; }
void setDrawStripes(BOOL b) { mDrawStripes = b; }
- void setColumnPadding(const S32 c) { mColumnPadding = c; }
- S32 getColumnPadding() { return mColumnPadding; }
+ void setColumnPadding(const S32 c) { mColumnPadding = c; }
+ S32 getColumnPadding() const { return mColumnPadding; }
+ void setRowPadding(const S32 c) { mColumnPadding = c; }
+ S32 getRowPadding() const { return mColumnPadding; }
void setCommitOnKeyboardMovement(BOOL b) { mCommitOnKeyboardMovement = b; }
void setCommitOnSelectionChange(BOOL b) { mCommitOnSelectionChange = b; }
void setAllowKeyboardMovement(BOOL b) { mAllowKeyboardMovement = b; }
@@ -317,6 +336,7 @@ public:
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char);
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
/*virtual*/ void setEnabled(BOOL enabled);
/*virtual*/ void setFocus( BOOL b );
@@ -428,7 +448,7 @@ private:
void updateLineHeightInsert(LLScrollListItem* item);
void reportInvalidInput();
BOOL isRepeatedChars(const LLWString& string) const;
- void selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
+ void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE);
void deselectItem(LLScrollListItem* itemp);
void commitIfChanged();
BOOL setSort(S32 column, BOOL ascending);
@@ -453,9 +473,11 @@ private:
bool mCommitOnKeyboardMovement;
bool mCommitOnSelectionChange;
bool mSelectionChanged;
+ ESelectionType mSelectionType;
bool mNeedsScroll;
bool mMouseWheelOpaque;
bool mCanSelect;
+ bool mCanSort; // Whether user is allowed to sort
bool mDisplayColumnHeaders;
bool mColumnsDirty;
bool mColumnWidthsDirty;
@@ -468,6 +490,7 @@ private:
LLRect mItemListRect;
S32 mColumnPadding;
+ S32 mRowPadding;
BOOL mBackgroundVisible;
BOOL mDrawStripes;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index df22c88afb..51c615dd00 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -40,6 +40,8 @@
LLScrollListItem::LLScrollListItem( const Params& p )
: mSelected(FALSE),
mHighlighted(FALSE),
+ mHoverIndex(-1),
+ mSelectedIndex(-1),
mEnabled(p.enabled),
mUserdata(p.userdata),
mItemValue(p.value)
@@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem()
mColumns.clear();
}
+void LLScrollListItem::setSelected(BOOL b)
+{
+ mSelected = b;
+ mSelectedIndex = -1;
+}
+
+void LLScrollListItem::setHighlighted(BOOL b)
+{
+ mHighlighted = b;
+ mHoverIndex = -1;
+}
+
+void LLScrollListItem::setHoverCell(S32 cell)
+{
+ mHoverIndex = cell;
+}
+
+void LLScrollListItem::setSelectedCell(S32 cell)
+{
+ mSelectedIndex = cell;
+}
+
void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
{
mColumns.push_back(LLScrollListCell::create(p));
@@ -120,12 +144,21 @@ std::string LLScrollListItem::getContentsCSV() const
}
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding)
{
// draw background rect
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLRect bg_rect = rect;
- gl_rect_2d( bg_rect, bg_color );
+ if (mSelectedIndex < 0 && getSelected())
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, select_color);
+ }
+ else if (mHoverIndex < 0)
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, hover_color);
+ }
S32 cur_x = rect.mLeft;
S32 num_cols = getNumColumns();
@@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
{
LLUI::translate((F32) cur_x, (F32) rect.mBottom);
+ if (mSelectedIndex == cur_col)
+ {
+ // select specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth(),
+ 0);
+ gl_rect_2d(highlight_rect, select_color);
+ }
+ else if (mHoverIndex == cur_col)
+ {
+ // highlight specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth() ,
+ 0);
+ gl_rect_2d(highlight_rect, hover_color);
+ }
+
cell->draw( fg_color, highlight_color );
}
LLUI::popMatrix();
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index 13655b5873..d2c3dd7721 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -77,15 +77,21 @@ public:
virtual ~LLScrollListItem();
- void setSelected( BOOL b ) { mSelected = b; }
+ void setSelected( BOOL b );
BOOL getSelected() const { return mSelected; }
void setEnabled( BOOL b ) { mEnabled = b; }
BOOL getEnabled() const { return mEnabled; }
- void setHighlighted( BOOL b ) { mHighlighted = b; }
+ void setHighlighted( BOOL b );
BOOL getHighlighted() const { return mHighlighted; }
+ void setSelectedCell( S32 cell );
+ S32 getSelectedCell() const { return mSelectedIndex; }
+
+ void setHoverCell( S32 cell );
+ S32 getHoverCell() const { return mHoverIndex; }
+
void setUserdata( void* userdata ) { mUserdata = userdata; }
void* getUserdata() const { return mUserdata; }
@@ -107,14 +113,21 @@ public:
std::string getContentsCSV() const;
- virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+ virtual void draw(const LLRect& rect,
+ const LLColor4& fg_color,
+ const LLColor4& hover_color, // highlight/hover selection of whole item or cell
+ const LLColor4& select_color, // highlight/hover selection of whole item or cell
+ const LLColor4& highlight_color, // highlights contents of cells (ex: text)
+ S32 column_padding);
protected:
LLScrollListItem( const Params& );
private:
BOOL mSelected;
- BOOL mHighlighted;
+ BOOL mHighlighted;
+ S32 mHoverIndex;
+ S32 mSelectedIndex;
BOOL mEnabled;
void* mUserdata;
LLSD mItemValue;
diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp
index 1fdd05a11c..bafeef41fb 100644
--- a/indra/llui/llsearcheditor.cpp
+++ b/indra/llui/llsearcheditor.cpp
@@ -34,7 +34,11 @@
LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
: LLUICtrl(p),
mSearchButton(NULL),
- mClearButton(NULL)
+ mClearButton(NULL),
+ mEditorImage(p.background_image),
+ mEditorImageFocused(p.background_image_focused),
+ mEditorSearchImage(p.background_image_highlight),
+ mHighlightTextField(p.highlight_text_field)
{
S32 srch_btn_top = p.search_button.top_pad + p.search_button.rect.height;
S32 srch_btn_right = p.search_button.rect.width + p.search_button.left_pad;
@@ -57,6 +61,8 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
// Set up line editor.
LLLineEditor::Params line_editor_params(p);
line_editor_params.name("filter edit box");
+ line_editor_params.background_image(p.background_image);
+ line_editor_params.background_image_focused(p.background_image_focused);
line_editor_params.rect(getLocalRect());
line_editor_params.follows.flags(FOLLOWS_ALL);
line_editor_params.text_pad_left(text_pad_left);
@@ -104,6 +110,20 @@ void LLSearchEditor::draw()
if (mClearButton)
mClearButton->setVisible(!mSearchEditor->getWText().empty());
+ if (mHighlightTextField)
+ {
+ if (!mSearchEditor->getWText().empty())
+ {
+ mSearchEditor->setBgImage(mEditorSearchImage);
+ mSearchEditor->setBgImageFocused(mEditorSearchImage);
+ }
+ else
+ {
+ mSearchEditor->setBgImage(mEditorImage);
+ mSearchEditor->setBgImageFocused(mEditorImageFocused);
+ }
+ }
+
LLUICtrl::draw();
}
diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h
index 3b12868225..c0f3c1d60c 100644
--- a/indra/llui/llsearcheditor.h
+++ b/indra/llui/llsearcheditor.h
@@ -47,14 +47,23 @@ public:
Optional<LLButton::Params> search_button,
clear_button;
Optional<bool> search_button_visible,
- clear_button_visible;
+ clear_button_visible,
+ highlight_text_field;
Optional<commit_callback_t> keystroke_callback;
+ Optional<LLUIImage*> background_image,
+ background_image_focused,
+ background_image_highlight;
+
Params()
: search_button("search_button"),
search_button_visible("search_button_visible"),
clear_button("clear_button"),
- clear_button_visible("clear_button_visible")
+ clear_button_visible("clear_button_visible"),
+ highlight_text_field("highlight_text_field"),
+ background_image("background_image"),
+ background_image_focused("background_image_focused"),
+ background_image_highlight("background_image_highlight")
{}
};
@@ -93,6 +102,13 @@ protected:
LLLineEditor* mSearchEditor;
LLButton* mSearchButton;
LLButton* mClearButton;
+
+ LLPointer<LLUIImage> mEditorImage;
+ LLPointer<LLUIImage> mEditorImageFocused;
+ LLPointer<LLUIImage> mEditorSearchImage;
+ LLPointer<LLUIImage> mEditorSearchImageFocused;
+
+ bool mHighlightTextField;
};
#endif // LL_SEARCHEDITOR_H
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index ebbb951ee6..62df5a2c38 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -42,7 +42,6 @@ static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar");
LLSlider::Params::Params()
: orientation ("orientation", std::string ("horizontal")),
- track_color("track_color"),
thumb_outline_color("thumb_outline_color"),
thumb_center_color("thumb_center_color"),
thumb_image("thumb_image"),
@@ -60,7 +59,6 @@ LLSlider::LLSlider(const LLSlider::Params& p)
: LLF32UICtrl(p),
mMouseOffset( 0 ),
mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL),
- mTrackColor(p.track_color()),
mThumbOutlineColor(p.thumb_outline_color()),
mThumbCenterColor(p.thumb_center_color()),
mThumbImage(p.thumb_image),
@@ -331,8 +329,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/llslider.h b/indra/llui/llslider.h
index 3b492d8182..484a5373b3 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -38,8 +38,7 @@ public:
{
Optional<std::string> orientation;
- Optional<LLUIColor> track_color,
- thumb_outline_color,
+ Optional<LLUIColor> thumb_outline_color,
thumb_center_color;
Optional<LLUIImage*> thumb_image,
@@ -99,7 +98,6 @@ private:
const EOrientation mOrientation;
LLRect mThumbRect;
- LLUIColor mTrackColor;
LLUIColor mThumbOutlineColor;
LLUIColor mThumbCenterColor;
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 0056cb6dc4..d80a434f22 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -283,6 +283,35 @@ void LLSliderCtrl::updateText()
}
}
+void LLSliderCtrl::updateSliderRect()
+{
+ S32 right = getRect().getWidth();
+ S32 top = getRect().getHeight();
+ S32 bottom = 0;
+ S32 left = 0;
+ static LLUICachedControl<S32> sliderctrl_spacing("UISliderctrlSpacing", 0);
+ if (mEditor)
+ {
+ LLRect editor_rect = mEditor->getRect();
+ S32 editor_width = editor_rect.getWidth();
+ editor_rect.mRight = right;
+ editor_rect.mLeft = right - editor_width;
+ mEditor->setRect(editor_rect);
+
+ right -= editor_width + sliderctrl_spacing;
+ }
+ if (mTextBox)
+ {
+ right -= mTextBox->getRect().getWidth() + sliderctrl_spacing;
+ }
+ if (mLabelBox)
+ {
+ left += mLabelBox->getRect().getWidth() + sliderctrl_spacing;
+ }
+
+ mSlider->setRect(LLRect(left, top,right,bottom));
+}
+
// static
void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata )
{
@@ -404,6 +433,18 @@ void LLSliderCtrl::onCommit()
LLF32UICtrl::onCommit();
}
+void LLSliderCtrl::setRect(const LLRect& rect)
+{
+ LLF32UICtrl::setRect(rect);
+ updateSliderRect();
+}
+
+//virtual
+void LLSliderCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLF32UICtrl::reshape(width, height, called_from_parent);
+ updateSliderRect();
+}
void LLSliderCtrl::setPrecision(S32 precision)
{
@@ -438,6 +479,7 @@ void LLSliderCtrl::onTabInto()
{
mEditor->onTabInto();
}
+ LLF32UICtrl::onTabInto();
}
void LLSliderCtrl::reportInvalidData()
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index 2bb8668b90..541c167717 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -125,6 +125,9 @@ public:
mSlider->setControlName(control_name, context);
}
+ /*virtual*/ void setRect(const LLRect& rect);
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+
static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata);
static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata);
@@ -146,6 +149,7 @@ protected:
}
private:
void updateText();
+ void updateSliderRect();
void reportInvalidData();
const LLFontGL* mFont;
diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp
index 7f64743e99..ebd8ca0923 100644
--- a/indra/llui/llspellcheck.cpp
+++ b/indra/llui/llspellcheck.cpp
@@ -44,14 +44,11 @@ static const std::string DICT_FILE_IGNORE = "user_ignore.dic";
static const std::string DICT_FILE_MAIN = "dictionaries.xml";
static const std::string DICT_FILE_USER = "user_dictionaries.xml";
-LLSD LLSpellChecker::sDictMap;
LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal;
LLSpellChecker::LLSpellChecker()
: mHunspell(NULL)
{
- // Load initial dictionary information
- refreshDictionaryMap();
}
LLSpellChecker::~LLSpellChecker()
@@ -59,6 +56,12 @@ LLSpellChecker::~LLSpellChecker()
delete mHunspell;
}
+void LLSpellChecker::initSingleton()
+{
+ // Load initial dictionary information
+ refreshDictionaryMap();
+}
+
bool LLSpellChecker::checkSpelling(const std::string& word) const
{
if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) )
@@ -94,10 +97,9 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str
return suggestions.size();
}
-// static
const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language)
{
- for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
+ for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it)
{
const LLSD& dict_entry = *it;
if (dict_language == dict_entry["language"].asString())
@@ -108,14 +110,12 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language)
return LLSD();
}
-// static
bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed)
{
const LLSD dict_info = getDictionaryData(dict_language);
return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) );
}
-// static
void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
{
const std::string dict_language = dict_info["language"].asString();
@@ -124,7 +124,7 @@ void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
return;
}
- for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
+ for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it)
{
LLSD& dict_entry = *it;
if (dict_language == dict_entry["language"].asString())
@@ -133,7 +133,7 @@ void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
return;
}
}
- sDictMap.append(dict_info);
+ mDictMap.append(dict_info);
return;
}
@@ -147,14 +147,14 @@ void LLSpellChecker::refreshDictionaryMap()
std::string user_filename(user_path + DICT_FILE_MAIN);
llifstream user_file(user_filename.c_str(), std::ios::binary);
if ( (!user_file.is_open())
- || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(sDictMap, user_file))
- || (0 == sDictMap.size()) )
+ || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, user_file))
+ || (0 == mDictMap.size()) )
{
std::string app_filename(app_path + DICT_FILE_MAIN);
llifstream app_file(app_filename.c_str(), std::ios::binary);
if ( (!app_file.is_open())
- || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(sDictMap, app_file))
- || (0 == sDictMap.size()) )
+ || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, app_file))
+ || (0 == mDictMap.size()) )
{
return;
}
@@ -178,7 +178,7 @@ void LLSpellChecker::refreshDictionaryMap()
// Look for installed dictionaries
std::string tmp_app_path, tmp_user_path;
- for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
+ for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it)
{
LLSD& sdDict = *it;
tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null;
@@ -416,7 +416,6 @@ bool LLSpellChecker::getUseSpellCheck()
return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell);
}
-// static
bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language)
{
// Only user-installed inactive dictionaries can be removed
@@ -426,7 +425,6 @@ bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language)
( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) );
}
-// static
void LLSpellChecker::removeDictionary(const std::string& dict_language)
{
if (!canRemoveDictionary(dict_language))
@@ -499,12 +497,3 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_language)
LLSpellChecker::instance().initHunspell(dict_language);
}
}
-
-// static
-void LLSpellChecker::initClass()
-{
- if (sDictMap.isUndefined())
- {
- refreshDictionaryMap();
- }
-}
diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h
index acac589e43..3da5e30955 100644
--- a/indra/llui/llspellcheck.h
+++ b/indra/llui/llspellcheck.h
@@ -34,10 +34,9 @@
class Hunspell;
-class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker>
+class LLSpellChecker : public LLSingleton<LLSpellChecker>
{
LLSINGLETON(LLSpellChecker);
- friend class LLInitClass<LLSpellChecker>;
~LLSpellChecker();
public:
@@ -48,6 +47,7 @@ public:
protected:
void addToDictFile(const std::string& dict_path, const std::string& word);
void initHunspell(const std::string& dict_language);
+ void initSingleton();
public:
typedef std::list<std::string> dict_list_t;
@@ -57,26 +57,24 @@ public:
bool isActiveDictionary(const std::string& dict_language) const;
void setSecondaryDictionaries(dict_list_t dict_list);
- static bool canRemoveDictionary(const std::string& dict_language);
+ bool canRemoveDictionary(const std::string& dict_language);
static const std::string getDictionaryAppPath();
static const std::string getDictionaryUserPath();
- static const LLSD getDictionaryData(const std::string& dict_language);
- static const LLSD& getDictionaryMap() { return sDictMap; }
+ const LLSD getDictionaryData(const std::string& dict_language);
+ const LLSD& getDictionaryMap() { return mDictMap; }
static bool getUseSpellCheck();
- static bool hasDictionary(const std::string& dict_language, bool check_installed = false);
- static void refreshDictionaryMap();
- static void removeDictionary(const std::string& dict_language);
+ bool hasDictionary(const std::string& dict_language, bool check_installed = false);
+ void refreshDictionaryMap();
+ void removeDictionary(const std::string& dict_language);
static void setUseSpellCheck(const std::string& dict_language);
protected:
static LLSD loadUserDictionaryMap();
- static void setDictionaryData(const LLSD& dict_info);
+ void setDictionaryData(const LLSD& dict_info);
static void saveUserDictionaryMap(const LLSD& dict_map);
public:
typedef boost::signals2::signal<void()> settings_change_signal_t;
static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb);
-protected:
- static void initClass();
protected:
Hunspell* mHunspell;
@@ -84,8 +82,8 @@ protected:
std::string mDictFile;
dict_list_t mDictSecondary;
std::vector<std::string> mIgnoreList;
+ LLSD mDictMap;
- static LLSD sDictMap;
static settings_change_signal_t sSettingsChangeSignal;
};
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ce3fc29d32..ee78b82429 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -442,7 +442,8 @@ void LLSpinCtrl::setAllowEdit(BOOL allow_edit)
void LLSpinCtrl::onTabInto()
{
- mEditor->onTabInto();
+ mEditor->onTabInto();
+ LLF32UICtrl::onTabInto();
}
diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp
index eda2d6047f..bb4969c81f 100644
--- a/indra/llui/llstatview.cpp
+++ b/indra/llui/llstatview.cpp
@@ -43,7 +43,7 @@ LLStatView::LLStatView(const LLStatView::Params& p)
BOOL isopen = getDisplayChildren();
if (mSetting.length() > 0)
{
- isopen = LLUI::sSettingGroups["config"]->getBOOL(mSetting);
+ isopen = LLUI::getInstance()->mSettingGroups["config"]->getBOOL(mSetting);
}
setDisplayChildren(isopen);
}
@@ -54,7 +54,7 @@ LLStatView::~LLStatView()
if (mSetting.length() > 0)
{
BOOL isopen = getDisplayChildren();
- LLUI::sSettingGroups["config"]->setBOOL(mSetting, isopen);
+ LLUI::getInstance()->mSettingGroups["config"]->setBOOL(mSetting, isopen);
}
}
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 6521b883f8..459fdcf2ae 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -38,6 +38,7 @@
#include "llrender.h"
#include "llfloater.h"
#include "lltrans.h"
+#include "lluiusage.h"
//----------------------------------------------------------------------------
@@ -220,6 +221,8 @@ LLTabContainer::Params::Params()
last_tab("last_tab"),
use_custom_icon_ctrl("use_custom_icon_ctrl", false),
open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false),
+ enable_tabs_flashing("enable_tabs_flashing", false),
+ tabs_flashing_color("tabs_flashing_color"),
tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
use_ellipses("use_ellipses"),
font_halign("halign")
@@ -259,6 +262,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mCustomIconCtrlUsed(p.use_custom_icon_ctrl),
mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop),
mTabIconCtrlPad(p.tab_icon_ctrl_pad),
+ mEnableTabsFlashing(p.enable_tabs_flashing),
+ mTabsFlashingColor(p.tabs_flashing_color),
mUseTabEllipses(p.use_ellipses)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@@ -280,6 +285,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mMinTabWidth = tabcntr_vert_tab_min_width;
}
+ if (p.tabs_flashing_color.isProvided())
+ {
+ mEnableTabsFlashing = true;
+ }
+
initButtons( );
}
@@ -1102,6 +1112,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.pad_left( mLabelPadLeft );
p.pad_right(2);
}
+
+ // inits flash timer
+ p.button_flash_enable = mEnableTabsFlashing;
+ p.flash_color = mTabsFlashingColor;
// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
if (mCustomIconCtrlUsed)
@@ -1543,6 +1557,8 @@ BOOL LLTabContainer::setTab(S32 which)
if (is_selected)
{
+ LLUIUsage::instance().logPanel(tuple->mTabPanel->getName());
+
// Make sure selected tab is within scroll region
if (mIsVertical)
{
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 6bf963313c..8f8cedb1b9 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -109,6 +109,12 @@ public:
* Open tabs on hover in drag and drop situations
*/
Optional<bool> open_tabs_on_drag_and_drop;
+
+ /**
+ * Enable tab flashing
+ */
+ Optional<bool> enable_tabs_flashing;
+ Optional<LLUIColor> tabs_flashing_color;
/**
* Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true)
@@ -310,6 +316,8 @@ private:
bool mCustomIconCtrlUsed;
bool mOpenTabsOnDragAndDrop;
+ bool mEnableTabsFlashing;
+ LLUIColor mTabsFlashingColor;
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index cc44f46706..9005d70b2e 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -152,6 +152,7 @@ LLTextBase::Params::Params()
plain_text("plain_text",false),
track_end("track_end", false),
read_only("read_only", false),
+ skip_link_underline("skip_link_underline", false),
spellcheck("spellcheck", false),
v_pad("v_pad", 0),
h_pad("h_pad", 0),
@@ -185,6 +186,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mFontShadow(p.font_shadow),
mPopupMenuHandle(),
mReadOnly(p.read_only),
+ mSkipLinkUnderline(p.skip_link_underline),
mSpellCheck(p.spellcheck),
mSpellCheckStart(-1),
mSpellCheckEnd(-1),
@@ -1019,7 +1021,38 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
// handle triple click
if (!mTripleClickTimer.hasExpired())
{
- selectAll();
+ S32 real_line = getLineNumFromDocIndex(mCursorPos, false);
+ S32 line_start = -1;
+ S32 line_end = -1;
+ for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->mLineNum < real_line)
+ {
+ continue;
+ }
+ if (it->mLineNum > real_line)
+ {
+ break;
+ }
+ if (line_start == -1)
+ {
+ line_start = it->mDocIndexStart;
+ }
+ line_end = it->mDocIndexEnd;
+ line_end = llclamp(line_end, 0, getLength());
+ }
+
+ if (line_start == -1)
+ {
+ return TRUE;
+ }
+
+ mSelectionEnd = line_start;
+ mSelectionStart = line_end;
+ setCursorPos(line_start);
+
return TRUE;
}
@@ -1150,7 +1183,7 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- if (width != getRect().getWidth() || height != getRect().getHeight())
+ if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape)
{
bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false;
@@ -2226,6 +2259,18 @@ void LLTextBase::needsReflow(S32 index)
mReflowIndex = llmin(mReflowIndex, index);
}
+S32 LLTextBase::removeFirstLine()
+{
+ if (!mLineInfoList.empty())
+ {
+ S32 length = getLineEnd(0);
+ deselect();
+ removeStringNoUndo(0, length);
+ return length;
+ }
+ return 0;
+}
+
void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params)
{
segment_vec_t segments;
@@ -2289,7 +2334,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
S32 cur_length = getLength();
LLStyleConstSP sp(new LLStyle(highlight_params));
LLTextSegmentPtr segmentp;
- if(underline_on_hover_only)
+ if (underline_on_hover_only || mSkipLinkUnderline)
{
highlight_params.font.style("NORMAL");
LLStyleConstSP normal_sp(new LLStyle(highlight_params));
@@ -2313,7 +2358,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
S32 segment_start = old_length;
S32 segment_end = old_length + wide_text.size();
LLStyleConstSP sp(new LLStyle(style_params));
- if (underline_on_hover_only)
+ if (underline_on_hover_only || mSkipLinkUnderline)
{
LLStyle::Params normal_style_params(style_params);
normal_style_params.font.style("NORMAL");
@@ -3113,6 +3158,7 @@ BOOL LLTextSegment::handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE;
BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }
BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; }
BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }
+BOOL LLTextSegment::handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; }
BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; }
const std::string& LLTextSegment::getName() const
{
@@ -3249,7 +3295,7 @@ BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask)
// Only process the click if it's actually in this segment, not to the right of the end-of-line.
if(mEditor.getSegmentAtLocalPos(x, y, false) == this)
{
- LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
+ LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND);
return TRUE;
}
}
@@ -3491,7 +3537,7 @@ F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start
/*virtual*/
BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask)
{
- mStyle = mHoveredStyle;
+ mStyle = mEditor.getSkipLinkUnderline() ? mNormalStyle : mHoveredStyle;
return LLNormalTextSegment::handleHover(x, y, mask);
}
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 99c243a346..590e7c9dbb 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -103,6 +103,7 @@ public:
/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
/*virtual*/ const std::string& getName() const;
/*virtual*/ void onMouseCaptureLost();
@@ -309,6 +310,7 @@ public:
border_visible,
track_end,
read_only,
+ skip_link_underline,
spellcheck,
allow_scroll,
plain_text,
@@ -406,6 +408,7 @@ public:
virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style
virtual std::string getText() const;
void setMaxTextLength(S32 length) { mMaxTextByteLength = length; }
+ S32 getMaxTextLength() { return mMaxTextByteLength; }
// wide-char versions
void setWText(const LLWString& text);
@@ -434,6 +437,7 @@ public:
S32 getLength() const { return getWText().length(); }
S32 getLineCount() const { return mLineInfoList.size(); }
+ S32 removeFirstLine(); // returns removed length
void addDocumentChild(LLView* view);
void removeDocumentChild(LLView* view);
@@ -444,6 +448,8 @@ public:
S32 getVPad() { return mVPad; }
S32 getHPad() { return mHPad; }
+ F32 getLineSpacingMult() { return mLineSpacingMult; }
+ S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline
S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line = true) const;
LLRect getLocalRectFromDocIndex(S32 pos) const;
@@ -452,6 +458,9 @@ public:
void setReadOnly(bool read_only) { mReadOnly = read_only; }
bool getReadOnly() { return mReadOnly; }
+ void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; }
+ bool getSkipLinkUnderline() { return mSkipLinkUnderline; }
+
void setPlainText(bool value) { mPlainText = value;}
bool getPlainText() const { return mPlainText; }
@@ -697,6 +706,8 @@ protected:
bool mAutoIndent;
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
+ bool mSkipLinkUnderline;
+
// support widgets
LLHandle<LLContextMenu> mPopupMenuHandle;
LLView* mDocumentView;
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 9faff1278d..134afc005b 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -107,7 +107,7 @@ BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
if (!handled && mClickedCallback && mShowCursorHand)
{
// Clickable text boxes change the cursor to a hand
- LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
+ LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND);
return TRUE;
}
return handled;
@@ -163,13 +163,13 @@ BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text
}
-void LLTextBox::reshapeToFitText()
+void LLTextBox::reshapeToFitText(BOOL called_from_parent)
{
reflow();
S32 width = getTextPixelWidth();
S32 height = getTextPixelHeight();
- reshape( width + 2 * mHPad, height + 2 * mVPad, FALSE );
+ reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent );
}
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index 061d2dd23d..c3e3b61912 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -60,7 +60,7 @@ public:
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL );
- void reshapeToFitText();
+ void reshapeToFitText(BOOL called_from_parent = FALSE);
S32 getTextPixelWidth();
S32 getTextPixelHeight();
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 137167db2a..b1f8b00cab 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -1045,7 +1045,7 @@ void LLTextEditor::removeCharOrTab()
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
@@ -1068,7 +1068,7 @@ void LLTextEditor::removeChar()
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
@@ -1315,7 +1315,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
break;
@@ -1333,7 +1333,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
}
break;
@@ -1665,7 +1665,7 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask)
}
else
{
- LLUI::reportBadKeystroke();
+ LLUI::getInstance()->reportBadKeystroke();
}
break;
@@ -2750,7 +2750,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
{
LLRect control_rect_screen;
localRectToScreen(mVisibleTextRect, &control_rect_screen);
- LLUI::screenRectToGL(control_rect_screen, control);
+ LLUI::getInstance()->screenRectToGL(control_rect_screen, control);
}
S32 preedit_left_position, preedit_right_position;
@@ -2804,7 +2804,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2;
S32 query_screen_x, query_screen_y;
localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y);
- LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
+ LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
}
if (bounds)
@@ -2831,7 +2831,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom);
LLRect preedit_rect_screen;
localRectToScreen(preedit_rect_local, &preedit_rect_screen);
- LLUI::screenRectToGL(preedit_rect_screen, bounds);
+ LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds);
}
return TRUE;
diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp
index f6b2ee1dc0..538508b856 100644
--- a/indra/llui/lltextutil.cpp
+++ b/indra/llui/lltextutil.cpp
@@ -78,7 +78,7 @@ void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& n
const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
{
- static const std::string PHONE_SEPARATOR = LLUI::sSettingGroups["config"]->getString("AvalinePhoneSeparator");
+ static const std::string PHONE_SEPARATOR = LLUI::getInstance()->mSettingGroups["config"]->getString("AvalinePhoneSeparator");
static const S32 PHONE_PART_LEN = 2;
static std::string formatted_phone_str;
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index ccb92ffbb2..3e56e0a589 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -55,7 +55,7 @@ boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const
void LLToggleableMenu::onVisibilityChange (BOOL curVisibilityIn)
{
S32 x,y;
- LLUI::getMousePositionLocal(LLUI::getRootView(), &x, &y);
+ LLUI::getInstance()->getMousePositionLocal(LLUI::getInstance()->getRootView(), &x, &y);
// STORM-1879: also check MouseCapture to see if the button was really
// clicked (otherwise the VisibilityChange was triggered via keyboard shortcut)
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index abc2b6e9ca..5150df25f2 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -967,6 +967,8 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
executeStopParam.function_name = executeStopFunction;
executeStopParam.parameter = commandp->executeStopParameters();
LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam);
+ button->setFunctionName(commandp->executeFunctionName());
+ LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL;
LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam);
button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2));
@@ -974,6 +976,8 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
}
else
{
+ button->setFunctionName(commandp->executeFunctionName());
+ LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL;
button->setCommitCallback(executeParam);
}
@@ -1125,7 +1129,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
- S32 drag_threshold = LLUI::sSettingGroups["config"]->getS32("DragAndDropDistanceThreshold");
+ static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3);
if (mouse_distance_squared > drag_threshold * drag_threshold
&& hasMouseCapture() &&
mStartDragItemCallback && mHandleDragItemCallback)
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 698b128d45..2f56a8b1d0 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -145,10 +145,10 @@ LLToolTip::Params::Params()
wrap("wrap", true),
pos("pos"),
message("message"),
- delay_time("delay_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" )),
- visible_time_over("visible_time_over", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )),
- visible_time_near("visible_time_near", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )),
- visible_time_far("visible_time_far", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )),
+ delay_time("delay_time", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" )),
+ visible_time_over("visible_time_over", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )),
+ visible_time_near("visible_time_near", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )),
+ visible_time_far("visible_time_far", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )),
sticky_rect("sticky_rect"),
image("image"),
text_color("text_color"),
@@ -358,8 +358,8 @@ void LLToolTip::draw()
if (mFadeTimer.getStarted())
{
- F32 tool_tip_fade_time = LLUI::sSettingGroups["config"]->getF32("ToolTipFadeTime");
- alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, 1.f, 0.f);
+ static LLCachedControl<F32> tool_tip_fade_time(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFadeTime", 0.2f);
+ alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time(), 1.f, 0.f);
if (alpha == 0.f)
{
// finished fading out, so hide ourselves
@@ -436,12 +436,12 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
{
LLCoordGL pos = params.pos;
// try to spawn at requested position
- LLUI::positionViewNearMouse(mToolTip, pos.mX, pos.mY);
+ LLUI::getInstance()->positionViewNearMouse(mToolTip, pos.mX, pos.mY);
}
else
{
// just spawn at mouse location
- LLUI::positionViewNearMouse(mToolTip);
+ LLUI::getInstance()->positionViewNearMouse(mToolTip);
}
//...update "sticky" rect and tooltip position
@@ -453,7 +453,7 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
{
S32 mouse_x;
S32 mouse_y;
- LLUI::getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y);
+ LLUI::getInstance()->getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y);
// allow mouse a little bit of slop before changing tooltips
mMouseNearRect.setCenterAndSize(mouse_x, mouse_y, 3, 3);
@@ -491,7 +491,7 @@ void LLToolTipMgr::show(const LLToolTip::Params& params)
// are we ready to show the tooltip?
if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc.
- && LLUI::getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough
+ && LLUI::getInstance()->getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough
{
bool tooltip_changed = mLastToolTipParams.message() != params_with_defaults.message()
|| mLastToolTipParams.pos() != params_with_defaults.pos()
@@ -563,7 +563,7 @@ void LLToolTipMgr::updateToolTipVisibility()
}
// hide tooltips when mouse cursor is hidden
- if (LLUI::getWindow()->isCursorHidden())
+ if (LLUI::getInstance()->getWindow()->isCursorHidden())
{
blockToolTips();
return;
@@ -574,7 +574,7 @@ void LLToolTipMgr::updateToolTipVisibility()
if (toolTipVisible())
{
S32 mouse_x, mouse_y;
- LLUI::getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y);
+ LLUI::getInstance()->getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y);
// mouse far away from tooltip
tooltip_timeout = mLastToolTipParams.visible_time_far;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 52190a1473..6f16745bd3 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -75,19 +75,6 @@
// Language for UI construction
std::map<std::string, std::string> gTranslation;
std::list<std::string> gUntranslated;
-/*static*/ LLUI::settings_map_t LLUI::sSettingGroups;
-/*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
-/*static*/ LLUIAudioCallback LLUI::sDeferredAudioCallback = NULL;
-/*static*/ LLWindow* LLUI::sWindow = NULL;
-/*static*/ LLView* LLUI::sRootView = NULL;
-/*static*/ BOOL LLUI::sDirty = FALSE;
-/*static*/ LLRect LLUI::sDirtyRect;
-/*static*/ LLHelp* LLUI::sHelpImpl = NULL;
-/*static*/ std::vector<std::string> LLUI::sXUIPaths;
-/*static*/ LLFrameTimer LLUI::sMouseIdleTimer;
-/*static*/ LLUI::add_popup_t LLUI::sAddPopupFunc;
-/*static*/ LLUI::remove_popup_t LLUI::sRemovePopupFunc;
-/*static*/ LLUI::clear_popups_t LLUI::sClearPopupsFunc;
// register filter editor here
static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
@@ -106,18 +93,19 @@ LLUUID find_ui_sound(const char * namep)
{
std::string name = ll_safe_string(namep);
LLUUID uuid = LLUUID(NULL);
- if (!LLUI::sSettingGroups["config"]->controlExists(name))
+ LLUI *ui_inst = LLUI::getInstance();
+ if (!ui_inst->mSettingGroups["config"]->controlExists(name))
{
LL_WARNS() << "tried to make UI sound for unknown sound name: " << name << LL_ENDL;
}
else
{
- uuid = LLUUID(LLUI::sSettingGroups["config"]->getString(name));
+ uuid = LLUUID(ui_inst->mSettingGroups["config"]->getString(name));
if (uuid.isNull())
{
- if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString())
+ if (ui_inst->mSettingGroups["config"]->getString(name) == LLUUID::null.asString())
{
- if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
+ if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
{
LL_INFOS() << "UI sound name: " << name << " triggered but silent (null uuid)" << LL_ENDL;
}
@@ -127,9 +115,9 @@ LLUUID find_ui_sound(const char * namep)
LL_WARNS() << "UI sound named: " << name << " does not translate to a valid uuid" << LL_ENDL;
}
}
- else if (LLUI::sAudioCallback != NULL)
+ else if (ui_inst->mAudioCallback != NULL)
{
- if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
+ if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
{
LL_INFOS() << "UI sound name: " << name << LL_ENDL;
}
@@ -144,7 +132,7 @@ void make_ui_sound(const char* namep)
LLUUID soundUUID = find_ui_sound(namep);
if(soundUUID.notNull())
{
- LLUI::sAudioCallback(soundUUID);
+ LLUI::getInstance()->mAudioCallback(soundUUID);
}
}
@@ -153,30 +141,30 @@ void make_ui_sound_deferred(const char* namep)
LLUUID soundUUID = find_ui_sound(namep);
if(soundUUID.notNull())
{
- LLUI::sDeferredAudioCallback(soundUUID);
+ LLUI::getInstance()->mDeferredAudioCallback(soundUUID);
}
}
-void LLUI::initClass(const settings_map_t& settings,
- LLImageProviderInterface* image_provider,
- LLUIAudioCallback audio_callback,
- LLUIAudioCallback deferred_audio_callback,
- const LLVector2* scale_factor,
- const std::string& language)
+LLUI::LLUI(const settings_map_t& settings,
+ LLImageProviderInterface* image_provider,
+ LLUIAudioCallback audio_callback,
+ LLUIAudioCallback deferred_audio_callback)
+: mSettingGroups(settings),
+mAudioCallback(audio_callback),
+mDeferredAudioCallback(deferred_audio_callback),
+mWindow(NULL), // set later in startup
+mRootView(NULL),
+mHelpImpl(NULL)
{
- LLRender2D::initClass(image_provider,scale_factor);
- sSettingGroups = settings;
+ LLRender2D::initParamSingleton(image_provider);
- if ((get_ptr_in_map(sSettingGroups, std::string("config")) == NULL) ||
- (get_ptr_in_map(sSettingGroups, std::string("floater")) == NULL) ||
- (get_ptr_in_map(sSettingGroups, std::string("ignores")) == NULL))
+ if ((get_ptr_in_map(mSettingGroups, std::string("config")) == NULL) ||
+ (get_ptr_in_map(mSettingGroups, std::string("floater")) == NULL) ||
+ (get_ptr_in_map(mSettingGroups, std::string("ignores")) == NULL))
{
LL_ERRS() << "Failure to initialize configuration groups" << LL_ENDL;
}
- sAudioCallback = audio_callback;
- sDeferredAudioCallback = deferred_audio_callback;
- sWindow = NULL; // set later in startup
LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
@@ -207,33 +195,13 @@ void LLUI::initClass(const settings_map_t& settings,
LLCommandManager::load();
}
-void LLUI::cleanupClass()
-{
- SUBSYSTEM_CLEANUP(LLRender2D);
-}
-
void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups)
{
- sAddPopupFunc = add_popup;
- sRemovePopupFunc = remove_popup;
- sClearPopupsFunc = clear_popups;
+ mAddPopupFunc = add_popup;
+ mRemovePopupFunc = remove_popup;
+ mClearPopupsFunc = clear_popups;
}
-//static
-void LLUI::dirtyRect(LLRect rect)
-{
- if (!sDirty)
- {
- sDirtyRect = rect;
- sDirty = TRUE;
- }
- else
- {
- sDirtyRect.unionWith(rect);
- }
-}
-
-//static
void LLUI::setMousePositionScreen(S32 x, S32 y)
{
#if defined(LL_DARWIN)
@@ -247,7 +215,6 @@ void LLUI::setMousePositionScreen(S32 x, S32 y)
LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert());
}
-//static
void LLUI::getMousePositionScreen(S32 *x, S32 *y)
{
LLCoordWindow cursor_pos_window;
@@ -257,7 +224,6 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y)
*y = ll_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VY]);
}
-//static
void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y)
{
S32 screen_x, screen_y;
@@ -266,7 +232,6 @@ void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y)
setMousePositionScreen(screen_x, screen_y);
}
-//static
void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y)
{
S32 screen_x, screen_y;
@@ -280,20 +245,19 @@ void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y)
// or on Windows if the SecondLife.exe executable is run directly, the
// language follows the OS language. In all cases the user can override
// the language manually in preferences. JC
-// static
-std::string LLUI::getLanguage()
+std::string LLUI::getUILanguage()
{
std::string language = "en";
- if (sSettingGroups["config"])
+ if (mSettingGroups["config"])
{
- language = sSettingGroups["config"]->getString("Language");
+ language = mSettingGroups["config"]->getString("Language");
if (language.empty() || language == "default")
{
- language = sSettingGroups["config"]->getString("InstallLanguage");
+ language = mSettingGroups["config"]->getString("InstallLanguage");
}
if (language.empty() || language == "default")
{
- language = sSettingGroups["config"]->getString("SystemLanguage");
+ language = mSettingGroups["config"]->getString("SystemLanguage");
}
if (language.empty() || language == "default")
{
@@ -303,6 +267,13 @@ std::string LLUI::getLanguage()
return language;
}
+// static
+std::string LLUI::getLanguage()
+{
+ // Note: lldateutil_test redefines this function
+ return LLUI::getInstance()->getUILanguage();
+}
+
struct SubDir : public LLInitParam::Block<SubDir>
{
Mandatory<std::string> value;
@@ -362,37 +333,32 @@ std::string LLUI::locateSkin(const std::string& filename)
return "";
}
-//static
LLVector2 LLUI::getWindowSize()
{
LLCoordWindow window_rect;
- sWindow->getSize(&window_rect);
+ mWindow->getSize(&window_rect);
return LLVector2(window_rect.mX / getScaleFactor().mV[VX], window_rect.mY / getScaleFactor().mV[VY]);
}
-//static
void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y)
{
*gl_x = ll_round((F32)screen_x * getScaleFactor().mV[VX]);
*gl_y = ll_round((F32)screen_y * getScaleFactor().mV[VY]);
}
-//static
void LLUI::glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y)
{
*screen_x = ll_round((F32)gl_x / getScaleFactor().mV[VX]);
*screen_y = ll_round((F32)gl_y / getScaleFactor().mV[VY]);
}
-//static
void LLUI::screenRectToGL(const LLRect& screen, LLRect *gl)
{
screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop);
screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom);
}
-//static
void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
{
glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop);
@@ -402,8 +368,8 @@ void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
{
- for (settings_map_t::iterator itor = sSettingGroups.begin();
- itor != sSettingGroups.end(); ++itor)
+ for (settings_map_t::iterator itor = mSettingGroups.begin();
+ itor != mSettingGroups.end(); ++itor)
{
LLControlGroup* control_group = itor->second;
if(control_group != NULL)
@@ -413,43 +379,38 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
}
}
- return *sSettingGroups["config"]; // default group
+ return *mSettingGroups["config"]; // default group
}
-//static
void LLUI::addPopup(LLView* viewp)
{
- if (sAddPopupFunc)
+ if (mAddPopupFunc)
{
- sAddPopupFunc(viewp);
+ mAddPopupFunc(viewp);
}
}
-//static
void LLUI::removePopup(LLView* viewp)
{
- if (sRemovePopupFunc)
+ if (mRemovePopupFunc)
{
- sRemovePopupFunc(viewp);
+ mRemovePopupFunc(viewp);
}
}
-//static
void LLUI::clearPopups()
{
- if (sClearPopupsFunc)
+ if (mClearPopupsFunc)
{
- sClearPopupsFunc();
+ mClearPopupsFunc();
}
}
-//static
void LLUI::reportBadKeystroke()
{
make_ui_sound("UISndBadKeystroke");
}
-
-//static
+
// spawn_x and spawn_y are top left corner of view in screen GL coordinates
void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
{
@@ -460,7 +421,7 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
S32 mouse_x;
S32 mouse_y;
- LLUI::getMousePositionScreen(&mouse_x, &mouse_y);
+ getMousePositionScreen(&mouse_x, &mouse_y);
// If no spawn location provided, use mouse position
if (spawn_x == S32_MAX || spawn_y == S32_MAX)
@@ -535,6 +496,18 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
return context;
}
+//static
+LLVector2& LLUI::getScaleFactor()
+{
+ return LLRender::sUIGLScaleFactor;
+}
+
+//static
+void LLUI::setScaleFactor(const LLVector2& scale_factor)
+{
+ LLRender::sUIGLScaleFactor = scale_factor;
+}
+
// LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index d7151dbee9..30dbd7248f 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.
@@ -109,8 +108,16 @@ class LLImageProviderInterface;
typedef void (*LLUIAudioCallback)(const LLUUID& uuid);
-class LLUI
+class LLUI : public LLParamSingleton<LLUI>
{
+public:
+ typedef std::map<std::string, LLControlGroup*> settings_map_t;
+
+private:
+ LLSINGLETON(LLUI , const settings_map_t &settings,
+ LLImageProviderInterface* image_provider,
+ LLUIAudioCallback audio_callback,
+ LLUIAudioCallback deferred_audio_callback);
LOG_CLASS(LLUI);
public:
//
@@ -232,36 +239,20 @@ public:
//
// Methods
//
- typedef std::map<std::string, LLControlGroup*> settings_map_t;
typedef boost::function<void(LLView*)> add_popup_t;
typedef boost::function<void(LLView*)> remove_popup_t;
typedef boost::function<void(void)> clear_popups_t;
- static void initClass(const settings_map_t& settings,
- LLImageProviderInterface* image_provider,
- LLUIAudioCallback audio_callback = NULL,
- LLUIAudioCallback deferred_audio_callback = NULL,
- const LLVector2 *scale_factor = NULL,
- const std::string& language = LLStringUtil::null);
- static void cleanupClass();
- static void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& );
-
- static void pushMatrix() { LLRender2D::pushMatrix(); }
- static void popMatrix() { LLRender2D::popMatrix(); }
- static void loadIdentity() { LLRender2D::loadIdentity(); }
- static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); }
-
- static LLRect sDirtyRect;
- static BOOL sDirty;
- static void dirtyRect(LLRect rect);
+ void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& );
// Return the ISO639 language name ("en", "ko", etc.) for the viewer UI.
// http://www.loc.gov/standards/iso639-2/php/code_list.php
- static std::string getLanguage();
+ std::string getUILanguage();
+ static std::string getLanguage(); // static for lldateutil_test compatibility
//helper functions (should probably move free standing rendering helper functions here)
- static LLView* getRootView() { return sRootView; }
- static void setRootView(LLView* view) { sRootView = view; }
+ LLView* getRootView() { return mRootView; }
+ void setRootView(LLView* view) { mRootView = view; }
/**
* Walk the LLView tree to resolve a path
* Paths can be discovered using Develop > XUI > Show XUI Paths
@@ -287,58 +278,65 @@ public:
* tree, the first "bar" anywhere under it, and "baz"
* as a direct child of that
*/
- static const LLView* resolvePath(const LLView* context, const std::string& path);
- static LLView* resolvePath(LLView* context, const std::string& path);
+ const LLView* resolvePath(const LLView* context, const std::string& path);
+ LLView* resolvePath(LLView* context, const std::string& path);
static std::string locateSkin(const std::string& filename);
- static void setMousePositionScreen(S32 x, S32 y);
- static void getMousePositionScreen(S32 *x, S32 *y);
- static void setMousePositionLocal(const LLView* viewp, S32 x, S32 y);
- static void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y);
- static LLVector2& getScaleFactor() { return LLRender2D::sGLScaleFactor; }
- static void setScaleFactor(const LLVector2& scale_factor) { LLRender2D::setScaleFactor(scale_factor); }
- static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); }
- static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0)
- { return LLRender2D::getUIImageByID(image_id, priority); }
- static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0)
- { return LLRender2D::getUIImage(name, priority); }
- static LLVector2 getWindowSize();
- static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
- static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
- static void screenRectToGL(const LLRect& screen, LLRect *gl);
- static void glRectToScreen(const LLRect& gl, LLRect *screen);
+ void setMousePositionScreen(S32 x, S32 y);
+ void getMousePositionScreen(S32 *x, S32 *y);
+ void setMousePositionLocal(const LLView* viewp, S32 x, S32 y);
+ void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y);
+ LLVector2 getWindowSize();
+ void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
+ void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
+ void screenRectToGL(const LLRect& screen, LLRect *gl);
+ void glRectToScreen(const LLRect& gl, LLRect *screen);
// Returns the control group containing the control name, or the default group
- static LLControlGroup& getControlControlGroup (const std::string& controlname);
- static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); }
- static void resetMouseIdleTimer() { sMouseIdleTimer.reset(); }
- static LLWindow* getWindow() { return sWindow; }
+ LLControlGroup& getControlControlGroup (const std::string& controlname);
+ F32 getMouseIdleTime() { return mMouseIdleTimer.getElapsedTimeF32(); }
+ void resetMouseIdleTimer() { mMouseIdleTimer.reset(); }
+ LLWindow* getWindow() { return mWindow; }
- static void addPopup(LLView*);
- static void removePopup(LLView*);
- static void clearPopups();
+ void addPopup(LLView*);
+ void removePopup(LLView*);
+ void clearPopups();
- static void reportBadKeystroke();
+ void reportBadKeystroke();
// Ensures view does not overlap mouse cursor, but is inside
// the view's parent rectangle. Used for tooltips, inspectors.
// Optionally override the view's default X/Y, which are relative to the
// view's parent.
- static void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX);
+ void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX);
+
+ // LLRender2D wrappers
+ static void pushMatrix() { LLRender2D::pushMatrix(); }
+ static void popMatrix() { LLRender2D::popMatrix(); }
+ static void loadIdentity() { LLRender2D::loadIdentity(); }
+ static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); }
+
+ static LLVector2& getScaleFactor();
+ static void setScaleFactor(const LLVector2& scale_factor);
+ static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); }
+ static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0)
+ { return LLRender2D::getInstance()->getUIImageByID(image_id, priority); }
+ static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0)
+ { return LLRender2D::getInstance()->getUIImage(name, priority); }
//
// Data
//
- static settings_map_t sSettingGroups;
- static LLUIAudioCallback sAudioCallback;
- static LLUIAudioCallback sDeferredAudioCallback;
- static LLWindow* sWindow;
- static LLView* sRootView;
- static LLHelp* sHelpImpl;
+ settings_map_t mSettingGroups;
+ LLUIAudioCallback mAudioCallback;
+ LLUIAudioCallback mDeferredAudioCallback;
+ LLWindow* mWindow;
+ LLView* mRootView;
+ LLHelp* mHelpImpl;
private:
- static std::vector<std::string> sXUIPaths;
- static LLFrameTimer sMouseIdleTimer;
- static add_popup_t sAddPopupFunc;
- static remove_popup_t sRemovePopupFunc;
- static clear_popups_t sClearPopupsFunc;
+ std::vector<std::string> mXUIPaths;
+ LLFrameTimer mMouseIdleTimer;
+ add_popup_t mAddPopupFunc;
+ remove_popup_t mRemovePopupFunc;
+ clear_popups_t mClearPopupsFunc;
};
@@ -363,7 +361,7 @@ public:
LLUICachedControl(const std::string& name,
const T& default_value,
const std::string& comment = "Declared In Code")
- : LLCachedControl<T>(LLUI::getControlControlGroup(name), name, default_value, comment)
+ : LLCachedControl<T>(LLUI::getInstance()->getControlControlGroup(name), name, default_value, comment)
{}
};
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index df74e113e9..5924542a19 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -35,6 +35,7 @@
#include "lluictrlfactory.h"
#include "lltabcontainer.h"
#include "llaccordionctrltab.h"
+#include "lluiusage.h"
static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
@@ -137,13 +138,29 @@ void LLUICtrl::initFromParams(const Params& p)
{
LLControlVariable* control = findControl(p.enabled_controls.enabled);
if (control)
+ {
setEnabledControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName()
+ << ": control " << p.enabled_controls.enabled()
+ << " does not exist." << LL_ENDL;
+ }
}
else if(p.enabled_controls.disabled.isChosen())
{
LLControlVariable* control = findControl(p.enabled_controls.disabled);
if (control)
+ {
setDisabledControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName()
+ << ": control " << p.enabled_controls.disabled()
+ << " does not exist." << LL_ENDL;
+ }
}
}
if(p.controls_visibility.isProvided())
@@ -152,13 +169,29 @@ void LLUICtrl::initFromParams(const Params& p)
{
LLControlVariable* control = findControl(p.controls_visibility.visible);
if (control)
+ {
setMakeVisibleControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign visibility control variable to " << getName()
+ << ": control " << p.controls_visibility.visible()
+ << " does not exist." << LL_ENDL;
+ }
}
else if (p.controls_visibility.invisible.isChosen())
{
LLControlVariable* control = findControl(p.controls_visibility.invisible);
if (control)
+ {
setMakeInvisibleControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign invisibility control variable to " << getName()
+ << ": control " << p.controls_visibility.invisible()
+ << " does not exist." << LL_ENDL;
+ }
}
}
@@ -250,6 +283,7 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa
else
{
std::string function_name = cb.function_name;
+ setFunctionName(function_name);
commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name));
if (func)
{
@@ -390,7 +424,19 @@ BOOL LLUICtrl::canFocusChildren() const
void LLUICtrl::onCommit()
{
if (mCommitSignal)
- (*mCommitSignal)(this, getValue());
+ {
+ if (!mFunctionName.empty())
+ {
+ LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL;
+ LLUIUsage::instance().logCommand(mFunctionName);
+ LLUIUsage::instance().logControl(getPathname());
+ }
+ else
+ {
+ //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL;
+ }
+ (*mCommitSignal)(this, getValue());
+ }
}
//virtual
@@ -497,6 +543,11 @@ void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
if (!control_name.empty())
{
LLControlVariable* control = context->findControl(control_name);
+ if (!control)
+ {
+ LL_WARNS() << "Failed to assign control variable to " << getName()
+ << ": control "<< control_name << " does not exist." << LL_ENDL;
+ }
setControlVariable(control);
}
}
@@ -560,6 +611,12 @@ void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));
}
}
+
+void LLUICtrl::setFunctionName(const std::string& function_name)
+{
+ mFunctionName = function_name;
+}
+
// static
bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
{
@@ -684,8 +741,9 @@ void LLUICtrl::resetDirty()
}
// virtual
-void LLUICtrl::onTabInto()
+void LLUICtrl::onTabInto()
{
+ onUpdateScrollToChild(this);
}
// virtual
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 63baed6793..67dd24341c 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -183,6 +183,8 @@ public:
void setMakeVisibleControlVariable(LLControlVariable* control);
void setMakeInvisibleControlVariable(LLControlVariable* control);
+ void setFunctionName(const std::string& function_name);
+
virtual void setTentative(BOOL b);
virtual BOOL getTentative() const;
virtual void setValue(const LLSD& value);
@@ -213,7 +215,8 @@ public:
virtual void setColor(const LLColor4& color);
- F32 getCurrentTransparency();
+ // Ansariel: Changed to virtual. We might want to change the transparency ourself!
+ virtual F32 getCurrentTransparency();
void setTransparencyType(ETypeTransparency type);
ETypeTransparency getTransparencyType() const {return mTransparencyType;}
@@ -309,6 +312,8 @@ protected:
LLControlVariable* mMakeInvisibleControlVariable;
boost::signals2::connection mMakeInvisibleControlConnection;
+ std::string mFunctionName;
+
static F32 sActiveControlTransparency;
static F32 sInactiveControlTransparency;
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 03d946f1b7..135ed57a4f 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -37,6 +37,7 @@
#include "llheteromap.h"
class LLView;
+void deleteView(LLView*); // Inside LLView.cpp, avoid having to potentially delete an incomplete type here.
// lookup widget constructor funcs by widget name
template <typename DERIVED_TYPE>
@@ -160,8 +161,8 @@ public:
LLXMLNodePtr root_node;
if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
- {
- LL_WARNS() << "Couldn't parse XUI file: " << instance().getCurFileName() << LL_ENDL;
+ {
+ LL_WARNS() << "Couldn't parse XUI from path: " << instance().getCurFileName() << ", from filename: " << filename << LL_ENDL;
goto fail;
}
@@ -174,14 +175,7 @@ public:
{
LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL;
-#if LL_DARWIN
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdelete-incomplete"
- delete view;
-#pragma clang diagnostic pop
-#else
- delete view;
-#endif
+ deleteView(view);
view = NULL;
}
}
diff --git a/indra/llui/lluiusage.cpp b/indra/llui/lluiusage.cpp
new file mode 100644
index 0000000000..ccae6643b9
--- /dev/null
+++ b/indra/llui/lluiusage.cpp
@@ -0,0 +1,146 @@
+/**
+* @file lluiuisage.cpp
+* @brief Source file for LLUIUsage
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, 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$
+*/
+
+#include "linden_common.h"
+#include "lluiusage.h"
+#include <boost/algorithm/string.hpp>
+
+LLUIUsage::LLUIUsage()
+{
+}
+
+LLUIUsage::~LLUIUsage()
+{
+}
+
+// static
+std::string LLUIUsage::sanitized(const std::string& s)
+{
+ // Remove characters that make the ViewerStats db unhappy
+ std::string result(s);
+ std::replace(result.begin(), result.end(), '.', '_');
+ std::replace(result.begin(), result.end(), ' ', '_');
+ return result;
+}
+
+// static
+void LLUIUsage::setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val)
+{
+ // Keep the last max_elts components of the specified path
+ std::vector<std::string> fields;
+ boost::split(fields, path, boost::is_any_of("/"));
+ auto first_pos = std::max(fields.begin(), fields.end() - max_elts);
+ auto end_pos = fields.end();
+ std::vector<std::string> last_fields(first_pos,end_pos);
+
+ setLLSDNested(sd, last_fields, val);
+}
+
+// setLLSDNested()
+// Accomplish the equivalent of
+// sd[fields[0]][fields[1]]... = val;
+// for an arbitrary number of fields.
+// This might be useful as an LLSD utility function; is not specific to LLUIUsage
+//
+// static
+void LLUIUsage::setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val)
+{
+ LLSD* fsd = &sd;
+ for (auto it=fields.begin(); it!=fields.end(); ++it)
+ {
+ if (it == fields.end()-1)
+ {
+ (*fsd)[*it] = val;
+ }
+ else
+ {
+ if (!(*fsd)[*it].isMap())
+ {
+ (*fsd)[*it] = LLSD::emptyMap();
+ }
+ fsd = &(*fsd)[*it];
+ }
+ }
+}
+
+void LLUIUsage::logCommand(const std::string& command)
+{
+ mCommandCounts[sanitized(command)]++;
+ LL_DEBUGS("UIUsage") << "command " << command << LL_ENDL;
+}
+
+void LLUIUsage::logControl(const std::string& control)
+{
+ mControlCounts[sanitized(control)]++;
+ LL_DEBUGS("UIUsage") << "control " << control << LL_ENDL;
+}
+
+
+void LLUIUsage::logFloater(const std::string& floater)
+{
+ mFloaterCounts[sanitized(floater)]++;
+ LL_DEBUGS("UIUsage") << "floater " << floater << LL_ENDL;
+}
+
+void LLUIUsage::logPanel(const std::string& p)
+{
+ mPanelCounts[sanitized(p)]++;
+ LL_DEBUGS("UIUsage") << "panel " << p << LL_ENDL;
+}
+
+LLSD LLUIUsage::asLLSD() const
+{
+ LLSD result;
+ for (auto const& it : mCommandCounts)
+ {
+ result["commands"][it.first] = LLSD::Integer(it.second);
+ }
+ for (auto const& it : mControlCounts)
+ {
+ setLLSDPath(result["controls"], it.first, 2, LLSD::Integer(it.second));
+ }
+ for (auto const& it : mFloaterCounts)
+ {
+ result["floaters"][it.first] = LLSD::Integer(it.second);
+ }
+ for (auto const& it : mPanelCounts)
+ {
+ result["panels"][it.first] = LLSD::Integer(it.second);
+ }
+ return result;
+}
+
+// Clear up some junk content generated during initial login/UI initialization
+void LLUIUsage::clear()
+{
+
+ LL_DEBUGS("UIUsage") << "clear" << LL_ENDL;
+ mCommandCounts.clear();
+ mControlCounts.clear();
+ mFloaterCounts.clear();
+ mPanelCounts.clear();
+}
+
diff --git a/indra/llui/lluiusage.h b/indra/llui/lluiusage.h
new file mode 100644
index 0000000000..a30cd80db3
--- /dev/null
+++ b/indra/llui/lluiusage.h
@@ -0,0 +1,57 @@
+/**
+* @file lluiuisage.h
+* @brief Header file for LLUIUsage
+*
+* $LicenseInfo:firstyear=2021&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2021, 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$
+*/
+
+#ifndef LL_LLUIUSAGE_H
+#define LL_LLUIUSAGE_H
+
+#include <map>
+#include "llsd.h"
+#include "llsingleton.h"
+
+// UIUsage tracking to see which operations and UI elements are most popular in a session
+class LLUIUsage : public LLSingleton<LLUIUsage>
+{
+public:
+ LLSINGLETON(LLUIUsage);
+ ~LLUIUsage();
+public:
+ static std::string sanitized(const std::string& s);
+ static void setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val);
+ static void setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val);
+ void logCommand(const std::string& command);
+ void logControl(const std::string& control);
+ void logFloater(const std::string& floater);
+ void logPanel(const std::string& p);
+ LLSD asLLSD() const;
+ void clear();
+private:
+ std::map<std::string,U32> mCommandCounts;
+ std::map<std::string,U32> mControlCounts;
+ std::map<std::string,U32> mFloaterCounts;
+ std::map<std::string,U32> mPanelCounts;
+};
+
+#endif // LLUIUIUSAGE.h
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index cd9b52d164..e43c52c0c2 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -176,7 +176,7 @@ void LLUrlEntryBase::callObservers(const std::string &id,
bool LLUrlEntryBase::isLinkDisabled() const
{
// this allows us to have a global setting to turn off text hyperlink highlighting/action
- bool globally_disabled = LLUI::sSettingGroups["config"]->getBOOL("DisableTextHyperlinkActions");
+ static LLCachedControl<bool> globally_disabled(*LLUI::getInstance()->mSettingGroups["config"], "DisableTextHyperlinkActions", false);
return globally_disabled;
}
@@ -454,13 +454,19 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
}
//
-// LLUrlEntrySeconlifeURL Describes *secondlife.com/ and *lindenlab.com/ urls to substitute icon 'hand.png' before link
+// LLUrlEntrySeconlifeURL Describes *secondlife.com/ *lindenlab.com/ *secondlifegrid.net/ and *tilia-inc.com/ urls to substitute icon 'hand.png' before link
//
LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL()
{
- mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com)"
+ mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com)"
"|"
- "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?))"
+ "(http://([-\\w\\.]*\\.)?secondlifegrid\\.net)"
+ "|"
+ "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)"
+ "|"
+ "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?)"
+ "|"
+ "(https?://([-\\w\\.]*\\.)?secondlife\\.io(:\\d{1,5})?))"
"\\/\\S*",
boost::regex::perl|boost::regex::icase);
@@ -495,12 +501,14 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const
}
//
-// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link
+// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com *lindenlab.com *secondlifegrid.net and *tilia-inc.com urls to substitute icon 'hand.png' before link
//
LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
{
- mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
- boost::regex::perl|boost::regex::icase);
+ mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\S)"
+ "|"
+ "https?://([-\\w\\.]*\\.)?secondlifegrid\\.net(?!\\S)",
+ boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
mMenuName = "menu_url_http.xml";
@@ -511,8 +519,7 @@ LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
//
-LLUrlEntryAgent::LLUrlEntryAgent() :
- mAvatarNameCacheConnection()
+LLUrlEntryAgent::LLUrlEntryAgent()
{
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
@@ -543,7 +550,15 @@ void LLUrlEntryAgent::callObservers(const std::string &id,
void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
- mAvatarNameCacheConnection.disconnect();
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id);
+ if (it != mAvatarNameCacheConnections.end())
+ {
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
+ }
std::string label = av_name.getCompleteName();
@@ -630,11 +645,17 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
}
else
{
- if (mAvatarNameCacheConnection.connected())
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id);
+ if (it != mAvatarNameCacheConnections.end())
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
}
- mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
+ mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
+
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -695,14 +716,21 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url)
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
//
-LLUrlEntryAgentName::LLUrlEntryAgentName() :
- mAvatarNameCacheConnection()
+LLUrlEntryAgentName::LLUrlEntryAgentName()
{}
void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
- mAvatarNameCacheConnection.disconnect();
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id);
+ if (it != mAvatarNameCacheConnections.end())
+ {
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
+ }
std::string label = getName(av_name);
// received the agent name from the server - tell our observers
@@ -737,11 +765,17 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
}
else
{
- if (mAvatarNameCacheConnection.connected())
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id);
+ if (it != mAvatarNameCacheConnections.end())
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
}
- mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
+ mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
+
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -1095,7 +1129,7 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
//
LLUrlEntryRegion::LLUrlEntryRegion()
{
- mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?",
+ mPattern = boost::regex("secondlife:///app/region/[A-Za-z0-9()_%]+(/\\d+)?(/\\d+)?(/\\d+)?/?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slurl.xml";
mTooltip = LLTrans::getString("TooltipSLURL");
@@ -1475,4 +1509,43 @@ void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_de
callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null);
}
+//
+// LLUrlEntryEmail Describes an IPv6 address
+//
+LLUrlEntryIPv6::LLUrlEntryIPv6()
+ : LLUrlEntryBase()
+{
+ mHostPath = "https?://\\[([a-f0-9:]+:+)+[a-f0-9]+]";
+ mPattern = boost::regex(mHostPath + "(:\\d{1,5})?(/\\S*)?",
+ boost::regex::perl | boost::regex::icase);
+ mMenuName = "menu_url_http.xml";
+ mTooltip = LLTrans::getString("TooltipHttpUrl");
+}
+
+std::string LLUrlEntryIPv6::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase);
+ boost::match_results<std::string::const_iterator> matches;
+
+ if (boost::regex_search(url, matches, regex))
+ {
+ return url.substr(0, matches[0].length());
+ }
+ else
+ {
+ return url;
+ }
+}
+std::string LLUrlEntryIPv6::getQuery(const std::string &url) const
+{
+ boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase);
+ boost::match_results<std::string::const_iterator> matches;
+
+ return boost::regex_replace(url, regex, "");
+}
+
+std::string LLUrlEntryIPv6::getUrl(const std::string &string) const
+{
+ return string;
+}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 78c149d9fd..4af1ab5096 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -212,10 +212,14 @@ public:
LLUrlEntryAgent();
~LLUrlEntryAgent()
{
- if (mAvatarNameCacheConnection.connected())
+ for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
}
+ mAvatarNameCacheConnections.clear();
}
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getIcon(const std::string &url);
@@ -227,7 +231,9 @@ protected:
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
private:
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
- boost::signals2::connection mAvatarNameCacheConnection;
+
+ typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
+ avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
///
@@ -241,10 +247,14 @@ public:
LLUrlEntryAgentName();
~LLUrlEntryAgentName()
{
- if (mAvatarNameCacheConnection.connected())
+ for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
}
+ mAvatarNameCacheConnections.clear();
}
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ LLStyle::Params getStyle() const;
@@ -253,7 +263,9 @@ protected:
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
private:
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
- boost::signals2::connection mAvatarNameCacheConnection;
+
+ typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
+ avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
@@ -513,5 +525,18 @@ public:
/*virtual*/ std::string getUrl(const std::string &string) const;
};
+///
+/// LLUrlEntryEmail Describes an IPv6 address
+///
+class LLUrlEntryIPv6 : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryIPv6();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getUrl(const std::string &string) const;
+ /*virtual*/ std::string getQuery(const std::string &url) const;
+
+ std::string mHostPath;
+};
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index ba6fa1e2e9..321a0ec5b9 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -79,6 +79,7 @@ LLUrlRegistry::LLUrlRegistry()
mUrlEntrySLLabel = new LLUrlEntrySLLabel();
registerUrl(mUrlEntrySLLabel);
registerUrl(new LLUrlEntryEmail());
+ registerUrl(new LLUrlEntryIPv6());
}
LLUrlRegistry::~LLUrlRegistry()
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 40537e6c4a..2781c991a7 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -60,6 +60,8 @@ static const S32 LINE_HEIGHT = 15;
S32 LLView::sDepth = 0;
bool LLView::sDebugRects = false;
+bool LLView::sIsRectDirty = false;
+LLRect LLView::sDirtyRect;
bool LLView::sDebugRectsShowNames = true;
bool LLView::sDebugKeys = false;
bool LLView::sDebugMouseHandling = false;
@@ -86,6 +88,11 @@ template class LLView* LLView::getChild<class LLView>(
static LLDefaultChildRegistry::Register<LLView> r("view");
+void deleteView(LLView *aView)
+{
+ delete aView;
+}
+
namespace LLInitParam
{
void TypeValues<LLView::EOrientation>::declareValues()
@@ -641,6 +648,16 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
}
// virtual
+void LLView::onUpdateScrollToChild(const LLUICtrl * cntrl)
+{
+ LLView* parent_view = getParent();
+ if (parent_view)
+ {
+ parent_view->onUpdateScrollToChild(cntrl);
+ }
+}
+
+// virtual
void LLView::translate(S32 x, S32 y)
{
mRect.translate(x, y);
@@ -816,7 +833,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
}
// This call differentiates this method from childrenHandleMouseEvent().
- LLUI::sWindow->setCursor(viewp->getHoverCursor());
+ LLUI::getInstance()->mWindow->setCursor(viewp->getHoverCursor());
if (viewp->handleHover(local_x, local_y, mask)
|| viewp->blockMouseEvent(local_x, local_y))
@@ -870,15 +887,23 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
std::string tooltip = getToolTip();
if (!tooltip.empty())
{
+ static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f);
+ static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f);
+ static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true);
// allow "scrubbing" over ui by showing next tooltip immediately
// if previous one was still visible
F32 timeout = LLToolTipMgr::instance().toolTipVisible()
- ? LLUI::sSettingGroups["config"]->getF32( "ToolTipFastDelay" )
- : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
- LLToolTipMgr::instance().show(LLToolTip::Params()
- .message(tooltip)
- .sticky_rect(calcScreenRect())
- .delay_time(timeout));
+ ? tooltip_fast_delay
+ : tooltip_delay;
+
+ // Even if we don't show tooltips, consume the event, nothing below should show tooltip
+ if (allow_ui_tooltips)
+ {
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(tooltip)
+ .sticky_rect(calcScreenRect())
+ .delay_time(timeout));
+ }
handled = TRUE;
}
@@ -1054,6 +1079,11 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
return childrenHandleScrollWheel( x, y, clicks ) != NULL;
}
+BOOL LLView::handleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ return childrenHandleScrollHWheel( x, y, clicks ) != NULL;
+}
+
BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
return childrenHandleRightMouseDown( x, y, mask ) != NULL;
@@ -1079,6 +1109,11 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false);
}
+LLView* LLView::childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false);
+}
+
// Called during downward traversal
LLView* LLView::childrenHandleKey(KEY key, MASK mask)
{
@@ -1142,7 +1177,7 @@ void LLView::drawChildren()
{
if (!mChildList.empty())
{
- LLView* rootp = LLUI::getRootView();
+ LLView* rootp = LLUI::getInstance()->getRootView();
++sDepth;
for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter)
@@ -1158,7 +1193,7 @@ void LLView::drawChildren()
if (viewp->getVisible() && viewp->getRect().isValid())
{
LLRect screen_rect = viewp->calcScreenRect();
- if ( rootp->getLocalRect().overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect))
+ if ( rootp->getLocalRect().overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect))
{
LLUI::pushMatrix();
{
@@ -1200,7 +1235,15 @@ void LLView::dirtyRect()
parent = parent->getParent();
}
- LLUI::dirtyRect(cur->calcScreenRect());
+ if (!sIsRectDirty)
+ {
+ sDirtyRect = cur->calcScreenRect();
+ sIsRectDirty = true;
+ }
+ else
+ {
+ sDirtyRect.unionWith(cur->calcScreenRect());
+ }
}
//Draw a box for debugging.
@@ -1371,7 +1414,9 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft;
S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom;
viewp->translate( delta_x, delta_y );
- if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight())
+ if (child_rect.getWidth() != viewp->getRect().getWidth()
+ || child_rect.getHeight() != viewp->getRect().getHeight()
+ || sForceReshape)
{
viewp->reshape(child_rect.getWidth(), child_rect.getHeight());
}
@@ -2223,9 +2268,9 @@ LLControlVariable *LLView::findControl(const std::string& name)
std::string control_group_key = name.substr(0, key_pos);
LLControlVariable* control;
// check if it's in the control group that name indicated
- if(LLUI::sSettingGroups[control_group_key])
+ if(LLUI::getInstance()->mSettingGroups[control_group_key])
{
- control = LLUI::sSettingGroups[control_group_key]->getControl(name);
+ control = LLUI::getInstance()->mSettingGroups[control_group_key]->getControl(name);
if (control)
{
return control;
@@ -2233,7 +2278,7 @@ LLControlVariable *LLView::findControl(const std::string& name)
}
}
- LLControlGroup& control_group = LLUI::getControlControlGroup(name);
+ LLControlGroup& control_group = LLUI::getInstance()->getControlControlGroup(name);
return control_group.getControl(name);
}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 8494bb338a..c60dcf3344 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -301,6 +301,7 @@ public:
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
virtual void onVisibilityChange ( BOOL new_visibility );
+ virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); }
void popVisible() { setVisible(mLastVisible); }
@@ -426,6 +427,7 @@ public:
/*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
@@ -498,7 +500,7 @@ public:
// return query for iterating over focus roots in tab order
static const LLViewQuery & getFocusRootsQuery();
- static LLWindow* getWindow(void) { return LLUI::sWindow; }
+ static LLWindow* getWindow(void) { return LLUI::getInstance()->mWindow; }
// Set up params after XML load before calling new(),
// usually to adjust layout.
@@ -556,6 +558,7 @@ protected:
LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask);
LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask);
LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks);
+ LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks);
LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask);
LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask);
LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask);
@@ -654,6 +657,9 @@ public:
// Draw debug rectangles around widgets to help with alignment and spacing
static bool sDebugRects;
+ static bool sIsRectDirty;
+ static LLRect sDirtyRect;
+
// Draw widget names and sizes when drawing debug rectangles, turning this
// off is useful to make the rectangles themselves easier to see.
static bool sDebugRectsShowNames;
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index 8754cfebbb..cb000aef74 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -44,7 +44,7 @@ LLViewerEventRecorder::LLViewerEventRecorder() {
bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() {
- return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
+ return LLUI::getInstance()->mSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
}
@@ -99,7 +99,7 @@ void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) {
void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) {
- LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui);
+ LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), xui);
if (! target_view) {
LL_DEBUGS() << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << LL_ENDL;
return;
@@ -216,7 +216,7 @@ void LLViewerEventRecorder::playbackRecording() {
LLSD LeapCommand;
// ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer
- LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");
+ LeapCommand =LLUI::getInstance()->mSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");
LL_DEBUGS() << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << LL_ENDL;
LLLeap::create("", LeapCommand, false); // exception=false
diff --git a/indra/llui/llviewinject.h b/indra/llui/llviewinject.h
index 0de3d155c4..7f18ec6fbe 100644
--- a/indra/llui/llviewinject.h
+++ b/indra/llui/llviewinject.h
@@ -32,7 +32,7 @@ namespace llview
public:
/**
* Construct TargetEvent with the desired target LLView*. (See
- * LLUI::resolvePath() to obtain an LLView* given a string pathname.)
+ * LLUI::getInstance()->resolvePath() to obtain an LLView* given a string pathname.)
* This sets up for operator().
*/
TargetEvent(LLView* view);
diff --git a/indra/llui/llvirtualtrackball.cpp b/indra/llui/llvirtualtrackball.cpp
new file mode 100644
index 0000000000..6e0aef740d
--- /dev/null
+++ b/indra/llui/llvirtualtrackball.cpp
@@ -0,0 +1,520 @@
+/**
+* @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));
+ btn_rt.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopMouseEnter, 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));
+ btn_rr.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateRightMouseEnter, 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));
+ btn_rb.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateBottomMouseEnter, 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));
+ btn_rl.mouseenter_callback.function(boost::bind(&LLVirtualTrackball::onRotateLeftMouseEnter, 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);
+ }
+
+ // hide the direction labels when disabled
+ BOOL enabled = isInEnabledChain();
+ mLabelN->setVisible(enabled);
+ mLabelE->setVisible(enabled);
+ mLabelS->setVisible(enabled);
+ mLabelW->setVisible(enabled);
+
+ 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::onRotateTopMouseEnter()
+{
+ mBtnRotateTop->setHighlight(true);
+}
+
+void LLVirtualTrackball::onRotateBottomMouseEnter()
+{
+ mBtnRotateBottom->setHighlight(true);
+}
+
+void LLVirtualTrackball::onRotateLeftMouseEnter()
+{
+ mBtnRotateLeft->setHighlight(true);
+}
+
+void LLVirtualTrackball::onRotateRightMouseEnter()
+{
+ mBtnRotateRight->setHighlight(true);
+}
+
+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;
+}
+
+// static
+void LLVirtualTrackball::getAzimuthAndElevation(const LLQuaternion &quat, F32 &azimuth, F32 &elevation)
+{
+ // LLQuaternion has own function to get azimuth, but it doesn't appear to return correct values (meant for 2d?)
+ LLVector3 point = VectorZero * quat;
+
+ if (!is_approx_zero(point.mV[VX]) || !is_approx_zero(point.mV[VY]))
+ {
+ azimuth = atan2f(point.mV[VX], point.mV[VY]);
+ }
+ else
+ {
+ azimuth = 0;
+ }
+
+ azimuth -= F_PI_BY_TWO;
+
+ if (azimuth < 0)
+ {
+ azimuth += F_PI * 2;
+ }
+
+ // while vector is '1', F32 is not sufficiently precise and we can get
+ // values like 1.0000012 which will result in -90deg angle instead of 90deg
+ F32 z = llclamp(point.mV[VZ], -1.f, 1.f);
+ elevation = asin(z); // because VectorZero's length is '1'
+}
+
+// static
+void LLVirtualTrackball::getAzimuthAndElevationDeg(const LLQuaternion &quat, F32 &azimuth, F32 &elevation)
+{
+ getAzimuthAndElevation(quat, azimuth, elevation);
+ azimuth *= RAD_TO_DEG;
+ elevation *= RAD_TO_DEG;
+}
+
+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;
+ }
+
+ // we are doing a lot of F32 mathematical operations with loss of precision,
+ // re-normalize to compensate
+ mValue.normalize();
+
+ 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..c7a893877b
--- /dev/null
+++ b/indra/llui/llvirtualtrackball.h
@@ -0,0 +1,163 @@
+/**
+* @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;
+
+ static void getAzimuthAndElevation(const LLQuaternion &quat, F32 &azimuth, F32 &elevation);
+ static void getAzimuthAndElevationDeg(const LLQuaternion &quat, F32 &azimuth, F32 &elevation);
+
+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();
+
+ void onRotateTopMouseEnter();
+ void onRotateBottomMouseEnter();
+ void onRotateLeftMouseEnter();
+ void onRotateRightMouseEnter();
+
+ 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..d7ba243e1d
--- /dev/null
+++ b/indra/llui/llxyvector.cpp
@@ -0,0 +1,337 @@
+/**
+* @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"
+
+#include "llmath.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),
+ logarithmic("logarithmic", FALSE)
+{
+}
+
+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),
+ mLogarithmic(p.logarithmic),
+ mValueX(0),
+ mValueY(0)
+{
+ 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()
+{
+ mLogScaleX = (2 * log(mMaxValueX)) / mTouchArea->getRect().getWidth();
+ mLogScaleY = (2 * log(mMaxValueY)) / mTouchArea->getRect().getHeight();
+
+ 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;
+ S32 pointY;
+
+ if (mLogarithmic)
+ {
+ pointX = (log(llabs(mValueX) + 1)) / mLogScaleX;
+ pointX *= (mValueX < 0) ? -1 : 1;
+ pointX += centerX;
+
+ pointY = (log(llabs(mValueY) + 1)) / mLogScaleY;
+ pointY *= (mValueY < 0) ? -1 : 1;
+ pointY += centerY;
+ }
+ else // linear
+ {
+ pointX = centerX + (mValueX * mTouchArea->getRect().getWidth() / (2 * mMaxValueX));
+ 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)
+{
+ mValueX = ll_round(llclamp(x, mMinValueX, mMaxValueX), mIncrementX);
+ mValueY = ll_round(llclamp(y, mMinValueY, mMaxValueY), mIncrementY);
+
+ 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())
+ {
+ if (mLogarithmic)
+ {
+ F32 valueX = llfastpow(F_E, mLogScaleX*(llabs(x - mTouchArea->getRect().getCenterX()))) - 1;
+ valueX *= (x < mTouchArea->getRect().getCenterX()) ? -1 : 1;
+
+ F32 valueY = llfastpow(F_E, mLogScaleY*(llabs(y - mTouchArea->getRect().getCenterY()))) - 1;
+ valueY *= (y < mTouchArea->getRect().getCenterY()) ? -1 : 1;
+
+ setValueAndCommit(valueX, valueY);
+ }
+ else //linear
+ {
+ F32 valueX = 2 * mMaxValueX * F32(x - mTouchArea->getRect().getCenterX()) / mTouchArea->getRect().getWidth();
+ F32 valueY = 2 * mMaxValueY * F32(y - mTouchArea->getRect().getCenterY()) / mTouchArea->getRect().getHeight();
+
+ setValueAndCommit(valueX, valueY);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL LLXYVector::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ if (hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ make_ui_sound("UISndClickRelease");
+ }
+
+ if (mTouchArea->getRect().pointInRect(x, y))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return LLUICtrl::handleMouseUp(x, y, mask);
+ }
+}
+
+BOOL LLXYVector::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+
+ if (mTouchArea->getRect().pointInRect(x, y))
+ {
+ gFocusMgr.setMouseCapture(this);
+ make_ui_sound("UISndClick");
+
+ return TRUE;
+ }
+ else
+ {
+ return LLUICtrl::handleMouseDown(x, y, mask);
+ }
+}
+
diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h
new file mode 100644
index 0000000000..bb3822dd26
--- /dev/null
+++ b/indra/llui/llxyvector.h
@@ -0,0 +1,122 @@
+/**
+* @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;
+ Optional<BOOL> logarithmic;
+
+ 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;
+
+ BOOL mLogarithmic;
+ F32 mLogScaleX;
+ F32 mLogScaleY;
+};
+
+#endif
+
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 119cbebc81..1a474cca90 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -36,6 +36,11 @@
#include <boost/regex.hpp>
+#if LL_WINDOWS
+// because something pulls in window and lldxdiag dependencies which in turn need wbemuuid.lib
+ #pragma comment(lib, "wbemuuid.lib")
+#endif
+
// namespace LLExperienceCache
// {
@@ -734,11 +739,6 @@ namespace tut
"XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX",
"secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30");
- // DEV-35459: SLURLs and teleport Links not parsed properly
- testRegex("Region with quote", url,
- "XXX secondlife:///app/region/A'ksha%20Oasis/41/166/701 XXX",
- "secondlife:///app/region/A%27ksha%20Oasis/41/166/701");
-
// Rendering tests.
testLabel("Render /app/region/Ahern/50/50/50/", url,
"secondlife:///app/region/Ahern/50/50/50/",
@@ -898,4 +898,38 @@ namespace tut
"and even no www something lindenlab.com",
"");
}
+
+ template<> template<>
+ void object::test<16>()
+ {
+ //
+ // test LLUrlEntryIPv6
+ //
+ LLUrlEntryIPv6 url;
+
+ // Regex tests.
+ testRegex("match urls with a protocol", url,
+ "this url should match http://[::1]",
+ "http://[::1]");
+
+ testRegex("match urls with a protocol and query", url,
+ "this url should match http://[::1]/file.mp3",
+ "http://[::1]/file.mp3");
+
+ testRegex("match urls with a protocol", url,
+ "this url should match http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]",
+ "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]");
+
+ testRegex("match urls with port", url,
+ "let's specify some port http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080",
+ "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080");
+
+ testRegex("don't match urls w/o protocol", url,
+ "looks like an url something [2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d] but no https prefix",
+ "");
+
+ testRegex("don't match incorrect urls", url,
+ "http://[ 2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d ]",
+ "");
+ }
}