summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt22
-rw-r--r--indra/llui/llaccordionctrl.cpp2
-rw-r--r--indra/llui/llaccordionctrltab.cpp65
-rw-r--r--indra/llui/llaccordionctrltab.h10
-rw-r--r--indra/llui/llbutton.cpp30
-rw-r--r--indra/llui/llbutton.h8
-rw-r--r--indra/llui/llcheckboxctrl.cpp66
-rw-r--r--indra/llui/llcheckboxctrl.h2
-rw-r--r--indra/llui/llcombobox.cpp45
-rw-r--r--indra/llui/llcombobox.h16
-rw-r--r--indra/llui/lldockcontrol.cpp31
-rw-r--r--indra/llui/llflatlistview.cpp3
-rw-r--r--indra/llui/llflatlistview.h3
-rw-r--r--indra/llui/llfloater.cpp229
-rw-r--r--indra/llui/llfloater.h21
-rw-r--r--indra/llui/llfloaterreg.cpp18
-rw-r--r--indra/llui/llfloaterreg.h6
-rw-r--r--indra/llui/llfloaterreglistener.cpp17
-rw-r--r--indra/llui/llfloaterreglistener.h1
-rw-r--r--indra/llui/llfocusmgr.cpp47
-rw-r--r--indra/llui/llfocusmgr.h13
-rw-r--r--indra/llui/llhandle.h8
-rw-r--r--indra/llui/lliconctrl.cpp5
-rw-r--r--indra/llui/lliconctrl.h7
-rw-r--r--indra/llui/lllayoutstack.cpp481
-rw-r--r--indra/llui/lllayoutstack.h106
-rw-r--r--indra/llui/lllineeditor.cpp73
-rw-r--r--indra/llui/lllineeditor.h21
-rw-r--r--indra/llui/llloadingindicator.cpp67
-rw-r--r--indra/llui/llloadingindicator.h31
-rw-r--r--indra/llui/llmenubutton.cpp151
-rw-r--r--indra/llui/llmenubutton.h34
-rw-r--r--indra/llui/llmenugl.cpp271
-rw-r--r--indra/llui/llmenugl.h19
-rw-r--r--indra/llui/llmultislider.cpp5
-rw-r--r--indra/llui/llmultisliderctrl.cpp2
-rw-r--r--indra/llui/llnotifications.cpp850
-rw-r--r--indra/llui/llnotifications.h253
-rw-r--r--indra/llui/llnotificationslistener.cpp7
-rw-r--r--indra/llui/llnotificationtemplate.h297
-rw-r--r--indra/llui/llnotificationvisibilityrule.h104
-rw-r--r--indra/llui/llpanel.cpp128
-rw-r--r--indra/llui/llpanel.h63
-rw-r--r--indra/llui/llprogressbar.cpp7
-rw-r--r--indra/llui/llprogressbar.h9
-rw-r--r--indra/llui/llradiogroup.cpp50
-rw-r--r--indra/llui/llradiogroup.h12
-rw-r--r--indra/llui/llrngwriter.cpp5
-rw-r--r--indra/llui/llscrollcontainer.cpp5
-rw-r--r--indra/llui/llscrolllistcolumn.cpp9
-rw-r--r--indra/llui/llscrolllistctrl.cpp88
-rw-r--r--indra/llui/llscrolllistctrl.h2
-rw-r--r--indra/llui/llsdparam.cpp234
-rw-r--r--indra/llui/llsdparam.h45
-rw-r--r--indra/llui/llslider.h1
-rw-r--r--indra/llui/llspinctrl.cpp2
-rw-r--r--indra/llui/llstyle.cpp8
-rw-r--r--indra/llui/llstyle.h7
-rw-r--r--indra/llui/lltextbase.cpp355
-rw-r--r--indra/llui/lltextbase.h11
-rw-r--r--indra/llui/lltexteditor.cpp16
-rw-r--r--indra/llui/lltexteditor.h1
-rw-r--r--indra/llui/lltoggleablemenu.cpp18
-rw-r--r--indra/llui/lltoggleablemenu.h5
-rw-r--r--indra/llui/lltooltip.cpp9
-rw-r--r--indra/llui/lltransutil.cpp5
-rw-r--r--indra/llui/llui.cpp186
-rw-r--r--indra/llui/llui.h113
-rw-r--r--indra/llui/lluicolortable.cpp16
-rw-r--r--indra/llui/lluictrl.cpp39
-rw-r--r--indra/llui/lluictrl.h18
-rw-r--r--indra/llui/lluictrlfactory.cpp246
-rw-r--r--indra/llui/lluictrlfactory.h203
-rw-r--r--indra/llui/lluiimage.cpp12
-rw-r--r--indra/llui/lluiimage.h17
-rw-r--r--indra/llui/lluistring.cpp19
-rw-r--r--indra/llui/lluistring.h16
-rw-r--r--indra/llui/llurlentry.cpp466
-rw-r--r--indra/llui/llurlentry.h144
-rw-r--r--indra/llui/llurlmatch.cpp9
-rw-r--r--indra/llui/llurlmatch.h22
-rw-r--r--indra/llui/llurlregistry.cpp21
-rw-r--r--indra/llui/llurlregistry.h8
-rw-r--r--indra/llui/llview.cpp63
-rw-r--r--indra/llui/llview.h74
-rw-r--r--indra/llui/llviewborder.cpp1
-rw-r--r--indra/llui/llwindowshade.cpp328
-rw-r--r--indra/llui/llwindowshade.h70
-rw-r--r--indra/llui/tests/llurlentry_stub.cpp142
-rw-r--r--indra/llui/tests/llurlentry_test.cpp195
-rw-r--r--indra/llui/tests/llurlmatch_test.cpp165
91 files changed, 4994 insertions, 2141 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 8e78a5fefd..684e393cba 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -111,6 +111,7 @@ set(llui_SOURCE_FILES
llviewmodel.cpp
llview.cpp
llviewquery.cpp
+ llwindowshade.cpp
)
set(llui_HEADER_FILES
@@ -158,6 +159,8 @@ set(llui_HEADER_FILES
llnotifications.h
llnotificationslistener.h
llnotificationsutil.h
+ llnotificationtemplate.h
+ llnotificationvisibilityrule.h
llpanel.h
llprogressbar.h
llradiogroup.h
@@ -208,6 +211,7 @@ set(llui_HEADER_FILES
llviewmodel.h
llview.h
llviewquery.h
+ llwindowshade.h
)
set_source_files_properties(${llui_HEADER_FILES}
@@ -240,12 +244,12 @@ target_link_libraries(llui
${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender
)
-if(LL_TESTS)
- # Add tests
- include(LLAddBuildTest)
- SET(llui_TEST_SOURCE_FILES
- llurlmatch.cpp
- llurlentry.cpp
- )
- LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
-endif(LL_TESTS)
+# Add tests
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ SET(llui_TEST_SOURCE_FILES
+ llurlmatch.cpp
+ llurlentry.cpp
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
+endif (LL_TESTS) \ No newline at end of file
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index f9ffaaa646..d636161baf 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -83,7 +83,7 @@ LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
mSingleExpansion = false;
mFitParent = false;
- LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");
+ buildFromFile( "accordion_parent.xml");
}
//---------------------------------------------------------------------------------
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index b7da5f4a1b..9e4849c58b 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -141,6 +141,7 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
textboxParams.use_ellipses = true;
textboxParams.bg_visible = false;
textboxParams.mouse_opaque = false;
+ textboxParams.parse_urls = false;
mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams);
addChild(mHeaderTextbox);
}
@@ -202,7 +203,8 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
- gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true);
+ F32 alpha = getCurrentTransparency();
+ gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true);
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
bool collapsible = (parent && parent->getCollapsible());
@@ -455,8 +457,7 @@ BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
{
if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- header->setFocus(true);
+ mHeader->setFocus(true);
changeOpenClose(getDisplayChildren());
//reset stored state
@@ -508,10 +509,9 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
std::string LLAccordionCtrlTab::getTitle() const
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->getTitle();
+ return mHeader->getTitle();
}
else
{
@@ -521,57 +521,51 @@ std::string LLAccordionCtrlTab::getTitle() const
void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitle(title, hl);
+ mHeader->setTitle(title, hl);
}
}
void LLAccordionCtrlTab::setTitleFontStyle(std::string style)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitleFontStyle(style);
+ mHeader->setTitleFontStyle(style);
}
}
void LLAccordionCtrlTab::setTitleColor(LLUIColor color)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitleColor(color);
+ mHeader->setTitleColor(color);
}
}
boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->setFocusReceivedCallback(cb);
+ return mHeader->setFocusReceivedCallback(cb);
}
return boost::signals2::connection();
}
boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->setFocusLostCallback(cb);
+ return mHeader->setFocusLostCallback(cb);
}
return boost::signals2::connection();
}
void LLAccordionCtrlTab::setSelected(bool is_selected)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setSelected(is_selected);
+ mHeader->setSelected(is_selected);
}
}
@@ -735,6 +729,12 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
return 1;
}
+
+ if (!getDisplayChildren())
+ {
+ // Don't pass scrolling event further if our contents are invisible (STORM-298).
+ return 1;
+ }
}
return LLUICtrl::notifyParent(info);
@@ -769,8 +769,7 @@ S32 LLAccordionCtrlTab::notify(const LLSD& info)
BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if( !header->hasFocus() )
+ if( !mHeader->hasFocus() )
return LLUICtrl::handleKey(key, mask, called_from_parent);
if ( (key == KEY_RETURN )&& mask == MASK_NONE)
@@ -823,15 +822,19 @@ BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
void LLAccordionCtrlTab::showAndFocusHeader()
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- header->setFocus(true);
- header->setSelected(mSelectionEnabled);
+ mHeader->setFocus(true);
+ mHeader->setSelected(mSelectionEnabled);
LLRect screen_rc;
- LLRect selected_rc = header->getRect();
+ LLRect selected_rc = mHeader->getRect();
localRectToScreen(selected_rc, &screen_rc);
- notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
+ // This call to notifyParent() is intended to deliver "scrollToShowRect" command
+ // to the parent LLAccordionCtrl so by calling it from the direct parent of this
+ // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain
+ // is shortened and messages from inside the collapsed tabs are avoided.
+ // See STORM-536.
+ getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
}
void LLAccordionCtrlTab::storeOpenCloseState()
{
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index d6ac8cbc8f..dddaa581e6 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -85,10 +85,10 @@ public:
Optional<bool> selection_enabled;
- Optional<S32> padding_left;
- Optional<S32> padding_right;
- Optional<S32> padding_top;
- Optional<S32> padding_bottom;
+ Optional<S32> padding_left,
+ padding_right,
+ padding_top,
+ padding_bottom;
Params();
};
@@ -170,7 +170,7 @@ public:
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
- virtual bool addChild(LLView* child, S32 tab_group);
+ virtual bool addChild(LLView* child, S32 tab_group = 0 );
bool isExpanded() const { return mDisplayChildren; }
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index f0f34ebd4f..45ceaff696 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -98,7 +98,8 @@ LLButton::Params::Params()
is_toggle("is_toggle", false),
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
- commit_on_return("commit_on_return", true)
+ commit_on_return("commit_on_return", true),
+ use_draw_context_alpha("use_draw_context_alpha", true)
{
addSynonym(is_toggle, "toggle");
held_down_delay.seconds = 0.5f;
@@ -114,7 +115,6 @@ LLButton::LLButton(const LLButton::Params& p)
mFlashing( FALSE ),
mCurGlowStrength(0.f),
mNeedsHighlight(FALSE),
- mMouseOver(false),
mUnselectedLabel(p.label()),
mSelectedLabel(p.label_selected()),
mGLFont(p.font),
@@ -159,7 +159,8 @@ LLButton::LLButton(const LLButton::Params& p)
mLastDrawCharsCount(0),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL),
- mHeldDownSignal(NULL)
+ mHeldDownSignal(NULL),
+ mUseDrawContextAlpha(p.use_draw_context_alpha)
{
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
@@ -499,11 +500,7 @@ void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
LLUICtrl::onMouseEnter(x, y, mask);
if (isInEnabledChain())
- {
mNeedsHighlight = TRUE;
- }
-
- mMouseOver = true;
}
void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
@@ -511,7 +508,6 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
LLUICtrl::onMouseLeave(x, y, mask);
mNeedsHighlight = FALSE;
- mMouseOver = true;
}
void LLButton::setHighlight(bool b)
@@ -545,7 +541,7 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
// virtual
void LLButton::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool flash = FALSE;
static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0);
static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);
@@ -564,11 +560,19 @@ void LLButton::draw()
pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));
}
- // Unselected image assignments
+ bool mouse_pressed_and_over = false;
+ if (hasMouseCapture())
+ {
+ S32 local_mouse_x ;
+ S32 local_mouse_y;
+ LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
+ mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y);
+ }
+
bool enabled = isInEnabledChain();
bool pressed = pressed_by_keyboard
- || (hasMouseCapture() && mMouseOver)
+ || mouse_pressed_and_over
|| mForcePressedState;
bool selected = getToggleState();
@@ -1117,7 +1121,7 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
// Get the visibility control name for the floater
std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
// Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
- button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+ button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
// Set the clicked callback to toggle the floater
button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));
}
@@ -1131,7 +1135,7 @@ void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
// Get the visibility control name for the floater
std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
// Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
- button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+ button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
// Set the clicked callback to toggle the floater
button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname));
}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index d87ceb7c42..0cfc393e05 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -27,7 +27,6 @@
#ifndef LL_LLBUTTON_H
#define LL_LLBUTTON_H
-#include "lluuid.h"
#include "llcontrol.h"
#include "lluictrl.h"
#include "v4color.h"
@@ -53,6 +52,8 @@ S32 round_up(S32 grid, S32 value);
class LLUICtrlFactory;
+class LLUIImage;
+class LLUUID;
//
// Classes
@@ -124,6 +125,8 @@ public:
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
+ Optional<bool> use_draw_context_alpha;
+
Params();
};
@@ -338,6 +341,8 @@ private:
S32 mImageOverlayTopPad;
S32 mImageOverlayBottomPad;
+ bool mUseDrawContextAlpha;
+
/*
* Space between image_overlay and label
*/
@@ -350,7 +355,6 @@ private:
BOOL mCommitOnReturn;
BOOL mFadeWhenDisabled;
bool mForcePressedState;
- bool mMouseOver;
LLFrameTimer mFlashingTimer;
};
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index cbc8f12472..4fe444c1a4 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -50,9 +50,7 @@ template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(
const std::string& name, BOOL recurse) const;
LLCheckBoxCtrl::Params::Params()
-: text_enabled_color("text_enabled_color"),
- text_disabled_color("text_disabled_color"),
- initial_value("initial_value", false),
+: initial_value("initial_value", false),
label_text("label_text"),
check_button("check_button"),
radio_style("radio_style")
@@ -61,8 +59,8 @@ LLCheckBoxCtrl::Params::Params()
LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
: LLUICtrl(p),
- mTextEnabledColor(p.text_enabled_color()),
- mTextDisabledColor(p.text_disabled_color()),
+ mTextEnabledColor(p.label_text.text_color()),
+ mTextDisabledColor(p.label_text.text_readonly_color()),
mFont(p.font())
{
mViewModel->setValue(LLSD(p.initial_value));
@@ -89,29 +87,20 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
{
tbparams.font(p.font);
}
- tbparams.text_color( p.enabled() ? p.text_enabled_color() : p.text_disabled_color() );
mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);
+ mLabel->reshapeToFitText();
addChild(mLabel);
- S32 text_width = mLabel->getTextBoundingRect().getWidth();
- S32 text_height = llround(mFont->getLineHeight());
- LLRect label_rect;
- label_rect.setOriginAndSize(
- llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
- llcheckboxctrl_vpad + 1, // padding to get better alignment
- text_width + llcheckboxctrl_hpad,
- text_height );
- mLabel->setShape(label_rect);
-
+ LLRect label_rect = mLabel->getRect();
// Button
// Note: button cover the label by extending all the way to the right.
- LLRect btn_rect;
+ LLRect btn_rect = p.check_button.rect();
btn_rect.setOriginAndSize(
- llcheckboxctrl_hpad,
- llcheckboxctrl_vpad,
- llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width + llcheckboxctrl_hpad,
- llmax( text_height, llcheckboxctrl_btn_size() ) + llcheckboxctrl_vpad);
+ btn_rect.mLeft,
+ btn_rect.mBottom,
+ llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft),
+ llmax( label_rect.getHeight(), btn_rect.mTop));
std::string active_true_id, active_false_id;
std::string inactive_true_id, inactive_false_id;
@@ -177,31 +166,20 @@ void LLCheckBoxCtrl::clear()
void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- //stretch or shrink bounding rectangle of label when rebuilding UI at new scale
- 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);
- S32 text_width = mLabel->getTextBoundingRect().getWidth();
- S32 text_height = llround(mFont->getLineHeight());
- LLRect label_rect;
- label_rect.setOriginAndSize(
- llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
- llcheckboxctrl_vpad,
- text_width,
- text_height );
- mLabel->setShape(label_rect);
-
- LLRect btn_rect;
+ mLabel->reshapeToFitText();
+
+ LLRect label_rect = mLabel->getRect();
+
+ // Button
+ // Note: button cover the label by extending all the way to the right.
+ LLRect btn_rect = mButton->getRect();
btn_rect.setOriginAndSize(
- llcheckboxctrl_hpad,
- llcheckboxctrl_vpad,
- llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width,
- llmax( text_height, llcheckboxctrl_btn_size() ) );
- mButton->setShape( btn_rect );
-
- LLUICtrl::reshape(width, height, called_from_parent);
+ btn_rect.mLeft,
+ btn_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);
}
//virtual
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index 0147088280..67d8091a97 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -52,8 +52,6 @@ public:
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<LLUIColor> text_enabled_color;
- Optional<LLUIColor> text_disabled_color;
Optional<bool> initial_value; // override LLUICtrl initial_value
Optional<LLTextBox::Params> label_text;
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 910bab9a97..a4d1854bc8 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -52,8 +52,6 @@
#include "lltooltip.h"
// Globals
-S32 LLCOMBOBOX_HEIGHT = 0;
-S32 LLCOMBOBOX_WIDTH = 0;
S32 MAX_COMBO_WIDTH = 500;
static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_box");
@@ -96,6 +94,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
mMaxChars(p.max_chars),
mPrearrangeCallback(p.prearrange_callback()),
mTextEntryCallback(p.text_entry_callback()),
+ mTextChangedCallback(p.text_changed_callback()),
mListPosition(p.list_position),
mLastSelectedIndex(-1),
mLabel(p.label)
@@ -139,8 +138,8 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
// Grab the mouse-up event and make sure the button state is correct
mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this));
- for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
- it != p.items().end();
+ for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin();
+ it != p.items.end();
++it)
{
LLScrollListItem::Params item_params = *it;
@@ -232,6 +231,10 @@ void LLComboBox::resetDirty()
}
}
+bool LLComboBox::itemExists(const std::string& name)
+{
+ return mList->getItemByLabel(name);
+}
// add item "name" to menu
LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOOL enabled)
@@ -317,7 +320,7 @@ void LLComboBox::setValue(const LLSD& value)
LLScrollListItem* item = mList->getFirstSelected();
if (item)
{
- setLabel(getSelectedItemLabel());
+ updateLabel();
}
mLastSelectedIndex = mList->getFirstSelectedIndex();
}
@@ -385,6 +388,23 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
}
}
+void LLComboBox::updateLabel()
+{
+ // Update the combo editor with the selected
+ // item label.
+ if (mTextEntry)
+ {
+ mTextEntry->setText(getSelectedItemLabel());
+ mTextEntry->setTentative(FALSE);
+ }
+
+ // If combo box doesn't allow text entry update
+ // the combo button label.
+ if (!mAllowTextEntry)
+ {
+ mButton->setLabel(getSelectedItemLabel());
+ }
+}
BOOL LLComboBox::remove(const std::string& name)
{
@@ -486,7 +506,7 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)
LLLineEditor::Params params = p.combo_editor;
params.rect(text_entry_rect);
params.default_text(LLStringUtil::null);
- params.max_length_bytes(mMaxChars);
+ params.max_length.bytes(mMaxChars);
params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
params.commit_on_focus_lost(false);
@@ -702,7 +722,7 @@ void LLComboBox::onItemSelected(const LLSD& data)
mLastSelectedIndex = getCurrentIndex();
if (mLastSelectedIndex != -1)
{
- setLabel(getSelectedItemLabel());
+ updateLabel();
if (mAllowTextEntry)
{
@@ -771,7 +791,8 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
return FALSE;
}
// if selection has changed, pop open list
- else if (mList->getLastSelectedItem() != last_selected_item)
+ else if (mList->getLastSelectedItem() != last_selected_item ||
+ (key == KEY_DOWN || key == KEY_UP) && !mList->isEmpty())
{
showList();
}
@@ -835,6 +856,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
mList->deselectAllItems();
mLastSelectedIndex = -1;
}
+ if (mTextChangedCallback != NULL)
+ {
+ (mTextChangedCallback)(line_editor, LLSD());
+ }
return;
}
@@ -879,6 +904,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
// RN: presumably text entry
updateSelection();
}
+ if (mTextChangedCallback != NULL)
+ {
+ (mTextChangedCallback)(line_editor, LLSD());
+ }
}
void LLComboBox::updateSelection()
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index f369147ded..64dbaea306 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -43,9 +43,6 @@
class LLFontGL;
class LLViewBorder;
-extern S32 LLCOMBOBOX_HEIGHT;
-extern S32 LLCOMBOBOX_WIDTH;
-
class LLComboBox
: public LLUICtrl, public LLCtrlListInterface
{
@@ -76,7 +73,8 @@ public:
allow_new_values;
Optional<S32> max_chars;
Optional<commit_callback_t> prearrange_callback,
- text_entry_callback;
+ text_entry_callback,
+ text_changed_callback;
Optional<EPreferredPosition, PreferredPositionValues> list_position;
@@ -136,6 +134,7 @@ public:
LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM);
BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed
void removeall() { clearRows(); }
+ bool itemExists(const std::string& name);
void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name
@@ -150,6 +149,9 @@ public:
// This is probably a UI abuse.
void setLabel(const LLStringExplicit& name);
+ // Updates the combobox label to match the selected list item.
+ void updateLabel();
+
BOOL remove(const std::string& name); // remove item "name", return TRUE if found and removed
BOOL setCurrentByIndex( S32 index );
@@ -193,6 +195,7 @@ public:
void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; }
void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
+ void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
void setButtonVisible(BOOL visible);
@@ -223,9 +226,10 @@ private:
BOOL mTextEntryTentative;
commit_callback_t mPrearrangeCallback;
commit_callback_t mTextEntryCallback;
+ commit_callback_t mTextChangedCallback;
commit_callback_t mSelectionCallback;
- boost::signals2::connection mTopLostSignalConnection;
- S32 mLastSelectedIndex;
+ boost::signals2::connection mTopLostSignalConnection;
+ S32 mLastSelectedIndex;
};
// A combo box with icons for the list of items.
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index d48674f306..b1c27126d9 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -160,8 +160,10 @@ bool LLDockControl::isDockVisible()
case TOP:
{
// check is dock inside parent rect
+ // assume that parent for all dockable flaoters
+ // is the root view
LLRect dockParentRect =
- mDockWidget->getParent()->calcScreenRect();
+ mDockWidget->getRootView()->calcScreenRect();
if (dockRect.mRight <= dockParentRect.mLeft
|| dockRect.mLeft >= dockParentRect.mRight)
{
@@ -220,10 +222,15 @@ void LLDockControl::moveDockable()
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mTop + dockableRect.getHeight();
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y += mDockTongue->getHeight();
+
+ if ( y > rootRect.mTop)
+ {
+ y = rootRect.mTop;
+ }
}
// check is dockable inside root view rect
@@ -257,7 +264,7 @@ void LLDockControl::moveDockable()
case BOTTOM:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mBottom;
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y -= mDockTongue->getHeight();
@@ -292,9 +299,21 @@ void LLDockControl::moveDockable()
break;
}
- // move dockable
- dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
- dockableRect.getHeight());
+ S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom - mDockTongueY) - mDockTongue->getHeight();
+
+ // A floater should be shrunk so it doesn't cover a part of its docking tongue and
+ // there is a space between a dockable floater and a control to which it is docked.
+ if (use_tongue && dockableRect.getHeight() >= max_available_height)
+ {
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height);
+ mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight());
+ }
+ else
+ {
+ // move dockable
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
+ dockableRect.getHeight());
+ }
LLRect localDocableParentRect;
mDockableFloater->getParent()->screenRectToLocal(dockableRect,
&localDocableParentRect);
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index c57c02f4b1..97a52fada4 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -87,9 +87,6 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
mItemsPanel->addChild(item);
break;
default:
- LL_WARNS("") << "Unsupported position." << LL_ENDL;
- delete new_pair;
- return false;
break;
}
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index 0515853698..92bf429031 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -450,8 +450,9 @@ private:
*/
class LLFlatListViewEx : public LLFlatListView
{
- LOG_CLASS(LLFlatListViewEx);
public:
+ LOG_CLASS(LLFlatListViewEx);
+
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
{
/**
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index e1203971ea..d19e33ea55 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1,4 +1,5 @@
/**
+
* @file llfloater.cpp
* @brief LLFloater base class
*
@@ -36,6 +37,7 @@
#include "lluictrlfactory.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
+#include "lldir.h"
#include "lldraghandle.h"
#include "llfloaterreg.h"
#include "llfocusmgr.h"
@@ -60,7 +62,6 @@
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
-
std::string LLFloater::sButtonNames[BUTTON_COUNT] =
{
"llfloater_close_btn", //BUTTON_CLOSE
@@ -199,6 +200,21 @@ void LLFloater::initClass()
{
sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
}
+
+ LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
+ updateActiveFloaterTransparency();
+ }
+
+ ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
+ updateInactiveFloaterTransparency();
+ }
+
}
// defaults for floater param block pulled from widgets/floater.xml
@@ -206,7 +222,7 @@ static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFl
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(), // intentionally do not pass params here, see initFromParams
- mDragHandle(NULL),
+ mDragHandle(NULL),
mTitle(p.title),
mShortTitle(p.short_title),
mSingleInstance(p.single_instance),
@@ -231,7 +247,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mTornOff(false),
mHasBeenDraggedWhileMinimized(FALSE),
mPreviousMinimizedBottom(0),
- mPreviousMinimizedLeft(0)
+ mPreviousMinimizedLeft(0),
+ mMinimizeSignal(NULL)
// mNotificationContext(NULL)
{
mHandle.bind(this);
@@ -255,9 +272,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
initFromParams(p);
- // chrome floaters don't take focus at all
- setFocusRoot(!getIsChrome());
-
initFloater(p);
}
@@ -345,6 +359,18 @@ void LLFloater::layoutDragHandle()
updateTitleButtons();
}
+// static
+void LLFloater::updateActiveFloaterTransparency()
+{
+ sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
+}
+
+// static
+void LLFloater::updateInactiveFloaterTransparency()
+{
+ sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
+}
+
void LLFloater::addResizeCtrls()
{
// Resize bars (sides)
@@ -493,13 +519,15 @@ LLFloater::~LLFloater()
setVisible(false); // We're not visible if we're destroyed
storeVisibilityControl();
storeDockStateControl();
+
+ delete mMinimizeSignal;
}
void LLFloater::storeRectControl()
{
if( mRectControl.size() > 1 )
{
- LLUI::sSettingGroups["floater"]->setRect( mRectControl, getRect() );
+ getControlGroup()->setRect( mRectControl, getRect() );
}
}
@@ -507,7 +535,7 @@ void LLFloater::storeVisibilityControl()
{
if( !sQuitting && mVisibilityControl.size() > 1 )
{
- LLUI::sSettingGroups["floater"]->setBOOL( mVisibilityControl, getVisible() );
+ getControlGroup()->setBOOL( mVisibilityControl, getVisible() );
}
}
@@ -515,10 +543,47 @@ void LLFloater::storeDockStateControl()
{
if( !sQuitting && mDocStateControl.size() > 1 )
{
- LLUI::sSettingGroups["floater"]->setBOOL( mDocStateControl, isDocked() );
+ getControlGroup()->setBOOL( mDocStateControl, isDocked() );
+ }
+}
+
+LLRect LLFloater::getSavedRect() const
+{
+ LLRect rect;
+
+ if (mRectControl.size() > 1)
+ {
+ rect = getControlGroup()->getRect(mRectControl);
+ }
+
+ return rect;
+}
+
+bool LLFloater::hasSavedRect() const
+{
+ return !getSavedRect().isEmpty();
+}
+
+// static
+std::string LLFloater::getControlName(const std::string& name, const LLSD& key)
+{
+ std::string ctrl_name = name;
+
+ // Add the key to the control name if appropriate.
+ if (key.isString() && !key.asString().empty())
+ {
+ ctrl_name += "_" + key.asString();
}
+
+ return ctrl_name;
}
+// static
+LLControlGroup* LLFloater::getControlGroup()
+{
+ // Floater size, position, visibility, etc are saved in per-account settings.
+ return LLUI::sSettingGroups["account"];
+}
void LLFloater::setVisible( BOOL visible )
{
@@ -775,7 +840,7 @@ void LLFloater::applyRectControl()
// override center if we have saved rect control
if (mRectControl.size() > 1)
{
- const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl);
+ const LLRect& rect = getControlGroup()->getRect(mRectControl);
if (rect.getWidth() > 0 && rect.getHeight() > 0)
{
translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom);
@@ -791,7 +856,7 @@ void LLFloater::applyDockState()
{
if (mDocStateControl.size() > 1)
{
- bool dockState = LLUI::sSettingGroups["floater"]->getBOOL(mDocStateControl);
+ bool dockState = getControlGroup()->getBOOL(mDocStateControl);
setDocked(dockState);
}
@@ -960,6 +1025,11 @@ void LLFloater::setMinimized(BOOL minimize)
if (minimize == mMinimized) return;
+ if(mMinimizeSignal)
+ {
+ (*mMinimizeSignal)(this, LLSD(minimize));
+ }
+
if (minimize)
{
// minimized flag should be turned on before release focus
@@ -1117,6 +1187,7 @@ void LLFloater::setFocus( BOOL b )
last_focus->setFocus(TRUE);
}
}
+ updateTransparency(b ? TT_ACTIVE : TT_INACTIVE);
}
// virtual
@@ -1389,6 +1460,9 @@ void LLFloater::setFrontmost(BOOL take_focus)
// there are more than one floater view
// so we need to query our parent directly
((LLFloaterView*)getParent())->bringToFront(this, take_focus);
+
+ // Make sure to set the appropriate transparency type (STORM-732).
+ updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE);
}
}
@@ -1576,7 +1650,8 @@ void LLFloater::onClickCloseBtn()
// virtual
void LLFloater::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ const F32 alpha = getCurrentTransparency();
+
// draw background
if( isBackgroundVisible() )
{
@@ -1674,7 +1749,6 @@ void LLFloater::draw()
void LLFloater::drawShadow(LLPanel* panel)
{
- F32 alpha = panel->getDrawContext().mAlpha;
S32 left = LLPANEL_BORDER_WIDTH;
S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
@@ -1691,10 +1765,32 @@ void LLFloater::drawShadow(LLPanel* panel)
shadow_color.mV[VALPHA] *= 0.5f;
}
gl_drop_shadow(left, top, right, bottom,
- shadow_color % alpha,
+ shadow_color % getCurrentTransparency(),
llround(shadow_offset));
}
+void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
+{
+ child_list_t children = *view->getChildList();
+ child_list_t::iterator it = children.begin();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
+ if (ctrl)
+ {
+ ctrl->setTransparencyType(transparency_type);
+ }
+
+ for(; it != children.end(); ++it)
+ {
+ updateTransparency(*it, transparency_type);
+ }
+}
+
+void LLFloater::updateTransparency(ETypeTransparency transparency_type)
+{
+ updateTransparency(this, transparency_type);
+}
+
void LLFloater::setCanMinimize(BOOL can_minimize)
{
// if removing minimize/restore button programmatically,
@@ -1954,6 +2050,7 @@ LLFloaterView::LLFloaterView (const Params& p)
: LLUICtrl (p),
mFocusCycleMode(FALSE),
+ mMinimizePositionVOffset(0),
mSnapOffsetBottom(0),
mSnapOffsetRight(0)
{
@@ -2352,7 +2449,9 @@ void LLFloaterView::closeAllChildren(bool app_quitting)
// Attempt to close floater. This will cause the "do you want to save"
// dialogs to appear.
- if (floaterp->canClose() && !floaterp->isDead())
+ // Skip invisible floaters if we're not quitting (STORM-192).
+ if (floaterp->canClose() && !floaterp->isDead() &&
+ (app_quitting || floaterp->getVisible()))
{
floaterp->closeFloater(app_quitting);
}
@@ -2491,9 +2590,13 @@ void LLFloaterView::draw()
LLRect LLFloaterView::getSnapRect() const
{
- LLRect snap_rect = getRect();
- snap_rect.mBottom += mSnapOffsetBottom;
- snap_rect.mRight -= mSnapOffsetRight;
+ LLRect snap_rect = getLocalRect();
+
+ LLView* snap_view = mSnapView.get();
+ if (snap_view)
+ {
+ snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this);
+ }
return snap_rect;
}
@@ -2664,18 +2767,20 @@ void LLFloater::setInstanceName(const std::string& name)
mInstanceName = name;
if (!mInstanceName.empty())
{
+ std::string ctrl_name = getControlName(mInstanceName, mKey);
+
// save_rect and save_visibility only apply to registered floaters
if (!mRectControl.empty())
{
- mRectControl = LLFloaterReg::declareRectControl(mInstanceName);
+ mRectControl = LLFloaterReg::declareRectControl(ctrl_name);
}
if (!mVisibilityControl.empty())
{
- mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName);
+ mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name);
}
if(!mDocStateControl.empty())
{
- mDocStateControl = LLFloaterReg::declareDockStateControl(mInstanceName);
+ mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);
}
}
@@ -2764,16 +2869,28 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
// close callback
if (p.close_callback.isProvided())
{
- mCloseSignal.connect(initCommitCallback(p.close_callback));
+ setCloseCallback(initCommitCallback(p.close_callback));
}
}
+boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t();
+ return mMinimizeSignal->connect(cb);
+}
+
+boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )
+{
+ return mCloseSignal.connect(cb);
+}
+
LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build");
bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
{
Params params(LLUICtrlFactory::getDefaultParams<LLFloater>());
- LLXUIParser::instance().readXUI(node, params, filename); // *TODO: Error checking
+ LLXUIParser parser;
+ parser.readXUI(node, params, filename); // *TODO: Error checking
if (output_node)
{
@@ -2781,8 +2898,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
setupParamsForExport(output_params, parent);
Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
output_node->setName(node->getName()->mString);
- LLXUIParser::instance().writeXUI(
- output_node, output_params, &default_params);
+ parser.writeXUI(output_node, output_params, &default_params);
}
// Default floater position to top-left corner of screen
@@ -2800,7 +2916,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
params.from_xui = true;
applyXUILayout(params, parent);
initFromParams(params);
-
+
initFloater(params);
LLMultiFloater* last_host = LLFloater::getFloaterHost();
@@ -2877,3 +2993,64 @@ bool LLFloater::isVisible(const LLFloater* floater)
{
return floater && floater->getVisible();
}
+
+static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters");
+
+bool LLFloater::buildFromFile(const std::string& filename, LLXMLNodePtr output_node)
+{
+ LLFastTimer timer(FTM_BUILD_FLOATERS);
+ LLXMLNodePtr root;
+
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return false;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return false;
+ }
+
+ // root must be called floater
+ if( !(root->hasName("floater") || root->hasName("multi_floater")) )
+ {
+ llwarns << "Root node should be named floater in: " << filename << llendl;
+ return false;
+ }
+
+ bool res = true;
+
+ lldebugs << "Building floater " << filename << llendl;
+ LLUICtrlFactory::instance().pushFileName(filename);
+ {
+ if (!getFactoryMap().empty())
+ {
+ LLPanel::sFactoryStack.push_front(&getFactoryMap());
+ }
+
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ getCommitCallbackRegistrar().pushScope();
+ getEnableCallbackRegistrar().pushScope();
+
+ res = initFloaterXML(root, getParent(), filename, output_node);
+
+ setXMLFilename(filename);
+
+ getCommitCallbackRegistrar().popScope();
+ getEnableCallbackRegistrar().popScope();
+
+ if (!getFactoryMap().empty())
+ {
+ LLPanel::sFactoryStack.pop_front();
+ }
+ }
+ LLUICtrlFactory::instance().popFileName();
+
+ return res;
+}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 5e482cbac3..5b7b020881 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -141,6 +141,10 @@ public:
// Don't export top/left for rect, only height/width
static void setupParamsForExport(Params& p, LLView* parent);
+ bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);
+
+ boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb );
void initFromParams(const LLFloater::Params& p);
bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);
@@ -203,6 +207,11 @@ public:
BOOL isResizable() const { return mResizable; }
void setResizeLimits( S32 min_width, S32 min_height );
void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; }
+ LLRect getSavedRect() const;
+ bool hasSavedRect() const;
+
+ static std::string getControlName(const std::string& name, const LLSD& key);
+ static LLControlGroup* getControlGroup();
bool isMinimizeable() const{ return mCanMinimize; }
bool isCloseable() const{ return mCanClose; }
@@ -276,6 +285,8 @@ public:
static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
static LLMultiFloater* getFloaterHost() {return sHostp; }
+
+ void updateTransparency(ETypeTransparency transparency_type);
protected:
@@ -333,6 +344,10 @@ private:
void addDragHandle();
void layoutDragHandle(); // repair layout
+ static void updateActiveFloaterTransparency();
+ static void updateInactiveFloaterTransparency();
+ void updateTransparency(LLView* view, ETypeTransparency transparency_type);
+
public:
// Called when floater is opened, passes mKey
// Public so external views or floaters can watch for this floater opening
@@ -342,6 +357,8 @@ public:
// Public so external views or floaters can watch for this floater closing
commit_signal_t mCloseSignal;
+ commit_signal_t* mMinimizeSignal;
+
protected:
std::string mRectControl;
std::string mVisibilityControl;
@@ -479,10 +496,10 @@ public:
// value is not defined.
S32 getZOrder(LLFloater* child);
- void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; }
- void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; }
+ void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; }
private:
+ LLHandle<LLView> mSnapView;
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
S32 mSnapOffsetRight;
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index ccffe98c96..4677d535db 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -121,7 +121,7 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
res = build_func(key);
- bool success = LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, NULL);
+ bool success = res->buildFromFile(xui_file, NULL);
if (!success)
{
llwarns << "Failed to build floater type: '" << name << "'." << llendl;
@@ -284,9 +284,9 @@ void LLFloaterReg::showInitialVisibleInstances()
{
const std::string& name = iter->first;
std::string controlname = getVisibilityControlName(name);
- if (LLUI::sSettingGroups["floater"]->controlExists(controlname))
+ if (LLFloater::getControlGroup()->controlExists(controlname))
{
- BOOL isvis = LLUI::sSettingGroups["floater"]->getBOOL(controlname);
+ BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname);
if (isvis)
{
showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true
@@ -340,7 +340,7 @@ std::string LLFloaterReg::getRectControlName(const std::string& name)
std::string LLFloaterReg::declareRectControl(const std::string& name)
{
std::string controlname = getRectControlName(name);
- LLUI::sSettingGroups["floater"]->declareRect(controlname, LLRect(),
+ LLFloater::getControlGroup()->declareRect(controlname, LLRect(),
llformat("Window Position and Size for %s", name.c_str()),
TRUE);
return controlname;
@@ -358,7 +358,7 @@ std::string LLFloaterReg::getVisibilityControlName(const std::string& name)
std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
{
std::string controlname = getVisibilityControlName(name);
- LLUI::sSettingGroups["floater"]->declareBOOL(controlname, FALSE,
+ LLFloater::getControlGroup()->declareBOOL(controlname, FALSE,
llformat("Window Visibility for %s", name.c_str()),
TRUE);
return controlname;
@@ -368,7 +368,7 @@ std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
std::string LLFloaterReg::declareDockStateControl(const std::string& name)
{
std::string controlname = getDockStateControlName(name);
- LLUI::sSettingGroups["floater"]->declareBOOL(controlname, TRUE,
+ LLFloater::getControlGroup()->declareBOOL(controlname, TRUE,
llformat("Window Docking state for %s", name.c_str()),
TRUE);
return controlname;
@@ -391,11 +391,11 @@ void LLFloaterReg::registerControlVariables()
for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
{
const std::string& name = iter->first;
- if (LLUI::sSettingGroups["floater"]->controlExists(getRectControlName(name)))
+ if (LLFloater::getControlGroup()->controlExists(getRectControlName(name)))
{
declareRectControl(name);
}
- if (LLUI::sSettingGroups["floater"]->controlExists(getVisibilityControlName(name)))
+ if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))
{
declareVisibilityControl(name);
}
@@ -419,7 +419,7 @@ void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LL
// Get the visibility control name for the floater
std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
// Set the control value to the floater visibility control (Sets the value as well)
- ctrl->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+ ctrl->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
}
// callback args may use "floatername.key" format
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 94387fb41a..8414b92113 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -27,14 +27,9 @@
#define LLFLOATERREG_H
/// llcommon
-#include "llboost.h"
#include "llrect.h"
-#include "llstl.h"
#include "llsd.h"
-/// llui
-#include "lluictrl.h"
-
#include <boost/function.hpp>
//*******************************************************
@@ -43,6 +38,7 @@
//
class LLFloater;
+class LLUICtrl;
typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc;
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index 821d4543ae..7525b8cab3 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -60,6 +60,11 @@ LLFloaterRegListener::LLFloaterRegListener():
"Ask to toggle the state of the floater specified in [\"name\"]",
&LLFloaterRegListener::toggleInstance,
requiredName);
+ add("instanceVisible",
+ "Return on [\"reply\"] an event whose [\"visible\"] indicates the visibility "
+ "of the floater specified in [\"name\"]",
+ &LLFloaterRegListener::instanceVisible,
+ requiredName);
LLSD requiredNameButton;
requiredNameButton["name"] = LLSD();
requiredNameButton["button"] = LLSD();
@@ -71,9 +76,7 @@ LLFloaterRegListener::LLFloaterRegListener():
void LLFloaterRegListener::getBuildMap(const LLSD& event) const
{
- // Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
- LLReqID reqID(event);
- LLSD reply(reqID.makeResponse());
+ LLSD reply;
// Build an LLSD map that mirrors sBuildMap. Since we have no good way to
// represent a C++ callable in LLSD, the only part of BuildData we can
// store is the filename. For each LLSD map entry, it would be more
@@ -86,7 +89,7 @@ void LLFloaterRegListener::getBuildMap(const LLSD& event) const
reply[mi->first] = mi->second.mFile;
}
// Send the reply to the LLEventPump named in event["reply"].
- LLEventPumps::instance().obtain(event["reply"]).post(reply);
+ sendReply(reply, event);
}
void LLFloaterRegListener::showInstance(const LLSD& event) const
@@ -104,6 +107,12 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const
LLFloaterReg::toggleInstance(event["name"], event["key"]);
}
+void LLFloaterRegListener::instanceVisible(const LLSD& event) const
+{
+ sendReply(LLSDMap("visible", LLFloaterReg::instanceVisible(event["name"], event["key"])),
+ event);
+}
+
void LLFloaterRegListener::clickButton(const LLSD& event) const
{
// If the caller requests a reply, build the reply.
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index 586656667c..24311a2dfa 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -47,6 +47,7 @@ private:
void showInstance(const LLSD& event) const;
void hideInstance(const LLSD& event) const;
void toggleInstance(const LLSD& event) const;
+ void instanceVisible(const LLSD& event) const;
void clickButton(const LLSD& event) const;
};
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 1f16d12add..724d190307 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -113,6 +113,16 @@ boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_s
+typedef std::list<LLHandle<LLView> > view_handle_list_t;
+typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
+struct LLFocusMgr::Impl
+{
+ // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
+ view_handle_list_t mCachedKeyboardFocusList;
+
+ focus_history_map_t mFocusHistory;
+};
+
LLFocusMgr gFocusMgr;
LLFocusMgr::LLFocusMgr()
@@ -123,10 +133,17 @@ LLFocusMgr::LLFocusMgr()
mDefaultKeyboardFocus( NULL ),
mKeystrokesOnly(FALSE),
mTopCtrl( NULL ),
- mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true
+ mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true
+ mImpl(new LLFocusMgr::Impl)
{
}
+LLFocusMgr::~LLFocusMgr()
+{
+ mImpl->mFocusHistory.clear();
+ delete mImpl;
+ mImpl = NULL;
+}
void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
{
@@ -179,7 +196,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
mKeyboardFocus = new_focus;
// list of the focus and it's ancestors
- view_handle_list_t old_focus_list = mCachedKeyboardFocusList;
+ view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList;
view_handle_list_t new_focus_list;
// walk up the tree to root and add all views to the new_focus_list
@@ -206,7 +223,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
LLView* old_focus_view = old_focus_iter->get();
if (old_focus_view)
{
- mCachedKeyboardFocusList.pop_front();
+ mImpl->mCachedKeyboardFocusList.pop_front();
old_focus_view->onFocusLost();
}
}
@@ -219,7 +236,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
LLView* new_focus_view = new_focus_riter->get();
if (new_focus_view)
{
- mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
+ mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
new_focus_view->onFocusReceived();
}
}
@@ -254,7 +271,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
if (focus_subtree)
{
LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus);
- mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
+ mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
}
}
@@ -315,6 +332,20 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f
}
}
+bool LLFocusMgr::keyboardFocusHasAccelerators() const
+{
+ LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
+ while( focus_view )
+ {
+ if(focus_view->hasAccelerators())
+ {
+ return true;
+ }
+
+ focus_view = focus_view->getParent();
+ }
+ return false;
+}
void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
{
@@ -442,8 +473,8 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
{
if (subtree_root)
{
- focus_history_map_t::const_iterator found_it = mFocusHistory.find(subtree_root->getHandle());
- if (found_it != mFocusHistory.end())
+ focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle());
+ if (found_it != mImpl->mFocusHistory.end())
{
// found last focus for this subtree
return static_cast<LLUICtrl*>(found_it->second.get());
@@ -456,6 +487,6 @@ void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root)
{
if (subtree_root)
{
- mFocusHistory.erase(subtree_root->getHandle());
+ mImpl->mFocusHistory.erase(subtree_root->getHandle());
}
}
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index eef82a3b5a..25ae1d2579 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -74,7 +74,7 @@ class LLFocusMgr
{
public:
LLFocusMgr();
- ~LLFocusMgr() { mFocusHistory.clear(); }
+ ~LLFocusMgr();
// Mouse Captor
void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse.
@@ -118,6 +118,10 @@ public:
void unlockFocus();
BOOL focusLocked() const { return mLockedView != NULL; }
+ bool keyboardFocusHasAccelerators() const;
+
+ struct Impl;
+
private:
LLUICtrl* mLockedView;
@@ -130,10 +134,6 @@ private:
LLFocusableElement* mDefaultKeyboardFocus;
BOOL mKeystrokesOnly;
- // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
- typedef std::list<LLHandle<LLView> > view_handle_list_t;
- view_handle_list_t mCachedKeyboardFocusList;
-
// Top View
LLUICtrl* mTopCtrl;
@@ -141,8 +141,7 @@ private:
BOOL mAppHasFocus;
- typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
- focus_history_map_t mFocusHistory;
+ Impl * mImpl;
};
extern LLFocusMgr gFocusMgr;
diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h
index a43f095d67..8c000eee48 100644
--- a/indra/llui/llhandle.h
+++ b/indra/llui/llhandle.h
@@ -61,13 +61,6 @@ public:
return *this;
}
- template<typename Subclass>
- LLHandle<T>& operator =(const LLHandle<Subclass>& other)
- {
- mTombStone = other.mTombStone;
- return *this;
- }
-
bool isDead() const
{
return mTombStone->getTarget() == NULL;
@@ -99,7 +92,6 @@ public:
{
return lhs.mTombStone > rhs.mTombStone;
}
-protected:
protected:
LLPointer<LLTombStone<T> > mTombStone;
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 627957061d..47f2cfaf89 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -41,6 +41,7 @@ static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
LLIconCtrl::Params::Params()
: image("image_name"),
color("color"),
+ use_draw_context_alpha("use_draw_context_alpha", true),
scale_image("scale_image")
{
tab_stop = false;
@@ -51,6 +52,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
: LLUICtrl(p),
mColor(p.color()),
mImagep(p.image),
+ mUseDrawContextAlpha(p.use_draw_context_alpha),
mPriority(0),
mDrawWidth(0),
mDrawHeight(0)
@@ -71,7 +73,8 @@ void LLIconCtrl::draw()
{
if( mImagep.notNull() )
{
- mImagep->draw(getLocalRect(), mColor.get() % getDrawContext().mAlpha );
+ const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
+ mImagep->draw(getLocalRect(), mColor.get() % alpha );
}
LLUICtrl::draw();
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 79a8b0fb28..efa0925a4a 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -30,6 +30,7 @@
#include "lluuid.h"
#include "v4color.h"
#include "lluictrl.h"
+#include "lluiimage.h"
#include "stdenums.h"
class LLTextBox;
@@ -48,6 +49,7 @@ public:
{
Optional<LLUIImage*> image;
Optional<LLUIColor> color;
+ Optional<bool> use_draw_context_alpha;
Ignored scale_image;
Params();
};
@@ -68,6 +70,7 @@ public:
void setColor(const LLColor4& color) { mColor = color; }
void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
+ const LLPointer<LLUIImage> getImage() { return mImagep; }
private:
void setIconImageDrawSize() ;
@@ -79,6 +82,10 @@ protected:
S32 mDrawWidth ;
S32 mDrawHeight ;
+ // If set to true (default), use the draw context transparency.
+ // If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
+ bool mUseDrawContextAlpha;
+
private:
LLUIColor mColor;
LLPointer<LLUIImage> mImagep;
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 5cc9add1e2..9b6830a816 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -35,97 +35,76 @@
#include "llresizebar.h"
#include "llcriticaldamp.h"
-static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML);
+static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
+static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
+void LLLayoutStack::OrientationNames::declareValues()
+{
+ declare("horizontal", HORIZONTAL);
+ declare("vertical", VERTICAL);
+}
//
-// LLLayoutStack
+// LLLayoutPanel
//
-struct LLLayoutStack::LayoutPanel
+LLLayoutPanel::LLLayoutPanel(const Params& p)
+: LLPanel(p),
+ mMinDim(p.min_dim),
+ mMaxDim(p.max_dim),
+ mAutoResize(p.auto_resize),
+ mUserResize(p.user_resize),
+ mCollapsed(FALSE),
+ mCollapseAmt(0.f),
+ mVisibleAmt(1.f), // default to fully visible
+ mResizeBar(NULL)
{
- LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp),
- mMinWidth(min_width),
- mMinHeight(min_height),
- mMaxWidth(max_width),
- mMaxHeight(max_height),
- mAutoResize(auto_resize),
- mUserResize(user_resize),
- mOrientation(orientation),
- mCollapsed(FALSE),
- mCollapseAmt(0.f),
- mVisibleAmt(1.f), // default to fully visible
- mResizeBar(NULL)
+ // panels initialized as hidden should not start out partially visible
+ if (!getVisible())
{
- LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
- LLRect resize_bar_rect = panelp->getRect();
-
- S32 min_dim;
- if (orientation == HORIZONTAL)
- {
- min_dim = mMinHeight;
- }
- else
- {
- min_dim = mMinWidth;
- }
- LLResizeBar::Params p;
- p.name("resize");
- p.resizing_view(mPanel);
- p.min_size(min_dim);
- p.side(side);
- p.snapping_enabled(false);
- mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
- // panels initialized as hidden should not start out partially visible
- if (!mPanel->getVisible())
- {
- mVisibleAmt = 0.f;
- }
+ mVisibleAmt = 0.f;
}
+}
- ~LayoutPanel()
- {
- // probably not necessary, but...
- delete mResizeBar;
- mResizeBar = NULL;
- }
+void LLLayoutPanel::initFromParams(const Params& p)
+{
+ LLPanel::initFromParams(p);
+ setFollowsNone();
+}
+
+
+LLLayoutPanel::~LLLayoutPanel()
+{
+ // probably not necessary, but...
+ delete mResizeBar;
+ mResizeBar = NULL;
+}
- F32 getCollapseFactor()
+F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
+{
+ if (orientation == LLLayoutStack::HORIZONTAL)
{
- if (mOrientation == HORIZONTAL)
- {
- F32 collapse_amt =
- clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
- return mVisibleAmt * collapse_amt;
- }
- else
+ F32 collapse_amt =
+ clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
+ return mVisibleAmt * collapse_amt;
+ }
+ else
{
F32 collapse_amt =
- clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
+ clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));
return mVisibleAmt * collapse_amt;
- }
}
+}
- LLPanel* mPanel;
- S32 mMinWidth;
- S32 mMinHeight;
-
- // mMaxWidth & mMaxHeight are added to make configurable max width of the nearby chat bar. EXT-5589
- // they are not processed by LLLayoutStack but they can be if necessary
- S32 mMaxWidth;
- S32 mMaxHeight;
- BOOL mAutoResize;
- BOOL mUserResize;
- BOOL mCollapsed;
- LLResizeBar* mResizeBar;
- ELayoutOrientation mOrientation;
- F32 mVisibleAmt;
- F32 mCollapseAmt;
-};
+//
+// LLLayoutStack
+//
LLLayoutStack::Params::Params()
-: orientation("orientation", std::string("vertical")),
+: orientation("orientation"),
animate("animate", true),
clip("clip", true),
+ open_time_constant("open_time_constant", 0.02f),
+ close_time_constant("close_time_constant", 0.03f),
border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
{
name="stack";
@@ -136,10 +115,12 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
mMinWidth(0),
mMinHeight(0),
mPanelSpacing(p.border_size),
- mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
+ mOrientation(p.orientation),
mAnimate(p.animate),
mAnimatedThisFrame(false),
- mClip(p.clip)
+ mClip(p.clip),
+ mOpenTimeConstant(p.open_time_constant),
+ mCloseTimeConstant(p.close_time_constant)
{}
LLLayoutStack::~LLLayoutStack()
@@ -157,18 +138,18 @@ void LLLayoutStack::draw()
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
// clip to layout rectangle, not bounding rectangle
- LLRect clip_rect = (*panel_it)->mPanel->getRect();
+ LLRect clip_rect = (*panel_it)->getRect();
// scale clipping rectangle by visible amount
if (mOrientation == HORIZONTAL)
{
- clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
+ clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
}
else
{
- clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
+ clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
}
- LLPanel* panelp = (*panel_it)->mPanel;
+ LLPanel* panelp = (*panel_it);
LLLocalClipRect clip(clip_rect, mClip);
// only force drawing invisible children if visible amount is non-zero
@@ -179,7 +160,7 @@ void LLLayoutStack::draw()
void LLLayoutStack::removeChild(LLView* view)
{
- LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
+ LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
if (embedded_panelp)
{
@@ -200,149 +181,16 @@ BOOL LLLayoutStack::postBuild()
return TRUE;
}
-static void get_attribute_s32_and_write(LLXMLNodePtr node,
- const char* name,
- S32 *value,
- S32 default_value,
- LLXMLNodePtr output_child)
-{
- BOOL has_attr = node->getAttributeS32(name, *value);
- if (has_attr && *value != default_value && output_child)
- {
- // create an attribute child node
- LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
- child_attr->setIntValue(*value);
- }
-}
-
-static void get_attribute_bool_and_write(LLXMLNodePtr node,
- const char* name,
- BOOL *value,
- BOOL default_value,
- LLXMLNodePtr output_child)
-{
- BOOL has_attr = node->getAttributeBOOL(name, *value);
- if (has_attr && *value != default_value && output_child)
- {
- LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
- child_attr->setBoolValue(*value);
- }
-}
-//static
-LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
-{
- LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
- LLXUIParser::instance().readXUI(node, p, LLUICtrlFactory::getInstance()->getCurFileName());
-
- // Export must happen before setupParams() mungles rectangles and before
- // this item gets added to parent (otherwise screws up last_child_rect
- // logic). JC
- if (output_node)
- {
- Params output_params(p);
- setupParamsForExport(output_params, parent);
- LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
- output_node->setName(node->getName()->mString);
- LLXUIParser::instance().writeXUI(
- output_node, output_params, &default_params);
- }
-
- p.from_xui = true;
- applyXUILayout(p, parent);
- LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
-
- if (parent && layout_stackp)
- {
- S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup();
-
- parent->addChild(layout_stackp, tab_group);
- }
-
- for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
- {
- const S32 DEFAULT_MIN_WIDTH = 0;
- const S32 DEFAULT_MIN_HEIGHT = 0;
- const S32 DEFAULT_MAX_WIDTH = S32_MAX;
- const S32 DEFAULT_MAX_HEIGHT = S32_MAX;
- const BOOL DEFAULT_AUTO_RESIZE = TRUE;
-
- S32 min_width = DEFAULT_MIN_WIDTH;
- S32 min_height = DEFAULT_MIN_HEIGHT;
- S32 max_width = DEFAULT_MAX_WIDTH;
- S32 max_height = DEFAULT_MAX_HEIGHT;
- BOOL auto_resize = DEFAULT_AUTO_RESIZE;
-
- LLXMLNodePtr output_child;
- if (output_node)
+bool LLLayoutStack::addChild(LLView* child, S32 tab_group)
{
- output_child = output_node->createChild("", FALSE);
- }
-
- // Layout stack allows child nodes to acquire additional attributes,
- // such as "min_width" in: <button label="Foo" min_width="100"/>
- // If these attributes exist and have non-default values, write them
- // to the output node.
- get_attribute_s32_and_write(child_node, "min_width", &min_width,
- DEFAULT_MIN_WIDTH, output_child);
- get_attribute_s32_and_write(child_node, "min_height", &min_height,
- DEFAULT_MIN_HEIGHT, output_child);
- get_attribute_s32_and_write(child_node, "max_width", &max_width,
- DEFAULT_MAX_WIDTH, output_child);
- get_attribute_s32_and_write(child_node, "max_height", &max_height,
- DEFAULT_MAX_HEIGHT, output_child);
- get_attribute_bool_and_write(child_node, "auto_resize", &auto_resize,
- DEFAULT_AUTO_RESIZE, output_child);
-
- if (child_node->hasName("layout_panel"))
- {
- BOOL user_resize = TRUE;
- get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
- TRUE, output_child);
- LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child_node, layout_stackp, output_child);
+ LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);
if (panelp)
{
- panelp->setFollowsNone();
- layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize);
+ mPanels.push_back(panelp);
}
+ return LLView::addChild(child, tab_group);
}
- else
- {
- BOOL user_resize = FALSE;
- get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
- FALSE, output_child);
-
- LLPanel::Params p;
- p.mouse_opaque(false);
- LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p);
- LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, LLPanel::child_registry_t::instance(), output_child);
- if (new_child)
- {
- // put child in new embedded panel
- layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize);
- // resize panel to contain widget and move widget to be contained in panel
- panelp->setRect(new_child->getRect());
- new_child->setOrigin(0, 0);
- }
- else
- {
- panelp->die();
- }
- }
-
- if (output_child && !output_child->mChildren && output_child->mAttributes.empty() && output_child->getValue().empty())
- {
- output_node->deleteChild(output_child);
- }
- }
-
- if (!layout_stackp->postBuild())
- {
- delete layout_stackp;
- return NULL;
- }
- return layout_stackp;
-}
S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
{
@@ -368,34 +216,30 @@ S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
return cur_width;
}
-void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
+void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)
{
- // panel starts off invisible (collapsed)
- if (animate == ANIMATE)
- {
- panel->setVisible(FALSE);
- }
- LayoutPanel* embedded_panel = new LayoutPanel(panel, mOrientation, min_width, min_height, max_width, max_height, auto_resize, user_resize);
-
- mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
-
- if (panel->getParent() != this)
- {
- addChild(panel);
- }
- addChild(embedded_panel->mResizeBar);
+ LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
+ LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel);
- // bring all resize bars to the front so that they are clickable even over the panels
- // with a bit of overlap
- for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+ if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel)
{
- LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
- sendChildToFront(resize_barp);
+ llwarns << "One of the panels was not found in stack or NULL was passed instead of valid panel" << llendl;
+ return;
}
+ e_panel_list_t::iterator it = std::find(mPanels.begin(), mPanels.end(), embedded_panel_to_move);
+ mPanels.erase(it);
+ it = move_to_front ? mPanels.begin() : std::find(mPanels.begin(), mPanels.end(), embedded_target_panel);
+ mPanels.insert(it, embedded_panel_to_move);
+}
- // start expanding panel animation
+void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate)
+{
+ addChild(panel);
+
+ // panel starts off invisible (collapsed)
if (animate == ANIMATE)
{
+ panel->mVisibleAmt = 0.f;
panel->setVisible(TRUE);
}
}
@@ -407,7 +251,7 @@ void LLLayoutStack::removePanel(LLPanel* panel)
void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
{
- LayoutPanel* panel_container = findEmbeddedPanel(panel);
+ LLLayoutPanel* panel_container = findEmbeddedPanel(panel);
if (!panel_container) return;
panel_container->mCollapsed = collapsed;
@@ -415,7 +259,7 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)
{
- LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+ LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
if (panel)
{
@@ -425,7 +269,7 @@ void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL au
void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)
{
- LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+ LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
if (panel)
{
@@ -433,27 +277,25 @@ void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_
}
}
-bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp)
+bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp)
{
- LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+ LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
if (panel)
{
- if (min_widthp) *min_widthp = panel->mMinWidth;
- if (min_heightp) *min_heightp = panel->mMinHeight;
+ if (min_dimp) *min_dimp = panel->mMinDim;
}
return NULL != panel;
}
-bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_widthp, S32* max_heightp)
+bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp)
{
- LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+ LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
if (panel)
{
- if (max_widthp) *max_widthp = panel->mMaxWidth;
- if (max_heightp) *max_heightp = panel->mMaxHeight;
+ if (max_dimp) *max_dimp = panel->mMaxDim;
}
return NULL != panel;
@@ -465,25 +307,23 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
LLFastTimer ft(FTM_UPDATE_LAYOUT);
static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
calcMinExtents();
+ createResizeBars();
// calculate current extents
S32 total_width = 0;
S32 total_height = 0;
- const F32 ANIM_OPEN_TIME = 0.02f;
- const F32 ANIM_CLOSE_TIME = 0.03f;
-
e_panel_list_t::iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- LLPanel* panelp = (*panel_it)->mPanel;
+ LLPanel* panelp = (*panel_it);
if (panelp->getVisible())
{
if (mAnimate)
{
if (!mAnimatedThisFrame)
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));
if ((*panel_it)->mVisibleAmt > 0.99f)
{
(*panel_it)->mVisibleAmt = 1.f;
@@ -501,7 +341,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
if (!mAnimatedThisFrame)
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
if ((*panel_it)->mVisibleAmt < 0.001f)
{
(*panel_it)->mVisibleAmt = 0.f;
@@ -516,21 +356,21 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
if ((*panel_it)->mCollapsed)
{
- (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
}
else
{
- (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
}
if (mOrientation == HORIZONTAL)
{
// enforce minimize size constraint by default
- if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
+ if (panelp->getRect().getWidth() < (*panel_it)->mMinDim)
{
- panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
+ panelp->reshape((*panel_it)->mMinDim, panelp->getRect().getHeight());
}
- total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
+ total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
// want n-1 panel gaps for n panels
if (panel_it != mPanels.begin())
{
@@ -540,11 +380,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
else //VERTICAL
{
// enforce minimize size constraint by default
- if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
+ if (panelp->getRect().getHeight() < (*panel_it)->mMinDim)
{
- panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
+ panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinDim);
}
- total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
+ total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
if (panel_it != mPanels.begin())
{
total_height += mPanelSpacing;
@@ -558,7 +398,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
// panels that are not fully visible do not count towards shrink headroom
- if ((*panel_it)->getCollapseFactor() < 1.f)
+ if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f)
{
continue;
}
@@ -571,11 +411,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
if (mOrientation == HORIZONTAL)
{
- shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
+ shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
}
else //VERTICAL
{
- shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
+ shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
}
}
else
@@ -583,13 +423,13 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
num_resizable_panels++;
if (mOrientation == HORIZONTAL)
{
- shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
- shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
+ shrink_headroom_available += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
+ shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
}
else //VERTICAL
{
- shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
- shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
+ shrink_headroom_available += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
+ shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
}
}
}
@@ -612,17 +452,25 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- LLPanel* panelp = (*panel_it)->mPanel;
+ LLPanel* panelp = (*panel_it);
S32 cur_width = panelp->getRect().getWidth();
S32 cur_height = panelp->getRect().getHeight();
- S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
- S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
+ S32 new_width = cur_width;
+ S32 new_height = cur_height;
+ if (mOrientation == HORIZONTAL)
+ {
+ new_width = llmax((*panel_it)->mMinDim, new_width);
+ }
+ else
+ {
+ new_height = llmax((*panel_it)->mMinDim, new_height);
+ }
S32 delta_size = 0;
// if panel can automatically resize (not animating, and resize flag set)...
- if ((*panel_it)->getCollapseFactor() == 1.f
+ if ((*panel_it)->getCollapseFactor(mOrientation) == 1.f
&& (force_resize || (*panel_it)->mAutoResize)
&& !(*panel_it)->mResizeBar->hasMouseCapture())
{
@@ -633,8 +481,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
// shrink proportionally to amount over minimum
// so we can do this in one pass
- delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
- shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
+ delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0;
+ shrink_headroom_available -= (cur_width - (*panel_it)->mMinDim);
}
else
{
@@ -643,7 +491,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
num_resizable_panels--;
}
pixels_to_distribute -= delta_size;
- new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
+ new_width = llmax((*panel_it)->mMinDim, cur_width + delta_size);
}
else
{
@@ -656,8 +504,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
// shrink proportionally to amount over minimum
// so we can do this in one pass
- delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
- shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
+ delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0;
+ shrink_headroom_available -= (cur_height - (*panel_it)->mMinDim);
}
else
{
@@ -665,7 +513,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
num_resizable_panels--;
}
pixels_to_distribute -= delta_size;
- new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
+ new_height = llmax((*panel_it)->mMinDim, cur_height + delta_size);
}
else
{
@@ -706,48 +554,48 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
if (mOrientation == HORIZONTAL)
{
- cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
+ cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
}
else //VERTICAL
{
- cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
+ cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
}
}
// update resize bars with new limits
- LLResizeBar* last_resize_bar = NULL;
+ LLLayoutPanel* last_resizeable_panel = NULL;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- LLPanel* panelp = (*panel_it)->mPanel;
+ LLPanel* panelp = (*panel_it);
if (mOrientation == HORIZONTAL)
{
(*panel_it)->mResizeBar->setResizeLimits(
- (*panel_it)->mMinWidth,
- (*panel_it)->mMinWidth + shrink_headroom_total);
+ (*panel_it)->mMinDim,
+ (*panel_it)->mMinDim + shrink_headroom_total);
}
else //VERTICAL
{
(*panel_it)->mResizeBar->setResizeLimits(
- (*panel_it)->mMinHeight,
- (*panel_it)->mMinHeight + shrink_headroom_total);
+ (*panel_it)->mMinDim,
+ (*panel_it)->mMinDim + shrink_headroom_total);
}
// toggle resize bars based on panel visibility, resizability, etc
BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
- if (resize_bar_enabled)
+ if ((*panel_it)->mUserResize || (*panel_it)->mAutoResize)
{
- last_resize_bar = (*panel_it)->mResizeBar;
+ last_resizeable_panel = (*panel_it);
}
}
// hide last resize bar as there is nothing past it
// resize bars need to be in between two resizable panels
- if (last_resize_bar)
+ if (last_resizeable_panel)
{
- last_resize_bar->setVisible(FALSE);
+ last_resizeable_panel->mResizeBar->setVisible(FALSE);
}
// not enough room to fit existing contents
@@ -766,14 +614,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
} // end LLLayoutStack::updateLayout
-LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
+LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
{
if (!panelp) return NULL;
e_panel_list_t::const_iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- if ((*panel_it)->mPanel == panelp)
+ if ((*panel_it) == panelp)
{
return *panel_it;
}
@@ -781,15 +629,15 @@ LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) co
return NULL;
}
-LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
+LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
{
- LayoutPanel* result = NULL;
+ LLLayoutPanel* result = NULL;
for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- LayoutPanel* p = *panel_it;
+ LLLayoutPanel* p = *panel_it;
- if (p->mPanel->getName() == name)
+ if (p->getName() == name)
{
result = p;
break;
@@ -810,9 +658,7 @@ void LLLayoutStack::calcMinExtents()
{
if (mOrientation == HORIZONTAL)
{
- mMinHeight = llmax( mMinHeight,
- (*panel_it)->mMinHeight);
- mMinWidth += (*panel_it)->mMinWidth;
+ mMinWidth += (*panel_it)->mMinDim;
if (panel_it != mPanels.begin())
{
mMinWidth += mPanelSpacing;
@@ -820,9 +666,7 @@ void LLLayoutStack::calcMinExtents()
}
else //VERTICAL
{
- mMinWidth = llmax( mMinWidth,
- (*panel_it)->mMinWidth);
- mMinHeight += (*panel_it)->mMinHeight;
+ mMinHeight += (*panel_it)->mMinDim;
if (panel_it != mPanels.begin())
{
mMinHeight += mPanelSpacing;
@@ -831,6 +675,37 @@ void LLLayoutStack::calcMinExtents()
}
}
+void LLLayoutStack::createResizeBars()
+{
+ for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+ {
+ LLLayoutPanel* lp = (*panel_it);
+ if (lp->mResizeBar == NULL)
+ {
+ LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
+ LLRect resize_bar_rect = getRect();
+
+ LLResizeBar::Params resize_params;
+ resize_params.name("resize");
+ resize_params.resizing_view(lp);
+ resize_params.min_size(lp->mMinDim);
+ resize_params.side(side);
+ resize_params.snapping_enabled(false);
+ LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params);
+ lp->mResizeBar = resize_bar;
+ LLView::addChild(resize_bar, 0);
+
+ // bring all resize bars to the front so that they are clickable even over the panels
+ // with a bit of overlap
+ for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+ {
+ LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
+ sendChildToFront(resize_barp);
+ }
+ }
+ }
+}
+
// update layout stack animations, etc. once per frame
// NOTE: we use this to size world view based on animating UI, *before* we draw the UI
// we might still need to call updateLayout during UI draw phase, in case UI elements
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index cd59ee3966..4ac8ef0ee9 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -28,34 +28,50 @@
#ifndef LL_LLLAYOUTSTACK_H
#define LL_LLLAYOUTSTACK_H
-#include "llview.h"
+#include "llpanel.h"
class LLPanel;
+class LLLayoutPanel;
+
class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
{
public:
+ typedef enum e_layout_orientation
+ {
+ HORIZONTAL,
+ VERTICAL
+ } ELayoutOrientation;
+
+ struct OrientationNames
+ : public LLInitParam::TypeValuesHelper<ELayoutOrientation, OrientationNames>
+ {
+ static void declareValues();
+ };
+
+ struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>
+ {};
+
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
- Optional<std::string> orientation;
+ Mandatory<ELayoutOrientation, OrientationNames> orientation;
Optional<S32> border_size;
Optional<bool> animate,
clip;
+ Optional<F32> open_time_constant,
+ close_time_constant;
Params();
};
- typedef enum e_layout_orientation
- {
- HORIZONTAL,
- VERTICAL
- } ELayoutOrientation;
+ typedef LayoutStackRegistry child_registry_t;
virtual ~LLLayoutStack();
/*virtual*/ void draw();
/*virtual*/ void removeChild(LLView*);
/*virtual*/ BOOL postBuild();
+ /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
@@ -68,29 +84,32 @@ public:
ANIMATE
} EAnimate;
- void addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
+ void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE);
void removePanel(LLPanel* panel);
void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
S32 getNumPanels() { return mPanels.size(); }
+ /**
+ * Moves panel_to_move before target_panel inside layout stack (both panels should already be there).
+ * If move_to_front is true target_panel is ignored and panel_to_move is moved to the beginning of mPanels
+ */
+ void movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front = false);
void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize);
void setPanelUserResize(const std::string& panel_name, BOOL user_resize);
/**
- * Gets minimal width and/or height of the specified by name panel.
+ * Gets minimal dimension along layout_stack axis of the specified by name panel.
*
- * If it is necessary to get only the one dimension pass NULL for another one.
* @returns true if specified by panel_name internal panel exists, false otherwise.
*/
- bool getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp);
+ bool getPanelMinSize(const std::string& panel_name, S32* min_dimp);
/**
- * Gets maximal width and/or height of the specified by name panel.
+ * Gets maximal dimension along layout_stack axis of the specified by name panel.
*
- * If it is necessary to get only the one dimension pass NULL for another one.
* @returns true if specified by panel_name internal panel exists, false otherwise.
*/
- bool getPanelMaxSize(const std::string& panel_name, S32* max_width, S32* max_height);
+ bool getPanelMaxSize(const std::string& panel_name, S32* max_dim);
void updateLayout(BOOL force_resize = FALSE);
@@ -105,19 +124,18 @@ protected:
friend class LLUICtrlFactory;
private:
- struct LayoutPanel;
-
+ void createResizeBars();
void calcMinExtents();
S32 getDefaultHeight(S32 cur_height);
S32 getDefaultWidth(S32 cur_width);
const ELayoutOrientation mOrientation;
- typedef std::vector<LayoutPanel*> e_panel_list_t;
+ typedef std::vector<LLLayoutPanel*> e_panel_list_t;
e_panel_list_t mPanels;
- LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
- LayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
+ LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
+ LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
S32 mMinWidth; // calculated by calcMinExtents
S32 mMinHeight; // calculated by calcMinExtents
@@ -127,6 +145,56 @@ private:
bool mAnimatedThisFrame;
bool mAnimate;
bool mClip;
+ F32 mOpenTimeConstant;
+ F32 mCloseTimeConstant;
}; // end class LLLayoutStack
+class LLLayoutPanel : public LLPanel
+{
+friend class LLLayoutStack;
+friend class LLUICtrlFactory;
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ Optional<S32> min_dim,
+ max_dim;
+ Optional<bool> user_resize,
+ auto_resize;
+
+ Params()
+ : min_dim("min_dim", 0),
+ max_dim("max_dim", 0),
+ user_resize("user_resize", true),
+ auto_resize("auto_resize", true)
+ {
+ addSynonym(min_dim, "min_width");
+ addSynonym(min_dim, "min_height");
+ addSynonym(max_dim, "max_width");
+ addSynonym(max_dim, "max_height");
+ }
+ };
+
+ ~LLLayoutPanel();
+
+ void initFromParams(const Params& p);
+ void setMinDim(S32 value) { mMinDim = value; }
+ void setMaxDim(S32 value) { mMaxDim = value; }
+
+protected:
+ LLLayoutPanel(const Params& p) ;
+
+
+ F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation);
+
+ S32 mMinDim;
+ S32 mMaxDim;
+ BOOL mAutoResize;
+ BOOL mUserResize;
+ BOOL mCollapsed;
+ class LLResizeBar* mResizeBar;
+ F32 mVisibleAmt;
+ F32 mCollapseAmt;
+};
+
+
#endif
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 2759167d04..0196080d90 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -78,7 +78,7 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>(
//
LLLineEditor::Params::Params()
-: max_length_bytes("max_length", 254),
+: max_length(""),
keystroke_callback("keystroke_callback"),
prevalidate_callback("prevalidate_callback"),
background_image("background_image"),
@@ -88,6 +88,7 @@ LLLineEditor::Params::Params()
revert_on_esc("revert_on_esc", true),
commit_on_focus_lost("commit_on_focus_lost", true),
ignore_tab("ignore_tab", true),
+ is_password("is_password", false),
cursor_color("cursor_color"),
text_color("text_color"),
text_readonly_color("text_readonly_color"),
@@ -108,7 +109,8 @@ LLLineEditor::Params::Params()
LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
: LLUICtrl(p),
- mMaxLengthBytes(p.max_length_bytes),
+ mMaxLengthBytes(p.max_length.bytes),
+ mMaxLengthChars(p.max_length.chars),
mCursorPos( 0 ),
mScrollHPos( 0 ),
mTextPadLeft(p.text_pad_left),
@@ -128,7 +130,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mBorderThickness( 0 ),
mIgnoreArrowKeys( FALSE ),
mIgnoreTab( p.ignore_tab ),
- mDrawAsterixes( FALSE ),
+ mDrawAsterixes( p.is_password ),
mSelectAllonFocusReceived( p.select_on_focus ),
mPassDelete(FALSE),
mReadOnly(FALSE),
@@ -313,6 +315,12 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
mMaxLengthBytes = max_len;
}
+void LLLineEditor::setMaxTextChars(S32 max_text_chars)
+{
+ S32 max_chars = llmax(0, max_text_chars);
+ mMaxLengthChars = max_chars;
+}
+
void LLLineEditor::getTextPadding(S32 *left, S32 *right)
{
*left = mTextPadLeft;
@@ -358,6 +366,16 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
}
mText.assign(truncated_utf8);
+ if (mMaxLengthChars)
+ {
+ LLWString truncated_wstring = utf8str_to_wstring(truncated_utf8);
+ if (truncated_wstring.size() > (U32)mMaxLengthChars)
+ {
+ truncated_wstring = truncated_wstring.substr(0, mMaxLengthChars);
+ }
+ mText.assign(wstring_to_utf8str(truncated_wstring));
+ }
+
if (all_selected)
{
// ...keep whole thing selected
@@ -371,7 +389,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
setCursor(llmin((S32)mText.length(), getCursor()));
// Set current history line to end of history.
- if(mLineHistory.end() != mLineHistory.begin())
+ if (mLineHistory.empty())
+ {
+ mCurrentHistoryLine = mLineHistory.end();
+ }
+ else
{
mCurrentHistoryLine = mLineHistory.end() - 1;
}
@@ -798,6 +820,7 @@ void LLLineEditor::addChar(const llwchar uni_char)
}
S32 cur_bytes = mText.getString().size();
+
S32 new_bytes = wchar_utf8_length(new_c);
BOOL allow_char = TRUE;
@@ -807,6 +830,14 @@ void LLLineEditor::addChar(const llwchar uni_char)
{
allow_char = FALSE;
}
+ else if (mMaxLengthChars)
+ {
+ S32 wide_chars = mText.getWString().size();
+ if ((wide_chars + 1) > mMaxLengthChars)
+ {
+ allow_char = FALSE;
+ }
+ }
if (allow_char)
{
@@ -1107,7 +1138,19 @@ void LLLineEditor::pasteHelper(bool is_primary)
clean_string = clean_string.substr(0, wchars_that_fit);
LLUI::reportBadKeystroke();
}
-
+
+ if (mMaxLengthChars)
+ {
+ U32 available_chars = mMaxLengthChars - mText.getWString().size();
+
+ if (available_chars < clean_string.size())
+ {
+ clean_string = clean_string.substr(0, available_chars);
+ }
+
+ LLUI::reportBadKeystroke();
+ }
+
mText.insert(getCursor(), clean_string);
setCursor( getCursor() + (S32)clean_string.length() );
deselect();
@@ -1266,12 +1309,12 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
// handle ctrl-uparrow if we have a history enabled line editor.
case KEY_UP:
- if( mHaveHistory && ( MASK_CONTROL == mask ) )
+ if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) )
{
if( mCurrentHistoryLine > mLineHistory.begin() )
{
mText.assign( *(--mCurrentHistoryLine) );
- setCursor(llmin((S32)mText.length(), getCursor()));
+ setCursorToEnd();
}
else
{
@@ -1281,14 +1324,14 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
break;
- // handle ctrl-downarrow if we have a history enabled line editor
+ // handle [ctrl]-downarrow if we have a history enabled line editor
case KEY_DOWN:
- if( mHaveHistory && ( MASK_CONTROL == mask ) )
+ if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) )
{
if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 )
{
mText.assign( *(++mCurrentHistoryLine) );
- setCursor(llmin((S32)mText.length(), getCursor()));
+ setCursorToEnd();
}
else
{
@@ -1491,8 +1534,11 @@ void LLLineEditor::drawBackground()
{
image = mBgImage;
}
+
+ if (!image) return;
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = getCurrentTransparency();
+
// optionally draw programmatic border
if (has_focus)
{
@@ -2248,3 +2294,8 @@ void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu)
else
mContextMenuHandle.markDead();
}
+
+void LLLineEditor::setFont(const LLFontGL* font)
+{
+ mGLFont = font;
+}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 76d0187712..fe191e5971 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -41,6 +41,7 @@
#include "lleditmenuhandler.h"
#include "lluictrl.h"
+#include "lluiimage.h"
#include "lluistring.h"
#include "llviewborder.h"
@@ -59,11 +60,19 @@ public:
typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t;
+ struct MaxLength : public LLInitParam::Choice<MaxLength>
+ {
+ Alternative<S32> bytes, chars;
+
+ MaxLength() : bytes("max_length_bytes", 254),
+ chars("max_length_chars", 0)
+ {}
+ };
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<std::string> default_text;
- Optional<S32> max_length_bytes;
-
+ Optional<MaxLength> max_length;
Optional<keystroke_callback_t> keystroke_callback;
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
@@ -77,7 +86,8 @@ public:
Optional<bool> select_on_focus,
revert_on_esc,
commit_on_focus_lost,
- ignore_tab;
+ ignore_tab,
+ is_password;
// colors
Optional<LLUIColor> cursor_color,
@@ -192,6 +202,7 @@ public:
const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
const LLFontGL* getFont() const { return mGLFont; }
+ void setFont(const LLFontGL* font);
void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(BOOL b) { mIgnoreTab = b; }
@@ -214,6 +225,7 @@ public:
void setKeystrokeCallback(callback_t callback, void* user_data);
void setMaxTextLength(S32 max_text_length);
+ void setMaxTextChars(S32 max_text_chars);
// Manipulate left and right padding for text
void getTextPadding(S32 *left, S32 *right);
void setTextPadding(S32 left, S32 right);
@@ -277,6 +289,7 @@ protected:
LLViewBorder* mBorder;
const LLFontGL* mGLFont;
S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes
+ S32 mMaxLengthChars; // Maximum number of characters in the string
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling.
LLFrameTimer mScrollTimer;
@@ -326,7 +339,7 @@ protected:
std::vector<S32> mPreeditPositions;
LLPreeditor::standouts_t mPreeditStandouts;
- LLHandle<LLView> mContextMenuHandle;
+ LLHandle<LLContextMenu> mContextMenuHandle;
private:
// Instances that by default point to the statics but can be overidden in XML.
diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp
index 7b29d92ea0..c4eec1835c 100644
--- a/indra/llui/llloadingindicator.cpp
+++ b/indra/llui/llloadingindicator.cpp
@@ -39,56 +39,24 @@
//static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
///////////////////////////////////////////////////////////////////////////////
-// LLLoadingIndicator::Data class
+// LLLoadingIndicator class
///////////////////////////////////////////////////////////////////////////////
-/**
- * Pre-loaded images shared by all instances of the widget
- */
-class LLLoadingIndicator::Data: public LLSingleton<LLLoadingIndicator::Data>
+LLLoadingIndicator::LLLoadingIndicator(const Params& p)
+: LLUICtrl(p),
+ mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f),
+ mCurImageIdx(0)
{
-public:
- /*virtual*/ void initSingleton(); // from LLSingleton
-
- LLPointer<LLUIImage> getNextImage(S8& idx) const;
- U8 getImagesCount() const { return NIMAGES; }
-private:
-
- static const U8 NIMAGES = 12;
- LLPointer<LLUIImage> mImages[NIMAGES];
-};
+}
-// virtual
-// Called right after the instance gets constructed.
-void LLLoadingIndicator::Data::initSingleton()
+void LLLoadingIndicator::initFromParams(const Params& p)
{
- // Load images.
- for (U8 i = 0; i < NIMAGES; ++i)
+ for (LLInitParam::ParamIterator<LLUIImage*>::const_iterator it = p.images().image.begin(), end_it = p.images().image.end();
+ it != end_it;
+ ++it)
{
- std::string img_name = llformat("Progress_%d", i+1);
- mImages[i] = LLUI::getUIImage(img_name, 0);
- llassert(mImages[i]);
+ mImages.push_back(it->getValue());
}
-}
-
-LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
-{
- // Calculate next index, performing array bounds checking.
- idx = (idx >= NIMAGES || idx < 0) ? 0 : (idx + 1) % NIMAGES;
- return mImages[idx];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// LLLoadingIndicator class
-///////////////////////////////////////////////////////////////////////////////
-
-LLLoadingIndicator::LLLoadingIndicator(const Params& p)
-: LLUICtrl(p)
- , mRotationsPerSec(p.rotations_per_sec > 0 ? p.rotations_per_sec : 1.0f)
- , mCurImageIdx(-1)
-{
- // Select initial image.
- mCurImagep = Data::instance().getNextImage(mCurImageIdx);
// Start timer for switching images.
start();
@@ -100,16 +68,21 @@ void LLLoadingIndicator::draw()
if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
{
// Switch to the next image.
- mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+ if (!mImages.empty())
+ {
+ mCurImageIdx = (mCurImageIdx + 1) % mImages.size();
+ }
// Restart timer.
start();
}
+ LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx];
+
// Draw current image.
- if( mCurImagep.notNull() )
+ if( cur_image.notNull() )
{
- mCurImagep->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
+ cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
}
LLUICtrl::draw();
@@ -123,6 +96,6 @@ void LLLoadingIndicator::stop()
void LLLoadingIndicator::start()
{
mImageSwitchTimer.start();
- F32 period = 1.0f / (Data::instance().getImagesCount() * mRotationsPerSec);
+ F32 period = 1.0f / (mImages.size() * mImagesPerSec);
mImageSwitchTimer.setTimerExpirySec(period);
}
diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h
index 4e4a224ef6..4c47cc267c 100644
--- a/indra/llui/llloadingindicator.h
+++ b/indra/llui/llloadingindicator.h
@@ -28,6 +28,7 @@
#define LL_LLLOADINGINDICATOR_H
#include "lluictrl.h"
+#include "lluiimage.h"
///////////////////////////////////////////////////////////////////////////////
// class LLLoadingIndicator
@@ -36,8 +37,8 @@
/**
* Perpetual loading indicator (a la MacOSX or YouTube)
*
- * Number of rotations per second can be overriden
- * with the "roations_per_sec" parameter.
+ * Number of rotations per second can be overridden
+ * with the "images_per_sec" parameter.
*
* Can start/stop spinning.
*
@@ -49,11 +50,24 @@ class LLLoadingIndicator
{
LOG_CLASS(LLLoadingIndicator);
public:
+
+ struct Images : public LLInitParam::Block<Images>
+ {
+ Multiple<LLUIImage*> image;
+
+ Images()
+ : image("image")
+ {}
+ };
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<F32> rotations_per_sec;
+ Optional<F32> images_per_sec;
+ Batch<Images> images;
+
Params()
- : rotations_per_sec("rotations_per_sec", 1.0f)
+ : images_per_sec("images_per_sec", 1.0f),
+ images("images")
{}
};
@@ -74,14 +88,15 @@ public:
private:
LLLoadingIndicator(const Params&);
- friend class LLUICtrlFactory;
+ void initFromParams(const Params&);
- class Data;
+ friend class LLUICtrlFactory;
- F32 mRotationsPerSec;
+ F32 mImagesPerSec;
S8 mCurImageIdx;
- LLPointer<LLUIImage> mCurImagep;
LLFrameTimer mImageSwitchTimer;
+
+ std::vector<LLUIImagePtr> mImages;
};
#endif // LL_LLLOADINGINDICATOR_H
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 3df05f4d3f..eed0085273 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,7 +29,7 @@
#include "llmenubutton.h"
// Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
@@ -44,58 +44,77 @@ LLMenuButton::Params::Params()
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
- mMenu(NULL),
- mMenuVisibleLastFrame(false)
+ mIsMenuShown(false),
+ mMenuPosition(MP_BOTTOM_LEFT)
{
std::string menu_filename = p.menu_filename;
if (!menu_filename.empty())
{
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!mMenu)
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
+ return;
}
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+
+ mMenuHandle = menu->getHandle();
+
+ updateMenuOrigin();
}
}
-void LLMenuButton::toggleMenu()
+boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
{
- if(!mMenu)
- return;
+ return LLUICtrl::setMouseDownCallback(cb);
+}
- if (mMenu->getVisible() || mMenuVisibleLastFrame)
- {
- mMenu->setVisible(FALSE);
- }
- else
+void LLMenuButton::hideMenu()
+{
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu)
{
- LLRect rect = getRect();
- //mMenu->needsArrange(); //so it recalculates the visible elements
- LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
+ menu->setVisible(FALSE);
}
}
-
-void LLMenuButton::hideMenu()
-{
- if(!mMenu)
- return;
- mMenu->setVisible(FALSE);
+LLToggleableMenu* LLMenuButton::getMenu()
+{
+ return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
+{
+ if (!menu) return;
+
+ mMenuHandle = menu->getHandle();
+ mMenuPosition = position;
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
+ if (mMenuHandle.isDead()) return FALSE;
+
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
+ // *HACK: We emit the mouse down signal to fire the callback bound to the
+ // menu emerging event before actually displaying the menu. See STORM-263.
+ LLUICtrl::handleMouseDown(-1, -1, MASK_NONE);
+
toggleMenu();
return TRUE;
}
- if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
- mMenu->setVisible(FALSE);
+ menu->setVisible(FALSE);
return TRUE;
}
@@ -104,34 +123,84 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
- if (hasTabStop() && !getIsChrome())
- {
- setFocus(TRUE);
- }
+ LLButton::handleMouseDown(x, y, mask);
toggleMenu();
- if (getSoundFlags() & MOUSE_DOWN)
- {
- make_ui_sound("UISndClick");
- }
-
return TRUE;
}
-void LLMenuButton::draw()
+void LLMenuButton::toggleMenu()
{
- //we save this off so next frame when we try to close it by
- //button click, and it hides menus before we get to it, we know
- mMenuVisibleLastFrame = mMenu && mMenu->getVisible();
-
- if (mMenuVisibleLastFrame)
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (!menu) return;
+
+ // Store the button rectangle to toggle menu visibility if a mouse event
+ // occurred inside or outside the button rect.
+ menu->setButtonRect(this);
+
+ if (!menu->toggleVisibility() && mIsMenuShown)
{
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+ else
+ {
+ menu->buildDrawLabels();
+ menu->arrangeAndClear();
+ menu->updateParent(LLMenuGL::sMenuContainer);
+
+ updateMenuOrigin();
+
+ LLMenuGL::showPopup(getParent(), menu, mX, mY);
+
setForcePressedState(true);
+ mIsMenuShown = true;
}
+}
- LLButton::draw();
+void LLMenuButton::updateMenuOrigin()
+{
+ if (mMenuHandle.isDead()) return;
+
+ LLRect rect = getRect();
- setForcePressedState(false);
+ switch (mMenuPosition)
+ {
+ case MP_TOP_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
+ break;
+ }
+ case MP_TOP_RIGHT:
+ {
+ const LLRect& menu_rect = mMenuHandle.get()->getRect();
+ mX = rect.mRight - menu_rect.getWidth();
+ mY = rect.mTop + menu_rect.getHeight();
+ break;
+ }
+ case MP_BOTTOM_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mBottom;
+ break;
+ }
+ }
}
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+ bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
+
+ // Reset the button "pressed" state only if the menu is shown by this particular
+ // menu button (not any other control) and is not being closed by a click on the button.
+ if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
+ {
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+}
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 81ca0e047c..7b657595da 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -29,7 +29,7 @@
#include "llbutton.h"
-class LLMenuGL;
+class LLToggleableMenu;
class LLMenuButton
: public LLButton
@@ -42,22 +42,42 @@ public:
Optional<std::string> menu_filename;
Params();
- };
+ };
+
+ typedef enum e_menu_position
+ {
+ MP_TOP_LEFT,
+ MP_TOP_RIGHT,
+ MP_BOTTOM_LEFT
+ } EMenuPosition;
- void toggleMenu();
- /*virtual*/ void draw();
+ boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
+
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
+
void hideMenu();
- LLMenuGL* getMenu() { return mMenu; }
+
+ LLToggleableMenu* getMenu();
+ void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
+
+ void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
protected:
friend class LLUICtrlFactory;
LLMenuButton(const Params&);
+ void toggleMenu();
+ void updateMenuOrigin();
+
+ void onMenuVisibilityChange(const LLSD& param);
+
private:
- LLMenuGL* mMenu;
- bool mMenuVisibleLastFrame;
+ LLHandle<LLView> mMenuHandle;
+ bool mIsMenuShown;
+ EMenuPosition mMenuPosition;
+ S32 mX;
+ S32 mY;
};
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 900a814238..8de9c769e2 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1462,7 +1462,7 @@ BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)
{
BOOL branch_visible = getBranch()->getVisible();
BOOL handled = getBranch()->handleAcceleratorKey(key, mask);
- if (handled && !branch_visible && getVisible())
+ if (handled && !branch_visible && isInVisibleChain())
{
// flash this menu entry because we triggered an invisible menu item
LLMenuHolderGL::setActivatedItem(this);
@@ -1637,6 +1637,10 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p)
}
LLButton::Params bparams;
+
+ // Disabled the Return key handling by LLMenuScrollItem instead of
+ // passing the key press to the currently selected menu item. See STORM-385.
+ bparams.commit_on_return(false);
bparams.mouse_opaque(true);
bparams.scale_image(false);
bparams.click_callback(p.scroll_callback);
@@ -1848,89 +1852,110 @@ BOOL LLMenuGL::isOpen()
}
}
-void LLMenuGL::scrollItemsUp()
+
+
+bool LLMenuGL::scrollItems(EScrollingDirection direction)
{
- // Slowing down the items scrolling when arrow button is held
+ // Slowing down items scrolling when arrow button is held
if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
{
mScrollItemsTimer.setTimerExpirySec(.033f);
}
else
{
- return;
+ return false;
}
- item_list_t::iterator cur_item_iter;
- item_list_t::iterator prev_item_iter;
- for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
+ switch (direction)
{
- if( (*cur_item_iter) == mFirstVisibleItem)
+ case SD_UP:
+ {
+ item_list_t::iterator cur_item_iter;
+ item_list_t::iterator prev_item_iter;
+ for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- break;
+ if( (*cur_item_iter) == mFirstVisibleItem)
+ {
+ break;
+ }
+ if ((*cur_item_iter)->getVisible())
+ {
+ prev_item_iter = cur_item_iter;
+ }
}
- if ((*cur_item_iter)->getVisible())
+
+ if ((*prev_item_iter)->getVisible())
{
- prev_item_iter = cur_item_iter;
+ mFirstVisibleItem = *prev_item_iter;
}
+ break;
}
-
- if ((*prev_item_iter)->getVisible())
- {
- mFirstVisibleItem = *prev_item_iter;
- }
-
- mNeedsArrange = TRUE;
- arrangeAndClear();
-}
-
-void LLMenuGL::scrollItemsDown()
-{
- // Slowing down the items scrolling when arrow button is held
- if (mScrollItemsTimer.hasExpired())
- {
- mScrollItemsTimer.setTimerExpirySec(.033f);
- }
- else
+ case SD_DOWN:
{
- return;
- }
-
- if (NULL == mFirstVisibleItem)
- {
- mFirstVisibleItem = *mItems.begin();
- }
-
- item_list_t::iterator cur_item_iter;
-
- for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
- {
- if( (*cur_item_iter) == mFirstVisibleItem)
+ if (NULL == mFirstVisibleItem)
{
- break;
+ mFirstVisibleItem = *mItems.begin();
}
- }
- item_list_t::iterator next_item_iter;
+ item_list_t::iterator cur_item_iter;
- if (cur_item_iter != mItems.end())
- {
- for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
+ for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- if( (*next_item_iter)->getVisible())
+ if( (*cur_item_iter) == mFirstVisibleItem)
{
break;
}
}
-
- if (next_item_iter != mItems.end() &&
- (*next_item_iter)->getVisible())
+
+ item_list_t::iterator next_item_iter;
+
+ if (cur_item_iter != mItems.end())
{
- mFirstVisibleItem = *next_item_iter;
+ for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
+ {
+ if( (*next_item_iter)->getVisible())
+ {
+ break;
+ }
+ }
+
+ if (next_item_iter != mItems.end() &&
+ (*next_item_iter)->getVisible())
+ {
+ mFirstVisibleItem = *next_item_iter;
+ }
}
+ break;
}
-
+ case SD_BEGIN:
+ {
+ mFirstVisibleItem = *mItems.begin();
+ break;
+ }
+ case SD_END:
+ {
+ item_list_t::reverse_iterator first_visible_item_iter = mItems.rend();
+
+ // Need to scroll through number of actual existing items in menu.
+ // Otherwise viewer will hang for a time needed to scroll U32_MAX
+ // times in std::advance(). STORM-659.
+ size_t nitems = mItems.size();
+ U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems;
+
+ // Advance by mMaxScrollableItems back from the end of the list
+ // to make the last item visible.
+ std::advance(first_visible_item_iter, scrollable_items);
+ mFirstVisibleItem = *first_visible_item_iter;
+ break;
+ }
+ default:
+ llwarns << "Unknown scrolling direction: " << direction << llendl;
+ }
+
mNeedsArrange = TRUE;
arrangeAndClear();
+
+ return true;
}
// rearrange the child rects so they fit the shape of the menu.
@@ -2162,7 +2187,7 @@ void LLMenuGL::arrange( void )
LLMenuScrollItem::Params item_params;
item_params.name(ARROW_UP);
item_params.arrow_type(LLMenuScrollItem::ARROW_UP);
- item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this));
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP));
mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
LLUICtrl::addChild(mArrowUpItem);
@@ -2173,7 +2198,7 @@ void LLMenuGL::arrange( void )
LLMenuScrollItem::Params item_params;
item_params.name(ARROW_DOWN);
item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN);
- item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this));
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN));
mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
LLUICtrl::addChild(mArrowDownItem);
@@ -2596,6 +2621,7 @@ LLMenuItemGL* LLMenuGL::getHighlightedItem()
LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
{
+ if (mItems.empty()) return NULL;
// highlighting first item on a torn off menu is the
// same as giving focus to it
if (!cur_item && getTornOff())
@@ -2603,14 +2629,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
((LLFloater*)getParent())->setFocus(TRUE);
}
- item_list_t::iterator cur_item_iter;
- for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter)
- {
- if( (*cur_item_iter) == cur_item)
- {
- break;
- }
- }
+ // Current item position in the items list
+ item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item);
item_list_t::iterator next_item_iter;
if (cur_item_iter == mItems.end())
@@ -2621,9 +2641,37 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
{
next_item_iter = cur_item_iter;
next_item_iter++;
+
+ // First visible item position in the items list
+ item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem);
+
if (next_item_iter == mItems.end())
{
next_item_iter = mItems.begin();
+
+ // If current item is the last in the list, the menu is scrolled to the beginning
+ // and the first item is highlighted.
+ if (mScrollable && !scrollItems(SD_BEGIN))
+ {
+ return NULL;
+ }
+ }
+ // If current item is the last visible, the menu is scrolled one item down
+ // and the next item is highlighted.
+ else if (mScrollable &&
+ (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems)
+ {
+ // Call highlightNextItem() recursively only if the menu was successfully scrolled down.
+ // If scroll timer hasn't expired yet the menu won't be scrolled and calling
+ // highlightNextItem() will result in an endless recursion.
+ if (scrollItems(SD_DOWN))
+ {
+ return highlightNextItem(cur_item, skip_disabled);
+ }
+ else
+ {
+ return NULL;
+ }
}
}
@@ -2674,6 +2722,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
{
+ if (mItems.empty()) return NULL;
+
// highlighting first item on a torn off menu is the
// same as giving focus to it
if (!cur_item && getTornOff())
@@ -2681,14 +2731,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
((LLFloater*)getParent())->setFocus(TRUE);
}
- item_list_t::reverse_iterator cur_item_iter;
- for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter)
- {
- if( (*cur_item_iter) == cur_item)
- {
- break;
- }
- }
+ // Current item reverse position from the end of the list
+ item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item);
item_list_t::reverse_iterator prev_item_iter;
if (cur_item_iter == mItems.rend())
@@ -2699,9 +2743,37 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
{
prev_item_iter = cur_item_iter;
prev_item_iter++;
+
+ // First visible item reverse position in the items list
+ item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem);
+
if (prev_item_iter == mItems.rend())
{
prev_item_iter = mItems.rbegin();
+
+ // If current item is the first in the list, the menu is scrolled to the end
+ // and the last item is highlighted.
+ if (mScrollable && !scrollItems(SD_END))
+ {
+ return NULL;
+ }
+ }
+ // If current item is the first visible, the menu is scrolled one item up
+ // and the previous item is highlighted.
+ else if (mScrollable &&
+ std::distance(first_visible_item_iter, cur_item_iter) <= 0)
+ {
+ // Call highlightNextItem() only if the menu was successfully scrolled up.
+ // If scroll timer hasn't expired yet the menu won't be scrolled and calling
+ // highlightNextItem() will result in an endless recursion.
+ if (scrollItems(SD_UP))
+ {
+ return highlightPrevItem(cur_item, skip_disabled);
+ }
+ else
+ {
+ return NULL;
+ }
}
}
@@ -2872,12 +2944,12 @@ BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
if( clicks > 0 )
{
while( clicks-- )
- scrollItemsDown();
+ scrollItems(SD_DOWN);
}
else
{
while( clicks++ )
- scrollItemsUp();
+ scrollItems(SD_UP);
}
return TRUE;
@@ -2986,6 +3058,11 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size
const S32 CURSOR_WIDTH = 12;
+ if(menu->getChildList()->empty())
+ {
+ return;
+ }
+
// 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.
@@ -3028,9 +3105,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE );
menu->getParent()->sendChildToFront(menu);
-
-
-
}
///============================================================================
@@ -3066,7 +3140,10 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
mAltKeyTrigger = FALSE;
}
- if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
+ if(!result
+ && (key == KEY_F10 && mask == MASK_CONTROL)
+ && !gKeyboard->getKeyRepeated(key)
+ && isInVisibleChain())
{
if (getHighlightedItem())
{
@@ -3449,8 +3526,10 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
else
{
//highlight first enabled one
- pMenu->highlightNextItem(NULL);
- handled = true;
+ if(pMenu->highlightNextItem(NULL))
+ {
+ handled = true;
+ }
}
}
}
@@ -3683,9 +3762,7 @@ public:
LLContextMenuBranch(const Params&);
virtual ~LLContextMenuBranch()
- {
- delete mBranch;
- }
+ {}
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -3693,21 +3770,21 @@ public:
// onCommit() - do the primary funcationality of the menu item.
virtual void onCommit( void );
- LLContextMenu* getBranch() { return mBranch; }
+ LLContextMenu* getBranch() { return mBranch.get(); }
void setHighlight( BOOL highlight );
protected:
void showSubMenu();
- LLContextMenu* mBranch;
+ LLHandle<LLContextMenu> mBranch;
};
LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)
: LLMenuItemGL(p),
- mBranch( p.branch )
+ mBranch( p.branch()->getHandle() )
{
- mBranch->hide();
- mBranch->setParentMenuItem(this);
+ mBranch.get()->hide();
+ mBranch.get()->setParentMenuItem(this);
}
// called to rebuild the draw label
@@ -3716,12 +3793,12 @@ void LLContextMenuBranch::buildDrawLabel( void )
{
// default enablement is this -- if any of the subitems are
// enabled, this item is enabled. JC
- U32 sub_count = mBranch->getItemCount();
+ U32 sub_count = mBranch.get()->getItemCount();
U32 i;
BOOL any_enabled = FALSE;
for (i = 0; i < sub_count; i++)
{
- LLMenuItemGL* item = mBranch->getItem(i);
+ LLMenuItemGL* item = mBranch.get()->getItem(i);
item->buildDrawLabel();
if (item->getEnabled() && !item->getDrawTextDisabled() )
{
@@ -3738,19 +3815,18 @@ void LLContextMenuBranch::buildDrawLabel( void )
appendAcceleratorString( st );
mDrawAccelLabel = st;
- // No special branch suffix
- mDrawBranchLabel.clear();
+ mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX;
}
void LLContextMenuBranch::showSubMenu()
{
- LLMenuItemGL* menu_item = mBranch->getParentMenuItem();
+ LLMenuItemGL* menu_item = mBranch.get()->getParentMenuItem();
if (menu_item != NULL && menu_item->getVisible())
{
S32 center_x;
S32 center_y;
localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
- mBranch->show(center_x, center_y);
+ mBranch.get()->show(center_x, center_y);
}
}
@@ -3770,7 +3846,7 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )
}
else
{
- mBranch->hide();
+ mBranch.get()->hide();
}
}
@@ -3801,6 +3877,11 @@ void LLContextMenu::setVisible(BOOL visible)
// Takes cursor position in screen space?
void LLContextMenu::show(S32 x, S32 y)
{
+ if (getChildList()->empty())
+ {
+ // nothing to show, so abort
+ return;
+ }
// 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.
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 19b738312e..7bde8e83ec 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -397,6 +397,15 @@ public:
static const std::string ARROW_UP;
static const std::string ARROW_DOWN;
+ // for scrollable menus
+ typedef enum e_scrolling_direction
+ {
+ SD_UP = 0,
+ SD_DOWN = 1,
+ SD_BEGIN = 2,
+ SD_END = 3
+ } EScrollingDirection;
+
protected:
LLMenuGL(const LLMenuGL::Params& p);
friend class LLUICtrlFactory;
@@ -503,8 +512,7 @@ public:
S32 getShortcutPad() { return mShortcutPad; }
- void scrollItemsUp();
- void scrollItemsDown();
+ bool scrollItems(EScrollingDirection direction);
BOOL isScrollable() const { return mScrollable; }
static class LLMenuHolderGL* sMenuContainer;
@@ -670,9 +678,12 @@ public:
BOOL appendContextSubMenu(LLContextMenu *menu);
+ LLHandle<LLContextMenu> getHandle() { mHandle.bind(this); return mHandle; }
+
protected:
- BOOL mHoveredAnyItem;
- LLMenuItemGL* mHoverItem;
+ BOOL mHoveredAnyItem;
+ LLMenuItemGL* mHoverItem;
+ LLRootHandle<LLContextMenu> mHandle;
};
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index 1f6fa12969..f744e9db41 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -35,6 +35,7 @@
#include "llkeyboard.h" // for the MASK constants
#include "llcontrol.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
#include <sstream>
@@ -101,8 +102,8 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
}
- for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders().begin();
- it != p.sliders().end();
+ for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin();
+ it != p.sliders.end();
++it)
{
if (it->name.isProvided())
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index bd65625f53..91e5b6b9de 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -130,7 +130,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
params.name("MultiSliderCtrl Editor");
params.rect(text_rect);
params.font(p.font);
- params.max_length_bytes(MAX_STRING_LENGTH);
+ params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
params.prevalidate_callback(&LLTextValidate::validateFloat);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 99d540a9de..6085c61f9a 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -27,8 +27,12 @@
#include "linden_common.h"
#include "llnotifications.h"
+#include "llnotificationtemplate.h"
+#include "llnotificationvisibilityrule.h"
+#include "llavatarnamecache.h"
#include "llinstantmessage.h"
+#include "llcachename.h"
#include "llxmlnode.h"
#include "lluictrl.h"
#include "lluictrlfactory.h"
@@ -37,6 +41,8 @@
#include "lltrans.h"
#include "llnotificationslistener.h"
#include "llstring.h"
+#include "llsdparam.h"
+#include "llsdutil.h"
#include <algorithm>
#include <boost/regex.hpp>
@@ -44,6 +50,59 @@
const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
+void NotificationPriorityValues::declareValues()
+{
+ declare("low", NOTIFICATION_PRIORITY_LOW);
+ declare("normal", NOTIFICATION_PRIORITY_NORMAL);
+ declare("high", NOTIFICATION_PRIORITY_HIGH);
+ declare("critical", NOTIFICATION_PRIORITY_CRITICAL);
+}
+
+LLNotificationForm::FormElementBase::FormElementBase()
+: name("name")
+{}
+
+LLNotificationForm::FormIgnore::FormIgnore()
+: text("text"),
+ control("control"),
+ invert_control("invert_control", false),
+ save_option("save_option", false)
+{}
+
+LLNotificationForm::FormButton::FormButton()
+: index("index"),
+ text("text"),
+ ignore("ignore"),
+ is_default("default"),
+ type("type")
+{
+ // set type here so it gets serialized
+ type = "button";
+}
+
+LLNotificationForm::FormInput::FormInput()
+: type("type"),
+ text("text"),
+ max_length_chars("max_length_chars"),
+ width("width", 0),
+ value("value")
+{}
+
+LLNotificationForm::FormElement::FormElement()
+: button("button"),
+ input("input")
+{}
+
+LLNotificationForm::FormElements::FormElements()
+: elements("")
+{}
+
+LLNotificationForm::Params::Params()
+: name("name"),
+ ignore("ignore"),
+ form_elements("")
+{}
+
// Local channel for persistent notifications
// Stores only persistent notifications.
// Class users can use connectChanged() to process persistent notifications
@@ -80,20 +139,9 @@ private:
bool filterIgnoredNotifications(LLNotificationPtr notification)
{
- // filter everything if we are to ignore ALL
- if(LLNotifications::instance().getIgnoreAllNotifications())
- {
- return false;
- }
-
LLNotificationFormPtr form = notification->getForm();
// Check to see if the user wants to ignore this alert
- if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
- {
- return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
- }
-
- return true;
+ return !notification->getForm()->getIgnored();
}
bool handleIgnoredNotification(const LLSD& payload)
@@ -125,6 +173,28 @@ bool handleIgnoredNotification(const LLSD& payload)
return false;
}
+bool defaultResponse(const LLSD& payload)
+{
+ if (payload["sigtype"].asString() == "add")
+ {
+ LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
+ if (pNotif)
+ {
+ // supply default response
+ pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON));
+ }
+ }
+ return false;
+}
+
+bool visibilityRuleMached(const LLSD& payload)
+{
+ // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification.
+ // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order.
+ return true;
+}
+
+
namespace LLNotificationFilters
{
// a sample filter
@@ -135,63 +205,68 @@ namespace LLNotificationFilters
};
LLNotificationForm::LLNotificationForm()
-: mFormData(LLSD::emptyArray()),
- mIgnore(IGNORE_NO)
+: mIgnore(IGNORE_NO)
{
}
-LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node)
-: mFormData(LLSD::emptyArray()),
- mIgnore(IGNORE_NO)
+LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)
+: mIgnore(IGNORE_NO),
+ mInvertSetting(false) // ignore settings by default mean true=show, false=ignore
{
- if (!xml_node->hasName("form"))
+ if (p.ignore.isProvided())
{
- llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
- }
- LLXMLNodePtr child = xml_node->getFirstChild();
- while(child)
- {
- child = LLNotifications::instance().checkForXMLTemplate(child);
+ mIgnoreMsg = p.ignore.text;
- LLSD item_entry;
- std::string element_name = child->getName()->mString;
+ if (!p.ignore.save_option)
+ {
+ mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
+ }
+ else
+ {
+ // 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));
+ }
- if (element_name == "ignore" )
+ BOOL show_notification = TRUE;
+ if (p.ignore.control.isProvided())
{
- bool save_option = false;
- child->getAttribute_bool("save_option", save_option);
- if (!save_option)
- {
- mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
- }
- else
- {
- // 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));
- }
- child->getAttributeString("text", mIgnoreMsg);
- BOOL show_notification = TRUE;
- LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
+ mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control);
+ mInvertSetting = p.ignore.invert_control;
}
else
{
- // flatten xml form entry into single LLSD map with type==name
- item_entry["type"] = element_name;
- const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
- for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
- attrib_it != attrib_end;
- ++attrib_it)
- {
- item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
- }
- item_entry["value"] = child->getTextContents();
- mFormData.append(item_entry);
+ LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", TRUE);
+ mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
}
+ }
+
+ LLParamSDParser parser;
+ parser.writeSD(mFormData, p.form_elements);
+
+ mFormData = mFormData[""];
+ if (!mFormData.isArray())
+ {
+ // change existing contents to a one element array
+ LLSD new_llsd_array = LLSD::emptyArray();
+ new_llsd_array.append(mFormData);
+ mFormData = new_llsd_array;
+ }
- child = child->getNextSibling();
+ for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray();
+ it != end_it;
+ ++it)
+ {
+ // lift contents of form element up a level, since element type is already encoded in "type" param
+ if (it->isMap() && it->beginMap() != it->endMap())
+ {
+ *it = it->beginMap()->second;
+ }
}
+
+ LL_DEBUGS("Notifications") << name << LL_ENDL;
+ LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL;
}
LLNotificationForm::LLNotificationForm(const LLSD& sd)
@@ -293,16 +368,101 @@ std::string LLNotificationForm::getDefaultOption()
return "";
}
-LLNotificationTemplate::LLNotificationTemplate() :
- mExpireSeconds(0),
- mExpireOption(-1),
- mURLOption(-1),
- mURLOpenExternally(-1),
- mPersist(false),
- mUnique(false),
- mPriority(NOTIFICATION_PRIORITY_NORMAL)
+LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
+{
+ return mIgnoreSetting;
+}
+
+bool LLNotificationForm::getIgnored()
{
- mForm = LLNotificationFormPtr(new LLNotificationForm());
+ bool show = true;
+ if (mIgnore != LLNotificationForm::IGNORE_NO
+ && mIgnoreSetting)
+ {
+ show = mIgnoreSetting->getValue().asBoolean();
+ if (mInvertSetting) show = !show;
+ }
+
+ return !show;
+}
+
+void LLNotificationForm::setIgnored(bool ignored)
+{
+ if (mIgnoreSetting)
+ {
+ if (mInvertSetting) ignored = !ignored;
+ mIgnoreSetting->setValue(!ignored);
+ }
+}
+
+LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p)
+: mName(p.name),
+ mType(p.type),
+ mMessage(p.value),
+ mLabel(p.label),
+ mIcon(p.icon),
+ mURL(p.url.value),
+ mExpireSeconds(p.duration),
+ mExpireOption(p.expire_option),
+ mURLOption(p.url.option),
+ mURLTarget(p.url.target),
+ mUnique(p.unique.isProvided()),
+ mPriority(p.priority),
+ mPersist(p.persist),
+ mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name())
+{
+ if (p.sound.isProvided()
+ && LLUI::sSettingGroups["config"]->controlExists(p.sound))
+ {
+ mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound));
+ }
+
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::UniquenessContext>::const_iterator it = p.unique.contexts.begin(),
+ end_it = p.unique.contexts.end();
+ it != end_it;
+ ++it)
+ {
+ mUniqueContext.push_back(it->value);
+ }
+
+ lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl;
+
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::Tag>::const_iterator it = p.tags.begin(),
+ end_it = p.tags.end();
+ it != end_it;
+ ++it)
+ {
+ lldebugs << " tag \"" << std::string(it->value) << "\"" << llendl;
+ mTags.push_back(it->value);
+ }
+
+ mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));
+}
+
+LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p)
+{
+ if (p.show.isChosen())
+ {
+ mType = p.show.type;
+ mTag = p.show.tag;
+ mName = p.show.name;
+ mVisible = true;
+ }
+ else if (p.hide.isChosen())
+ {
+ mType = p.hide.type;
+ mTag = p.hide.tag;
+ mName = p.hide.name;
+ mVisible = false;
+ }
+ else if (p.respond.isChosen())
+ {
+ mType = p.respond.type;
+ mTag = p.respond.tag;
+ mName = p.respond.name;
+ mVisible = false;
+ mResponse = p.respond.response;
+ }
}
LLNotification::LLNotification(const LLNotification::Params& p) :
@@ -499,7 +659,7 @@ void LLNotification::respond(const LLSD& response)
{
mResponder->handleRespond(asLLSD(), response);
}
- else
+ else if (!mResponseFunctorName.empty())
{
// look up the functor
LLNotificationFunctorRegistry::ResponseFunctor functor =
@@ -507,6 +667,11 @@ void LLNotification::respond(const LLSD& response)
// and then call it
functor(asLLSD(), response);
}
+ else
+ {
+ // no registered responder
+ return;
+ }
if (mTemporaryResponder && !isReusable())
{
@@ -517,8 +682,7 @@ void LLNotification::respond(const LLSD& response)
if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
{
- BOOL show_notification = mIgnored ? FALSE : TRUE;
- LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
+ mForm->setIgnored(mIgnored);
if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
{
LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
@@ -528,6 +692,68 @@ void LLNotification::respond(const LLSD& response)
update();
}
+void LLNotification::respondWithDefault()
+{
+ respond(getResponseTemplate(WITH_DEFAULT_BUTTON));
+}
+
+
+const std::string& LLNotification::getName() const
+{
+ return mTemplatep->mName;
+}
+
+const std::string& LLNotification::getIcon() const
+{
+ return mTemplatep->mIcon;
+}
+
+
+bool LLNotification::isPersistent() const
+{
+ return mTemplatep->mPersist;
+}
+
+std::string LLNotification::getType() const
+{
+ return (mTemplatep ? mTemplatep->mType : "");
+}
+
+S32 LLNotification::getURLOption() const
+{
+ return (mTemplatep ? mTemplatep->mURLOption : -1);
+}
+
+S32 LLNotification::getURLOpenExternally() const
+{
+ return(mTemplatep? mTemplatep->mURLTarget == "_external": -1);
+}
+
+bool LLNotification::hasUniquenessConstraints() const
+{
+ return (mTemplatep ? mTemplatep->mUnique : false);
+}
+
+bool LLNotification::matchesTag(const std::string& tag)
+{
+ bool result = false;
+
+ if(mTemplatep)
+ {
+ std::list<std::string>::iterator it;
+ for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++)
+ {
+ if((*it) == tag)
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
void LLNotification::setIgnored(bool ignore)
{
mIgnored = ignore;
@@ -567,13 +793,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
{
const LLSD& these_substitutions = this->getSubstitutions();
const LLSD& those_substitutions = that->getSubstitutions();
+ const LLSD& this_payload = this->getPayload();
+ const LLSD& that_payload = that->getPayload();
// highlander bit sez there can only be one of these
for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end();
it != end_it;
++it)
{
- if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString())
+ // if templates differ in either substitution strings or payload with the given field name
+ // then they are considered inequivalent
+ // use of get() avoids converting the LLSD value to a map as the [] operator would
+ if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()
+ || this_payload.get(*it).asString() != that_payload.get(*it).asString())
{
return false;
}
@@ -607,6 +839,8 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele
// apply substitution to form labels
mForm->formatElements(mSubstitutions);
+ mIgnored = mForm->getIgnored();
+
LLDate rightnow = LLDate::now();
if (mTemplatep->mExpireSeconds)
{
@@ -961,16 +1195,18 @@ bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
bool LLNotifications::uniqueHandler(const LLSD& payload)
{
+ std::string cmd = payload["sigtype"];
+
LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
if (pNotif && pNotif->hasUniquenessConstraints())
{
- if (payload["sigtype"].asString() == "add")
+ if (cmd == "add")
{
// not a duplicate according to uniqueness criteria, so we keep it
// and store it for future uniqueness checks
mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
}
- else if (payload["sigtype"].asString() == "delete")
+ else if (cmd == "delete")
{
mUniqueNotifications.erase(pNotif->getName());
}
@@ -983,12 +1219,16 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
{
LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
- if (!pNotif || !pNotif->hasUniquenessConstraints())
+ std::string cmd = payload["sigtype"];
+
+ if (!pNotif || cmd != "add")
{
return false;
}
- // checks against existing unique notifications
+ // Update the existing unique notification with the data from this particular instance...
+ // This guarantees that duplicate notifications will be collapsed to the one
+ // most recently triggered
for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
existing_it != mUniqueNotifications.end();
++existing_it)
@@ -1001,7 +1241,7 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
// of this unique notification and update it
existing_notification->updateFrom(pNotif);
// then delete the new one
- pNotif->cancel();
+ cancel(pNotif);
}
}
@@ -1030,6 +1270,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN
void LLNotifications::initSingleton()
{
loadTemplates();
+ loadVisibilityRules();
createDefaultChannels();
}
@@ -1037,15 +1278,19 @@ void LLNotifications::createDefaultChannels()
{
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
- LLNotificationChannel::buildChannel("Expiration", "",
+ LLNotificationChannel::buildChannel("Enabled", "",
+ !boost::bind(&LLNotifications::getIgnoreAllNotifications, this));
+ LLNotificationChannel::buildChannel("Expiration", "Enabled",
boost::bind(&LLNotifications::expirationFilter, this, _1));
- LLNotificationChannel::buildChannel("Unexpired", "",
+ LLNotificationChannel::buildChannel("Unexpired", "Enabled",
!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
LLNotificationChannel::buildChannel("Unique", "Unexpired",
boost::bind(&LLNotifications::uniqueFilter, this, _1));
LLNotificationChannel::buildChannel("Ignore", "Unique",
filterIgnoredNotifications);
- LLNotificationChannel::buildChannel("Visible", "Ignore",
+ LLNotificationChannel::buildChannel("VisibilityRules", "Ignore",
+ boost::bind(&LLNotifications::isVisibleByRules, this, _1));
+ LLNotificationChannel::buildChannel("Visible", "VisibilityRules",
&LLNotificationFilters::includeEverything);
// create special persistent notification channel
@@ -1053,30 +1298,22 @@ void LLNotifications::createDefaultChannels()
new LLPersistentNotificationChannel();
// connect action methods to these channels
+ LLNotifications::instance().getChannel("Enabled")->
+ connectFailedFilter(&defaultResponse);
LLNotifications::instance().getChannel("Expiration")->
connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
// uniqueHandler slot should be added as first slot of the signal due to
// usage LLStopWhenHandled combiner in LLStandardSignal
LLNotifications::instance().getChannel("Unique")->
connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
-// failedUniquenessTest slot isn't necessary
-// LLNotifications::instance().getChannel("Unique")->
-// connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
+ LLNotifications::instance().getChannel("Unique")->
+ connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
LLNotifications::instance().getChannel("Ignore")->
connectFailedFilter(&handleIgnoredNotification);
+ LLNotifications::instance().getChannel("VisibilityRules")->
+ connectFailedFilter(&visibilityRuleMached);
}
-bool LLNotifications::addTemplate(const std::string &name,
- LLNotificationTemplatePtr theTemplate)
-{
- if (mTemplates.count(name))
- {
- llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
- return false;
- }
- mTemplates[name] = theTemplate;
- return true;
-}
LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
{
@@ -1095,11 +1332,6 @@ bool LLNotifications::templateExists(const std::string& name)
return (mTemplates.count(name) != 0);
}
-void LLNotifications::clearTemplates()
-{
- mTemplates.clear();
-}
-
void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
{
LLNotificationPtr temp_notify(new LLNotification(params));
@@ -1129,7 +1361,6 @@ LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
typedef std::map<std::string, std::string> StringMap;
void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
{
- //llwarns << "replaceSubstitutionStrings" << llendl;
// walk the list of attributes looking for replacements
for (LLXMLAttribList::iterator it=node->mAttributes.begin();
it != node->mAttributes.end(); ++it)
@@ -1143,13 +1374,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
if (found != replacements.end())
{
replacement = found->second;
- //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
-
+ lldebugs << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl;
it->second->setValue(replacement);
}
else
{
- llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
+ llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl;
}
}
}
@@ -1162,197 +1392,147 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
}
}
-// private to this file
-// returns true if the template request was invalid and there's nothing else we
-// can do with this node, false if you should keep processing (it may have
-// replaced the contents of the node referred to)
-LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
+void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace)
{
- if (item->hasName("usetemplate"))
+ if (form.ignore.isProvided() && form.ignore.text() == pattern)
{
- std::string replacementName;
- if (item->getAttributeString("name", replacementName))
+ form.ignore.text = replace;
+ }
+ for (LLInitParam::ParamIterator<LLNotificationForm::FormElement>::iterator it = form.form_elements.elements.begin(),
+ end_it = form.form_elements.elements.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->button.isChosen() && it->button.text() == pattern)
{
- StringMap replacements;
- for (LLXMLAttribList::const_iterator it=item->mAttributes.begin();
- it != item->mAttributes.end(); ++it)
- {
- replacements[it->second->getName()->mString] = it->second->getValue();
- }
- if (mXmlTemplates.count(replacementName))
- {
- item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
-
- // walk the nodes looking for $(substitution) here and replace
- replaceSubstitutionStrings(item, replacements);
- }
- else
- {
- llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
- }
+ it->button.text = replace;
}
}
- return item;
+}
+
+void addPathIfExists(const std::string& new_path, std::vector<std::string>& paths)
+{
+ if (gDirUtilp->fileExists(new_path))
+ {
+ paths.push_back(new_path);
+ }
}
bool LLNotifications::loadTemplates()
{
- const std::string xml_filename = "notifications.xml";
- LLXMLNodePtr root;
+ std::vector<std::string> search_paths;
- BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
+ std::string skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml";
+ std::string localized_skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml";
+
+ addPathIfExists(gDirUtilp->getDefaultSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getDefaultSkinDir() + localized_skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getSkinDir() + localized_skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getUserSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getUserSkinDir() + localized_skin_relative_path, search_paths);
+
+ std::string base_filename = search_paths.front();
+ LLXMLNodePtr root;
+ BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths);
if (!success || root.isNull() || !root->hasName( "notifications" ))
{
- llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
+ llerrs << "Problem reading UI Notifications file: " << base_filename << llendl;
return false;
}
-
- clearTemplates();
-
- for (LLXMLNodePtr item = root->getFirstChild();
- item.notNull(); item = item->getNextSibling())
+
+ LLNotificationTemplate::Notifications params;
+ LLXUIParser parser;
+ parser.readXUI(root, params, base_filename);
+
+ if(!params.validateBlock())
{
- // we do this FIRST so that item can be changed if we
- // encounter a usetemplate -- we just replace the
- // current xml node and keep processing
- item = checkForXMLTemplate(item);
-
- if (item->hasName("global"))
- {
- std::string global_name;
- if (item->getAttributeString("name", global_name))
- {
- mGlobalStrings[global_name] = item->getTextContents();
- }
- continue;
- }
-
- if (item->hasName("template"))
- {
- // store an xml template; templates must have a single node (can contain
- // other nodes)
- std::string name;
- item->getAttributeString("name", name);
- LLXMLNodePtr ptr = item->getFirstChild();
- mXmlTemplates[name] = ptr;
- continue;
- }
-
- if (!item->hasName("notification"))
- {
- llwarns << "Unexpected entity " << item->getName()->mString <<
- " found in " << xml_filename << llendl;
- continue;
- }
-
- // now we know we have a notification entry, so let's build it
- LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
+ llerrs << "Problem reading UI Notifications file: " << base_filename << llendl;
+ return false;
+ }
- if (!item->getAttributeString("name", pTemplate->mName))
- {
- llwarns << "Unable to parse notification with no name" << llendl;
- continue;
- }
-
- //llinfos << "Parsing " << pTemplate->mName << llendl;
-
- pTemplate->mMessage = item->getTextContents();
- pTemplate->mDefaultFunctor = pTemplate->mName;
- item->getAttributeString("type", pTemplate->mType);
- item->getAttributeString("icon", pTemplate->mIcon);
- item->getAttributeString("label", pTemplate->mLabel);
- item->getAttributeU32("duration", pTemplate->mExpireSeconds);
- item->getAttributeU32("expireOption", pTemplate->mExpireOption);
-
- std::string priority;
- item->getAttributeString("priority", priority);
- pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
- if (!priority.empty())
- {
- if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
- if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
- if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
- if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
- }
-
- item->getAttributeString("functor", pTemplate->mDefaultFunctor);
+ mTemplates.clear();
- BOOL persist = false;
- item->getAttributeBOOL("persist", persist);
- pTemplate->mPersist = persist;
-
- std::string sound;
- item->getAttributeString("sound", sound);
- if (!sound.empty())
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings.begin(), end_it = params.strings.end();
+ it != end_it;
+ ++it)
+ {
+ mGlobalStrings[it->name] = it->value;
+ }
+
+ std::map<std::string, LLNotificationForm::Params> form_templates;
+
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::Template>::const_iterator it = params.templates.begin(), end_it = params.templates.end();
+ it != end_it;
+ ++it)
+ {
+ form_templates[it->name] = it->form;
+ }
+
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::Params>::iterator it = params.notifications.begin(), end_it = params.notifications.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->form_ref.form_template.isChosen())
{
- // test for bad sound effect name / missing effect
- if (LLUI::sSettingGroups["config"]->controlExists(sound))
+ // replace form contents from template
+ it->form_ref.form = form_templates[it->form_ref.form_template.name];
+ if(it->form_ref.form_template.yes_text.isProvided())
{
- pTemplate->mSoundEffect =
- LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
+ replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text);
}
- else
+ if(it->form_ref.form_template.no_text.isProvided())
{
- llwarns << "Unknown sound effect control name " << sound
- << llendl;
+ replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text);
}
- }
-
- for (LLXMLNodePtr child = item->getFirstChild();
- !child.isNull(); child = child->getNextSibling())
- {
- child = checkForXMLTemplate(child);
-
- // <url>
- if (child->hasName("url"))
+ if(it->form_ref.form_template.cancel_text.isProvided())
{
- pTemplate->mURL = child->getTextContents();
- child->getAttributeU32("option", pTemplate->mURLOption);
- child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
+ replaceFormText(it->form_ref.form, "$canceltext", it->form_ref.form_template.cancel_text);
}
-
- if (child->hasName("unique"))
- {
- pTemplate->mUnique = true;
- for (LLXMLNodePtr formitem = child->getFirstChild();
- !formitem.isNull(); formitem = formitem->getNextSibling())
- {
- if (formitem->hasName("context"))
- {
- std::string key;
- formitem->getAttributeString("key", key);
- pTemplate->mUniqueContext.push_back(key);
- //llwarns << "adding " << key << " to unique context" << llendl;
- }
- else
- {
- llwarns << "'unique' has unrecognized subelement "
- << formitem->getName()->mString << llendl;
- }
- }
- }
-
- // <form>
- if (child->hasName("form"))
+ if(it->form_ref.form_template.ignore_text.isProvided())
{
- pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
+ replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text);
}
}
- addTemplate(pTemplate->mName, pTemplate);
+ mTemplates[it->name] = LLNotificationTemplatePtr(new LLNotificationTemplate(*it));
}
-
- //std::ostringstream ostream;
- //root->writeToOstream(ostream, "\n ");
- //llwarns << ostream.str() << llendl;
-
+
+ return true;
+}
+
+bool LLNotifications::loadVisibilityRules()
+{
+ const std::string xml_filename = "notification_visibility.xml";
+ std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename);
+
+ LLNotificationVisibilityRule::Rules params;
+ LLSimpleXUIParser parser;
+ parser.readXUI(full_filename, params);
+
+ if(!params.validateBlock())
+ {
+ llerrs << "Problem reading UI Notification Visibility Rules file: " << full_filename << llendl;
+ return false;
+ }
+
+ mVisibilityRules.clear();
+
+ for(LLInitParam::ParamIterator<LLNotificationVisibilityRule::Rule>::iterator it = params.rules.begin(),
+ end_it = params.rules.end();
+ it != end_it;
+ ++it)
+ {
+ mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(*it)));
+ }
+
return true;
}
// Add a simple notification (from XUI)
void LLNotifications::addFromCallback(const LLSD& name)
{
- add(LLNotification::Params().name(name.asString()));
+ add(name.asString(), LLSD(), LLSD());
}
LLNotificationPtr LLNotifications::add(const std::string& name,
@@ -1396,6 +1576,8 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
void LLNotifications::add(const LLNotificationPtr pNotif)
{
+ if (pNotif == NULL) return;
+
// first see if we already have it -- if so, that's a problem
LLNotificationSet::iterator it=mItems.find(pNotif);
if (it != mItems.end())
@@ -1408,6 +1590,8 @@ void LLNotifications::add(const LLNotificationPtr pNotif)
void LLNotifications::cancel(LLNotificationPtr pNotif)
{
+ if (pNotif == NULL || pNotif->isCancelled()) return;
+
LLNotificationSet::iterator it=mItems.find(pNotif);
if (it == mItems.end())
{
@@ -1417,6 +1601,30 @@ void LLNotifications::cancel(LLNotificationPtr pNotif)
updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
}
+void LLNotifications::cancelByName(const std::string& name)
+{
+ std::vector<LLNotificationPtr> notifs_to_cancel;
+ for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end();
+ it != end_it;
+ ++it)
+ {
+ LLNotificationPtr pNotif = *it;
+ if (pNotif->getName() == name)
+ {
+ notifs_to_cancel.push_back(pNotif);
+ }
+ }
+
+ for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end();
+ it != end_it;
+ ++it)
+ {
+ LLNotificationPtr pNotif = *it;
+ pNotif->cancel();
+ updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
+ }
+}
+
void LLNotifications::update(const LLNotificationPtr pNotif)
{
LLNotificationSet::iterator it=mItems.find(pNotif);
@@ -1471,6 +1679,93 @@ bool LLNotifications::getIgnoreAllNotifications()
return mIgnoreAllNotifications;
}
+bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
+{
+ if(n->isRespondedTo())
+ {
+ // This avoids infinite recursion in the case where the filter calls respond()
+ return true;
+ }
+
+ VisibilityRuleList::iterator it;
+
+ 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.
+ lldebugs
+ << "notification \"" << n->getName() << "\" "
+ << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, "
+ << "name = \"" << (*it)->mName << "\" "
+ << "tag = \"" << (*it)->mTag << "\" "
+ << "type = \"" << (*it)->mType << "\" "
+ << llendl;
+
+ if(!(*it)->mType.empty())
+ {
+ if((*it)->mType != n->getType())
+ {
+ // Type doesn't match, so skip this rule.
+ continue;
+ }
+ }
+
+ if(!(*it)->mTag.empty())
+ {
+ // check this notification's tag(s) against it->mTag and continue if no match is found.
+ if(!n->matchesTag((*it)->mTag))
+ {
+ // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule.
+ continue;
+ }
+ }
+
+ if(!(*it)->mName.empty())
+ {
+ // check this notification's name against the notification's name and continue if no match is found.
+ if((*it)->mName != n->getName())
+ {
+ // This rule's non-empty name didn't match the notification. Skip this rule.
+ continue;
+ }
+ }
+
+ // If we got here, the rule matches. Don't evaluate subsequent rules.
+ if(!(*it)->mVisible)
+ {
+ // This notification is being hidden.
+
+ if((*it)->mResponse.empty())
+ {
+ // Response property is empty. Cancel this notification.
+ lldebugs << "cancelling notification " << n->getName() << llendl;
+
+ cancel(n);
+ }
+ else
+ {
+ // Response property is not empty. Return the specified response.
+ LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON);
+ // TODO: verify that the response template has an item with the correct name
+ response[(*it)->mResponse] = true;
+
+ lldebugs << "responding to notification " << n->getName() << " with response = " << response << llendl;
+
+ n->respond(response);
+ }
+
+ return false;
+ }
+
+ // If we got here, exit the loop and return true.
+ break;
+ }
+
+ lldebugs << "allowing notification " << n->getName() << llendl;
+
+ return true;
+}
+
+
// ---
// END OF LLNotifications implementation
// =========================================================
@@ -1481,17 +1776,50 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
return s;
}
-void LLPostponedNotification::onCachedNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, bool is_group)
+//static
+void LLPostponedNotification::lookupName(LLPostponedNotification* thiz,
+ const LLUUID& id,
+ bool is_group)
{
- mName = first + " " + last;
+ if (is_group)
+ {
+ gCacheName->getGroup(id,
+ boost::bind(&LLPostponedNotification::onGroupNameCache,
+ thiz, _1, _2, _3));
+ }
+ else
+ {
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLPostponedNotification::onAvatarNameCache,
+ thiz, _1, _2));
+ }
+}
- LLStringUtil::trim(mName);
- if (mName.empty())
+void LLPostponedNotification::onGroupNameCache(const LLUUID& id,
+ const std::string& full_name,
+ bool is_group)
+{
+ finalizeName(full_name);
+}
+
+void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
+ std::string name = av_name.getCompleteName();
+
+ // from PE merge - we should figure out if this is the right thing to do
+ if (name.empty())
{
- llwarns << "Empty name received for Id: " << id << llendl;
- mName = SYSTEM_FROM;
+ llwarns << "Empty name received for Id: " << agent_id << llendl;
+ name = SYSTEM_FROM;
}
+
+ finalizeName(name);
+}
+
+void LLPostponedNotification::finalizeName(const std::string& name)
+{
+ mName = name;
modifyNotificationParams();
LLNotifications::instance().add(mParams);
cleanup();
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 2cc8803f10..0c4d4fc897 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -98,9 +98,8 @@
#include "llinitparam.h"
#include "llnotificationslistener.h"
#include "llnotificationptr.h"
-#include "llcachename.h"
-
+class LLAvatarName;
typedef enum e_notification_priority
{
NOTIFICATION_PRIORITY_UNSPECIFIED,
@@ -110,6 +109,11 @@ typedef enum e_notification_priority
NOTIFICATION_PRIORITY_CRITICAL
} ENotificationPriority;
+struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues>
+{
+ static void declareValues();
+};
+
class LLNotificationResponderInterface
{
public:
@@ -157,6 +161,69 @@ class LLNotificationForm
LOG_CLASS(LLNotificationForm);
public:
+ struct FormElementBase : public LLInitParam::Block<FormElementBase>
+ {
+ Optional<std::string> name;
+
+ FormElementBase();
+ };
+
+ struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase>
+ {
+ Optional<std::string> text;
+ Optional<bool> save_option;
+ Optional<std::string> control;
+ Optional<bool> invert_control;
+
+ FormIgnore();
+ };
+
+ struct FormButton : public LLInitParam::Block<FormButton, FormElementBase>
+ {
+ Mandatory<S32> index;
+ Mandatory<std::string> text;
+ Optional<std::string> ignore;
+ Optional<bool> is_default;
+
+ Mandatory<std::string> type;
+
+ FormButton();
+ };
+
+ struct FormInput : public LLInitParam::Block<FormInput, FormElementBase>
+ {
+ Mandatory<std::string> type;
+ Optional<S32> width;
+ Optional<S32> max_length_chars;
+ Optional<std::string> text;
+
+ Optional<std::string> value;
+ FormInput();
+ };
+
+ struct FormElement : public LLInitParam::Choice<FormElement>
+ {
+ Alternative<FormButton> button;
+ Alternative<FormInput> input;
+
+ FormElement();
+ };
+
+ struct FormElements : public LLInitParam::Block<FormElements>
+ {
+ Multiple<FormElement> elements;
+ FormElements();
+ };
+
+ struct Params : public LLInitParam::Block<Params>
+ {
+ Optional<std::string> name;
+ Optional<FormIgnore> ignore;
+ Optional<FormElements> form_elements;
+
+ Params();
+ };
+
typedef enum e_ignore_type
{
IGNORE_NO,
@@ -167,8 +234,7 @@ public:
LLNotificationForm();
LLNotificationForm(const LLSD& sd);
- LLNotificationForm(const std::string& name,
- const LLPointer<class LLXMLNode> xml_node);
+ LLNotificationForm(const std::string& name, const Params& p);
LLSD asLLSD() const;
@@ -181,97 +247,35 @@ public:
// appends form elements from another form serialized as LLSD
void append(const LLSD& sub_form);
std::string getDefaultOption();
+ LLPointer<class LLControlVariable> getIgnoreSetting();
+ bool getIgnored();
+ void setIgnored(bool ignored);
EIgnoreType getIgnoreType() { return mIgnore; }
std::string getIgnoreMessage() { return mIgnoreMsg; }
private:
- LLSD mFormData;
- EIgnoreType mIgnore;
- std::string mIgnoreMsg;
+ LLSD mFormData;
+ EIgnoreType mIgnore;
+ std::string mIgnoreMsg;
+ LLPointer<class LLControlVariable> mIgnoreSetting;
+ bool mInvertSetting;
};
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
-// This is the class of object read from the XML file (notifications.xml,
-// from the appropriate local language directory).
-struct LLNotificationTemplate
-{
- LLNotificationTemplate();
- // the name of the notification -- the key used to identify it
- // Ideally, the key should follow variable naming rules
- // (no spaces or punctuation).
- std::string mName;
- // The type of the notification
- // used to control which queue it's stored in
- std::string mType;
- // The text used to display the notification. Replaceable parameters
- // are enclosed in square brackets like this [].
- std::string mMessage;
- // The label for the notification; used for
- // certain classes of notification (those with a window and a window title).
- // Also used when a notification pops up underneath the current one.
- // Replaceable parameters can be used in the label.
- std::string mLabel;
- // The name of the icon image. This should include an extension.
- std::string mIcon;
- // This is the Highlander bit -- "There Can Be Only One"
- // An outstanding notification with this bit set
- // is updated by an incoming notification with the same name,
- // rather than creating a new entry in the queue.
- // (used for things like progress indications, or repeating warnings
- // like "the grid is going down in N minutes")
- bool mUnique;
- // if we want to be unique only if a certain part of the payload is constant
- // specify the field names for the payload. The notification will only be
- // combined if all of the fields named in the context are identical in the
- // new and the old notification; otherwise, the notification will be
- // duplicated. This is to support suppressing duplicate offers from the same
- // sender but still differentiating different offers. Example: Invitation to
- // conference chat.
- std::vector<std::string> mUniqueContext;
- // If this notification expires automatically, this value will be
- // nonzero, and indicates the number of seconds for which the notification
- // will be valid (a teleport offer, for example, might be valid for
- // 300 seconds).
- U32 mExpireSeconds;
- // if the offer expires, one of the options is chosen automatically
- // based on its "value" parameter. This controls which one.
- // If expireSeconds is specified, expireOption should also be specified.
- U32 mExpireOption;
- // if the notification contains a url, it's stored here (and replaced
- // into the message where [_URL] is found)
- std::string mURL;
- // if there's a URL in the message, this controls which option visits
- // that URL. Obsolete this and eliminate the buttons for affected
- // messages when we allow clickable URLs in the UI
- U32 mURLOption;
-
- U32 mURLOpenExternally;
- //This is a flag that tells if the url needs to open externally dispite
- //what the user setting is.
-
- // does this notification persist across sessions? if so, it will be
- // serialized to disk on first receipt and read on startup
- bool mPersist;
- // This is the name of the default functor, if present, to be
- // used for the notification's callback. It is optional, and used only if
- // the notification is constructed without an identified functor.
- std::string mDefaultFunctor;
- // The form data associated with a given notification (buttons, text boxes, etc)
- LLNotificationFormPtr mForm;
- // default priority for notifications of this type
- ENotificationPriority mPriority;
- // UUID of the audio file to be played when this notification arrives
- // this is loaded as a name, but looked up to get the UUID upon template load.
- // If null, it wasn't specified.
- LLUUID mSoundEffect;
-};
+
+struct LLNotificationTemplate;
// we want to keep a map of these by name, and it's best to manage them
// with smart pointers
typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
+
+struct LLNotificationVisibilityRule;
+
+typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
+
/**
* @class LLNotification
* @brief The object that expresses the details of a notification
@@ -302,7 +306,7 @@ public:
// optional
Optional<LLSD> substitutions;
Optional<LLSD> payload;
- Optional<ENotificationPriority> priority;
+ Optional<ENotificationPriority, NotificationPriorityValues> priority;
Optional<LLSD> form_elements;
Optional<LLDate> time_stamp;
Optional<LLNotificationContext*> context;
@@ -445,6 +449,7 @@ public:
LLSD asLLSD();
void respond(const LLSD& sd);
+ void respondWithDefault();
void* getResponder() { return mResponderObj; }
@@ -462,6 +467,13 @@ public:
return mRespondedTo;
}
+ bool isActive() const
+ {
+ return !isRespondedTo()
+ && !isCancelled()
+ && !isExpired();
+ }
+
const LLSD& getResponse() { return mResponse; }
bool isIgnored() const
@@ -469,15 +481,11 @@ public:
return mIgnored;
}
- const std::string& getName() const
- {
- return mTemplatep->mName;
- }
+ const std::string& getName() const;
- bool isPersistent() const
- {
- return mTemplatep->mPersist;
- }
+ const std::string& getIcon() const;
+
+ bool isPersistent() const;
const LLUUID& id() const
{
@@ -499,28 +507,12 @@ public:
return mTimestamp;
}
- std::string getType() const
- {
- return (mTemplatep ? mTemplatep->mType : "");
- }
-
+ std::string getType() const;
std::string getMessage() const;
std::string getLabel() const;
-
std::string getURL() const;
-// {
-// return (mTemplatep ? mTemplatep->mURL : "");
-// }
-
- S32 getURLOption() const
- {
- return (mTemplatep ? mTemplatep->mURLOption : -1);
- }
-
- S32 getURLOpenExternally() const
- {
- return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
- }
+ S32 getURLOption() const;
+ S32 getURLOpenExternally() const;
const LLNotificationFormPtr getForm();
@@ -590,7 +582,9 @@ public:
std::string summarize() const;
- bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
+ bool hasUniquenessConstraints() const;
+
+ bool matchesTag(const std::string& tag);
virtual ~LLNotification() {}
};
@@ -869,10 +863,14 @@ class LLNotifications :
friend class LLSingleton<LLNotifications>;
public:
- // load notification descriptions from file;
+ // load all notification descriptions from file
+ // calling more than once will overwrite existing templates
+ // but never delete a template
+ bool loadTemplates();
+
+ // load visibility rules from file;
// OK to call more than once because it will reload
- bool loadTemplates();
- LLPointer<class LLXMLNode> checkForXMLTemplate(LLPointer<class LLXMLNode> item);
+ bool loadVisibilityRules();
// Add a simple notification (from XUI)
void addFromCallback(const LLSD& name);
@@ -894,6 +892,7 @@ public:
void add(const LLNotificationPtr pNotif);
void cancel(LLNotificationPtr pNotif);
+ void cancelByName(const std::string& name);
void update(const LLNotificationPtr pNotif);
LLNotificationPtr find(LLUUID uuid);
@@ -917,9 +916,9 @@ public:
// test for existence
bool templateExists(const std::string& name);
- // useful if you're reloading the file
- void clearTemplates(); // erase all templates
+ typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList;
+
void forceResponse(const LLNotification::Params& params, S32 option);
void createDefaultChannels();
@@ -935,6 +934,8 @@ public:
void setIgnoreAllNotifications(bool ignore);
bool getIgnoreAllNotifications();
+ bool isVisibleByRules(LLNotificationPtr pNotification);
+
private:
// we're a singleton, so we don't have a public constructor
LLNotifications();
@@ -950,15 +951,12 @@ private:
LLNotificationChannelPtr pHistoryChannel;
LLNotificationChannelPtr pExpirationChannel;
- // put your template in
- bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
TemplateMap mTemplates;
+ VisibilityRuleList mVisibilityRules;
+
std::string mFileName;
- typedef std::map<std::string, LLPointer<class LLXMLNode> > XMLTemplateMap;
- XMLTemplateMap mXmlTemplates;
-
LLNotificationMap mUniqueNotifications;
typedef std::map<std::string, std::string> GlobalStringMap;
@@ -994,17 +992,20 @@ public:
{
// upcast T to the base type to restrict T derivation from LLPostponedNotification
LLPostponedNotification* thiz = new T();
-
thiz->mParams = params;
- gCacheName->get(id, is_group, boost::bind(
- &LLPostponedNotification::onCachedNameReceived, thiz, _1, _2,
- _3, _4));
+ // Avoid header file dependency on llcachename.h
+ lookupName(thiz, id, is_group);
}
private:
- void onCachedNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, bool is_group);
+ static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group);
+ // only used for groups
+ void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
+ // only used for avatars
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+ // used for both group and avatar names
+ void finalizeName(const std::string& name);
void cleanup()
{
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index 44a90398fd..3bbeb3a778 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llnotificationslistener.h"
#include "llnotifications.h"
+#include "llnotificationtemplate.h"
#include "llsd.h"
#include "llui.h"
@@ -182,7 +183,11 @@ void LLNotificationsListener::ignore(const LLSD& params) const
if (params["name"].isDefined())
{
// ["name"] was passed: ignore just that notification
- LLUI::sSettingGroups["ignores"]->setBOOL(params["name"], ignore);
+ LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]);
+ if (templatep)
+ {
+ templatep->mForm->setIgnored(ignore);
+ }
}
else
{
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
new file mode 100644
index 0000000000..eff572b553
--- /dev/null
+++ b/indra/llui/llnotificationtemplate.h
@@ -0,0 +1,297 @@
+/**
+* @file llnotificationtemplate.h
+* @brief Description of notification contents
+* @author Q (with assistance from Richard and Coco)
+*
+* $LicenseInfo:firstyear=2008&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2010, 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_LLNOTIFICATION_TEMPLATE_H
+#define LL_LLNOTIFICATION_TEMPLATE_H
+
+//#include <string>
+//#include <list>
+//#include <vector>
+//#include <map>
+//#include <set>
+//#include <iomanip>
+//#include <sstream>
+//
+//#include <boost/utility.hpp>
+//#include <boost/shared_ptr.hpp>
+//#include <boost/enable_shared_from_this.hpp>
+//#include <boost/type_traits.hpp>
+//
+//// we want to minimize external dependencies, but this one is important
+//#include "llsd.h"
+//
+//// and we need this to manage the notification callbacks
+//#include "llevents.h"
+//#include "llfunctorregistry.h"
+//#include "llpointer.h"
+#include "llinitparam.h"
+//#include "llnotificationslistener.h"
+//#include "llnotificationptr.h"
+//#include "llcachename.h"
+#include "llnotifications.h"
+
+
+typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
+
+// This is the class of object read from the XML file (notifications.xml,
+// from the appropriate local language directory).
+struct LLNotificationTemplate
+{
+ struct GlobalString : public LLInitParam::Block<GlobalString>
+ {
+ Mandatory<std::string> name,
+ value;
+
+ GlobalString()
+ : name("name"),
+ value("value")
+ {}
+ };
+
+ struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
+ {
+ Mandatory<std::string> value;
+
+ UniquenessContext()
+ : value("value")
+ {
+ addSynonym(value, "key");
+ }
+
+ };
+
+ struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint>
+ {
+ private:
+ // this idiom allows
+ // <notification unique="true">
+ // as well as
+ // <notification> <unique> <context></context> </unique>...
+ Optional<bool> dummy_val;
+ public:
+ Multiple<UniquenessContext> contexts;
+
+ UniquenessConstraint()
+ : contexts("context"),
+ dummy_val("")
+ {}
+ };
+
+ // Templates are used to define common form types, such as OK/Cancel dialogs, etc.
+
+ struct Template : public LLInitParam::Block<Template>
+ {
+ Mandatory<std::string> name;
+ Mandatory<LLNotificationForm::Params> form;
+
+ Template()
+ : name("name"),
+ form("form")
+ {}
+ };
+
+ // Reference a template to use its form elements
+ struct TemplateRef : public LLInitParam::Block<TemplateRef>
+ {
+ Mandatory<std::string> name;
+ Optional<std::string> yes_text,
+ no_text,
+ cancel_text,
+ ignore_text;
+
+ TemplateRef()
+ : name("name"),
+ yes_text("yestext"),
+ no_text("notext"),
+ cancel_text("canceltext"),
+ ignore_text("ignoretext")
+ {}
+ };
+
+ struct URL : public LLInitParam::Block<URL>
+ {
+ Mandatory<S32> option;
+ Mandatory<std::string> value;
+ Optional<std::string> target;
+ Ignored name;
+
+ URL()
+ : option("option", -1),
+ value("value"),
+ target("target", "_blank"),
+ name("name")
+ {}
+ };
+
+ struct FormRef : public LLInitParam::Choice<FormRef>
+ {
+ Alternative<LLNotificationForm::Params> form;
+ Alternative<TemplateRef> form_template;
+
+ FormRef()
+ : form("form"),
+ form_template("usetemplate")
+ {}
+ };
+
+ struct Tag : public LLInitParam::Block<Tag>
+ {
+ Mandatory<std::string> value;
+
+ Tag()
+ : value("value")
+ {}
+ };
+
+ struct Params : public LLInitParam::Block<Params>
+ {
+ Mandatory<std::string> name;
+ Optional<bool> persist;
+ Optional<std::string> functor,
+ icon,
+ label,
+ sound,
+ type,
+ value;
+ Optional<U32> duration;
+ Optional<S32> expire_option;
+ Optional<URL> url;
+ Optional<UniquenessConstraint> unique;
+ Optional<FormRef> form_ref;
+ Optional<ENotificationPriority,
+ NotificationPriorityValues> priority;
+ Multiple<Tag> tags;
+
+
+ Params()
+ : name("name"),
+ persist("persist", false),
+ functor("functor"),
+ icon("icon"),
+ label("label"),
+ priority("priority"),
+ sound("sound"),
+ type("type"),
+ value("value"),
+ duration("duration"),
+ expire_option("expireOption", -1),
+ url("url"),
+ unique("unique"),
+ form_ref(""),
+ tags("tag")
+ {}
+
+ };
+
+ struct Notifications : public LLInitParam::Block<Notifications>
+ {
+ Multiple<GlobalString> strings;
+ Multiple<Template> templates;
+ Multiple<Params> notifications;
+
+ Notifications()
+ : strings("global"),
+ notifications("notification"),
+ templates("template")
+ {}
+ };
+
+ LLNotificationTemplate(const Params& p);
+ // the name of the notification -- the key used to identify it
+ // Ideally, the key should follow variable naming rules
+ // (no spaces or punctuation).
+ std::string mName;
+ // The type of the notification
+ // used to control which queue it's stored in
+ std::string mType;
+ // The text used to display the notification. Replaceable parameters
+ // are enclosed in square brackets like this [].
+ std::string mMessage;
+ // The label for the notification; used for
+ // certain classes of notification (those with a window and a window title).
+ // Also used when a notification pops up underneath the current one.
+ // Replaceable parameters can be used in the label.
+ std::string mLabel;
+ // The name of the icon image. This should include an extension.
+ std::string mIcon;
+ // This is the Highlander bit -- "There Can Be Only One"
+ // An outstanding notification with this bit set
+ // is updated by an incoming notification with the same name,
+ // rather than creating a new entry in the queue.
+ // (used for things like progress indications, or repeating warnings
+ // like "the grid is going down in N minutes")
+ bool mUnique;
+ // if we want to be unique only if a certain part of the payload or substitutions args
+ // are constant specify the field names for the payload. The notification will only be
+ // combined if all of the fields named in the context are identical in the
+ // new and the old notification; otherwise, the notification will be
+ // duplicated. This is to support suppressing duplicate offers from the same
+ // sender but still differentiating different offers. Example: Invitation to
+ // conference chat.
+ std::vector<std::string> mUniqueContext;
+ // If this notification expires automatically, this value will be
+ // nonzero, and indicates the number of seconds for which the notification
+ // will be valid (a teleport offer, for example, might be valid for
+ // 300 seconds).
+ U32 mExpireSeconds;
+ // if the offer expires, one of the options is chosen automatically
+ // based on its "value" parameter. This controls which one.
+ // If expireSeconds is specified, expireOption should also be specified.
+ U32 mExpireOption;
+ // if the notification contains a url, it's stored here (and replaced
+ // into the message where [_URL] is found)
+ std::string mURL;
+ // if there's a URL in the message, this controls which option visits
+ // that URL. Obsolete this and eliminate the buttons for affected
+ // messages when we allow clickable URLs in the UI
+ U32 mURLOption;
+
+ std::string mURLTarget;
+ //This is a flag that tells if the url needs to open externally dispite
+ //what the user setting is.
+
+ // does this notification persist across sessions? if so, it will be
+ // serialized to disk on first receipt and read on startup
+ bool mPersist;
+ // This is the name of the default functor, if present, to be
+ // used for the notification's callback. It is optional, and used only if
+ // the notification is constructed without an identified functor.
+ std::string mDefaultFunctor;
+ // The form data associated with a given notification (buttons, text boxes, etc)
+ LLNotificationFormPtr mForm;
+ // default priority for notifications of this type
+ ENotificationPriority mPriority;
+ // UUID of the audio file to be played when this notification arrives
+ // this is loaded as a name, but looked up to get the UUID upon template load.
+ // If null, it wasn't specified.
+ LLUUID mSoundEffect;
+ // List of tags that rules can match against.
+ std::list<std::string> mTags;
+};
+
+#endif //LL_LLNOTIFICATION_TEMPLATE_H
+
diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h
new file mode 100644
index 0000000000..78bdec2a8f
--- /dev/null
+++ b/indra/llui/llnotificationvisibilityrule.h
@@ -0,0 +1,104 @@
+/**
+* @file llnotificationvisibility.h
+* @brief Rules for
+* @author Monroe
+*
+* $LicenseInfo:firstyear=2010&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2010, 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_LLNOTIFICATION_VISIBILITY_RULE_H
+#define LL_LLNOTIFICATION_VISIBILITY_RULE_H
+
+#include "llinitparam.h"
+//#include "llnotifications.h"
+
+
+
+// This is the class of object read from the XML file (notification_visibility.xml,
+// from the appropriate local language directory).
+struct LLNotificationVisibilityRule
+{
+ struct Filter : public LLInitParam::Block<Filter>
+ {
+ Optional<std::string> type,
+ tag,
+ name;
+
+ Filter()
+ : type("type"),
+ tag("tag"),
+ name("name")
+ {}
+ };
+
+ struct Respond : public LLInitParam::Block<Respond, Filter>
+ {
+ Mandatory<std::string> response;
+
+ Respond()
+ : response("response")
+ {}
+ };
+
+ struct Rule : public LLInitParam::Choice<Rule>
+ {
+ Alternative<Filter> show;
+ Alternative<Filter> hide;
+ Alternative<Respond> respond;
+
+ Rule()
+ : show("show"),
+ hide("hide"),
+ respond("respond")
+ {}
+ };
+
+ struct Rules : public LLInitParam::Block<Rules>
+ {
+ Multiple<Rule> rules;
+
+ Rules()
+ : rules("")
+ {}
+ };
+
+ LLNotificationVisibilityRule(const Rule& p);
+
+ // If true, this rule makes matching notifications visible. Otherwise, it makes them invisible.
+ bool mVisible;
+
+ // Which response to give when making a notification invisible. An empty string means the notification should be cancelled instead of responded to.
+ std::string mResponse;
+
+ // String to match against the notification's "type". An empty string matches all notifications.
+ std::string mType;
+
+ // String to match against the notification's tag(s). An empty string matches all notifications.
+ std::string mTag;
+
+ // String to match against the notification's name. An empty string matches all notifications.
+ std::string mName;
+
+};
+
+#endif //LL_LLNOTIFICATION_VISIBILITY_RULE_H
+
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index b2e08c48c5..b2383106a8 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -35,6 +35,7 @@
#include "llfontgl.h"
#include "llrect.h"
#include "llerror.h"
+#include "lldir.h"
#include "lltimer.h"
#include "llaccordionctrltab.h"
@@ -52,6 +53,8 @@
#include "lltabcontainer.h"
static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML);
+LLPanel::factory_stack_t LLPanel::sFactoryStack;
+
// Compiler optimization, generate extern template
template class LLPanel* LLView::getChild<class LLPanel>(
@@ -191,6 +194,8 @@ void LLPanel::draw()
// draw background
if( mBgVisible )
{
+ alpha = getCurrentTransparency();
+
LLRect local_rect = getLocalRect();
if (mBgOpaque )
{
@@ -380,8 +385,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
LLPanel* panelp = NULL;
- {
- LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
+ { LLFastTimer _(FTM_PANEL_CONSTRUCTION);
if(!class_attr.empty())
{
@@ -394,7 +398,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
if (!panelp)
{
- panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name);
+ panelp = createFactoryPanel(name);
llassert(panelp);
if (!panelp)
@@ -407,20 +411,20 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
// factory panels may have registered their own factory maps
if (!panelp->getFactoryMap().empty())
{
- LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap());
+ sFactoryStack.push_back(&panelp->getFactoryMap());
}
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
panelp->mCommitCallbackRegistrar.pushScope();
panelp->mEnableCallbackRegistrar.pushScope();
- panelp->initPanelXML(node, parent, output_node);
+ panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>());
panelp->mCommitCallbackRegistrar.popScope();
panelp->mEnableCallbackRegistrar.popScope();
if (!panelp->getFactoryMap().empty())
{
- LLUICtrlFactory::instance().popFactoryFunctions();
+ sFactoryStack.pop_back();
}
return panelp;
@@ -432,7 +436,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
//and LLView::initFromParams will use them to set visible and enabled
setVisible(p.visible);
setEnabled(p.enabled);
-
+ setFocusRoot(p.focus_root);
setSoundFlags(p.sound_flags);
// control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
@@ -444,8 +448,8 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
setVisibleCallback(initCommitCallback(p.visible_callback));
}
- for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings().begin();
- it != p.strings().end();
+ for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin();
+ it != p.strings.end();
++it)
{
mUIStrings[it->name] = it->value;
@@ -487,11 +491,9 @@ static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");
static LLFastTimer::DeclareTimer FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference");
static LLFastTimer::DeclareTimer FTM_PANEL_POSTBUILD("Panel PostBuild");
-BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
+BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
{
- const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel>());
Params params(default_params);
-
{
LLFastTimer timer(FTM_PANEL_SETUP);
@@ -505,6 +507,8 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
setXMLFilename(xml_filename);
}
+ LLXUIParser parser;
+
if (!xml_filename.empty())
{
LLUICtrlFactory::instance().pushFileName(xml_filename);
@@ -514,12 +518,11 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
{
//if we are exporting, we want to export the current xml
//not the referenced xml
- LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
+ parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
Params output_params(params);
setupParamsForExport(output_params, parent);
output_node->setName(node->getName()->mString);
- LLXUIParser::instance().writeXUI(
- output_node, output_params, &default_params);
+ parser.writeXUI(output_node, output_params, &default_params);
return TRUE;
}
@@ -530,7 +533,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
return FALSE;
}
- LLXUIParser::instance().readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
+ parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
// add children using dimensions from referenced xml for consistent layout
setShape(params.rect);
@@ -540,15 +543,14 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
}
// ask LLUICtrlFactory for filename, since xml_filename might be empty
- LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
+ parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
if (output_node)
{
Params output_params(params);
setupParamsForExport(output_params, parent);
output_node->setName(node->getName()->mString);
- LLXUIParser::instance().writeXUI(
- output_node, output_params, &default_params);
+ parser.writeXUI(output_node, output_params, &default_params);
}
params.from_xui = true;
@@ -904,7 +906,7 @@ LLPanel *LLPanel::childGetVisiblePanelWithHelp()
child = *it;
// do we have a panel with a help topic?
LLPanel *panel = dynamic_cast<LLPanel *>(child);
- if (panel && panel->getVisible() && !panel->getHelpTopic().empty())
+ if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
{
return panel;
}
@@ -959,3 +961,89 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::
return mVisibleSignal->connect(cb);
}
+
+static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
+
+//-----------------------------------------------------------------------------
+// buildPanel()
+//-----------------------------------------------------------------------------
+BOOL LLPanel::buildFromFile(const std::string& filename, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
+{
+ LLFastTimer timer(FTM_BUILD_PANELS);
+ BOOL didPost = FALSE;
+ LLXMLNodePtr root;
+
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return didPost;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return didPost;
+ }
+
+ // root must be called panel
+ if( !root->hasName("panel" ) )
+ {
+ llwarns << "Root node should be named panel in : " << filename << llendl;
+ return didPost;
+ }
+
+ lldebugs << "Building panel " << filename << llendl;
+
+ LLUICtrlFactory::instance().pushFileName(filename);
+ {
+ if (!getFactoryMap().empty())
+ {
+ sFactoryStack.push_back(&getFactoryMap());
+ }
+
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ getCommitCallbackRegistrar().pushScope();
+ getEnableCallbackRegistrar().pushScope();
+
+ didPost = initPanelXML(root, NULL, output_node, default_params);
+
+ getCommitCallbackRegistrar().popScope();
+ getEnableCallbackRegistrar().popScope();
+
+ setXMLFilename(filename);
+
+ if (!getFactoryMap().empty())
+ {
+ sFactoryStack.pop_back();
+ }
+ }
+ LLUICtrlFactory::instance().popFileName();
+ return didPost;
+}
+
+//-----------------------------------------------------------------------------
+// createFactoryPanel()
+//-----------------------------------------------------------------------------
+LLPanel* LLPanel::createFactoryPanel(const std::string& name)
+{
+ std::deque<const LLCallbackMap::map_t*>::iterator itor;
+ for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor)
+ {
+ const LLCallbackMap::map_t* factory_map = *itor;
+
+ // Look up this panel's name in the map.
+ LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
+ if (iter != factory_map->end())
+ {
+ // Use the factory to create the panel, instead of using a default LLPanel.
+ LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
+ return ret;
+ }
+ }
+ LLPanel::Params panel_p;
+ return LLUICtrlFactory::create<LLPanel>(panel_p);
+}
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index a7224648c1..7bbbeaf709 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -32,6 +32,7 @@
#include "llcallbackmap.h"
#include "lluictrl.h"
#include "llviewborder.h"
+#include "lluiimage.h"
#include "lluistring.h"
#include "v4color.h"
#include <list>
@@ -104,7 +105,10 @@ protected:
LLPanel(const LLPanel::Params& params = getDefaultParams());
public:
-// LLPanel(const std::string& name, const LLRect& rect = LLRect(), BOOL bordered = TRUE);
+ BOOL buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL, const LLPanel::Params&default_params = getDefaultParams());
+
+ static LLPanel* createFactoryPanel(const std::string& name);
+
/*virtual*/ ~LLPanel();
// LLView interface
@@ -157,7 +161,7 @@ public:
EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
void initFromParams(const Params& p);
- BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+ BOOL initPanelXML( LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params);
bool hasString(const std::string& name);
std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const;
@@ -256,6 +260,8 @@ protected:
commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD()
std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer
+ typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
+ static factory_stack_t sFactoryStack;
private:
BOOL mBgVisible; // any background at all?
@@ -285,4 +291,57 @@ extern template class LLPanel* LLView::getChild<class LLPanel>(
const std::string& name, BOOL recurse) const;
#endif
+typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc;
+
+// local static instance for registering a particular panel class
+
+class LLRegisterPanelClass
+: public LLSingleton< LLRegisterPanelClass >
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func)
+ {
+ mPanelClassesNames[tag] = func;
+ }
+
+ LLPanel* createPanelClass(const std::string& tag)
+ {
+ param_name_map_t::iterator iT = mPanelClassesNames.find(tag);
+ if(iT == mPanelClassesNames.end())
+ return 0;
+ return iT->second();
+ }
+ template<typename T>
+ static T* defaultPanelClassBuilder()
+ {
+ T* pT = new T();
+ return pT;
+ }
+
+private:
+ typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t;
+
+ param_name_map_t mPanelClassesNames;
+};
+
+
+// local static instance for registering a particular panel class
+template<typename T>
+class LLRegisterPanelClassWrapper
+: public LLRegisterPanelClass
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ LLRegisterPanelClassWrapper(const std::string& tag);
+};
+
+
+template<typename T>
+LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
+{
+ LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
+}
+
+
#endif
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index aaa328754d..84a890edfa 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -38,6 +38,7 @@
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
static LLDefaultChildRegistry::Register<LLProgressBar> r("progress_bar");
@@ -50,7 +51,7 @@ LLProgressBar::Params::Params()
LLProgressBar::LLProgressBar(const LLProgressBar::Params& p)
-: LLView(p),
+: LLUICtrl(p),
mImageBar(p.image_bar),
mImageFill(p.image_fill),
mColorBackground(p.color_bg()),
@@ -80,7 +81,7 @@ void LLProgressBar::draw()
mImageFill->draw(progress_rect, bar_color);
}
-void LLProgressBar::setPercent(const F32 percent)
+void LLProgressBar::setValue(const LLSD& value)
{
- mPercentDone = llclamp(percent, 0.f, 100.f);
+ mPercentDone = llclamp((F32)value.asReal(), 0.f, 100.f);
}
diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h
index 13297f7493..a8ec83ea00 100644
--- a/indra/llui/llprogressbar.h
+++ b/indra/llui/llprogressbar.h
@@ -27,14 +27,15 @@
#ifndef LL_LLPROGRESSBAR_H
#define LL_LLPROGRESSBAR_H
-#include "llview.h"
#include "llframetimer.h"
+#include "lluictrl.h"
+#include "lluiimage.h"
class LLProgressBar
- : public LLView
+ : public LLUICtrl
{
public:
- struct Params : public LLInitParam::Block<Params, LLView::Params>
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<LLUIImage*> image_bar,
image_fill;
@@ -47,7 +48,7 @@ public:
LLProgressBar(const Params&);
virtual ~LLProgressBar();
- void setPercent(const F32 percent);
+ void setValue(const LLSD& value);
/*virtual*/ void draw();
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 83c42a5ab8..3a12debf7e 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -69,7 +69,7 @@ protected:
static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");
LLRadioGroup::Params::Params()
-: has_border("draw_border"),
+: allow_deselect("allow_deselect"),
items("item")
{
addSynonym(items, "radio_item");
@@ -85,23 +85,13 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
: LLUICtrl(p),
mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
mSelectedIndex(-1),
- mHasBorder(p.has_border)
-{
- if (mHasBorder)
- {
- LLViewBorder::Params params;
- params.name("radio group border");
- params.rect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
- params.bevel_style(LLViewBorder::BEVEL_NONE);
- LLViewBorder * vb = LLUICtrlFactory::create<LLViewBorder> (params);
- addChild (vb);
- }
-}
+ mAllowDeselect(p.allow_deselect)
+{}
void LLRadioGroup::initFromParams(const Params& p)
{
- for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
- it != p.items().end();
+ for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin();
+ it != p.items.end();
++it)
{
LLRadioGroup::ItemParams item_params(*it);
@@ -184,7 +174,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
{
- if (index < 0 || (S32)mRadioButtons.size() <= index )
+ if ((S32)mRadioButtons.size() <= index )
{
return FALSE;
}
@@ -202,13 +192,16 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
mSelectedIndex = index;
- LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
- radio_item->setTabStop(true);
- radio_item->setValue( TRUE );
-
- if (hasFocus())
+ if (mSelectedIndex >= 0)
{
- mRadioButtons[mSelectedIndex]->focusFirstItem(FALSE, FALSE);
+ LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
+ radio_item->setTabStop(true);
+ radio_item->setValue( TRUE );
+
+ if (hasFocus())
+ {
+ radio_item->focusFirstItem(FALSE, FALSE);
+ }
}
if (!from_event)
@@ -307,8 +300,15 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
LLRadioCtrl* radio = *iter;
if (radio == clicked_radio)
{
- // llinfos << "clicked button " << index << llendl;
- setSelectedIndex(index);
+ if (index == mSelectedIndex && mAllowDeselect)
+ {
+ // don't select anything
+ setSelectedIndex(-1);
+ }
+ else
+ {
+ setSelectedIndex(index);
+ }
// BUG: Calls click callback even if button didn't actually change
onCommit();
@@ -346,7 +346,7 @@ void LLRadioGroup::setValue( const LLSD& value )
}
else
{
- llwarns << "LLRadioGroup::setValue: value not found: " << value.asString() << llendl;
+ setSelectedIndex(-1, TRUE);
}
}
}
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 0588900600..8bd5698538 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -49,7 +49,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<bool> has_border;
+ Optional<bool> allow_deselect;
Multiple<ItemParams, AtLeast<1> > items;
Params();
};
@@ -73,7 +73,6 @@ public:
void setIndexEnabled(S32 index, BOOL enabled);
// return the index value of the selected item
S32 getSelectedIndex() const { return mSelectedIndex; }
-
// set the index value programatically
BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE);
@@ -103,12 +102,13 @@ public:
/*virtual*/ BOOL operateOnAll(EOperation op);
private:
- const LLFontGL* mFont;
- S32 mSelectedIndex;
+ const LLFontGL* mFont;
+ S32 mSelectedIndex;
+
typedef std::vector<class LLRadioCtrl*> button_list_t;
- button_list_t mRadioButtons;
+ button_list_t mRadioButtons;
- BOOL mHasBorder;
+ bool mAllowDeselect; // user can click on an already selected option to deselect it
};
#endif
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index 50b7bbab90..5e6840d7df 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -30,10 +30,15 @@
#include "lluicolor.h"
#include "lluictrlfactory.h"
+static LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
+static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
+static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
+
//
// LLRNGWriter - writes Relax NG schema files based on a param block
//
LLRNGWriter::LLRNGWriter()
+: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
{
// register various callbacks for inspecting the contents of a param block
registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4));
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 3146418a7d..380c477eb2 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -422,9 +422,10 @@ void LLScrollContainer::draw()
// Draw background
if( mIsOpaque )
{
+ F32 alpha = getCurrentTransparency();
+
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4fv( mBackgroundColor.get().mV );
- gl_rect_2d( mInnerRect );
+ gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha);
}
// Draw mScrolledViews and update scroll bars.
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index 2a4c1ca44c..696e4a2bb1 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -83,7 +83,14 @@ void LLScrollColumnHeader::draw()
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
- setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+ if (draw_arrow)
+ {
+ setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
+ }
+ else
+ {
+ setImageOverlay(LLUUID::null);
+ }
// Draw children
LLButton::draw();
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 84e438cfb7..b7848ec37c 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -259,15 +259,15 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
}
- for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns().begin();
- row_it != p.contents.columns().end();
+ for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns.begin();
+ row_it != p.contents.columns.end();
++row_it)
{
addColumn(*row_it);
}
- for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows().begin();
- row_it != p.contents.rows().end();
+ for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows.begin();
+ row_it != p.contents.rows.end();
++row_it)
{
addRow(*row_it);
@@ -322,6 +322,7 @@ LLScrollListCtrl::~LLScrollListCtrl()
delete mSortCallback;
std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
+ std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
}
@@ -537,23 +538,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
setNeedsSort();
break;
- case ADD_SORTED:
- {
- // sort by column 0, in ascending order
- std::vector<sort_column_t> single_sort_column;
- single_sort_column.push_back(std::make_pair(0, TRUE));
-
- mItemList.push_back(item);
- std::stable_sort(
- mItemList.begin(),
- mItemList.end(),
- SortScrollListItem(single_sort_column,mSortCallback));
-
- // ADD_SORTED just sorts by first column...
- // this might not match user sort criteria, so flag list as being in unsorted state
- setNeedsSort();
- break;
- }
+ case ADD_DEFAULT:
case ADD_BOTTOM:
mItemList.push_back(item);
setNeedsSort();
@@ -1498,8 +1483,9 @@ void LLScrollListCtrl::draw()
// Draw background
if (mBackgroundVisible)
{
+ F32 alpha = getCurrentTransparency();
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() );
+ gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() % alpha : mBgReadOnlyColor.get() % alpha );
}
if (mColumnsDirty)
@@ -2386,10 +2372,10 @@ void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )
void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending)
{
- std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.find(name);
+ column_map_t::iterator itor = mColumns.find(name);
if (itor != mColumns.end())
{
- sortByColumnIndex((*itor).second.mIndex, ascending);
+ sortByColumnIndex((*itor).second->mIndex, ascending);
}
}
@@ -2435,11 +2421,11 @@ void LLScrollListCtrl::dirtyColumns()
// just in case someone indexes into it immediately
mColumnsIndexed.resize(mColumns.size());
- std::map<std::string, LLScrollListColumn>::iterator column_itor;
+ column_map_t::iterator column_itor;
for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
{
- LLScrollListColumn *column = &column_itor->second;
- mColumnsIndexed[column_itor->second.mIndex] = column;
+ LLScrollListColumn *column = column_itor->second;
+ mColumnsIndexed[column_itor->second->mIndex] = column;
}
}
@@ -2578,7 +2564,8 @@ BOOL LLScrollListCtrl::canDeselect() const
void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
{
LLScrollListColumn::Params p;
- LLParamSDParser::instance().readSD(column, p);
+ LLParamSDParser parser;
+ parser.readSD(column, p);
addColumn(p, pos);
}
@@ -2596,8 +2583,8 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
if (mColumns.find(name) == mColumns.end())
{
// Add column
- mColumns[name] = LLScrollListColumn(column_params, this);
- LLScrollListColumn* new_column = &mColumns[name];
+ mColumns[name] = new LLScrollListColumn(column_params, this);
+ LLScrollListColumn* new_column = mColumns[name];
new_column->mIndex = mColumns.size()-1;
// Add button
@@ -2619,14 +2606,14 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
S32 top = mItemListRect.mTop;
S32 left = mItemListRect.mLeft;
- for (std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.begin();
+ for (column_map_t::iterator itor = mColumns.begin();
itor != mColumns.end();
++itor)
{
- if (itor->second.mIndex < new_column->mIndex &&
- itor->second.getWidth() > 0)
+ if (itor->second->mIndex < new_column->mIndex &&
+ itor->second->getWidth() > 0)
{
- left += itor->second.getWidth() + mColumnPadding;
+ left += itor->second->getWidth() + mColumnPadding;
}
}
@@ -2682,8 +2669,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
if (column->mSortingColumn != column->mName
&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
{
- LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
- column_index = info_redir.mIndex;
+ LLScrollListColumn* info_redir = parent->mColumns[column->mSortingColumn];
+ column_index = info_redir->mIndex;
}
// if this column is the primary sort key, reverse the direction
@@ -2716,16 +2703,17 @@ BOOL LLScrollListCtrl::hasSortOrder() const
void LLScrollListCtrl::clearColumns()
{
- std::map<std::string, LLScrollListColumn>::iterator itor;
+ column_map_t::iterator itor;
for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
{
- LLScrollColumnHeader *header = itor->second.mHeader;
+ LLScrollColumnHeader *header = itor->second->mHeader;
if (header)
{
removeChild(header);
delete header;
}
}
+ std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
mColumns.clear();
mSortColumns.clear();
mTotalStaticColumnWidth = 0;
@@ -2759,36 +2747,40 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
column_map_t::iterator column_itor = mColumns.find(name);
if (column_itor != mColumns.end())
{
- return &column_itor->second;
+ return column_itor->second;
}
return NULL;
}
-
+LLFastTimer::DeclareTimer FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item");
LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
{
+ LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
LLScrollListItem::Params item_params;
- LLParamSDParser::instance().readSD(element, item_params);
+ LLParamSDParser parser;
+ parser.readSD(element, item_params);
item_params.userdata = userdata;
return addRow(item_params, pos);
}
LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
{
+ LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
LLScrollListItem *new_item = new LLScrollListItem(item_p);
return addRow(new_item, item_p, pos);
}
LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
{
+ LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
if (!item_p.validateBlock() || !new_item) return NULL;
new_item->setNumColumns(mColumns.size());
// Add any columns we don't already have
S32 col_index = 0;
- for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns().begin();
- itor != item_p.columns().end();
+ for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns.begin();
+ itor != item_p.columns.end();
++itor)
{
LLScrollListCell::Params cell_p = *itor;
@@ -2816,7 +2808,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
new_column.width.pixel_width = cell_p.width;
}
addColumn(new_column);
- columnp = &mColumns[column];
+ columnp = mColumns[column];
new_item->setNumColumns(mColumns.size());
}
@@ -2839,7 +2831,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
col_index++;
}
- if (item_p.columns().empty())
+ if (item_p.columns.empty())
{
if (mColumns.empty())
{
@@ -2853,7 +2845,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value));
if (cell)
{
- LLScrollListColumn* columnp = &(mColumns.begin()->second);
+ LLScrollListColumn* columnp = mColumns.begin()->second;
new_item->setColumn(0, cell);
if (columnp->mHeader
@@ -2868,10 +2860,10 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
// add dummy cells for missing columns
for (column_map_t::iterator column_it = mColumns.begin(); column_it != mColumns.end(); ++column_it)
{
- S32 column_idx = column_it->second.mIndex;
+ S32 column_idx = column_it->second->mIndex;
if (new_item->getColumn(column_idx) == NULL)
{
- LLScrollListColumn* column_ptr = &column_it->second;
+ LLScrollListColumn* column_ptr = column_it->second;
LLScrollListCell::Params cell_p;
cell_p.width = column_ptr->getWidth();
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 8a2f893ba2..09ab89960d 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -491,7 +491,7 @@ private:
mutable bool mSorted;
- typedef std::map<std::string, LLScrollListColumn> column_map_t;
+ typedef std::map<std::string, LLScrollListColumn*> column_map_t;
column_map_t mColumns;
BOOL mDirty;
diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp
index 54c3060c4a..9ad13054cb 100644
--- a/indra/llui/llsdparam.cpp
+++ b/indra/llui/llsdparam.cpp
@@ -29,55 +29,61 @@
// Project includes
#include "llsdparam.h"
+#include "llsdutil.h"
+
+static LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
+static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
+static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
//
// LLParamSDParser
//
LLParamSDParser::LLParamSDParser()
+: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
{
using boost::bind;
- registerParserFuncs<S32>(bind(&LLParamSDParser::readTypedValue<S32>, this, _1, &LLSD::asInteger),
- bind(&LLParamSDParser::writeTypedValue<S32>, this, _1, _2));
- registerParserFuncs<U32>(bind(&LLParamSDParser::readTypedValue<U32>, this, _1, &LLSD::asInteger),
- bind(&LLParamSDParser::writeU32Param, this, _1, _2));
- registerParserFuncs<F32>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asReal),
- bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
- registerParserFuncs<F64>(bind(&LLParamSDParser::readTypedValue<F64>, this, _1, &LLSD::asReal),
- bind(&LLParamSDParser::writeTypedValue<F64>, this, _1, _2));
- registerParserFuncs<bool>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asBoolean),
- bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
- registerParserFuncs<std::string>(bind(&LLParamSDParser::readTypedValue<std::string>, this, _1, &LLSD::asString),
- bind(&LLParamSDParser::writeTypedValue<std::string>, this, _1, _2));
- registerParserFuncs<LLUUID>(bind(&LLParamSDParser::readTypedValue<LLUUID>, this, _1, &LLSD::asUUID),
- bind(&LLParamSDParser::writeTypedValue<LLUUID>, this, _1, _2));
- registerParserFuncs<LLDate>(bind(&LLParamSDParser::readTypedValue<LLDate>, this, _1, &LLSD::asDate),
- bind(&LLParamSDParser::writeTypedValue<LLDate>, this, _1, _2));
- registerParserFuncs<LLURI>(bind(&LLParamSDParser::readTypedValue<LLURI>, this, _1, &LLSD::asURI),
- bind(&LLParamSDParser::writeTypedValue<LLURI>, this, _1, _2));
- registerParserFuncs<LLSD>(bind(&LLParamSDParser::readSDParam, this, _1),
- bind(&LLParamSDParser::writeTypedValue<LLSD>, this, _1, _2));
-}
-
-bool LLParamSDParser::readSDParam(void* value_ptr)
-{
- if (!mCurReadSD) return false;
- *((LLSD*)value_ptr) = *mCurReadSD;
- return true;
+ if (sReadFuncs.empty())
+ {
+ registerParserFuncs<LLInitParam::NoParamValue>(readNoValue, &LLParamSDParser::writeNoValue);
+ registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>);
+ registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param);
+ registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>);
+ registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>);
+ registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>);
+ registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>);
+ registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>);
+ registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>);
+ registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>);
+ registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>);
+ }
}
// special case handling of U32 due to ambiguous LLSD::assign overload
-bool LLParamSDParser::writeU32Param(const void* val_ptr, const parser_t::name_stack_t& name_stack)
+bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
{
- if (!mWriteSD) return false;
+ LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
+ if (!sdparser.mWriteRootSD) return false;
- LLSD* sd_to_write = getSDWriteNode(name_stack);
+ LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
if (!sd_to_write) return false;
sd_to_write->assign((S32)*((const U32*)val_ptr));
return true;
}
+bool LLParamSDParser::writeNoValue(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
+{
+ LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
+ if (!sdparser.mWriteRootSD) return false;
+
+ LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
+ if (!sd_to_write) return false;
+
+ return true;
+}
+
+
void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)
{
mCurReadSD = NULL;
@@ -89,10 +95,13 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool
void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
{
- mWriteSD = &sd;
+ mNameStack.clear();
+ mWriteRootSD = &sd;
block.serializeBlock(*this);
}
+const LLSD NO_VALUE_MARKER;
+
void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block)
{
if (sd.isMap())
@@ -116,6 +125,11 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block
readSDValues(*it, block);
}
}
+ else if (sd.isUndefined())
+ {
+ mCurReadSD = &NO_VALUE_MARKER;
+ block.submitValue(mNameStack, *this);
+ }
else
{
mCurReadSD = &sd;
@@ -139,6 +153,162 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block
LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)
{
//TODO: implement nested LLSD writing
- return mWriteSD;
+ LLSD* sd_to_write = mWriteRootSD;
+ bool new_traversal = false;
+ for (name_stack_t::const_iterator it = name_stack.begin(), prev_it = mNameStack.begin();
+ it != name_stack.end();
+ ++it)
+ {
+ bool new_array_entry = false;
+ if (prev_it == mNameStack.end())
+ {
+ new_traversal = true;
+ }
+ else
+ {
+ if (!new_traversal // have not diverged yet from previous trace
+ && prev_it->first == it->first // names match
+ && prev_it->second != it->second) // versions differ
+ {
+ // name stacks match, but version numbers differ in last place.
+ // create a different entry at this point using an LLSD array
+ new_array_entry = true;
+ }
+ if (prev_it->first != it->first // names differ
+ || prev_it->second != it->second) // versions differ
+ {
+ // at this point we have diverged from our last trace
+ // so any elements referenced here are new
+ new_traversal = true;
+ }
+ }
+
+ LLSD* child_sd = &(*sd_to_write)[it->first];
+
+ if (child_sd->isArray())
+ {
+ if (new_traversal)
+ {
+ // write to new element at end
+ sd_to_write = &(*child_sd)[child_sd->size()];
+ }
+ else
+ {
+ // write to last of existing elements, or first element if empty
+ sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)];
+ }
+ }
+ else
+ {
+ if (new_array_entry && !child_sd->isArray())
+ {
+ // copy child contents into first element of an array
+ LLSD new_array = LLSD::emptyArray();
+ new_array.append(*child_sd);
+ // assign array to slot that previously held the single value
+ *child_sd = new_array;
+ // return next element in that array
+ sd_to_write = &((*child_sd)[1]);
+ }
+ else
+ {
+ sd_to_write = child_sd;
+ }
+ }
+ if (prev_it != mNameStack.end())
+ {
+ ++prev_it;
+ }
+ }
+ mNameStack = name_stack;
+
+ //llinfos << ll_pretty_print_sd(*mWriteRootSD) << llendl;
+ return sd_to_write;
+}
+
+bool LLParamSDParser::readNoValue(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+ return self.mCurReadSD == &NO_VALUE_MARKER;
+}
+
+
+bool LLParamSDParser::readS32(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((S32*)val_ptr) = self.mCurReadSD->asInteger();
+ return true;
+}
+
+bool LLParamSDParser::readU32(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((U32*)val_ptr) = self.mCurReadSD->asInteger();
+ return true;
+}
+
+bool LLParamSDParser::readF32(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((F32*)val_ptr) = self.mCurReadSD->asReal();
+ return true;
+}
+
+bool LLParamSDParser::readF64(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((F64*)val_ptr) = self.mCurReadSD->asReal();
+ return true;
+}
+
+bool LLParamSDParser::readBool(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((bool*)val_ptr) = self.mCurReadSD->asBoolean();
+ return true;
}
+bool LLParamSDParser::readString(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((std::string*)val_ptr) = self.mCurReadSD->asString();
+ return true;
+}
+
+bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID();
+ return true;
+}
+
+bool LLParamSDParser::readDate(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((LLDate*)val_ptr) = self.mCurReadSD->asDate();
+ return true;
+}
+
+bool LLParamSDParser::readURI(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((LLURI*)val_ptr) = self.mCurReadSD->asURI();
+ return true;
+}
+
+bool LLParamSDParser::readSD(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+
+ *((LLSD*)val_ptr) = *self.mCurReadSD;
+ return true;
+}
diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h
index e028fc30c2..69dab2b411 100644
--- a/indra/llui/llsdparam.h
+++ b/indra/llui/llsdparam.h
@@ -31,17 +31,14 @@
#include "llinitparam.h"
class LLParamSDParser
-: public LLInitParam::Parser,
- public LLSingleton<LLParamSDParser>
+: public LLInitParam::Parser
{
LOG_CLASS(LLParamSDParser);
typedef LLInitParam::Parser parser_t;
-protected:
- LLParamSDParser();
- friend class LLSingleton<LLParamSDParser>;
public:
+ LLParamSDParser();
void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
@@ -51,20 +48,12 @@ private:
void readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block);
template<typename T>
- bool readTypedValue(void* val_ptr, boost::function<T(const LLSD&)> parser_func)
- {
- if (!mCurReadSD) return false;
-
- *((T*)val_ptr) = parser_func(*mCurReadSD);
- return true;
- }
-
- template<typename T>
- bool writeTypedValue(const void* val_ptr, const parser_t::name_stack_t& name_stack)
+ static bool writeTypedValue(Parser& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
{
- if (!mWriteSD) return false;
+ LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
+ if (!sdparser.mWriteRootSD) return false;
- LLSD* sd_to_write = getSDWriteNode(name_stack);
+ LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
if (!sd_to_write) return false;
sd_to_write->assign(*((const T*)val_ptr));
@@ -73,12 +62,25 @@ private:
LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack);
- bool readSDParam(void* value_ptr);
- bool writeU32Param(const void* value_ptr, const parser_t::name_stack_t& name_stack);
+ static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack);
+ static bool writeNoValue(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack);
+
+ static bool readNoValue(Parser& parser, void* val_ptr);
+ static bool readS32(Parser& parser, void* val_ptr);
+ static bool readU32(Parser& parser, void* val_ptr);
+ static bool readF32(Parser& parser, void* val_ptr);
+ static bool readF64(Parser& parser, void* val_ptr);
+ static bool readBool(Parser& parser, void* val_ptr);
+ static bool readString(Parser& parser, void* val_ptr);
+ static bool readUUID(Parser& parser, void* val_ptr);
+ static bool readDate(Parser& parser, void* val_ptr);
+ static bool readURI(Parser& parser, void* val_ptr);
+ static bool readSD(Parser& parser, void* val_ptr);
Parser::name_stack_t mNameStack;
const LLSD* mCurReadSD;
- LLSD* mWriteSD;
+ LLSD* mWriteRootSD;
+ LLSD* mCurWriteSD;
};
template<typename T>
@@ -88,7 +90,8 @@ class LLSDParamAdapter : public T
LLSDParamAdapter() {}
LLSDParamAdapter(const LLSD& sd)
{
- LLParamSDParser::instance().readSD(sd, *this);
+ LLParamSDParser parser;
+ parser.readSD(sd, *this);
}
LLSDParamAdapter(const T& val)
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 68823ed68e..700c17ea3e 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -29,6 +29,7 @@
#include "llf32uictrl.h"
#include "v4color.h"
+#include "lluiimage.h"
class LLSlider : public LLF32UICtrl
{
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 9decfa0b25..6b4e9cf923 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -119,7 +119,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
{
params.font(p.font);
}
- params.max_length_bytes(MAX_STRING_LENGTH);
+ params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
if( mPrecision>0 )//should accept float numbers
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 5e09cee78b..bb731f4f7e 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -40,7 +40,8 @@ LLStyle::Params::Params()
selected_color("selected_color", LLColor4::black),
font("font", LLFontGL::getFontMonospace()),
image("image"),
- link_href("href")
+ link_href("href"),
+ is_link("is_link")
{}
@@ -51,6 +52,7 @@ LLStyle::LLStyle(const LLStyle::Params& p)
mSelectedColor(p.selected_color),
mFont(p.font()),
mLink(p.link_href),
+ mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()),
mDropShadow(p.drop_shadow),
mImagep(p.image())
{}
@@ -73,7 +75,7 @@ void LLStyle::setLinkHREF(const std::string& href)
BOOL LLStyle::isLink() const
{
- return mLink.size();
+ return mIsLink;
}
BOOL LLStyle::isVisible() const
@@ -86,7 +88,7 @@ void LLStyle::setVisible(BOOL is_visible)
mVisible = is_visible;
}
-LLUIImagePtr LLStyle::getImage() const
+LLPointer<LLUIImage> LLStyle::getImage() const
{
return mImagep;
}
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index 66cd639936..9f1eba79d8 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -30,6 +30,7 @@
#include "v4color.h"
#include "llui.h"
#include "llinitparam.h"
+#include "lluiimage.h"
class LLFontGL;
@@ -46,6 +47,7 @@ public:
Optional<const LLFontGL*> font;
Optional<LLUIImage*> image;
Optional<std::string> link_href;
+ Optional<bool> is_link;
Params();
};
LLStyle(const Params& p = Params());
@@ -71,7 +73,7 @@ public:
void setLinkHREF(const std::string& href);
BOOL isLink() const;
- LLUIImagePtr getImage() const;
+ LLPointer<LLUIImage> getImage() const;
void setImage(const LLUUID& src);
void setImage(const std::string& name);
@@ -106,7 +108,8 @@ private:
std::string mFontName;
const LLFontGL* mFont;
std::string mLink;
- LLUIImagePtr mImagep;
+ bool mIsLink;
+ LLPointer<LLUIImage> mImagep;
};
typedef LLPointer<LLStyle> LLStyleSP;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 574b24cf13..349dbc3405 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -5,7 +5,7 @@
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2009-2010, 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
@@ -157,6 +157,7 @@ LLTextBase::Params::Params()
read_only("read_only", false),
v_pad("v_pad", 0),
h_pad("h_pad", 0),
+ clip("clip", true),
clip_partial("clip_partial", true),
line_spacing("line_spacing"),
max_text_length("max_length", 255),
@@ -199,6 +200,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mVAlign(p.font_valign),
mLineSpacingMult(p.line_spacing.multiple),
mLineSpacingPixels(p.line_spacing.pixels),
+ mClip(p.clip),
mClipPartial(p.clip_partial && !p.allow_scroll),
mTrackEnd( p.track_end ),
mScrollIndex(-1),
@@ -278,7 +280,7 @@ bool LLTextBase::truncate()
if (getLength() >= S32(mMaxTextByteLength / 4))
{
// Have to check actual byte size
- LLWString text(getWText());
+ LLWString text(getWText());
S32 utf8_byte_size = wstring_utf8_length(text);
if ( utf8_byte_size > mMaxTextByteLength )
{
@@ -334,7 +336,7 @@ void LLTextBase::drawSelectionBackground()
// binary search for line that starts before top of visible buffer
line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
- line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
+ line_list_t::const_iterator end_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
bool done = false;
@@ -475,8 +477,8 @@ void LLTextBase::drawCursor()
{
LLColor4 text_color;
const LLFontGL* fontp;
- text_color = segmentp->getColor();
- fontp = segmentp->getStyle()->getFont();
+ text_color = segmentp->getColor();
+ fontp = segmentp->getStyle()->getFont();
fontp->render(text, mCursorPos, cursor_rect,
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
LLFontGL::LEFT, mVAlign,
@@ -512,7 +514,6 @@ void LLTextBase::drawText()
selection_right = llmax( mSelectionStart, mSelectionEnd );
}
- LLRect scrolled_view_rect = getVisibleDocumentRect();
std::pair<S32, S32> line_range = getVisibleLines(mClipPartial);
S32 first_line = line_range.first;
S32 last_line = line_range.second;
@@ -545,10 +546,9 @@ void LLTextBase::drawText()
line_end = next_start;
}
- LLRect text_rect(line.mRect.mLeft + mVisibleTextRect.mLeft - scrolled_view_rect.mLeft,
- line.mRect.mTop - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom,
- llmin(mDocumentView->getRect().getWidth(), line.mRect.mRight) - scrolled_view_rect.mLeft,
- line.mRect.mBottom - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom);
+ LLRect text_rect(line.mRect);
+ text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents
+ text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position
// draw a single line of text
S32 seg_start = line_start;
@@ -654,7 +654,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
}
text.insert(pos, wstr);
- getViewModel()->setDisplay(text);
+ getViewModel()->setDisplay(text);
if ( truncate() )
{
@@ -669,7 +669,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
{
- LLWString text(getWText());
+ LLWString text(getWText());
segment_set_t::iterator seg_iter = getSegIterContaining(pos);
while(seg_iter != mSegments.end())
{
@@ -716,7 +716,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
}
text.erase(pos, length);
- getViewModel()->setDisplay(text);
+ getViewModel()->setDisplay(text);
// recreate default segment in case we erased everything
createDefaultSegment();
@@ -733,9 +733,9 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc)
{
return 0;
}
- LLWString text(getWText());
+ LLWString text(getWText());
text[pos] = wc;
- getViewModel()->setDisplay(text);
+ getViewModel()->setDisplay(text);
onValueChange(pos, pos + 1);
needsReflow(pos);
@@ -856,7 +856,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask)
// Did we just click on a link?
if (mURLClickSignal
&& cur_segment->getStyle()
- && cur_segment->getStyle()->isLink())
+ && cur_segment->getStyle()->isLink())
{
// *TODO: send URL here?
(*mURLClickSignal)(this, LLSD() );
@@ -993,44 +993,68 @@ void LLTextBase::draw()
updateScrollFromCursor();
}
- LLRect doc_rect;
+ LLRect text_rect;
if (mScroller)
{
- mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &doc_rect, this);
+ mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &text_rect, this);
}
else
{
- doc_rect = getLocalRect();
+ LLRect visible_lines_rect;
+ std::pair<S32, S32> line_range = getVisibleLines(mClipPartial);
+ for (S32 i = line_range.first; i < line_range.second; i++)
+ {
+ if (visible_lines_rect.isEmpty())
+ {
+ visible_lines_rect = mLineInfoList[i].mRect;
+ }
+ else
+ {
+ visible_lines_rect.unionWith(mLineInfoList[i].mRect);
+ }
+ }
+ text_rect = visible_lines_rect;
+ text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom);
}
if (mBGVisible)
{
+ F32 alpha = getCurrentTransparency();
// clip background rect against extents, if we support scrolling
LLRect bg_rect = mVisibleTextRect;
if (mScroller)
{
- bg_rect.intersectWith(doc_rect);
+ bg_rect.intersectWith(text_rect);
}
LLColor4 bg_color = mReadOnly
? mReadOnlyBgColor.get()
: hasFocus()
? mFocusBgColor.get()
: mWriteableBgColor.get();
- gl_rect_2d(doc_rect, bg_color, TRUE);
+ gl_rect_2d(text_rect, bg_color % alpha, TRUE);
}
- // draw document view
- LLUICtrl::draw();
-
- {
- // only clip if we support scrolling...
- // since convention is that text boxes never vertically truncate their contents
- // regardless of rect bounds
- LLLocalClipRect clip(doc_rect, mScroller != NULL);
+ bool should_clip = mClip || mScroller != NULL;
+ { LLLocalClipRect clip(text_rect, should_clip);
+
+ // draw document view
+ if (mScroller)
+ {
+ drawChild(mScroller);
+ }
+ else
+ {
+ drawChild(mDocumentView);
+ }
+
drawSelectionBackground();
drawText();
drawCursor();
}
+
+ mDocumentView->setVisible(FALSE);
+ LLUICtrl::draw();
+ mDocumentView->setVisible(TRUE);
}
@@ -1094,8 +1118,7 @@ void LLTextBase::updateScrollFromCursor()
// scroll so that the cursor is at the top of the page
LLRect scroller_doc_window = getVisibleDocumentRect();
- LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos);
- cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom);
+ LLRect cursor_rect_doc = getDocRectFromDocIndex(mCursorPos);
mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5));
}
@@ -1139,7 +1162,7 @@ void LLTextBase::reflow()
S32 first_line = getFirstVisibleLine();
// if scroll anchor not on first line, update it to first character of first line
- if (!mLineInfoList.empty()
+ if ((first_line < mLineInfoList.size())
&& (mScrollIndex < mLineInfoList[first_line].mDocIndexStart
|| mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
{
@@ -1341,9 +1364,9 @@ S32 LLTextBase::getLineStart( S32 line ) const
{
S32 num_lines = getLineCount();
if (num_lines == 0)
- {
+ {
return 0;
- }
+ }
line = llclamp(line, 0, num_lines-1);
return mLineInfoList[line].mDocIndexStart;
@@ -1353,9 +1376,9 @@ S32 LLTextBase::getLineEnd( S32 line ) const
{
S32 num_lines = getLineCount();
if (num_lines == 0)
- {
+ {
return 0;
- }
+ }
line = llclamp(line, 0, num_lines-1);
return mLineInfoList[line].mDocIndexEnd;
@@ -1414,7 +1437,7 @@ S32 LLTextBase::getFirstVisibleLine() const
return iter - mLineInfoList.begin();
}
-std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible)
+std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible)
{
LLRect visible_region = getVisibleDocumentRect();
line_list_t::const_iterator first_iter;
@@ -1423,14 +1446,14 @@ std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible)
// make sure we have an up-to-date mLineInfoList
reflow();
- if (fully_visible)
+ if (require_fully_visible)
{
first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top());
- last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom());
+ last_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom());
}
else
{
- first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
+ first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top());
}
return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin());
@@ -1591,7 +1614,10 @@ void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params&
// appendText modifies mCursorPos...
appendText(text, false, input_params);
// ...so move cursor to top after appending text
- startOfDoc();
+ if (!mTrackEnd)
+ {
+ startOfDoc();
+ }
onValueChange(0, getLength());
}
@@ -1602,28 +1628,42 @@ std::string LLTextBase::getText() const
return getViewModel()->getValue().asString();
}
+// IDEVO - icons can be UI image names or UUID sent from
+// server with avatar display name
+static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
+{
+ if (LLUUID::validate(icon_name))
+ {
+ return LLUI::getUIImageByID( LLUUID(icon_name) );
+ }
+ else
+ {
+ return LLUI::getUIImage(icon_name);
+ }
+}
+
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LLStyle::Params style_params(input_params);
style_params.fillFrom(getDefaultStyleParams());
S32 part = (S32)LLTextParser::WHOLE;
- if(mParseHTML)
+ if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
{
S32 start=0,end=0;
LLUrlMatch match;
std::string text = new_text;
while ( LLUrlRegistry::instance().findUrl(text, match,
- boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) )
+ boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )
{
+
+ LLTextUtil::processUrlMatch(&match,this);
+
start = match.getStart();
end = match.getEnd()+1;
- LLStyle::Params link_params = style_params;
- link_params.color = match.getColor();
- link_params.readonly_color = match.getColor();
- link_params.font.style("UNDERLINE");
- link_params.link_href = match.getUrl();
+ LLStyle::Params link_params(style_params);
+ link_params.overwriteFrom(match.getStyle());
// output the text before the Url
if (start > 0)
@@ -1640,30 +1680,20 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
std::string subtext=text.substr(0,start);
appendAndHighlightText(subtext, part, style_params);
}
-
- // inserts an avatar icon preceding the Url if appropriate
- LLTextUtil::processUrlMatch(&match,this);
-
- // output the styled Url (unless we've been asked to suppress hyperlinking)
- if (match.isLinkDisabled())
+ // output the styled Url
+ appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
+
+ // set the tooltip for the Url label
+ if (! match.getTooltip().empty())
{
- appendAndHighlightText(match.getLabel(), part, style_params);
+ segment_set_t::iterator it = getSegIterContaining(getLength()-1);
+ if (it != mSegments.end())
+ {
+ LLTextSegmentPtr segment = *it;
+ segment->setToolTip(match.getTooltip());
+ }
}
- else
- {
- appendAndHighlightText(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
- // set the tooltip for the Url label
- if (! match.getTooltip().empty())
- {
- segment_set_t::iterator it = getSegIterContaining(getLength()-1);
- if (it != mSegments.end())
- {
- LLTextSegmentPtr segment = *it;
- segment->setToolTip(match.getTooltip());
- }
- }
- }
// move on to the rest of the text after the Url
if (end < (S32)text.length())
{
@@ -1848,8 +1878,9 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig
}
-void LLTextBase::replaceUrlLabel(const std::string &url,
- const std::string &label)
+void LLTextBase::replaceUrl(const std::string &url,
+ const std::string &label,
+ const std::string &icon)
{
// get the full (wide) text for the editor so we can change it
LLWString text = getWText();
@@ -1870,7 +1901,7 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
seg->setEnd(seg_start + seg_length);
// if we find a link with our Url, then replace the label
- if (style->isLink() && style->getLinkHREF() == url)
+ if (style->getLinkHREF() == url)
{
S32 start = seg->getStart();
S32 end = seg->getEnd();
@@ -1879,6 +1910,21 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
modified = true;
}
+ // Icon might be updated when more avatar or group info
+ // becomes available
+ if (style->isImage() && style->getLinkHREF() == url)
+ {
+ LLUIImagePtr image = image_from_icon_name( icon );
+ if (image)
+ {
+ LLStyle::Params icon_params;
+ icon_params.image = image;
+ LLStyleConstSP new_style(new LLStyle(icon_params));
+ seg->setStyle(new_style);
+ modified = true;
+ }
+ }
+
// work out the character offset for the next segment
seg_start = seg->getEnd();
}
@@ -1901,7 +1947,7 @@ void LLTextBase::setWText(const LLWString& text)
const LLWString& LLTextBase::getWText() const
{
- return getViewModel()->getDisplay();
+ return getViewModel()->getDisplay();
}
// If round is true, if the position is on the right half of a character, the cursor
@@ -1912,9 +1958,12 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
{
// Figure out which line we're nearest to.
LLRect visible_region = getVisibleDocumentRect();
+ LLRect doc_rect = mDocumentView->getRect();
+
+ S32 doc_y = local_y - doc_rect.mBottom;
// binary search for line that starts before local_y
- line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mVisibleTextRect.mBottom + visible_region.mBottom, compare_bottom());
+ line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_y, compare_bottom());
if (line_iter == mLineInfoList.end())
{
@@ -1922,7 +1971,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
}
S32 pos = getLength();
- S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft - visible_region.mLeft;
+ S32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft;
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
@@ -1944,7 +1993,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
}
// if we've reached a line of text *below* the mouse cursor, doc index is first character on that line
- if (hit_past_end_of_line && local_y - mVisibleTextRect.mBottom + visible_region.mBottom > line_iter->mRect.mTop)
+ if (hit_past_end_of_line && doc_y > line_iter->mRect.mTop)
{
pos = segment_line_start;
break;
@@ -1973,11 +2022,10 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
pos = segment_line_start + offset;
break;
}
- else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)
+ else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd)
{
// segment wraps to next line, so just set doc pos to the end of the line
- // segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
- pos = llmin(getLength(), line_iter->mDocIndexEnd);
+ pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength());
break;
}
start_x += text_width;
@@ -2193,19 +2241,39 @@ bool LLTextBase::scrolledToEnd()
return mScroller->isAtBottom();
}
-
bool LLTextBase::setCursor(S32 row, S32 column)
{
- if (0 <= row && row < (S32)mLineInfoList.size())
+ if (row < 0 || column < 0) return false;
+
+ S32 n_lines = mLineInfoList.size();
+ for (S32 line = row; line < n_lines; ++line)
{
- S32 doc_pos = mLineInfoList[row].mDocIndexStart;
- column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
- doc_pos += column;
- updateCursorXPos();
+ const line_info& li = mLineInfoList[line];
+
+ if (li.mLineNum < row)
+ {
+ continue;
+ }
+ else if (li.mLineNum > row)
+ {
+ break; // invalid column specified
+ }
+
+ // Found the given row.
+ S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;;
+ if (column >= line_length)
+ {
+ column -= line_length;
+ continue;
+ }
+ // Found the given column.
+ updateCursorXPos();
+ S32 doc_pos = li.mDocIndexStart + column;
return setCursorPos(doc_pos);
}
- return false;
+
+ return false; // invalid row or column specified
}
@@ -2360,10 +2428,37 @@ LLRect LLTextBase::getVisibleDocumentRect() const
{
return mScroller->getVisibleContentRect();
}
- else
+ else if (mClip)
{
- // entire document rect is visible when not scrolling
+ LLRect visible_text_rect = getVisibleTextRect();
+ LLRect doc_rect = mDocumentView->getRect();
+ visible_text_rect.translate(-doc_rect.mLeft, -doc_rect.mBottom);
+
+ // reject partially visible lines
+ LLRect visible_lines_rect;
+ for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end();
+ it != end_it;
+ ++it)
+ {
+ bool line_visible = mClipPartial ? visible_text_rect.contains(it->mRect) : visible_text_rect.overlaps(it->mRect);
+ if (line_visible)
+ {
+ if (visible_lines_rect.isEmpty())
+ {
+ visible_lines_rect = it->mRect;
+ }
+ else
+ {
+ visible_lines_rect.unionWith(it->mRect);
+ }
+ }
+ }
+ return visible_lines_rect;
+ }
+ else
+ { // entire document rect is visible
// but offset according to height of widget
+
LLRect doc_rect = mDocumentView->getLocalRect();
doc_rect.mLeft -= mDocumentView->getRect().mLeft;
// adjust for height of text above widget baseline
@@ -2481,21 +2576,21 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha;
- if( selection_start > seg_start )
+ if( selection_start > seg_start )
{
// Draw normally
S32 start = seg_start;
S32 end = llmin( selection_start, seg_end );
S32 length = end - start;
font->render(text, start,
- rect,
- color,
- LLFontGL::LEFT, mEditor.mVAlign,
- LLFontGL::NORMAL,
- mStyle->getShadowType(),
- length,
- &right_x,
- mEditor.getUseEllipses());
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses());
}
rect.mLeft = (S32)ceil(right_x);
@@ -2507,14 +2602,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 length = end - start;
font->render(text, start,
- rect,
- mStyle->getSelectedColor().get(),
- LLFontGL::LEFT, mEditor.mVAlign,
- LLFontGL::NORMAL,
- LLFontGL::NO_SHADOW,
- length,
- &right_x,
- mEditor.getUseEllipses());
+ rect,
+ mStyle->getSelectedColor().get(),
+ LLFontGL::LEFT, mEditor.mVAlign,
+ LLFontGL::NORMAL,
+ LLFontGL::NO_SHADOW,
+ length,
+ &right_x,
+ mEditor.getUseEllipses());
}
rect.mLeft = (S32)ceil(right_x);
if( selection_end < seg_end )
@@ -2524,14 +2619,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 end = seg_end;
S32 length = end - start;
font->render(text, start,
- rect,
- color,
- LLFontGL::LEFT, mEditor.mVAlign,
- LLFontGL::NORMAL,
- mStyle->getShadowType(),
- length,
- &right_x,
- mEditor.getUseEllipses());
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses());
}
return right_x;
}
@@ -2869,11 +2964,18 @@ bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width
S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
LLUIImagePtr image = mStyle->getImage();
+
+ if (image.isNull())
+ {
+ return 1;
+ }
+
S32 image_width = image->getWidth();
if(line_offset == 0 || num_pixels>image_width + IMAGE_HPAD)
{
return 1;
}
+
return 0;
}
@@ -2883,18 +2985,21 @@ F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 select
{
LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha;
LLUIImagePtr image = mStyle->getImage();
- S32 style_image_height = image->getHeight();
- S32 style_image_width = image->getWidth();
- // Text is drawn from the top of the draw_rect downward
-
- S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
- // Align image to center of draw rect
- S32 image_bottom = text_center - (style_image_height / 2);
- image->draw(draw_rect.mLeft, image_bottom,
- style_image_width, style_image_height, color);
-
- const S32 IMAGE_HPAD = 3;
- return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
+ if (image.notNull())
+ {
+ S32 style_image_height = image->getHeight();
+ S32 style_image_width = image->getWidth();
+ // Text is drawn from the top of the draw_rect downward
+
+ S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
+ // Align image to center of draw rect
+ S32 image_bottom = text_center - (style_image_height / 2);
+ image->draw(draw_rect.mLeft, image_bottom,
+ style_image_width, style_image_height, color);
+
+ const S32 IMAGE_HPAD = 3;
+ return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
+ }
}
return 0.0;
}
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index e5dfecad54..7d545a1ba6 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -235,6 +235,7 @@ class LLTextBase
public:
friend class LLTextSegment;
friend class LLNormalTextSegment;
+ friend class LLUICtrlFactory;
struct LineSpacingParams : public LLInitParam::Choice<LineSpacingParams>
{
@@ -264,6 +265,7 @@ public:
use_ellipses,
parse_urls,
parse_highlights,
+ clip,
clip_partial;
Optional<S32> v_pad,
@@ -337,7 +339,7 @@ public:
void addDocumentChild(LLView* view);
void removeDocumentChild(LLView* view);
const LLView* getDocumentView() const { return mDocumentView; }
- LLRect getVisibleTextRect() { return mVisibleTextRect; }
+ LLRect getVisibleTextRect() const { return mVisibleTextRect; }
LLRect getTextBoundingRect();
LLRect getVisibleDocumentRect() const;
@@ -492,7 +494,11 @@ protected:
// misc
void updateRects();
void needsScroll() { mScrollNeeded = TRUE; }
- void replaceUrlLabel(const std::string &url, const std::string &label);
+
+ struct URLLabelCallback;
+ // Replace a URL with a new icon and label, for example, when
+ // avatar names are looked up.
+ void replaceUrl(const std::string &url, const std::string &label, const std::string& icon);
void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params());
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
@@ -547,6 +553,7 @@ protected:
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
bool mReadOnly;
bool mBGVisible; // render background?
+ bool mClip; // clip text to widget rect
bool mClipPartial; // false if we show lines that are partially inside bounding rect
bool mPlainText; // didn't use Image or Icon segments
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 94bf716e7d..9bd445988d 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -277,6 +277,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mHPad += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
updateRects();
}
+
+ mParseOnTheFly = TRUE;
}
void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
@@ -324,8 +326,10 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param
blockUndo();
deselect();
-
+
+ mParseOnTheFly = FALSE;
LLTextBase::setText(utf8str, input_params);
+ mParseOnTheFly = TRUE;
resetDirty();
}
@@ -588,6 +592,10 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
}
+ // Disabling parsing on the fly to avoid updating text segments
+ // until all indentation commands are executed.
+ mParseOnTheFly = FALSE;
+
// Find each start-of-line and indent it
do
{
@@ -613,6 +621,8 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
while( cur < right );
+ mParseOnTheFly = TRUE;
+
if( (right < getLength()) && (text[right] == '\n') )
{
right++;
@@ -1367,6 +1377,7 @@ void LLTextEditor::pastePrimary()
// paste from primary (itsprimary==true) or clipboard (itsprimary==false)
void LLTextEditor::pasteHelper(bool is_primary)
{
+ mParseOnTheFly = FALSE;
bool can_paste_it;
if (is_primary)
{
@@ -1450,6 +1461,7 @@ void LLTextEditor::pasteHelper(bool is_primary)
deselect();
onKeyStroke();
+ mParseOnTheFly = TRUE;
}
@@ -2385,7 +2397,7 @@ void LLTextEditor::loadKeywords(const std::string& filename,
void LLTextEditor::updateSegments()
{
- if (mReflowIndex < S32_MAX && mKeywords.isLoaded())
+ if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly)
{
LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
// HACK: No non-ascii keywords for now
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 58ecefdccb..9e4b95003b 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -315,6 +315,7 @@ private:
BOOL mAllowEmbeddedItems;
bool mShowContextMenu;
+ bool mParseOnTheFly;
LLUUID mSourceID;
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index 0eb2dc1387..d29260750f 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
: LLMenuGL(p),
mButtonRect(),
+ mVisibilityChangeSignal(NULL),
mClosedByButtonClick(false)
{
}
+LLToggleableMenu::~LLToggleableMenu()
+{
+ delete mVisibilityChangeSignal;
+}
+
+boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
+{
+ if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
+ return mVisibilityChangeSignal->connect(cb);
+}
+
// virtual
void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
@@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
mClosedByButtonClick = true;
}
+
+ if (mVisibilityChangeSignal)
+ {
+ (*mVisibilityChangeSignal)(this,
+ LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
+ }
}
void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
index f036cdfffb..2094bd776f 100644
--- a/indra/llui/lltoggleablemenu.h
+++ b/indra/llui/lltoggleablemenu.h
@@ -41,6 +41,10 @@ protected:
LLToggleableMenu(const Params&);
friend class LLUICtrlFactory;
public:
+ ~LLToggleableMenu();
+
+ boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
+
virtual void handleVisibilityChange (BOOL curVisibilityIn);
const LLRect& getButtonRect() const { return mButtonRect; }
@@ -57,6 +61,7 @@ public:
protected:
bool mClosedByButtonClick;
LLRect mButtonRect;
+ commit_signal_t* mVisibilityChangeSignal;
};
#endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index b02d3122fe..6390039794 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -78,9 +78,9 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask)
LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance();
- if (x != last_x && y != last_y)
+ if (x != last_x && y != last_y && !tooltip_mgr.getMouseNearRect().pointInRect(x, y))
{
- // allow new tooltips because mouse moved
+ // allow new tooltips because mouse moved outside of mouse near rect
tooltip_mgr.unblockToolTips();
}
@@ -276,8 +276,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
if (p.styled_message.isProvided())
{
- for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message().begin();
- text_it != p.styled_message().end();
+ for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message.begin();
+ text_it != p.styled_message.end();
++text_it)
{
mTextBox->appendText(text_it->text(), false, text_it->style);
@@ -580,6 +580,7 @@ void LLToolTipMgr::updateToolTipVisibility()
if (mToolTip->getVisibleTime() > tooltip_timeout)
{
hideToolTips();
+ unblockToolTips();
}
}
}
diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp
index 9d0ff9d5cb..58fa8a0828 100644
--- a/indra/llui/lltransutil.cpp
+++ b/indra/llui/lltransutil.cpp
@@ -26,10 +26,11 @@
#include "linden_common.h"
+#include "lltransutil.h"
+
#include "lltrans.h"
#include "lluictrlfactory.h"
-
-#include "lltransutil.h"
+#include "llxmlnode.h"
bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args)
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index d33d8e3178..8020ca802b 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -61,6 +61,8 @@
// for XUIParse
#include "llquaternion.h"
#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/find_iterator.hpp>
+#include <boost/algorithm/string/finder.hpp>
//
// Globals
@@ -950,7 +952,7 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
}
// Draw gray and white checkerboard with black border
-void gl_rect_2d_checkerboard(const LLRect& rect)
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
{
// Initialize the first time this is called.
const S32 PIXELS = 32;
@@ -971,11 +973,11 @@ void gl_rect_2d_checkerboard(const LLRect& rect)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// ...white squares
- gGL.color3f( 1.f, 1.f, 1.f );
+ gGL.color4f( 1.f, 1.f, 1.f, alpha );
gl_rect_2d(rect);
// ...gray squares
- gGL.color3f( .7f, .7f, .7f );
+ gGL.color4f( .7f, .7f, .7f, alpha );
gGL.flush();
glPolygonStipple( checkerboard );
@@ -1596,23 +1598,25 @@ void LLUI::initClass(const settings_map_t& settings,
sWindow = NULL; // set later in startup
LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
+ LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
+
// Callbacks for associating controls with floater visibilty:
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));
+ reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2));
+ reg.add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2));
+ reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2));
+ reg.add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));
// Button initialization callback for toggle buttons
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
+ reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
// Button initialization callback for toggle buttons on dockale floaters
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));
+ reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));
// Display the help topic for the current context
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
+ reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
// Currently unused, but kept for reference:
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
+ reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
// Used by menus along with Floater.Toggle to display visibility as a checkmark
LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2));
@@ -1620,8 +1624,11 @@ void LLUI::initClass(const settings_map_t& settings,
void LLUI::cleanupClass()
{
+ if(sImageProvider)
+ {
sImageProvider->cleanUp();
}
+}
void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups)
{
@@ -1796,7 +1803,8 @@ void LLUI::setupPaths()
LLXMLNodePtr root;
BOOL success = LLXMLNode::parseFile(filename, root, NULL);
Paths paths;
- LLXUIParser::instance().readXUI(root, paths, filename);
+ LLXUIParser parser;
+ parser.readXUI(root, paths, filename);
sXUIPaths.clear();
@@ -1805,14 +1813,14 @@ void LLUI::setupPaths()
LLStringUtil::format_map_t path_args;
path_args["[LANGUAGE]"] = LLUI::getLanguage();
- for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories().begin(),
- end_it = paths.directories().end();
+ for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories.begin(),
+ end_it = paths.directories.end();
it != end_it;
++it)
{
std::string path_val_ui;
- for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs().begin(),
- subdir_end_it = it->subdirs().end();
+ for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs.begin(),
+ subdir_end_it = it->subdirs.end();
subdir_it != subdir_end_it;)
{
path_val_ui += subdir_it->value();
@@ -2014,37 +2022,84 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE );
}
+LLView* LLUI::resolvePath(LLView* context, const std::string& path)
+{
+ // Nothing about resolvePath() should require non-const LLView*. If caller
+ // wants non-const, call the const flavor and then cast away const-ness.
+ return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path));
+}
+
+const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
+{
+ // Create an iterator over slash-separated parts of 'path'. Dereferencing
+ // this iterator returns an iterator_range over the substring. Unlike
+ // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent
+ // delimiters: leading/trailing slash produces an empty substring, double
+ // slash produces an empty substring. That's what we need.
+ boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend;
+
+ if (ti == tend)
+ {
+ // 'path' is completely empty, no navigation
+ return context;
+ }
+
+ // leading / means "start at root"
+ if (ti->empty())
+ {
+ context = getRootView();
+ ++ti;
+ }
+
+ bool recurse = false;
+ for (; ti != tend && context; ++ti)
+ {
+ if (ti->empty())
+ {
+ recurse = true;
+ }
+ else
+ {
+ std::string part(ti->begin(), ti->end());
+ context = context->findChildView(part, recurse);
+ recurse = false;
+ }
+ }
+
+ return context;
+}
+
// LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp
namespace LLInitParam
{
- TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color),
red("red"),
green("green"),
blue("blue"),
alpha("alpha"),
control("")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLUIColor>::setValueFromBlock() const
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
{
if (control.isProvided())
{
- mData.mValue = LLUIColorTable::instance().getColor(control);
+ updateValue(LLUIColorTable::instance().getColor(control));
}
else
{
- mData.mValue = LLColor4(red, green, blue, alpha);
+ updateValue(LLColor4(red, green, blue, alpha));
}
}
- void TypedParam<LLUIColor>::setBlockFromValue()
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
{
- LLColor4 color = mData.mValue.get();
+ LLColor4 color = getValue();
red.set(color.mV[VRED], false);
green.set(color.mV[VGREEN], false);
blue.set(color.mV[VBLUE], false);
@@ -2052,38 +2107,32 @@ namespace LLInitParam
control.set("", false);
}
- void TypeValues<LLUIColor>::declareValues()
- {
- declare("white", LLColor4::white);
- declare("black", LLColor4::black);
- declare("red", LLColor4::red);
- declare("green", LLColor4::green);
- declare("blue", LLColor4::blue);
- }
-
bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
{
return !(a->getFontDesc() < b->getFontDesc())
&& !(b->getFontDesc() < a->getFontDesc());
}
- TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, _name, value, func, min_count, max_count),
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp),
name("name"),
size("size"),
style("style")
{
- setBlockFromValue();
+ if (!fontp)
+ {
+ updateValue(LLFontGL::getFontDefault());
+ }
addSynonym(name, "");
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
{
const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
if (res_fontp)
{
- mData.mValue = res_fontp;
+ updateValue(res_fontp);
return;
}
@@ -2093,22 +2142,26 @@ namespace LLInitParam
const LLFontGL* fontp = LLFontGL::getFont(desc);
if (fontp)
{
- mData.mValue = fontp;
- }
+ updateValue(fontp);
+ }
+ else
+ {
+ updateValue(LLFontGL::getFontDefault());
+ }
}
- void TypedParam<const LLFontGL*>::setBlockFromValue()
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
{
- if (mData.mValue)
+ if (getValue())
{
- name.set(LLFontGL::nameFromFont(mData.mValue), false);
- size.set(LLFontGL::sizeFromFont(mData.mValue), false);
- style.set(LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()), false);
+ name.set(LLFontGL::nameFromFont(getValue()), false);
+ size.set(LLFontGL::sizeFromFont(getValue()), false);
+ style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), false);
}
}
- TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLRect, TypeValues<LLRect> >::ParamValue(const LLRect& rect)
+ : super_t(rect),
left("left"),
top("top"),
right("right"),
@@ -2116,10 +2169,10 @@ namespace LLInitParam
width("width"),
height("height")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLRect>::setValueFromBlock() const
+ void ParamValue<LLRect, TypeValues<LLRect> >::updateValueFromBlock()
{
LLRect rect;
@@ -2180,40 +2233,41 @@ namespace LLInitParam
rect.mBottom = bottom;
rect.mTop = top;
}
- mData.mValue = rect;
+ updateValue(rect);
}
- void TypedParam<LLRect>::setBlockFromValue()
+ void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue()
{
// because of the ambiguity in specifying a rect by position and/or dimensions
// we clear the "provided" flag so that values from xui/etc have priority
// over those calculated from the rect object
- left.set(mData.mValue.mLeft, false);
- right.set(mData.mValue.mRight, false);
- bottom.set(mData.mValue.mBottom, false);
- top.set(mData.mValue.mTop, false);
- width.set(mData.mValue.getWidth(), false);
- height.set(mData.mValue.getHeight(), false);
+ LLRect& value = getValue();
+ left.set(value.mLeft, false);
+ right.set(value.mRight, false);
+ bottom.set(value.mBottom, false);
+ top.set(value.mTop, false);
+ width.set(value.getWidth(), false);
+ height.set(value.getHeight(), false);
}
- TypedParam<LLCoordGL>::TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::ParamValue(const LLCoordGL& coord)
+ : super_t(coord),
x("x"),
y("y")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLCoordGL>::setValueFromBlock() const
+ void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateValueFromBlock()
{
- mData.mValue.set(x, y);
+ updateValue(LLCoordGL(x, y));
}
- void TypedParam<LLCoordGL>::setBlockFromValue()
+ void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue()
{
- x.set(mData.mValue.mX, false);
- y.set(mData.mValue.mY, false);
+ x.set(getValue().mX, false);
+ y.set(getValue().mY, false);
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index fc545c85d5..c583d58d5a 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -33,15 +33,12 @@
#include "llrect.h"
#include "llcontrol.h"
#include "llcoord.h"
-#include "lluiimage.h" // *TODO: break this dependency, need to add #include "lluiimage.h" to all widgets that hold an Optional<LLUIImage*> in their paramblocks
#include "llinitparam.h"
#include "llregistry.h"
#include "lluicolor.h"
#include "lluicolortable.h"
#include <boost/signals2.hpp>
#include "lllazyvalue.h"
-#include "llhandle.h" // *TODO: remove this dependency, added as a
- // convenience when LLHandle moved to llhandle.h
#include "llframetimer.h"
// LLUIFactory
@@ -79,7 +76,7 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LL
void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE );
-void gl_rect_2d_checkerboard(const LLRect& rect);
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f);
void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines);
@@ -185,6 +182,33 @@ public:
//helper functions (should probably move free standing rendering helper functions here)
static LLView* getRootView() { return sRootView; }
static void setRootView(LLView* view) { sRootView = view; }
+ /**
+ * Walk the LLView tree to resolve a path
+ * Paths can be discovered using Develop > XUI > Show XUI Paths
+ *
+ * A leading "/" indicates the root of the tree is the starting
+ * position of the search, (otherwise the context node is used)
+ *
+ * Adjacent "//" mean that the next level of the search is done
+ * recursively ("descendant" rather than "child").
+ *
+ * Return values: If no match is found, NULL is returned,
+ * otherwise the matching LLView* is returned.
+ *
+ * Examples:
+ *
+ * "/" -> return the root view
+ * "/foo" -> find "foo" as a direct child of the root
+ * "foo" -> find "foo" as a direct child of the context node
+ * "//foo" -> find the first "foo" child anywhere in the tree
+ * "/foo/bar" -> find "foo" as direct child of the root, and
+ * "bar" as a direct child of "foo"
+ * "//foo//bar/baz" -> find the first "foo" anywhere in the
+ * 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);
static std::string locateSkin(const std::string& filename);
static void setMousePositionScreen(S32 x, S32 y);
static void getMousePositionScreen(S32 *x, S32 *y);
@@ -238,8 +262,6 @@ private:
// Moved LLLocalClipRect to lllocalcliprect.h
-// Moved all LLHandle-related code to llhandle.h
-
//RN: maybe this needs to moved elsewhere?
class LLImageProviderInterface
{
@@ -371,10 +393,10 @@ public:
namespace LLInitParam
{
template<>
- class TypedParam<LLRect>
- : public BlockValue<LLRect>
+ class ParamValue<LLRect, TypeValues<LLRect> >
+ : public CustomParamValue<LLRect>
{
- typedef BlockValue<LLRect> super_t;
+ typedef CustomParamValue<LLRect> super_t;
public:
Optional<S32> left,
top,
@@ -383,62 +405,43 @@ namespace LLInitParam
width,
height;
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
+ ParamValue(const LLRect& value);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
template<>
- struct TypeValues<LLUIColor> : public TypeValuesHelper<LLUIColor>
+ class ParamValue<LLUIColor, TypeValues<LLUIColor> >
+ : public CustomParamValue<LLUIColor>
{
- static void declareValues();
- };
+ typedef CustomParamValue<LLUIColor> super_t;
- template<>
- class TypedParam<LLUIColor>
- : public BlockValue<LLUIColor>
- {
- typedef BlockValue<LLUIColor> super_t;
public:
- Optional<F32> red,
- green,
- blue,
- alpha;
- Optional<std::string> control;
-
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ Optional<F32> red,
+ green,
+ blue,
+ alpha;
+ Optional<std::string> control;
+
+ ParamValue(const LLUIColor& color);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
- // provide a better default for Optional<const LLFontGL*> than NULL
- template <>
- struct DefaultInitializer<const LLFontGL*>
- {
- // return reference to a single default instance of T
- // built-in types will be initialized to zero, default constructor otherwise
- static const LLFontGL* get()
- {
- static const LLFontGL* sDefaultFont = LLFontGL::getFontDefault();
- return sDefaultFont;
- }
- };
-
-
template<>
- class TypedParam<const LLFontGL*>
- : public BlockValue<const LLFontGL*>
+ class ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >
+ : public CustomParamValue<const LLFontGL* >
{
- typedef BlockValue<const LLFontGL*> super_t;
+ typedef CustomParamValue<const LLFontGL*> super_t;
public:
Optional<std::string> name,
size,
style;
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ ParamValue(const LLFontGL* value);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
template<>
@@ -467,17 +470,17 @@ namespace LLInitParam
template<>
- class TypedParam<LLCoordGL>
- : public BlockValue<LLCoordGL>
+ class ParamValue<LLCoordGL, TypeValues<LLCoordGL> >
+ : public CustomParamValue<LLCoordGL>
{
- typedef BlockValue<LLCoordGL> super_t;
+ typedef CustomParamValue<LLCoordGL> super_t;
public:
Optional<S32> x,
y;
- TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ ParamValue(const LLCoordGL& val);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
}
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index 9891e38f7b..9455d09cc0 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -56,8 +56,8 @@ void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table
typedef std::map<std::string, std::string> string_string_map_t;
string_string_map_t unresolved_refs;
- for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries().begin();
- it != p.color_entries().end();
+ for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin();
+ it != p.color_entries.end();
++it)
{
ColorEntryParams color_entry = *it;
@@ -215,6 +215,12 @@ bool LLUIColorTable::loadFromSettings()
result |= loadFromFilename(current_filename, mLoadedColors);
}
+ current_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SKIN, "colors.xml");
+ if(current_filename != default_filename)
+ {
+ result |= loadFromFilename(current_filename, mLoadedColors);
+ }
+
std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
loadFromFilename(user_filename, mUserSetColors);
@@ -237,7 +243,8 @@ void LLUIColorTable::saveUserSettings() const
}
LLXMLNodePtr output_node = new LLXMLNode("colors", false);
- LLXUIParser::instance().writeXUI(output_node, params);
+ LLXUIParser parser;
+ parser.writeXUI(output_node, params);
if(!output_node->isNull())
{
@@ -303,7 +310,8 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_
}
Params params;
- LLXUIParser::instance().readXUI(root, params, filename);
+ LLXUIParser parser;
+ parser.readXUI(root, params, filename);
if(params.validateBlock())
{
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 3ac3bf8c41..0a06b5e74f 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -36,6 +36,9 @@
static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
+F32 LLUICtrl::sActiveControlTransparency = 1.0f;
+F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
+
// Compiler optimization, generate extern template
template class LLUICtrl* LLView::getChild<class LLUICtrl>(
const std::string& name, BOOL recurse) const;
@@ -110,7 +113,8 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
mMouseUpSignal(NULL),
mRightMouseDownSignal(NULL),
mRightMouseUpSignal(NULL),
- mDoubleClickSignal(NULL)
+ mDoubleClickSignal(NULL),
+ mTransparencyType(TT_DEFAULT)
{
mUICtrlHandle.bind(this);
}
@@ -823,7 +827,7 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot()
{
LLUICtrl* focus_root = NULL;
LLUICtrl* next_view = this;
- while(next_view)
+ while(next_view && next_view->hasTabStop())
{
if (next_view->isFocusRoot())
{
@@ -923,6 +927,37 @@ BOOL LLUICtrl::getTentative() const
void LLUICtrl::setColor(const LLColor4& color)
{ }
+F32 LLUICtrl::getCurrentTransparency()
+{
+ F32 alpha = 0;
+
+ switch(mTransparencyType)
+ {
+ case TT_DEFAULT:
+ alpha = getDrawContext().mAlpha;
+ break;
+
+ case TT_ACTIVE:
+ alpha = sActiveControlTransparency;
+ break;
+
+ case TT_INACTIVE:
+ alpha = sInactiveControlTransparency;
+ break;
+
+ case TT_FADING:
+ alpha = sInactiveControlTransparency / 2;
+ break;
+ }
+
+ return alpha;
+}
+
+void LLUICtrl::setTransparencyType(ETypeTransparency type)
+{
+ mTransparencyType = type;
+}
+
boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
{
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 76dfdf754c..b37e9f6b1b 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -120,6 +120,13 @@ public:
Params();
};
+ enum ETypeTransparency
+ {
+ TT_DEFAULT,
+ TT_ACTIVE, // focused floater
+ TT_INACTIVE, // other floaters
+ TT_FADING, // fading toast
+ };
/*virtual*/ ~LLUICtrl();
void initFromParams(const Params& p);
@@ -202,6 +209,11 @@ public:
virtual void setColor(const LLColor4& color);
+ F32 getCurrentTransparency();
+
+ void setTransparencyType(ETypeTransparency type);
+ ETypeTransparency getTransparencyType() const {return mTransparencyType;}
+
BOOL focusNextItem(BOOL text_entry_only);
BOOL focusPrevItem(BOOL text_entry_only);
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
@@ -283,6 +295,10 @@ protected:
boost::signals2::connection mMakeVisibleControlConnection;
LLControlVariable* mMakeInvisibleControlVariable;
boost::signals2::connection mMakeInvisibleControlConnection;
+
+ static F32 sActiveControlTransparency;
+ static F32 sInactiveControlTransparency;
+
private:
BOOL mTabStop;
@@ -290,6 +306,8 @@ private:
BOOL mTentative;
LLRootHandle<LLUICtrl> mUICtrlHandle;
+ ETypeTransparency mTransparencyType;
+
class DefaultTabGroupFirstSorter;
};
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 15a382660e..25e7a31e90 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -42,7 +42,7 @@
#include "llquaternion.h"
// this library includes
-#include "llfloater.h"
+#include "llpanel.h"
LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");
LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams");
@@ -93,10 +93,12 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
std::string filename = std::string("widgets") + gDirUtilp->getDirDelimiter() + widget_tag + ".xml";
LLXMLNodePtr root_node;
- if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
+ std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), filename);
+ if (!full_filename.empty())
{
- LLUICtrlFactory::instance().pushFileName(filename);
- LLXUIParser::instance().readXUI(root_node, block, filename);
+ LLUICtrlFactory::instance().pushFileName(full_filename);
+ LLSimpleXUIParser parser;
+ parser.readXUI(full_filename, block);
LLUICtrlFactory::instance().popFileName();
}
}
@@ -150,7 +152,27 @@ static LLFastTimer::DeclareTimer FTM_XML_PARSE("XML Reading/Parsing");
bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
{
LLFastTimer timer(FTM_XML_PARSE);
- return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
+
+ std::vector<std::string> paths;
+ std::string path = gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), xui_filename);
+ if (!path.empty())
+ {
+ paths.push_back(path);
+ }
+
+ std::string localize_path = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), xui_filename);
+ if (!localize_path.empty() && localize_path != path)
+ {
+ paths.push_back(localize_path);
+ }
+
+ if (paths.empty())
+ {
+ // sometimes whole path is passed in as filename
+ paths.push_back(xui_filename);
+ }
+
+ return LLXMLNode::getLayeredXMLNode(root, paths);
}
@@ -171,70 +193,6 @@ bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXML
}
}
-static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters");
-
-//-----------------------------------------------------------------------------
-// buildFloater()
-//-----------------------------------------------------------------------------
-bool LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, LLXMLNodePtr output_node)
-{
- LLFastTimer timer(FTM_BUILD_FLOATERS);
- LLXMLNodePtr root;
-
- //if exporting, only load the language being exported,
- //instead of layering localized version on top of english
- if (output_node)
- {
- if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
- {
- llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
- return false;
- }
- }
- else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
- {
- llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
- return false;
- }
-
- // root must be called floater
- if( !(root->hasName("floater") || root->hasName("multi_floater")) )
- {
- llwarns << "Root node should be named floater in: " << filename << llendl;
- return false;
- }
-
- bool res = true;
-
- lldebugs << "Building floater " << filename << llendl;
- pushFileName(filename);
- {
- if (!floaterp->getFactoryMap().empty())
- {
- mFactoryStack.push_front(&floaterp->getFactoryMap());
- }
-
- // for local registry callbacks; define in constructor, referenced in XUI or postBuild
- floaterp->getCommitCallbackRegistrar().pushScope();
- floaterp->getEnableCallbackRegistrar().pushScope();
-
- res = floaterp->initFloaterXML(root, floaterp->getParent(), filename, output_node);
-
- floaterp->setXMLFilename(filename);
-
- floaterp->getCommitCallbackRegistrar().popScope();
- floaterp->getEnableCallbackRegistrar().popScope();
-
- if (!floaterp->getFactoryMap().empty())
- {
- mFactoryStack.pop_front();
- }
- }
- popFileName();
-
- return res;
-}
-
//-----------------------------------------------------------------------------
// saveToXML()
//-----------------------------------------------------------------------------
@@ -243,69 +201,6 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
return 0;
}
-static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
-
-//-----------------------------------------------------------------------------
-// buildPanel()
-//-----------------------------------------------------------------------------
-BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node)
-{
- LLFastTimer timer(FTM_BUILD_PANELS);
- BOOL didPost = FALSE;
- LLXMLNodePtr root;
-
- //if exporting, only load the language being exported,
- //instead of layering localized version on top of english
- if (output_node)
- {
- if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
- {
- llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
- return didPost;
- }
- }
- else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
- {
- llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
- return didPost;
- }
-
- // root must be called panel
- if( !root->hasName("panel" ) )
- {
- llwarns << "Root node should be named panel in : " << filename << llendl;
- return didPost;
- }
-
- lldebugs << "Building panel " << filename << llendl;
-
- pushFileName(filename);
- {
- if (!panelp->getFactoryMap().empty())
- {
- mFactoryStack.push_front(&panelp->getFactoryMap());
- }
-
- // for local registry callbacks; define in constructor, referenced in XUI or postBuild
- panelp->getCommitCallbackRegistrar().pushScope();
- panelp->getEnableCallbackRegistrar().pushScope();
-
- didPost = panelp->initPanelXML(root, NULL, output_node);
-
- panelp->getCommitCallbackRegistrar().popScope();
- panelp->getEnableCallbackRegistrar().popScope();
-
- panelp->setXMLFilename(filename);
-
- if (!panelp->getFactoryMap().empty())
- {
- mFactoryStack.pop_front();
- }
- }
- popFileName();
- return didPost;
-}
-
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@@ -337,32 +232,9 @@ LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const
return view;
}
-//-----------------------------------------------------------------------------
-// createFactoryPanel()
-//-----------------------------------------------------------------------------
-LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
-{
- std::deque<const LLCallbackMap::map_t*>::iterator itor;
- for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
- {
- const LLCallbackMap::map_t* factory_map = *itor;
-
- // Look up this panel's name in the map.
- LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
- if (iter != factory_map->end())
- {
- // Use the factory to create the panel, instead of using a default LLPanel.
- LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
- return ret;
- }
- }
- LLPanel::Params panel_p;
- return create<LLPanel>(panel_p);
-}
-
std::string LLUICtrlFactory::getCurFileName()
{
- return mFileNames.empty() ? "" : gDirUtilp->getWorkingDir() + gDirUtilp->getDirDelimiter() + mFileNames.back();
+ return mFileNames.empty() ? "" : mFileNames.back();
}
@@ -376,36 +248,6 @@ void LLUICtrlFactory::popFileName()
mFileNames.pop_back();
}
-
-//-----------------------------------------------------------------------------
-
-//static
-BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color)
-{
- std::string colorstring;
- BOOL res = node->getAttributeString(name.c_str(), colorstring);
- if (res)
- {
- if (LLUIColorTable::instance().colorExists(colorstring))
- {
- color.setVec(LLUIColorTable::instance().getColor(colorstring));
- }
- else
- {
- res = FALSE;
- }
- }
- if (!res)
- {
- res = LLColor4::parseColor(colorstring, &color);
- }
- if (!res)
- {
- res = node->getAttributeColor(name.c_str(), color);
- }
- return res;
-}
-
//static
void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)
{
@@ -421,28 +263,22 @@ std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename)
return gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename);
}
-void LLUICtrlFactory::pushFactoryFunctions(const LLCallbackMap::map_t* map)
-{
- mFactoryStack.push_back(map);
-}
-
-void LLUICtrlFactory::popFactoryFunctions()
-{
- if (!mFactoryStack.empty())
- {
- mFactoryStack.pop_back();
- }
-}
-
//static
void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest)
{
dest->setName(src->getName()->mString);
}
+template<typename T>
+const LLInitParam::BaseBlock& get_empty_param_block()
+{
+ static typename T::Params params;
+ return params;
+}
+
// adds a widget and its param block to various registries
//static
-void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag)
+void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag)
{
// associate parameter block type with template .xml file
std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
@@ -462,17 +298,9 @@ void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const st
}
}
LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, tag);
- // associate widget type with factory function
- LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type, creator_func);
//FIXME: comment this in when working on schema generation
//LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type);
- //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &getEmptyParamBlock<T>);
-}
-
-//static
-dummy_widget_creator_func_t* LLUICtrlFactory::getDefaultWidgetFunc(const std::type_info* widget_type)
-{
- return LLDefaultWidgetRegistry::instance().getValue(widget_type);
+ //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>);
}
//static
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 58ec5d8387..499b97f52d 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -27,24 +27,13 @@
#ifndef LLUICTRLFACTORY_H
#define LLUICTRLFACTORY_H
-#include "llcallbackmap.h"
+#include "llfasttimer.h"
#include "llinitparam.h"
#include "llregistry.h"
-#include "v4color.h"
-#include "llfasttimer.h"
-
#include "llxuiparser.h"
-#include <boost/function.hpp>
-#include <iosfwd>
-#include <stack>
-#include <set>
-
-class LLPanel;
-class LLFloater;
class LLView;
-
// sort functor for typeid maps
struct LLCompareTypeID
{
@@ -85,12 +74,6 @@ class LLWidgetNameRegistry
: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID>
{};
-// lookup factory functions for default widget instances by widget type
-typedef LLView* (*dummy_widget_creator_func_t)(const std::string&);
-class LLDefaultWidgetRegistry
-: public LLRegistrySingleton<const std::type_info*, dummy_widget_creator_func_t, LLDefaultWidgetRegistry, LLCompareTypeID>
-{};
-
// lookup function for generating empty param block by widget type
// this is used for schema generation
//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
@@ -157,58 +140,21 @@ public:
return ParamDefaults<typename T::Params, 0>::instance().get();
}
- bool buildFloater(LLFloater* floaterp, const std::string &filename, LLXMLNodePtr output_node);
- BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL);
-
// Does what you want for LLFloaters and LLPanels
// Returns 0 on success
S32 saveToXML(LLView* viewp, const std::string& filename);
+ // filename tracking for debugging info
std::string getCurFileName();
void pushFileName(const std::string& name);
void popFileName();
- static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color);
-
- LLPanel* createFactoryPanel(const std::string& name);
-
- void pushFactoryFunctions(const LLCallbackMap::map_t* map);
- void popFactoryFunctions();
-
- template<typename T>
- static T* createWidget(const typename T::Params& params, LLView* parent = NULL)
- {
- T* widget = NULL;
-
- if (!params.validateBlock())
- {
- llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
- //return NULL;
- }
-
- {
- LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
- widget = new T(params);
- }
- {
- LLFastTimer timer(FTM_INIT_FROM_PARAMS);
- widget->initFromParams(params);
- }
-
- if (parent)
- {
- S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
- setCtrlParent(widget, parent, tab_group);
- }
- return widget;
- }
-
template<typename T>
static T* create(typename T::Params& params, LLView* parent = NULL)
{
params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
- T* widget = createWidget<T>(params, parent);
+ T* widget = createWidgetImpl<T>(params, parent);
if (widget)
{
widget->postBuild();
@@ -266,21 +212,54 @@ fail:
template<class T>
static T* getDefaultWidget(const std::string& name)
{
- dummy_widget_creator_func_t* dummy_func = getDefaultWidgetFunc(&typeid(T));
- return dummy_func ? dynamic_cast<T*>((*dummy_func)(name)) : NULL;
+ typename T::Params widget_params;
+ widget_params.name = name;
+ return create<T>(widget_params);
}
- template <class T>
- static LLView* createDefaultWidget(const std::string& name)
- {
- typename T::Params params;
- params.name(name);
-
- return create<T>(params);
- }
+ static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
+
+ static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
+ static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
+
+private:
+ //NOTE: both friend declarations are necessary to keep both gcc and msvc happy
+ template <typename T> friend class LLChildRegistry;
+ template <typename T> template <typename U> friend class LLChildRegistry<T>::Register;
static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
+ // helper function for adding widget type info to various registries
+ static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
+
+ static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
+
+ template<typename T>
+ static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
+ {
+ T* widget = NULL;
+
+ if (!params.validateBlock())
+ {
+ llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+ //return NULL;
+ }
+
+ { LLFastTimer _(FTM_WIDGET_CONSTRUCTION);
+ widget = new T(params);
+ }
+ { LLFastTimer _(FTM_INIT_FROM_PARAMS);
+ widget->initFromParams(params);
+ }
+
+ if (parent)
+ {
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
+ setCtrlParent(widget, parent, tab_group);
+ }
+ return widget;
+ }
+
template<typename T>
static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
{
@@ -288,7 +267,8 @@ fail:
typename T::Params params(getDefaultParams<T>());
- LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
+ LLXUIParser parser;
+ parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
if (output_node)
{
@@ -298,14 +278,13 @@ fail:
// Export only the differences between this any default params
typename T::Params default_params(getDefaultParams<T>());
copyName(node, output_node);
- LLXUIParser::instance().writeXUI(
- output_node, output_params, &default_params);
+ parser.writeXUI(output_node, output_params, &default_params);
}
// Apply layout transformations, usually munging rect
params.from_xui = true;
T::applyXUILayout(params, parent);
- T* widget = createWidget<T>(params, parent);
+ T* widget = createWidgetImpl<T>(params, parent);
typedef typename T::child_registry_t registry_t;
@@ -320,20 +299,6 @@ fail:
return widget;
}
- static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
-
- static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
-
- static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
-
- static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
-
- // helper function for adding widget type info to various registries
- static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag);
-
-private:
- // return default widget instance factory func for a given type
- static dummy_widget_creator_func_t* getDefaultWidgetFunc(const std::type_info* widget_type);
static const std::string* getWidgetTag(const std::type_info* widget_type);
@@ -343,20 +308,10 @@ private:
// Avoid directly using LLUI and LLDir in the template code
static std::string findSkinnedFilename(const std::string& filename);
- typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
- factory_stack_t mFactoryStack;
-
- LLPanel* mDummyPanel;
+ class LLPanel* mDummyPanel;
std::vector<std::string> mFileNames;
};
-template<typename T>
-const LLInitParam::BaseBlock& getEmptyParamBlock()
-{
- static typename T::Params params;
- return params;
-}
-
// this is here to make gcc happy with reference to LLUICtrlFactory
template<typename DERIVED>
template<typename T>
@@ -364,7 +319,7 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
{
// add this widget to various registries
- LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), &LLUICtrlFactory::createDefaultWidget<T>, tag);
+ LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
// since registry_t depends on T, do this in line here
// TODO: uncomment this for schema generation
@@ -372,58 +327,4 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
//LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
}
-
-typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc;
-
-// local static instance for registering a particular panel class
-
-class LLRegisterPanelClass
-: public LLSingleton< LLRegisterPanelClass >
-{
-public:
- // reigister with either the provided builder, or the generic templated builder
- void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func)
- {
- mPanelClassesNames[tag] = func;
- }
-
- LLPanel* createPanelClass(const std::string& tag)
- {
- param_name_map_t::iterator iT = mPanelClassesNames.find(tag);
- if(iT == mPanelClassesNames.end())
- return 0;
- return iT->second();
- }
- template<typename T>
- static T* defaultPanelClassBuilder()
- {
- T* pT = new T();
- return pT;
- }
-
-private:
- typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t;
-
- param_name_map_t mPanelClassesNames;
-};
-
-
-// local static instance for registering a particular panel class
-template<typename T>
-class LLRegisterPanelClassWrapper
-: public LLRegisterPanelClass
-{
-public:
- // reigister with either the provided builder, or the generic templated builder
- LLRegisterPanelClassWrapper(const std::string& tag);
-};
-
-
-template<typename T>
-LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
-{
- LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
-}
-
-
#endif //LLUICTRLFACTORY_H
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
index 1ffad4806e..f37947a50b 100644
--- a/indra/llui/lluiimage.cpp
+++ b/indra/llui/lluiimage.cpp
@@ -155,32 +155,32 @@ void LLUIImage::onImageLoaded()
namespace LLInitParam
{
- void TypedParam<LLUIImage*>::setValueFromBlock() const
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
{
// The keyword "none" is specifically requesting a null image
// do not default to current value. Used to overwrite template images.
if (name() == "none")
{
- mData.mValue = NULL;
+ updateValue(NULL);
return;
}
LLUIImage* imagep = LLUI::getUIImage(name());
if (imagep)
{
- mData.mValue = imagep;
+ updateValue(imagep);
}
}
- void TypedParam<LLUIImage*>::setBlockFromValue()
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
{
- if (mData.mValue == NULL)
+ if (getValue() == NULL)
{
name.set("none", false);
}
else
{
- name.set(mData.mValue->getName(), false);
+ name.set(getValue()->getName(), false);
}
}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index 38107c112d..139d88e0ac 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -92,22 +92,23 @@ protected:
namespace LLInitParam
{
template<>
- class TypedParam<LLUIImage*, TypeValues<LLUIImage*>, false>
- : public BlockValue<LLUIImage*>
+ class ParamValue<LLUIImage*, TypeValues<LLUIImage*> >
+ : public CustomParamValue<LLUIImage*>
{
typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type T_const_ref;
- typedef BlockValue<LLUIImage*> super_t;
+ typedef CustomParamValue<LLUIImage*> super_t;
public:
Optional<std::string> name;
- TypedParam(BlockDescriptor& descriptor, const char* name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count)
+ ParamValue(LLUIImage* const& image)
+ : super_t(image)
{
- setBlockFromValue();
+ updateBlockFromValue();
+ addSynonym(name, "name");
}
- void setValueFromBlock() const;
- void setBlockFromValue();
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
// Need custom comparison function for our test app, which only loads
diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp
index 3e9b956ee6..ac69d3bf85 100644
--- a/indra/llui/lluistring.cpp
+++ b/indra/llui/lluistring.cpp
@@ -34,7 +34,7 @@ LLFastTimer::DeclareTimer FTM_UI_STRING("UI String");
LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args)
: mOrig(instring),
- mArgs(args)
+ mArgs(new LLStringUtil::format_map_t(args))
{
dirty();
}
@@ -48,7 +48,7 @@ void LLUIString::assign(const std::string& s)
void LLUIString::setArgList(const LLStringUtil::format_map_t& args)
{
- mArgs = args;
+ getArgs() = args;
dirty();
}
@@ -68,7 +68,7 @@ void LLUIString::setArgs(const LLSD& sd)
void LLUIString::setArg(const std::string& key, const std::string& replacement)
{
- mArgs[key] = replacement;
+ getArgs()[key] = replacement;
dirty();
}
@@ -129,14 +129,14 @@ void LLUIString::updateResult() const
mResult = mOrig;
// get the defailt args + local args
- if (mArgs.empty())
+ if (!mArgs || mArgs->empty())
{
LLStringUtil::format(mResult, LLTrans::getDefaultArgs());
}
else
{
LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs();
- combined_args.insert(mArgs.begin(), mArgs.end());
+ combined_args.insert(mArgs->begin(), mArgs->end());
LLStringUtil::format(mResult, combined_args);
}
}
@@ -147,3 +147,12 @@ void LLUIString::updateWResult() const
mWResult = utf8str_to_wstring(getUpdatedResult());
}
+
+LLStringUtil::format_map_t& LLUIString::getArgs()
+{
+ if (!mArgs)
+ {
+ mArgs = new LLStringUtil::format_map_t;
+ }
+ return *mArgs;
+}
diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h
index fc7ac37d99..cb40c85582 100644
--- a/indra/llui/lluistring.h
+++ b/indra/llui/lluistring.h
@@ -58,9 +58,10 @@ class LLUIString
public:
// These methods all perform appropriate argument substitution
// and modify mOrig where appropriate
- LLUIString() : mNeedsResult(false), mNeedsWResult(false) {}
+ LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);
- LLUIString(const std::string& instring) { assign(instring); }
+ LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }
+ ~LLUIString() { delete mArgs; }
void assign(const std::string& instring);
LLUIString& operator=(const std::string& s) { assign(s); return *this; }
@@ -80,15 +81,15 @@ public:
S32 length() const { return getUpdatedWResult().size(); }
void clear();
- void clearArgs() { mArgs.clear(); }
-
+ void clearArgs() { if (mArgs) mArgs->clear(); }
+
// These utility functions are included for text editing.
// They do not affect mOrig and do not perform argument substitution
void truncate(S32 maxchars);
void erase(S32 charidx, S32 len);
void insert(S32 charidx, const LLWString& wchars);
void replace(S32 charidx, llwchar wc);
-
+
private:
// something changed, requiring reformatting of strings
void dirty();
@@ -99,11 +100,12 @@ private:
// do actual work of updating strings (non-inlined)
void updateResult() const;
void updateWResult() const;
-
+ LLStringUtil::format_map_t& getArgs();
+
std::string mOrig;
mutable std::string mResult;
mutable LLWString mWResult; // for displaying
- LLStringUtil::format_map_t mArgs;
+ LLStringUtil::format_map_t* mArgs;
// controls lazy evaluation
mutable bool mNeedsResult;
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 5680ab8bd4..9db1feafd1 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -27,22 +27,25 @@
#include "linden_common.h"
#include "llurlentry.h"
+#include "lluictrl.h"
#include "lluri.h"
#include "llurlmatch.h"
#include "llurlregistry.h"
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lltrans.h"
#include "lluicolortable.h"
+#include "message.h"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
+// Utility functions
+std::string localize_slapp_label(const std::string& url, const std::string& full_name);
-LLUrlEntryBase::LLUrlEntryBase() :
- mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")),
- mDisabledLink(false)
-{
-}
+
+LLUrlEntryBase::LLUrlEntryBase()
+{}
LLUrlEntryBase::~LLUrlEntryBase()
{
@@ -53,6 +56,22 @@ std::string LLUrlEntryBase::getUrl(const std::string &string) const
return escapeUrl(string);
}
+//virtual
+std::string LLUrlEntryBase::getIcon(const std::string &url)
+{
+ return mIcon;
+}
+
+LLStyle::Params LLUrlEntryBase::getStyle() const
+{
+ LLStyle::Params style_params;
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.font.style = "UNDERLINE";
+ return style_params;
+}
+
+
std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const
{
// return the id from a SLURL in the format /app/{cmd}/{id}/about
@@ -130,22 +149,35 @@ void LLUrlEntryBase::addObserver(const std::string &id,
mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer));
}
}
-
-void LLUrlEntryBase::callObservers(const std::string &id, const std::string &label)
+
+// *NOTE: See also LLUrlEntryAgent::callObservers()
+void LLUrlEntryBase::callObservers(const std::string &id,
+ const std::string &label,
+ const std::string &icon)
{
// notify all callbacks waiting on the given uuid
- std::multimap<std::string, LLUrlEntryObserver>::iterator it;
- for (it = mObservers.find(id); it != mObservers.end();)
+ typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
+ std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
+ for (observer_it it = matching_range.first; it != matching_range.second;)
{
// call the callback - give it the new label
LLUrlEntryObserver &observer = it->second;
- (*observer.signal)(it->second.url, label);
+ (*observer.signal)(it->second.url, label, icon);
// then remove the signal - we only need to call it once
delete observer.signal;
mObservers.erase(it++);
}
}
+/// is this a match for a URL that should not be hyperlinked?
+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");
+
+ return globally_disabled;
+}
+
static std::string getStringAfterToken(const std::string str, const std::string token)
{
size_t pos = str.find(token);
@@ -188,7 +220,13 @@ LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel()
std::string LLUrlEntryHTTPLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
- return getLabelFromWikiLink(url);
+ std::string label = getLabelFromWikiLink(url);
+ return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url);
+}
+
+std::string LLUrlEntryHTTPLabel::getTooltip(const std::string &string) const
+{
+ return getUrl(string);
}
std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
@@ -308,16 +346,35 @@ LLUrlEntryAgent::LLUrlEntryAgent()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_agent.xml";
mIcon = "Generic_Person";
- mColor = LLUIColorTable::instance().getColor("AgentLinkColor");
}
-void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+// virtual
+void LLUrlEntryAgent::callObservers(const std::string &id,
+ const std::string &label,
+ const std::string &icon)
+{
+ // notify all callbacks waiting on the given uuid
+ typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
+ std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
+ for (observer_it it = matching_range.first; it != matching_range.second;)
+ {
+ // call the callback - give it the new label
+ LLUrlEntryObserver &observer = it->second;
+ std::string final_label = localize_slapp_label(observer.url, label);
+ (*observer.signal)(observer.url, final_label, icon);
+ // then remove the signal - we only need to call it once
+ delete observer.signal;
+ mObservers.erase(it++);
+ }
+}
+
+void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
+ const LLAvatarName& av_name)
{
+ std::string label = av_name.getCompleteName();
+
// received the agent name from the server - tell our observers
- callObservers(id.asString(), first + " " + last);
+ callObservers(id.asString(), label, mIcon);
}
LLUUID LLUrlEntryAgent::getID(const std::string &string) const
@@ -330,6 +387,10 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
// return a tooltip corresponding to the URL type instead of the generic one
std::string url = getUrl(string);
+ if (LLStringUtil::endsWith(url, "/inspect"))
+ {
+ return LLTrans::getString("TooltipAgentInspect");
+ }
if (LLStringUtil::endsWith(url, "/mute"))
{
return LLTrans::getString("TooltipAgentMute");
@@ -379,50 +440,182 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
}
LLUUID agent_id(agent_id_string);
- std::string full_name;
if (agent_id.isNull())
{
return LLTrans::getString("AvatarNameNobody");
}
- else if (gCacheName->getFullName(agent_id, full_name))
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(agent_id, &av_name))
{
- // customize label string based on agent SLapp suffix
- if (LLStringUtil::endsWith(url, "/mute"))
- {
- return LLTrans::getString("SLappAgentMute") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/unmute"))
- {
- return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/im"))
- {
- return LLTrans::getString("SLappAgentIM") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/pay"))
- {
- return LLTrans::getString("SLappAgentPay") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/offerteleport"))
- {
- return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/requestfriend"))
- {
- return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
- }
- return full_name;
+ std::string label = av_name.getCompleteName();
+
+ // handle suffixes like /mute or /offerteleport
+ label = localize_slapp_label(url, label);
+ return label;
+ }
+ else
+ {
+ LLAvatarNameCache::get(agent_id,
+ boost::bind(&LLUrlEntryAgent::onAvatarNameCache,
+ this, _1, _2));
+ addObserver(agent_id_string, url, cb);
+ return LLTrans::getString("LoadingData");
+ }
+}
+
+LLStyle::Params LLUrlEntryAgent::getStyle() const
+{
+ LLStyle::Params style_params = LLUrlEntryBase::getStyle();
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ return style_params;
+}
+
+std::string localize_slapp_label(const std::string& url, const std::string& full_name)
+{
+ // customize label string based on agent SLapp suffix
+ if (LLStringUtil::endsWith(url, "/mute"))
+ {
+ return LLTrans::getString("SLappAgentMute") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/unmute"))
+ {
+ return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/im"))
+ {
+ return LLTrans::getString("SLappAgentIM") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/pay"))
+ {
+ return LLTrans::getString("SLappAgentPay") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/offerteleport"))
+ {
+ return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/requestfriend"))
+ {
+ return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
+ }
+ return full_name;
+}
+
+
+std::string LLUrlEntryAgent::getIcon(const std::string &url)
+{
+ // *NOTE: Could look up a badge here by calling getIDStringFromUrl()
+ // and looking up the badge for the agent.
+ return mIcon;
+}
+
+//
+// LLUrlEntryAgentName describes a Second Life agent name Url, e.g.,
+// 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()
+{}
+
+void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
+ const LLAvatarName& av_name)
+{
+ std::string label = getName(av_name);
+ // received the agent name from the server - tell our observers
+ callObservers(id.asString(), label, mIcon);
+}
+
+std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ if (!gCacheName)
+ {
+ // probably at the login screen, use short string for layout
+ return LLTrans::getString("LoadingData");
+ }
+
+ std::string agent_id_string = getIDStringFromUrl(url);
+ if (agent_id_string.empty())
+ {
+ // something went wrong, just give raw url
+ return unescapeUrl(url);
+ }
+
+ LLUUID agent_id(agent_id_string);
+ if (agent_id.isNull())
+ {
+ return LLTrans::getString("AvatarNameNobody");
+ }
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(agent_id, &av_name))
+ {
+ return getName(av_name);
}
else
{
- gCacheName->get(agent_id, FALSE,
- boost::bind(&LLUrlEntryAgent::onAgentNameReceived,
- this, _1, _2, _3, _4));
+ LLAvatarNameCache::get(agent_id,
+ boost::bind(&LLUrlEntryAgentCompleteName::onAvatarNameCache,
+ this, _1, _2));
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
}
+LLStyle::Params LLUrlEntryAgentName::getStyle() const
+{
+ // don't override default colors
+ return LLStyle::Params().is_link(false);
+}
+
+//
+// LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+//
+LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.getCompleteName();
+}
+
+//
+// LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+//
+LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.mDisplayName;
+}
+
+//
+// LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+//
+LLUrlEntryAgentUserName::LLUrlEntryAgentUserName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.mUsername.empty() ? avatar_name.getLegacyName() : avatar_name.mUsername;
+}
+
//
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
@@ -436,18 +629,16 @@ LLUrlEntryGroup::LLUrlEntryGroup()
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
mTooltip = LLTrans::getString("TooltipGroupUrl");
- mColor = LLUIColorTable::instance().getColor("GroupLinkColor");
}
void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+ const std::string& name,
+ bool is_group)
{
// received the group name from the server - tell our observers
- callObservers(id.asString(), first);
+ callObservers(id.asString(), name, mIcon);
}
LLUUID LLUrlEntryGroup::getID(const std::string &string) const
@@ -483,14 +674,23 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
}
else
{
- gCacheName->get(group_id, TRUE,
+ gCacheName->getGroup(group_id,
boost::bind(&LLUrlEntryGroup::onGroupNameReceived,
- this, _1, _2, _3, _4));
+ this, _1, _2, _3));
addObserver(group_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
}
+LLStyle::Params LLUrlEntryGroup::getStyle() const
+{
+ LLStyle::Params style_params = LLUrlEntryBase::getStyle();
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ return style_params;
+}
+
+
//
// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
@@ -541,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
return LLUrlEntryBase::getLocation(url);
}
+// LLUrlEntryParcel statics.
+LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null);
+LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
+LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid);
+bool LLUrlEntryParcel::sDisconnected(false);
+std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
+
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
@@ -552,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_parcel.xml";
mTooltip = LLTrans::getString("TooltipParcelUrl");
+
+ sParcelInfoObservers.insert(this);
+}
+
+LLUrlEntryParcel::~LLUrlEntryParcel()
+{
+ sParcelInfoObservers.erase(this);
}
std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
+ LLSD path_array = LLURI(url).pathArray();
+ S32 path_parts = path_array.size();
+
+ if (path_parts < 3) // no parcel id
+ {
+ llwarns << "Failed to parse url [" << url << "]" << llendl;
+ return url;
+ }
+
+ std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id
+
+ // Add an observer to call LLUrlLabelCallback when we have parcel name.
+ addObserver(parcel_id_string, url, cb);
+
+ LLUUID parcel_id(parcel_id_string);
+
+ sendParcelInfoRequest(parcel_id);
+
return unescapeUrl(url);
}
+void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id)
+{
+ if (sRegionHost == LLHost::invalid || sDisconnected) return;
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessage("ParcelInfoRequest");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, sAgentID );
+ msg->addUUID("SessionID", sSessionID);
+ msg->nextBlock("Data");
+ msg->addUUID("ParcelID", parcel_id);
+ msg->sendReliable(sRegionHost);
+}
+
+void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label)
+{
+ callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon);
+}
+
+// static
+void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
+{
+ std::string label(LLStringUtil::null);
+ if (!parcel_data.name.empty())
+ {
+ label = parcel_data.name;
+ }
+ // If parcel name is empty use Sim_name (x, y, z) for parcel label.
+ else if (!parcel_data.sim_name.empty())
+ {
+ S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS;
+ S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS;
+ S32 region_z = llround(parcel_data.global_z);
+
+ label = llformat("%s (%d, %d, %d)",
+ parcel_data.sim_name.c_str(), region_x, region_y, region_z);
+ }
+
+ for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin();
+ iter != sParcelInfoObservers.end();
+ ++iter)
+ {
+ LLUrlEntryParcel* url_entry = *iter;
+ if (url_entry)
+ {
+ url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label);
+ }
+ }
+}
+
//
// LLUrlEntryPlace Describes secondlife://<location> URLs
//
@@ -607,6 +889,69 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
}
//
+// LLUrlEntryRegion Describes secondlife:///app/region/REGION_NAME/X/Y/Z URLs, e.g.
+// secondlife:///app/region/Ahern/128/128/0
+//
+LLUrlEntryRegion::LLUrlEntryRegion()
+{
+ mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?",
+ boost::regex::perl|boost::regex::icase);
+ mMenuName = "menu_url_slurl.xml";
+ mTooltip = LLTrans::getString("TooltipSLURL");
+}
+
+std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ //
+ // we handle SLURLs in the following formats:
+ // - secondlife:///app/region/Place/X/Y/Z
+ // - secondlife:///app/region/Place/X/Y
+ // - secondlife:///app/region/Place/X
+ // - secondlife:///app/region/Place
+ //
+
+ LLSD path_array = LLURI(url).pathArray();
+ S32 path_parts = path_array.size();
+
+ if (path_parts < 3) // no region name
+ {
+ llwarns << "Failed to parse url [" << url << "]" << llendl;
+ return url;
+ }
+
+ std::string label = unescapeUrl(path_array[2]); // region name
+
+ if (path_parts > 3) // secondlife:///app/region/Place/X
+ {
+ std::string x = path_array[3];
+ label += " (" + x;
+
+ if (path_parts > 4) // secondlife:///app/region/Place/X/Y
+ {
+ std::string y = path_array[4];
+ label += "," + y;
+
+ if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z
+ {
+ std::string z = path_array[5];
+ label = label + "," + z;
+ }
+ }
+
+ label += ")";
+ }
+
+ return label;
+}
+
+std::string LLUrlEntryRegion::getLocation(const std::string &url) const
+{
+ LLSD path_array = LLURI(url).pathArray();
+ std::string region_name = unescapeUrl(path_array[2]);
+ return region_name;
+}
+
+//
// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
// secondlife:///app/teleport/Ahern/50/50/50/
// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/
@@ -789,9 +1134,8 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
//
LLUrlEntryNoLink::LLUrlEntryNoLink()
{
- mPattern = boost::regex("<nolink>[^<]*</nolink>",
+ mPattern = boost::regex("<nolink>.*</nolink>",
boost::regex::perl|boost::regex::icase);
- mDisabledLink = true;
}
std::string LLUrlEntryNoLink::getUrl(const std::string &url) const
@@ -805,6 +1149,13 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
return getUrl(url);
}
+LLStyle::Params LLUrlEntryNoLink::getStyle() const
+{
+ // Don't render as URL (i.e. no context menu or hand cursor).
+ return LLStyle::Params().is_link(false);
+}
+
+
//
// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
//
@@ -812,7 +1163,6 @@ LLUrlEntryIcon::LLUrlEntryIcon()
{
mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>",
boost::regex::perl|boost::regex::icase);
- mDisabledLink = true;
}
std::string LLUrlEntryIcon::getUrl(const std::string &url) const
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index e25eaa7555..5f82721c0f 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -30,13 +30,20 @@
#include "lluuid.h"
#include "lluicolor.h"
+#include "llstyle.h"
+
+#include "llhost.h" // for resolving parcel name by parcel id
+
#include <boost/signals2.hpp>
#include <boost/regex.hpp>
#include <string>
#include <map>
+class LLAvatarName;
+
typedef boost::signals2::signal<void (const std::string& url,
- const std::string& label)> LLUrlLabelSignal;
+ const std::string& label,
+ const std::string& icon)> LLUrlLabelSignal;
typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback;
///
@@ -71,10 +78,10 @@ public:
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
/// Return an icon that can be displayed next to Urls of this type
- virtual std::string getIcon(const std::string &url) { return mIcon; }
+ virtual std::string getIcon(const std::string &url);
- /// Return the color to render the displayed text
- LLUIColor getColor() const { return mColor; }
+ /// Return the style to render the displayed text
+ virtual LLStyle::Params getStyle() const;
/// Given a matched Url, return a tooltip string for the hyperlink
virtual std::string getTooltip(const std::string &string) const { return mTooltip; }
@@ -85,14 +92,13 @@ public:
/// Return the name of a SL location described by this Url, if any
virtual std::string getLocation(const std::string &url) const { return ""; }
- /// is this a match for a URL that should not be hyperlinked?
- bool isLinkDisabled() const { return mDisabledLink; }
-
/// Should this link text be underlined only when mouse is hovered over it?
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
+ bool isLinkDisabled() const;
+
protected:
std::string getIDStringFromUrl(const std::string &url) const;
std::string escapeUrl(const std::string &url) const;
@@ -100,7 +106,7 @@ protected:
std::string getLabelFromWikiLink(const std::string &url) const;
std::string getUrlFromWikiLink(const std::string &string) const;
void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);
- void callObservers(const std::string &id, const std::string &label);
+ virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);
typedef struct {
std::string url;
@@ -111,9 +117,7 @@ protected:
std::string mIcon;
std::string mMenuName;
std::string mTooltip;
- LLUIColor mColor;
std::multimap<std::string, LLUrlEntryObserver> mObservers;
- bool mDisabledLink;
};
///
@@ -134,6 +138,7 @@ class LLUrlEntryHTTPLabel : public LLUrlEntryBase
public:
LLUrlEntryHTTPLabel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getTooltip(const std::string &string) const;
/*virtual*/ std::string getUrl(const std::string &string) const;
};
@@ -162,18 +167,78 @@ public:
///
/// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
-///
class LLUrlEntryAgent : public LLUrlEntryBase
{
public:
LLUrlEntryAgent();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getIcon(const std::string &url);
/*virtual*/ std::string getTooltip(const std::string &string) const;
+ /*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
+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);
+};
+
+///
+/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
+/// that displays various forms of user name
+/// This is a base class for the various implementations of name display
+class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::trackable
+{
+public:
+ LLUrlEntryAgentName();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ LLStyle::Params getStyle() const;
+protected:
+ // override this to pull out relevant name fields
+ virtual std::string getName(const LLAvatarName& avatar_name) = 0;
private:
- void onAgentNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group);
+ void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
+};
+
+
+///
+/// LLUrlEntryAgentCompleteName Describes a Second Life agent name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+/// that displays the full display name + user name for an avatar
+/// such as "James Linden (james.linden)"
+class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentCompleteName();
+private:
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
+};
+
+///
+/// LLUrlEntryAgentDisplayName Describes a Second Life agent display name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+/// that displays the just the display name for an avatar
+/// such as "James Linden"
+class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentDisplayName();
+private:
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
+};
+
+///
+/// LLUrlEntryAgentUserName Describes a Second Life agent username Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+/// that displays the just the display name for an avatar
+/// such as "james.linden"
+class LLUrlEntryAgentUserName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentUserName();
+private:
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
};
///
@@ -185,10 +250,10 @@ class LLUrlEntryGroup : public LLUrlEntryBase
public:
LLUrlEntryGroup();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
private:
- void onGroupNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group);
+ void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
};
///
@@ -223,8 +288,44 @@ private:
class LLUrlEntryParcel : public LLUrlEntryBase
{
public:
+ struct LLParcelData
+ {
+ LLUUID parcel_id;
+ std::string name;
+ std::string sim_name;
+ F32 global_x;
+ F32 global_y;
+ F32 global_z;
+ };
+
LLUrlEntryParcel();
+ ~LLUrlEntryParcel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+
+ // Sends a parcel info request to sim.
+ void sendParcelInfoRequest(const LLUUID& parcel_id);
+
+ // Calls observers of certain parcel id providing them with parcel label.
+ void onParcelInfoReceived(const std::string &id, const std::string &label);
+
+ // Processes parcel label and triggers notifying observers.
+ static void processParcelInfo(const LLParcelData& parcel_data);
+
+ // Next 4 setters are used to update agent and viewer connection information
+ // upon events like user login, viewer disconnect and user changing region host.
+ // These setters are made public to be accessible from newview and should not be
+ // used in other cases.
+ static void setAgentID(const LLUUID& id) { sAgentID = id; }
+ static void setSessionID(const LLUUID& id) { sSessionID = id; }
+ static void setRegionHost(const LLHost& host) { sRegionHost = host; }
+ static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
+
+private:
+ static LLUUID sAgentID;
+ static LLUUID sSessionID;
+ static LLHost sRegionHost;
+ static bool sDisconnected;
+ static std::set<LLUrlEntryParcel*> sParcelInfoObservers;
};
///
@@ -240,6 +341,18 @@ public:
};
///
+/// LLUrlEntryRegion Describes a Second Life location Url, e.g.,
+/// secondlife:///app/region/Ahern/128/128/0
+///
+class LLUrlEntryRegion : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryRegion();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getLocation(const std::string &url) const;
+};
+
+///
/// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
/// secondlife:///app/teleport/Ahern/50/50/50/
///
@@ -297,6 +410,7 @@ public:
LLUrlEntryNoLink();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getUrl(const std::string &string) const;
+ /*virtual*/ LLStyle::Params getStyle() const;
};
///
diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp
index e53b0c4370..c1f1382a9f 100644
--- a/indra/llui/llurlmatch.cpp
+++ b/indra/llui/llurlmatch.cpp
@@ -37,16 +37,15 @@ LLUrlMatch::LLUrlMatch() :
mIcon(""),
mMenuName(""),
mLocation(""),
- mDisabledLink(false),
mUnderlineOnHoverOnly(false)
{
}
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
const std::string &label, const std::string &tooltip,
- const std::string &icon, const LLUIColor& color,
+ const std::string &icon, const LLStyle::Params& style,
const std::string &menu, const std::string &location,
- bool disabled_link, const LLUUID& id, bool underline_on_hover_only)
+ const LLUUID& id, bool underline_on_hover_only)
{
mStart = start;
mEnd = end;
@@ -54,10 +53,10 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mLabel = label;
mTooltip = tooltip;
mIcon = icon;
- mColor = color;
+ mStyle = style;
+ mStyle.link_href = url;
mMenuName = menu;
mLocation = location;
- mDisabledLink = disabled_link;
mID = id;
mUnderlineOnHoverOnly = underline_on_hover_only;
}
diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h
index d1b2112ee7..2818f45207 100644
--- a/indra/llui/llurlmatch.h
+++ b/indra/llui/llurlmatch.h
@@ -28,11 +28,11 @@
#ifndef LL_LLURLMATCH_H
#define LL_LLURLMATCH_H
-#include "linden_common.h"
+//#include "linden_common.h"
#include <string>
#include <vector>
-#include "lluicolor.h"
+#include "llstyle.h"
///
/// LLUrlMatch describes a single Url that was matched within a string by
@@ -69,7 +69,7 @@ public:
std::string getIcon() const { return mIcon; }
/// Return the color to render the displayed text
- LLUIColor getColor() const { return mColor; }
+ LLStyle::Params getStyle() const { return mStyle; }
/// Return the name of a XUI file containing the context menu items
std::string getMenuName() const { return mMenuName; }
@@ -77,21 +77,17 @@ public:
/// return the SL location that this Url describes, or "" if none.
std::string getLocation() const { return mLocation; }
- /// is this a match for a URL that should not be hyperlinked?
- bool isLinkDisabled() const { return mDisabledLink; }
-
/// Should this link text be underlined only when mouse is hovered over it?
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
/// Change the contents of this match object (used by LLUrlRegistry)
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
const std::string &tooltip, const std::string &icon,
- const LLUIColor& color, const std::string &menu,
- const std::string &location, bool disabled_link
- , const LLUUID& id, bool underline_on_hover_only = false );
-
- const LLUUID& getID() const { return mID;}
+ const LLStyle::Params& style, const std::string &menu,
+ const std::string &location, const LLUUID& id,
+ bool underline_on_hover_only = false );
+ const LLUUID& getID() const { return mID; }
private:
U32 mStart;
U32 mEnd;
@@ -101,10 +97,8 @@ private:
std::string mIcon;
std::string mMenuName;
std::string mLocation;
-
LLUUID mID;
- LLUIColor mColor;
- bool mDisabledLink;
+ LLStyle::Params mStyle;
bool mUnderlineOnHoverOnly;
};
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 9d215cf7ef..523ee5d78c 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -31,22 +31,30 @@
#include <boost/regex.hpp>
// default dummy callback that ignores any label updates from the server
-void LLUrlRegistryNullCallback(const std::string &url, const std::string &label)
+void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon)
{
}
LLUrlRegistry::LLUrlRegistry()
{
+ mUrlEntry.reserve(20);
+
// Urls are matched in the order that they were registered
registerUrl(new LLUrlEntryNoLink());
registerUrl(new LLUrlEntryIcon());
registerUrl(new LLUrlEntrySLURL());
registerUrl(new LLUrlEntryHTTP());
registerUrl(new LLUrlEntryHTTPLabel());
+ registerUrl(new LLUrlEntryAgentCompleteName());
+ registerUrl(new LLUrlEntryAgentDisplayName());
+ registerUrl(new LLUrlEntryAgentUserName());
+ // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
+ // LLUrlEntryAgent is a less specific (catchall for agent urls)
registerUrl(new LLUrlEntryAgent());
registerUrl(new LLUrlEntryGroup());
registerUrl(new LLUrlEntryParcel());
registerUrl(new LLUrlEntryTeleport());
+ registerUrl(new LLUrlEntryRegion());
registerUrl(new LLUrlEntryWorldMap());
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
@@ -71,10 +79,13 @@ LLUrlRegistry::~LLUrlRegistry()
}
}
-void LLUrlRegistry::registerUrl(LLUrlEntryBase *url)
+void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)
{
if (url)
{
+ if (force_front) // IDEVO
+ mUrlEntry.insert(mUrlEntry.begin(), url);
+ else
mUrlEntry.push_back(url);
}
}
@@ -174,10 +185,9 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
match_entry->getLabel(url, cb),
match_entry->getTooltip(url),
match_entry->getIcon(url),
- match_entry->getColor(),
+ match_entry->getStyle(),
match_entry->getMenuName(),
match_entry->getLocation(url),
- match_entry->isLinkDisabled(),
match_entry->getID(url),
match_entry->underlineOnHoverOnly(url));
return true;
@@ -210,10 +220,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
match.getLabel(),
match.getTooltip(),
match.getIcon(),
- match.getColor(),
+ match.getStyle(),
match.getMenuName(),
match.getLocation(),
- match.isLinkDisabled(),
match.getID(),
match.underlineOnHoverOnly());
return true;
diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h
index 24ce516c43..da16171a97 100644
--- a/indra/llui/llurlregistry.h
+++ b/indra/llui/llurlregistry.h
@@ -37,7 +37,9 @@
#include <vector>
/// This default callback for findUrl() simply ignores any label updates
-void LLUrlRegistryNullCallback(const std::string &url, const std::string &label);
+void LLUrlRegistryNullCallback(const std::string &url,
+ const std::string &label,
+ const std::string &icon);
///
/// LLUrlRegistry is a singleton that contains a set of Url types that
@@ -64,7 +66,9 @@ public:
~LLUrlRegistry();
/// add a new Url handler to the registry (will be freed on destruction)
- void registerUrl(LLUrlEntryBase *url);
+ /// optionally force it to the front of the list, making it take
+ /// priority over other regular expression matches for URLs
+ void registerUrl(LLUrlEntryBase *url, bool force_front = false);
/// get the next Url in an input string, starting at a given character offset
/// your callback is invoked if the matched Url's label changes in the future
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index fe5ef269a9..245126d178 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -102,11 +102,8 @@ LLView::Params::Params()
left_pad("left_pad"),
left_delta("left_delta", S32_MAX),
from_xui("from_xui", false),
- user_resize("user_resize"),
- auto_resize("auto_resize"),
+ focus_root("focus_root", false),
needs_translate("translate"),
- min_width("min_width"),
- max_width("max_width"),
xmlns("xmlns"),
xmlns_xsi("xmlns:xsi"),
xsi_schemaLocation("xsi:schemaLocation"),
@@ -117,16 +114,16 @@ LLView::Params::Params()
}
LLView::LLView(const LLView::Params& p)
-: mName(p.name),
+: mVisible(p.visible),
+ mName(p.name),
mParentView(NULL),
mReshapeFlags(FOLLOWS_NONE),
mFromXUI(p.from_xui),
- mIsFocusRoot(FALSE),
+ mIsFocusRoot(p.focus_root),
mLastVisible(FALSE),
mNextInsertionOrdinal(0),
mHoverCursor(getCursorFromString(p.hover_cursor)),
mEnabled(p.enabled),
- mVisible(p.visible),
mMouseOpaque(p.mouse_opaque),
mSoundFlags(p.sound_flags),
mUseBoundingRect(p.use_bounding_rect),
@@ -167,8 +164,6 @@ LLView::~LLView()
if (mDefaultWidgets)
{
- std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
- DeletePairedPointer());
delete mDefaultWidgets;
mDefaultWidgets = NULL;
}
@@ -218,7 +213,7 @@ void LLView::setUseBoundingRect( BOOL use_bounding_rect )
}
}
-BOOL LLView::getUseBoundingRect()
+BOOL LLView::getUseBoundingRect() const
{
return mUseBoundingRect;
}
@@ -343,7 +338,7 @@ void LLView::removeChild(LLView* child)
}
else
{
- llerrs << "LLView::removeChild called with non-child" << llendl;
+ llwarns << child->getName() << "is not a child of " << getName() << llendl;
}
updateBoundingRect();
}
@@ -1304,7 +1299,13 @@ void LLView::drawChildren()
{
if (!mChildList.empty())
{
- LLRect rootRect = getRootView()->getRect();
+ static const LLRect* rootRect = NULL;
+
+ if (!mParentView)
+ {
+ rootRect = &mRect;
+ }
+
LLRect screenRect;
++sDepth;
@@ -1318,7 +1319,7 @@ void LLView::drawChildren()
{
// Only draw views that are within the root view
localRectToScreen(viewp->getRect(),&screenRect);
- if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
+ if ( rootRect->overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
{
LLUI::pushMatrix();
{
@@ -1370,12 +1371,12 @@ void LLView::drawDebugRect()
// drawing solids requires texturing be disabled
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- if (mUseBoundingRect)
+ if (getUseBoundingRect())
{
LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);
}
- LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
+ LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect;
// draw red rectangle for the border
LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f);
@@ -1573,7 +1574,7 @@ void LLView::updateBoundingRect()
LLRect cur_rect = mBoundingRect;
- if (mUseBoundingRect)
+ if (getUseBoundingRect())
{
mBoundingRect = calcBoundingRect();
}
@@ -1583,7 +1584,7 @@ void LLView::updateBoundingRect()
}
// give parent view a chance to resize, in case we just moved, for example
- if (getParent() && getParent()->mUseBoundingRect)
+ if (getParent() && getParent()->getUseBoundingRect())
{
getParent()->updateBoundingRect();
}
@@ -1607,7 +1608,7 @@ LLRect LLView::calcScreenBoundingRect() const
{
LLRect screen_rect;
// get bounding rect, if used
- LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect;
+ LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect;
// convert to local coordinates, as defined by mRect
bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
@@ -1686,16 +1687,7 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const
//-----------------------------------------------------------------------------
LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
{
- LLView* child = findChildView(name, recurse);
- if (!child)
- {
- child = getDefaultWidget<LLView>(name);
- if (!child)
- {
- child = LLUICtrlFactory::createDefaultWidget<LLView>(name);
- }
- }
- return child;
+ return getChild<LLView>(name, recurse);
}
static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets");
@@ -1736,14 +1728,14 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const
{
- return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+ return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)
? mBoundingRect.pointInRect( x, y )
: mRect.pointInRect( x, y );
}
BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const
{
- return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+ return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)
? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom )
: mRect.localPointInRect( x, y );
}
@@ -1972,7 +1964,7 @@ void LLView::centerWithin(const LLRect& bounds)
translate( left - getRect().mLeft, bottom - getRect().mBottom );
}
-BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view) const
+BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const
{
const LLView* cur_view = this;
const LLView* root_view = NULL;
@@ -2015,7 +2007,7 @@ BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LL
return FALSE;
}
-BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const
+BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const
{
LLRect cur_rect = local;
const LLView* cur_view = this;
@@ -2806,11 +2798,14 @@ LLView::root_to_view_iterator_t LLView::endRootToView()
// only create maps on demand, as they incur heap allocation/deallocation cost
// when a view is constructed/deconstructed
-LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const
+LLView& LLView::getDefaultWidgetContainer() const
{
if (!mDefaultWidgets)
{
- mDefaultWidgets = new default_widget_map_t();
+ LLView::Params p;
+ p.name = "default widget container";
+ p.visible = false; // ensures default widgets can't steal focus, etc.
+ mDefaultWidgets = new LLView(p);
}
return *mDefaultWidgets;
}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index f7175112bf..594a5eec6b 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "llcoord.h"
#include "llfontgl.h"
+#include "llhandle.h"
#include "llmortician.h"
#include "llmousehandler.h"
#include "llstring.h"
@@ -116,7 +117,8 @@ public:
visible,
mouse_opaque,
use_bounding_rect,
- from_xui;
+ from_xui,
+ focus_root;
Optional<S32> tab_group,
default_tab_group;
@@ -128,26 +130,22 @@ public:
Optional<std::string> layout;
Optional<LLRect> rect;
+
// Historical bottom-left layout used bottom_delta and left_delta
// for relative positioning. New layout "topleft" prefers specifying
// based on top edge.
- Optional<S32> bottom_delta, // deprecated
- top_pad, // from last bottom to my top
- top_delta, // from last top to my top
- left_pad, // from last right to my left
- left_delta; // from last left to my left
-
- // these are nested attributes for LLLayoutPanel
+ Optional<S32> bottom_delta, // from last bottom to my bottom
+ top_pad, // from last bottom to my top
+ top_delta, // from last top to my top
+ left_pad, // from last right to my left
+ left_delta; // from last left to my left
+
//FIXME: get parent context involved in parsing traversal
- Ignored user_resize,
- auto_resize,
- needs_translate,
- min_width,
- max_width,
- xmlns,
- xmlns_xsi,
- xsi_schemaLocation,
- xsi_type;
+ Ignored needs_translate, // cue for translation tools
+ xmlns, // xml namespace
+ xmlns_xsi, // xml namespace
+ xsi_schemaLocation, // xml schema
+ xsi_type; // xml schema type
Params();
};
@@ -238,7 +236,7 @@ public:
void setSoundFlags(U8 flags) { mSoundFlags = flags; }
void setName(std::string name) { mName = name; }
void setUseBoundingRect( BOOL use_bounding_rect );
- BOOL getUseBoundingRect();
+ BOOL getUseBoundingRect() const;
ECursorType getHoverCursor() { return mHoverCursor; }
@@ -277,6 +275,11 @@ public:
BOOL focusNextRoot();
BOOL focusPrevRoot();
+ // Normally we want the app menus to get priority on accelerated keys
+ // However, sometimes we want to give specific views a first chance
+ // iat handling them. (eg. the script editor)
+ virtual bool hasAccelerators() const { return false; };
+
// delete all children. Override this function if you need to
// perform any extra clean up such as cached pointers to selected
// children, etc.
@@ -285,7 +288,7 @@ public:
void setAllChildrenEnabled(BOOL b);
virtual void setVisible(BOOL visible);
- BOOL getVisible() const { return mVisible; }
+ const BOOL& getVisible() const { return mVisible; }
virtual void setEnabled(BOOL enabled);
BOOL getEnabled() const { return mEnabled; }
/// 'available' in this context means 'visible and enabled': in other
@@ -404,21 +407,16 @@ public:
BOOL blockMouseEvent(S32 x, S32 y) const;
// See LLMouseHandler virtuals for screenPointToLocal and localPointToScreen
- BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view) const;
- BOOL localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const;
+ BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const;
+ BOOL localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const;
void screenRectToLocal( const LLRect& screen, LLRect* local ) const;
void localRectToScreen( const LLRect& local, LLRect* screen ) const;
LLControlVariable *findControl(const std::string& name);
- // Moved setValue(), getValue(), setControlValue(), setControlName(),
- // controlListener() to LLUICtrl because an LLView is NOT assumed to
- // contain a value. If that's what you want, use LLUICtrl instead.
-// virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
-
const child_list_t* getChildList() const { return &mChildList; }
- const child_list_const_iter_t beginChild() { return mChildList.begin(); }
- const child_list_const_iter_t endChild() { return mChildList.end(); }
+ child_list_const_iter_t beginChild() const { return mChildList.begin(); }
+ child_list_const_iter_t endChild() const { return mChildList.end(); }
// LLMouseHandler functions
// Default behavior is to pass events to children
@@ -465,12 +463,8 @@ public:
template <class T> T* getDefaultWidget(const std::string& name) const
{
- default_widget_map_t::const_iterator found_it = getDefaultWidgetMap().find(name);
- if (found_it == getDefaultWidgetMap().end())
- {
- return NULL;
- }
- return dynamic_cast<T*>(found_it->second);
+ LLView* widgetp = getDefaultWidgetContainer().findChildView(name);
+ return dynamic_cast<T*>(widgetp);
}
//////////////////////////////////////////////
@@ -550,11 +544,13 @@ private:
LLView* mParentView;
child_list_t mChildList;
- std::string mName;
// location in pixels, relative to surrounding structure, bottom,left=0,0
+ BOOL mVisible;
LLRect mRect;
LLRect mBoundingRect;
+
std::string mLayout;
+ std::string mName;
U32 mReshapeFlags;
@@ -576,17 +572,15 @@ private:
LLRootHandle<LLView> mHandle;
BOOL mLastVisible;
- BOOL mVisible;
-
S32 mNextInsertionOrdinal;
static LLWindow* sWindow; // All root views must know about their window.
typedef std::map<std::string, LLView*> default_widget_map_t;
// allocate this map no demand, as it is rarely needed
- mutable default_widget_map_t* mDefaultWidgets;
+ mutable LLView* mDefaultWidgets;
- default_widget_map_t& getDefaultWidgetMap() const;
+ LLView& getDefaultWidgetContainer() const;
public:
// Depth in view hierarchy during rendering
@@ -653,7 +647,7 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co
return NULL;
}
- getDefaultWidgetMap()[name] = result;
+ getDefaultWidgetContainer().addChild(result);
}
}
return result;
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index 89cd34c37c..32d7ea7c25 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -28,6 +28,7 @@
#include "llrender.h"
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
static LLDefaultChildRegistry::Register<LLViewBorder> r("view_border");
diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp
new file mode 100644
index 0000000000..77e94385d4
--- /dev/null
+++ b/indra/llui/llwindowshade.cpp
@@ -0,0 +1,328 @@
+/**
+ * @file LLWindowShade.cpp
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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 "llwindowshade.h"
+
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "lliconctrl.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "lllineeditor.h"
+
+const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
+const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
+
+LLWindowShade::Params::Params()
+: bg_image("bg_image"),
+ modal("modal", false),
+ text_color("text_color"),
+ can_close("can_close", true)
+{
+ mouse_opaque = false;
+}
+
+LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
+: LLUICtrl(params),
+ mNotification(params.notification),
+ mModal(params.modal),
+ mFormHeight(0),
+ mTextColor(params.text_color)
+{
+ setFocusRoot(true);
+}
+
+void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
+{
+ LLUICtrl::initFromParams(params);
+
+ LLLayoutStack::Params layout_p;
+ layout_p.name = "notification_stack";
+ layout_p.rect = params.rect;
+ layout_p.follows.flags = FOLLOWS_ALL;
+ layout_p.mouse_opaque = false;
+ layout_p.orientation = LLLayoutStack::VERTICAL;
+ layout_p.border_size = 0;
+
+ LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+ addChild(stackp);
+
+ LLLayoutPanel::Params panel_p;
+ panel_p.rect = LLRect(0, 30, 800, 0);
+ panel_p.name = "notification_area";
+ panel_p.visible = false;
+ panel_p.user_resize = false;
+ panel_p.background_visible = true;
+ panel_p.bg_alpha_image = params.bg_image;
+ panel_p.auto_resize = false;
+ LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(notification_panel);
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = true;
+ panel_p.user_resize = false;
+ panel_p.rect = params.rect;
+ panel_p.name = "background_area";
+ panel_p.mouse_opaque = false;
+ panel_p.background_visible = false;
+ panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f);
+ LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(dummy_panel);
+
+ layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
+ layout_p.rect = LLRect(0, 30, 800, 0);
+ layout_p.follows.flags = FOLLOWS_ALL;
+ layout_p.orientation = LLLayoutStack::HORIZONTAL;
+ stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+ notification_panel->addChild(stackp);
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.rect.height = 30;
+ LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(panel);
+
+ LLIconCtrl::Params icon_p;
+ icon_p.name = "notification_icon";
+ icon_p.rect = LLRect(5, 23, 21, 8);
+ panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
+
+ LLTextBox::Params text_p;
+ text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0);
+ text_p.follows.flags = FOLLOWS_ALL;
+ text_p.text_color = mTextColor;
+ text_p.font = LLFontGL::getFontSansSerifSmall();
+ text_p.font.style = "BOLD";
+ text_p.name = "notification_text";
+ text_p.use_ellipses = true;
+ text_p.wrap = true;
+ panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = false;
+ panel_p.user_resize = false;
+ panel_p.name="form_elements";
+ panel_p.rect = LLRect(0, 30, 130, 0);
+ LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(form_elements_panel);
+
+ if (params.can_close)
+ {
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = false;
+ panel_p.user_resize = false;
+ panel_p.rect = LLRect(0, 30, 25, 0);
+ LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(close_panel);
+
+ LLButton::Params button_p;
+ button_p.name = "close_notification";
+ button_p.rect = LLRect(5, 23, 21, 7);
+ button_p.image_color.control="DkGray_66";
+ button_p.image_unselected.name="Icon_Close_Foreground";
+ button_p.image_selected.name="Icon_Close_Press";
+ button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
+
+ close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
+ }
+
+ LLSD payload = mNotification->getPayload();
+
+ LLNotificationFormPtr formp = mNotification->getForm();
+ LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
+ notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon());
+ notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage());
+ notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage());
+
+ LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();
+ LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
+ form_elements.deleteAllChildren();
+
+ const S32 FORM_PADDING_HORIZONTAL = 10;
+ const S32 FORM_PADDING_VERTICAL = 3;
+ const S32 WIDGET_HEIGHT = 24;
+ const S32 LINE_EDITOR_WIDTH = 120;
+ S32 cur_x = FORM_PADDING_HORIZONTAL;
+ S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT;
+ S32 form_width = cur_x;
+
+ if (ignore_type != LLNotificationForm::IGNORE_NO)
+ {
+ LLCheckBoxCtrl::Params checkbox_p;
+ checkbox_p.name = "ignore_check";
+ checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+ checkbox_p.label = formp->getIgnoreMessage();
+ checkbox_p.label_text.text_color = LLColor4::black;
+ checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1);
+ checkbox_p.initial_value = formp->getIgnored();
+
+ LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
+ check->setRect(check->getBoundingRect());
+ form_elements.addChild(check);
+ cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
+ form_width = llmax(form_width, cur_x);
+ }
+
+ for (S32 i = 0; i < formp->getNumElements(); i++)
+ {
+ LLSD form_element = formp->getElement(i);
+ std::string type = form_element["type"].asString();
+ if (type == "button")
+ {
+ LLButton::Params button_p;
+ button_p.name = form_element["name"];
+ button_p.label = form_element["text"];
+ button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+ button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString());
+ button_p.auto_resize = true;
+
+ LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
+ button->autoResize();
+ form_elements.addChild(button);
+
+ if (form_element["default"].asBoolean())
+ {
+ form_elements.setDefaultBtn(button);
+ }
+
+ cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
+ form_width = llmax(form_width, cur_x);
+ }
+ else if (type == "text" || type == "password")
+ {
+ // if not at beginning of line...
+ if (cur_x != FORM_PADDING_HORIZONTAL)
+ {
+ // start new line
+ cur_x = FORM_PADDING_HORIZONTAL;
+ cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+ }
+ LLTextBox::Params label_p;
+ label_p.name = form_element["name"].asString() + "_label";
+ label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+ label_p.initial_value = form_element["text"];
+ label_p.text_color = mTextColor;
+ label_p.font_valign = LLFontGL::VCENTER;
+ label_p.v_pad = 5;
+ LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
+ textbox->reshapeToFitText();
+ textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL);
+ form_elements.addChild(textbox);
+ cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
+
+ LLLineEditor::Params line_p;
+ line_p.name = form_element["name"];
+ line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString());
+ line_p.is_password = type == "password";
+ line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+
+ LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
+ form_elements.addChild(line_editor);
+ form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL);
+
+ // reset to start of next line
+ cur_x = FORM_PADDING_HORIZONTAL;
+ cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+ }
+ }
+
+ mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT;
+ form_elements.reshape(form_width, mFormHeight);
+ form_elements.setMinDim(form_width);
+
+ // move all form elements back onto form surface
+ S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y;
+ for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end();
+ it != end_it;
+ ++it)
+ {
+ (*it)->translate(0, delta_y);
+ }
+}
+
+void LLWindowShade::show()
+{
+ getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
+ getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
+
+ setMouseOpaque(mModal);
+}
+
+void LLWindowShade::draw()
+{
+ LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
+
+ LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
+
+ notification_area->reshape(notification_area->getRect().getWidth(),
+ llclamp(message_rect.getHeight() + 10,
+ llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
+ MAX_NOTIFICATION_AREA_HEIGHT));
+
+ LLUICtrl::draw();
+ if (mNotification && !mNotification->isActive())
+ {
+ hide();
+ }
+}
+
+void LLWindowShade::hide()
+{
+ getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
+ getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
+
+ setMouseOpaque(false);
+}
+
+void LLWindowShade::onCloseNotification()
+{
+ LLNotifications::instance().cancel(mNotification);
+}
+
+void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
+{
+ bool check = ctrl->getValue().asBoolean();
+ if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+ {
+ // question was "show again" so invert value to get "ignore"
+ check = !check;
+ }
+ mNotification->setIgnored(check);
+}
+
+void LLWindowShade::onClickNotificationButton(const std::string& name)
+{
+ if (!mNotification) return;
+
+ mNotificationResponse[name] = true;
+
+ mNotification->respond(mNotificationResponse);
+}
+
+void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
+{
+ mNotificationResponse[name] = ctrl->getValue().asString();
+}
diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h
new file mode 100644
index 0000000000..09ffc2cd54
--- /dev/null
+++ b/indra/llui/llwindowshade.h
@@ -0,0 +1,70 @@
+/**
+ * @file llwindowshade.h
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_LLWINDOWSHADE_H
+#define LL_LLWINDOWSHADE_H
+
+#include "lluictrl.h"
+#include "llnotifications.h"
+#include "lluiimage.h"
+
+class LLWindowShade : public LLUICtrl
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+ {
+ Mandatory<LLNotificationPtr> notification;
+ Optional<LLUIImage*> bg_image;
+ Optional<LLUIColor> text_color;
+ Optional<bool> modal,
+ can_close;
+
+ Params();
+ };
+
+ void show();
+ /*virtual*/ void draw();
+ void hide();
+
+private:
+ friend class LLUICtrlFactory;
+
+ LLWindowShade(const Params& p);
+ void initFromParams(const Params& params);
+
+ void onCloseNotification();
+ void onClickNotificationButton(const std::string& name);
+ void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);
+ void onClickIgnore(LLUICtrl* ctrl);
+
+ LLNotificationPtr mNotification;
+ LLSD mNotificationResponse;
+ bool mModal;
+ S32 mFormHeight;
+ LLUIColor mTextColor;
+};
+
+#endif // LL_LLWINDOWSHADE_H
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index ff53ae5624..26b3b17577 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -27,11 +27,29 @@
#include "llstring.h"
#include "llfile.h"
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lluuid.h"
+#include "message.h"
#include <string>
+// Stub for LLAvatarNameCache
+bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
+{
+ return false;
+}
+
+void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
+{
+ return;
+}
+
+bool LLAvatarNameCache::useDisplayNames()
+{
+ return false;
+}
+
//
// Stub implementation for LLCacheName
//
@@ -47,7 +65,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
return TRUE;
}
-boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
+{
+ return boost::signals2::connection();
+}
+
+boost::signals2::connection LLCacheName::getGroup(const LLUUID& id, const LLCacheNameCallback& callback)
{
return boost::signals2::connection();
}
@@ -67,3 +90,120 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
{
return std::string();
}
+
+//
+// Stub implementation for LLStyle::Params::Params
+//
+
+LLStyle::Params::Params()
+{
+}
+
+//
+// Stub implementations for various LLInitParam classes
+//
+
+namespace LLInitParam
+{
+ BaseBlock::BaseBlock() {}
+ BaseBlock::~BaseBlock() {}
+ Param::Param(BaseBlock* enclosing_block)
+ : mIsProvided(false)
+ {
+ const U8* my_addr = reinterpret_cast<const U8*>(this);
+ const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
+ mEnclosingBlockOffset = (U16)(my_addr - block_addr);
+ }
+ void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {}
+
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}
+ void BaseBlock::addSynonym(Param& param, const std::string& synonym) {}
+ param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
+
+ void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
+ {
+ descriptor.mCurrentBlockPtr = this;
+ }
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; }
+ void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {}
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; }
+ bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
+
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color)
+ {}
+
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
+ {}
+
+ bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
+ {
+ return false;
+ }
+
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp)
+ {}
+
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
+ {}
+
+ void TypeValues<LLFontGL::HAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::VAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::ShadowType>::declareValues()
+ {}
+
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
+ {}
+
+
+ bool ParamCompare<LLUIImage*, false>::equals(
+ LLUIImage* const &a,
+ LLUIImage* const &b)
+ {
+ return false;
+ }
+
+ bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b)
+ {
+ return false;
+ }
+
+}
+
+//static
+LLFontGL* LLFontGL::getFontDefault()
+{
+ return NULL;
+}
+
+char const* const _PREHASH_AgentData = (char *)"AgentData";
+char const* const _PREHASH_AgentID = (char *)"AgentID";
+
+LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
+
+LLMessageSystem* gMessageSystem = NULL;
+
+//
+// Stub implementation for LLMessageSystem
+//
+void LLMessageSystem::newMessage(const char *name) { }
+void LLMessageSystem::nextBlockFast(const char *blockname) { }
+void LLMessageSystem::nextBlock(const char *blockname) { }
+void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { }
+void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { }
+S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; }
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 95affe4460..2f814f4200 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -27,12 +27,22 @@
#include "linden_common.h"
#include "../llurlentry.h"
+#include "../lluictrl.h"
#include "llurlentry_stub.cpp"
#include "lltut.h"
#include "../lluicolortable.h"
+#include "../lluiimage.h"
#include <boost/regex.hpp>
+typedef std::map<std::string, LLControlGroup*> settings_map_t;
+settings_map_t LLUI::sSettingGroups;
+
+BOOL LLControlGroup::getBOOL(const std::string& name)
+{
+ return false;
+}
+
LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const
{
return LLUIColor();
@@ -40,6 +50,42 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa
LLUIColor::LLUIColor() : mColorPtr(NULL) {}
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+}
+
+//virtual
+S32 LLUIImage::getWidth() const
+{
+ return 0;
+}
+
+//virtual
+S32 LLUIImage::getHeight() const
+{
+ return 0;
+}
+
+namespace LLInitParam
+{
+ S32 Parser::sNextParseGeneration = 0;
+ BlockDescriptor::BlockDescriptor() {}
+ ParamDescriptor::ParamDescriptor(param_handle_t p,
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count){}
+ ParamDescriptor::~ParamDescriptor() {}
+
+}
+
namespace tut
{
struct LLUrlEntryData
@@ -73,6 +119,45 @@ namespace tut
ensure_equals(testname, url, expected);
}
+ void dummyCallback(const std::string &url, const std::string &label, const std::string& icon)
+ {
+ }
+
+ void testLabel(const std::string &testname, LLUrlEntryBase &entry,
+ const char *text, const std::string &expected)
+ {
+ boost::regex regex = entry.getPattern();
+ std::string label = "";
+ boost::cmatch result;
+ bool found = boost::regex_search(text, result, regex);
+ if (found)
+ {
+ S32 start = static_cast<U32>(result[0].first - text);
+ S32 end = static_cast<U32>(result[0].second - text);
+ std::string url = std::string(text+start, end-start);
+ label = entry.getLabel(url, boost::bind(dummyCallback, _1, _2, _3));
+ }
+ ensure_equals(testname, label, expected);
+ }
+
+ void testLocation(const std::string &testname, LLUrlEntryBase &entry,
+ const char *text, const std::string &expected)
+ {
+ boost::regex regex = entry.getPattern();
+ std::string location = "";
+ boost::cmatch result;
+ bool found = boost::regex_search(text, result, regex);
+ if (found)
+ {
+ S32 start = static_cast<U32>(result[0].first - text);
+ S32 end = static_cast<U32>(result[0].second - text);
+ std::string url = std::string(text+start, end-start);
+ location = entry.getLocation(url);
+ }
+ ensure_equals(testname, location, expected);
+ }
+
+
template<> template<>
void object::test<1>()
{
@@ -667,4 +752,114 @@ namespace tut
"<nolink>My Object</nolink>",
"My Object");
}
+
+ template<> template<>
+ void object::test<13>()
+ {
+ //
+ // test LLUrlEntryRegion - secondlife:///app/region/<location> URLs
+ //
+ LLUrlEntryRegion url;
+
+ // Regex tests.
+ testRegex("no valid region", url,
+ "secondlife:///app/region/",
+ "");
+
+ testRegex("invalid coords", url,
+ "secondlife:///app/region/Korea2/a/b/c",
+ "secondlife:///app/region/Korea2/"); // don't count invalid coords
+
+ testRegex("Ahern (50,50,50) [1]", url,
+ "secondlife:///app/region/Ahern/50/50/50/",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [2]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [3]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50 XXX",
+ "secondlife:///app/region/Ahern/50/50/50");
+
+ testRegex("Ahern (50,50,50) multicase", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50) [1]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/");
+
+ testRegex("Ahern (50,50) [2]", url,
+ "XXX secondlife:///app/region/Ahern/50/50 XXX",
+ "secondlife:///app/region/Ahern/50/50");
+
+ // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
+ testRegex("Region with brackets", url,
+ "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/",
+ "Ahern (50,50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50/50", url,
+ "secondlife:///app/region/Ahern/50/50/50",
+ "Ahern (50,50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50/", url,
+ "secondlife:///app/region/Ahern/50/50/",
+ "Ahern (50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50", url,
+ "secondlife:///app/region/Ahern/50/50",
+ "Ahern (50,50)");
+
+ testLabel("Render /app/region/Ahern/50/", url,
+ "secondlife:///app/region/Ahern/50/",
+ "Ahern (50)");
+
+ testLabel("Render /app/region/Ahern/50", url,
+ "secondlife:///app/region/Ahern/50",
+ "Ahern (50)");
+
+ testLabel("Render /app/region/Ahern/", url,
+ "secondlife:///app/region/Ahern/",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern/ within context", url,
+ "XXX secondlife:///app/region/Ahern/ XXX",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern", url,
+ "secondlife:///app/region/Ahern",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern within context", url,
+ "XXX secondlife:///app/region/Ahern XXX",
+ "Ahern");
+
+ testLabel("Render /app/region/Product%20Engine/", url,
+ "secondlife:///app/region/Product%20Engine/",
+ "Product Engine");
+
+ testLabel("Render /app/region/Product%20Engine", url,
+ "secondlife:///app/region/Product%20Engine",
+ "Product Engine");
+
+ // Location parsing texts.
+ testLocation("Location /app/region/Ahern/50/50/50/", url,
+ "secondlife:///app/region/Ahern/50/50/50/",
+ "Ahern");
+
+ testLocation("Location /app/region/Product%20Engine", url,
+ "secondlife:///app/region/Product%20Engine",
+ "Product Engine");
+ }
}
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
index 4e38bea1bd..e09ef33d49 100644
--- a/indra/llui/tests/llurlmatch_test.cpp
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -25,14 +25,147 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "../llurlmatch.h"
+#include "../lluiimage.h"
#include "lltut.h"
-// link seam
+// link seams
+
LLUIColor::LLUIColor()
: mColorPtr(NULL)
{}
+LLStyle::Params::Params()
+{
+}
+
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+}
+
+//virtual
+S32 LLUIImage::getWidth() const
+{
+ return 0;
+}
+
+//virtual
+S32 LLUIImage::getHeight() const
+{
+ return 0;
+}
+
+namespace LLInitParam
+{
+ BaseBlock::BaseBlock() {}
+ BaseBlock::~BaseBlock() {}
+
+ S32 Parser::sNextParseGeneration = 0;
+
+ BlockDescriptor::BlockDescriptor() {}
+ ParamDescriptor::ParamDescriptor(param_handle_t p,
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count){}
+ ParamDescriptor::~ParamDescriptor() {}
+
+ void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {}
+
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}
+ param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
+ void BaseBlock::addSynonym(Param& param, const std::string& synonym) {}
+
+ void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
+ {
+ descriptor.mCurrentBlockPtr = this;
+ }
+
+ Param::Param(BaseBlock* enclosing_block)
+ : mIsProvided(false)
+ {
+ const U8* my_addr = reinterpret_cast<const U8*>(this);
+ const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
+ mEnclosingBlockOffset = (U16)(my_addr - block_addr);
+ }
+
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; }
+ void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {}
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; }
+ bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
+
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color)
+ {}
+
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
+ {}
+
+ bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
+ {
+ return false;
+ }
+
+
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp)
+ {}
+
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
+ {}
+
+ void TypeValues<LLFontGL::HAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::VAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::ShadowType>::declareValues()
+ {}
+
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
+ {}
+
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
+ {}
+
+ bool ParamCompare<LLUIImage*, false>::equals(
+ LLUIImage* const &a,
+ LLUIImage* const &b)
+ {
+ return false;
+ }
+
+ bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b)
+ {
+ return false;
+ }
+
+}
+
+//static
+LLFontGL* LLFontGL::getFontDefault()
+{
+ return NULL;
+}
+
+
namespace tut
{
struct LLUrlMatchData
@@ -59,7 +192,7 @@ namespace tut
LLUrlMatch match;
ensure("empty()", match.empty());
- match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("! empty()", ! match.empty());
}
@@ -72,7 +205,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getStart() == 0", match.getStart(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getStart() == 10", match.getStart(), 10);
}
@@ -85,7 +218,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getEnd() == 0", match.getEnd(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getEnd() == 20", match.getEnd(), 20);
}
@@ -98,10 +231,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getUrl() == ''", match.getUrl(), "");
- match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "http://slurl.com/", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
}
@@ -114,10 +247,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getLabel() == ''", match.getLabel(), "");
- match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "Label", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
}
@@ -130,10 +263,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getTooltip() == ''", match.getTooltip(), "");
- match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
}
@@ -146,10 +279,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getIcon() == ''", match.getIcon(), "");
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
}
@@ -162,10 +295,10 @@ namespace tut
LLUrlMatch match;
ensure("getMenuName() empty", match.getMenuName().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null);
ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("getMenuName() empty (2)", match.getMenuName().empty());
}
@@ -178,10 +311,10 @@ namespace tut
LLUrlMatch match;
ensure("getLocation() empty", match.getLocation().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null);
ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("getLocation() empty (2)", match.getLocation().empty());
}
}