summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorBryan O'Sullivan <bos@lindenlab.com>2009-06-22 15:02:19 -0700
committerBryan O'Sullivan <bos@lindenlab.com>2009-06-22 15:02:19 -0700
commitbaa73fddd9287ddafd2d31551cb253b355ed910a (patch)
treee3f0986617fe6c0ee0a14df6aac13c6bb6f92507 /indra/llui
parentdc3833f31b8a20220ddb1775e1625c016c397435 (diff)
parentfcaa1ad46fd1df4cfec9dee12caf6e7b5bf32136 (diff)
Merge with viewer-2.0.0-3 branch
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/llbutton.cpp54
-rw-r--r--indra/llui/llbutton.h8
-rw-r--r--indra/llui/llcheckboxctrl.cpp2
-rw-r--r--indra/llui/llcheckboxctrl.h2
-rw-r--r--indra/llui/llcombobox.cpp57
-rw-r--r--indra/llui/llcombobox.h7
-rw-r--r--indra/llui/llcontainerview.cpp2
-rw-r--r--indra/llui/llfloater.cpp40
-rw-r--r--indra/llui/llfloater.h10
-rw-r--r--indra/llui/llfloaterreg.h3
-rw-r--r--indra/llui/llflyoutbutton.cpp2
-rw-r--r--indra/llui/lliconctrl.cpp2
-rw-r--r--indra/llui/lliconctrl.h2
-rw-r--r--indra/llui/lllayoutstack.cpp78
-rw-r--r--indra/llui/lllayoutstack.h9
-rw-r--r--indra/llui/lllazyvalue.h5
-rw-r--r--indra/llui/lllineeditor.cpp30
-rw-r--r--indra/llui/lllineeditor.h3
-rw-r--r--indra/llui/llmenugl.cpp480
-rw-r--r--indra/llui/llmenugl.h37
-rw-r--r--indra/llui/llmultifloater.h2
-rw-r--r--indra/llui/llmultislider.cpp2
-rw-r--r--indra/llui/llmultisliderctrl.cpp2
-rw-r--r--indra/llui/llnotifications.cpp10
-rw-r--r--indra/llui/llnotifications.h4
-rw-r--r--indra/llui/llpanel.cpp196
-rw-r--r--indra/llui/llpanel.h15
-rw-r--r--indra/llui/llprogressbar.cpp2
-rw-r--r--indra/llui/llradiogroup.cpp15
-rw-r--r--indra/llui/llradiogroup.h9
-rw-r--r--indra/llui/llscrollbar.cpp6
-rw-r--r--indra/llui/llscrollcontainer.cpp16
-rw-r--r--indra/llui/llscrollcontainer.h1
-rw-r--r--indra/llui/llscrollingpanellist.cpp2
-rw-r--r--indra/llui/llscrolllistcolumn.cpp10
-rw-r--r--indra/llui/llscrolllistcolumn.h14
-rw-r--r--indra/llui/llscrolllistctrl.cpp6
-rw-r--r--indra/llui/llscrolllistctrl.h2
-rw-r--r--indra/llui/llscrolllistitem.h6
-rw-r--r--indra/llui/llsearcheditor.cpp2
-rw-r--r--indra/llui/llslider.cpp3
-rw-r--r--indra/llui/llsliderctrl.cpp3
-rw-r--r--indra/llui/llspinctrl.cpp2
-rw-r--r--indra/llui/llstatbar.cpp2
-rw-r--r--indra/llui/llstatview.cpp14
-rw-r--r--indra/llui/llstatview.h3
-rw-r--r--indra/llui/lltabcontainer.cpp40
-rw-r--r--indra/llui/lltabcontainer.h14
-rw-r--r--indra/llui/lltextbox.cpp2
-rw-r--r--indra/llui/lltextbox.h2
-rw-r--r--indra/llui/lltexteditor.cpp2
-rw-r--r--indra/llui/lltexteditor.h2
-rw-r--r--indra/llui/llui.cpp26
-rw-r--r--indra/llui/llui.h7
-rw-r--r--indra/llui/lluicolortable.cpp155
-rw-r--r--indra/llui/lluicolortable.h58
-rw-r--r--indra/llui/lluictrl.cpp107
-rw-r--r--indra/llui/lluictrl.h45
-rw-r--r--indra/llui/lluictrlfactory.cpp205
-rw-r--r--indra/llui/lluictrlfactory.h190
-rw-r--r--indra/llui/lluiimage.cpp10
-rw-r--r--indra/llui/lluiimage.h7
-rw-r--r--indra/llui/lluistring.cpp7
-rw-r--r--indra/llui/llview.cpp319
-rw-r--r--indra/llui/llview.h50
-rw-r--r--indra/llui/llviewborder.cpp2
67 files changed, 1946 insertions, 488 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index f3595a7b05..117e8e28ab 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -81,6 +81,7 @@ set(llui_SOURCE_FILES
lltextparser.cpp
lltrans.cpp
llui.cpp
+ lluicolortable.cpp
lluictrl.cpp
lluictrlfactory.cpp
lluiimage.cpp
@@ -153,6 +154,7 @@ set(llui_HEADER_FILES
lltexteditor.h
lltextparser.h
lltrans.h
+ lluicolortable.h
lluiconstants.h
lluictrlfactory.h
lluictrl.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index cdd364797c..f2aa9c0d4c 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -53,7 +53,7 @@
#include "llrender.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLButton> r("button");
+static LLDefaultWidgetRegistry::Register<LLButton> r("button");
// globals loaded from settings.xml
S32 LLBUTTON_H_PAD = 0;
@@ -90,7 +90,6 @@ LLButton::Params::Params()
mouse_down_callback("mouse_down_callback"),
mouse_up_callback("mouse_up_callback"),
mouse_held_callback("mouse_held_callback"),
- mouse_held_once_callback("mouse_held_once_callback"),
is_toggle("is_toggle", false),
scale_image("scale_image", true),
help_url("help_url"),
@@ -147,7 +146,7 @@ LLButton::LLButton(const LLButton::Params& p)
mFadeWhenDisabled(FALSE)
{
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
- static LLButton::Params default_params(LLUICtrlFactory::getDefaultParams<LLButton::Params>());
+ static Params default_params(LLUICtrlFactory::getDefaultParams<Params>());
//if we aren't a picture_style button set label as name if not provided
if (!p.picture_style.isProvided() || !p.picture_style)
@@ -199,6 +198,11 @@ LLButton::LLButton(const LLButton::Params& p)
}
}
+ if (mImageUnselected.isNull())
+ {
+ llwarns << "Button: " << getName() << " with no image!" << llendl;
+ }
+
if (p.click_callback.isProvided())
initCommitCallback(p.click_callback, mCommitSignal); // alias -> commit_callback
if (p.mouse_down_callback.isProvided())
@@ -256,6 +260,12 @@ boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t
{
return mHeldDownSignal.connect(cb);
}
+
+boost::signals2::connection LLButton::setRightClickedCallback( const commit_signal_t::slot_type& cb )
+{
+ return mRightClickSignal.connect(cb);
+}
+
// *TODO: Deprecate (for backwards compatability only)
boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
@@ -375,6 +385,36 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
return TRUE;
}
+BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ // Route future Mouse messages here preemptively. (Release on mouse up.)
+ gFocusMgr.setMouseCapture( this );
+
+ if (hasTabStop() && !getIsChrome())
+ {
+ setFocus(TRUE);
+ }
+
+
+ return TRUE;
+}
+
+BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+ // We only handle the click if the click both started and ended within us
+ if( hasMouseCapture() )
+ {
+ // Always release the mouse
+ gFocusMgr.setMouseCapture( NULL );
+
+ if (pointInView(x, y))
+ {
+ mRightClickSignal(this, getValue());
+ }
+ }
+ return TRUE;
+}
+
void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
{
@@ -615,7 +655,7 @@ void LLButton::draw()
else
{
// no image
- llwarns << "No image for button " << getName() << llendl;
+ lldebugs << "No image for button " << getName() << llendl;
// draw it in pink so we can find it
gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1, FALSE);
}
@@ -813,6 +853,10 @@ void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label )
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
{
mImageUnselected = image;
+ if (mImageUnselected.isNull())
+ {
+ llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl;
+ }
}
void LLButton::autoResize()
@@ -854,7 +898,7 @@ void LLButton::resize(LLUIString label)
{
if (btn_width - (mRightHPad + mLeftHPad) < label_width)
{
- setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight+ label_width + mLeftHPad + mRightHPad , getRect().mBottom));
+ setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom));
}
}
}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 99f4b94805..1398e5c14b 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -107,8 +107,7 @@ public:
Optional<CommitCallbackParam> click_callback, // alias -> commit_callback
mouse_down_callback,
mouse_up_callback,
- mouse_held_callback,
- mouse_held_once_callback;
+ mouse_held_callback;
// misc
Optional<bool> is_toggle,
@@ -138,6 +137,8 @@ public:
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+ virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
virtual void draw();
/*virtual*/ BOOL postBuild();
@@ -155,6 +156,9 @@ public:
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
// Passes a 'count' parameter in the commit param payload, i.e. param["count"])
boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
+ boost::signals2::connection setRightClickedCallback( const commit_signal_t::slot_type& cb ); // right mouse down and up within button
+
+
// *TODO: Deprecate (for backwards compatability only)
boost::signals2::connection setClickedCallback( button_callback_t cb, void* data );
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 7b37344db7..932a1b6297 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -52,7 +52,7 @@ const U32 MAX_STRING_LENGTH = 10;
template LLCheckBoxCtrl* LLView::getChild<LLCheckBoxCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
-static LLRegisterWidget<LLCheckBoxCtrl> r("check_box");
+static LLDefaultWidgetRegistry::Register<LLCheckBoxCtrl> r("check_box");
LLCheckBoxCtrl::Params::Params()
: text_enabled_color("text_enabled_color"),
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index fe719e3b6a..2f8f088a3e 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -65,7 +65,7 @@ public:
Optional<LLTextBox::Params> label_text;
Optional<LLButton::Params> check_button;
- Deprecated radio_style;
+ Ignored radio_style;
Params();
};
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 09f7a6c813..51ab3326fe 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -65,7 +65,7 @@ S32 MAX_COMBO_WIDTH = 500;
template LLComboBox* LLView::getChild<LLComboBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
-static LLRegisterWidget<LLComboBox> register_combo_box("combo_box");
+static LLDefaultWidgetRegistry::Register<LLComboBox> register_combo_box("combo_box");
void LLComboBox::PreferredPositionValues::declareValues()
{
@@ -98,6 +98,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
: LLUICtrl(p),
mTextEntry(NULL),
mTextEntryTentative(p.show_text_as_tentative),
+ mHasAutocompletedText(false),
mAllowTextEntry(p.allow_text_entry),
mMaxChars(p.max_chars),
mPrearrangeCallback(p.prearrange_callback()),
@@ -482,7 +483,6 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)
params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
params.focus_lost_callback(NULL);
- params.select_on_focus(true);
params.handle_edit_keys_directly(true);
params.commit_on_focus_lost(false);
params.follows.flags(FOLLOWS_ALL);
@@ -640,18 +640,17 @@ void LLComboBox::onButtonDown()
{
if (!mList->getVisible())
{
+ // this might change selection, so do it first
+ prearrangeList();
+
+ // highlight the last selected item from the original selection before potentially selecting a new item
+ // as visual cue to original value of combo box
LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
if (last_selected_item)
{
- // highlight the original selection before potentially selecting a new item
mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
}
- if( mPrearrangeCallback )
- {
- mPrearrangeCallback( this, LLSD() );
- }
-
if (mList->getItemCount() != 0)
{
showList();
@@ -810,6 +809,7 @@ void LLComboBox::setTextEntry(const LLStringExplicit& text)
if (mTextEntry)
{
mTextEntry->setText(text);
+ mHasAutocompletedText = FALSE;
updateSelection();
}
}
@@ -848,10 +848,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1));
if (!mList->getVisible())
{
- if( mPrearrangeCallback )
- {
- mPrearrangeCallback( this, LLSD() );
- }
+ prearrangeList();
if (mList->getItemCount() != 0)
{
@@ -866,10 +863,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
setCurrentByIndex(llmax(0, getCurrentIndex() - 1));
if (!mList->getVisible())
{
- if( mPrearrangeCallback )
- {
- mPrearrangeCallback( this, LLSD() );
- }
+ prearrangeList();
if (mList->getItemCount() != 0)
{
@@ -891,7 +885,7 @@ void LLComboBox::updateSelection()
LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
// user-entered portion of string, based on assumption that any selected
// text was a result of auto-completion
- LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText();
+ LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText();
std::string full_string = mTextEntry->getText();
// go ahead and arrange drop down list on first typed character, even
@@ -899,23 +893,14 @@ void LLComboBox::updateSelection()
// callback to populate content
if( mTextEntry->getWText().size() == 1 )
{
- if (mPrearrangeCallback)
- {
- mPrearrangeCallback( this, LLSD() );
- }
+ prearrangeList(mTextEntry->getText());
}
if (mList->selectItemByLabel(full_string, FALSE))
{
mTextEntry->setTentative(FALSE);
}
- else if (!mList->selectItemByPrefix(left_wstring, FALSE))
- {
- mList->deselectAllItems();
- mTextEntry->setText(wstring_to_utf8str(user_wstring));
- mTextEntry->setTentative(mTextEntryTentative);
- }
- else
+ else if (mList->selectItemByPrefix(left_wstring, FALSE))
{
LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
@@ -923,6 +908,14 @@ void LLComboBox::updateSelection()
mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
mTextEntry->endSelection();
mTextEntry->setTentative(FALSE);
+ mHasAutocompletedText = TRUE;
+ }
+ else // no matching items found
+ {
+ mList->deselectAllItems();
+ mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion
+ mTextEntry->setTentative(mTextEntryTentative);
+ mHasAutocompletedText = FALSE;
}
}
@@ -948,6 +941,14 @@ void LLComboBox::setFocus(BOOL b)
}
}
+void LLComboBox::prearrangeList(std::string filter)
+{
+ if (mPrearrangeCallback)
+ {
+ mPrearrangeCallback(this, LLSD(filter));
+ }
+}
+
//============================================================================
// LLCtrlListInterface functions
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index e7a864eb82..bc98690a01 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -106,6 +106,7 @@ protected:
friend class LLUICtrlFactory;
LLComboBox(const Params&);
void initFromParams(const Params&);
+ void prearrangeList(std::string filter = "");
public:
// LLView interface
@@ -213,18 +214,18 @@ public:
virtual void showList();
virtual void hideList();
- void onTextEntry(LLLineEditor* line_editor);
+ virtual void onTextEntry(LLLineEditor* line_editor);
protected:
LLButton* mButton;
+ LLLineEditor* mTextEntry;
LLScrollListCtrl* mList;
EPreferredPosition mListPosition;
LLPointer<LLUIImage> mArrowImage;
LLUIString mLabel;
+ BOOL mHasAutocompletedText;
private:
- S32 mButtonPadding;
- LLLineEditor* mTextEntry;
BOOL mAllowTextEntry;
S32 mMaxChars;
BOOL mTextEntryTentative;
diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp
index a63023e35c..40cc430e25 100644
--- a/indra/llui/llcontainerview.cpp
+++ b/indra/llui/llcontainerview.cpp
@@ -42,7 +42,7 @@
#include "llscrollcontainer.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLContainerView> r("container_view");
+static LLDefaultWidgetRegistry::Register<LLContainerView> r("container_view");
LLContainerView::LLContainerView(const LLContainerView::Params& p)
: LLView(p),
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index be7e050b58..8932a7ccf2 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -188,6 +188,13 @@ bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
//************************************
+//static
+const LLFloater::Params& LLFloater::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLFloater::Params>();
+}
+
+
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(),
mDragHandle(NULL),
@@ -1710,6 +1717,7 @@ LLFloaterView::LLFloaterView (const Params& p)
: LLUICtrl (p),
mFocusCycleMode(FALSE),
mSnapOffsetBottom(0)
+ ,mSnapOffsetRight(0)
{
}
@@ -2214,6 +2222,7 @@ LLRect LLFloaterView::getSnapRect() const
{
LLRect snap_rect = getRect();
snap_rect.mBottom += mSnapOffsetBottom;
+ snap_rect.mRight -= mSnapOffsetRight;
return snap_rect;
}
@@ -2397,6 +2406,35 @@ void LLFloater::setKey(const LLSD& newkey)
mKey = newkey;
}
+//static
+void LLFloater::setupParamsForExport(Params& p, LLView* parent)
+{
+ // Do rectangle munging to topleft layout first
+ LLPanel::setupParamsForExport(p, parent);
+
+ // Copy the rectangle out to apply layout constraints
+ LLRect rect = p.rect;
+
+ // Null out other settings
+ p.rect.left.setProvided(false);
+ p.rect.top.setProvided(false);
+ p.rect.right.setProvided(false);
+ p.rect.bottom.setProvided(false);
+
+ // Explicitly set width/height
+ p.rect.width.set( rect.getWidth(), true );
+ p.rect.height.set( rect.getHeight(), true );
+
+ // If you can't resize this floater, don't export min_height
+ // and min_width
+ bool can_resize = p.can_resize;
+ if (!can_resize)
+ {
+ p.min_height.setProvided(false);
+ p.min_width.setProvided(false);
+ }
+}
+
void LLFloater::initFromParams(const LLFloater::Params& p)
{
// control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
@@ -2453,7 +2491,7 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floa
LLFloater::setFloaterHost((LLMultiFloater*) this);
}
- addChildren(node, output_node);
+ LLUICtrlFactory::createChildren(this, node, output_node);
if (node->hasName("multi_floater"))
{
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index f6c783b0bf..3e80f1b284 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -141,10 +141,16 @@ public:
}
};
- LLFloater(const LLSD& key = LLSD(), const LLFloater::Params& params = LLFloater::Params());
+ // use this to avoid creating your own default LLFloater::Param instance
+ static const Params& getDefaultParams();
+
+ LLFloater(const LLSD& key = LLSD(), const Params& params = getDefaultParams());
virtual ~LLFloater();
+ // Don't export top/left for rect, only height/width
+ static void setupParamsForExport(Params& p, LLView* parent);
+
void initFromParams(const LLFloater::Params& p);
void initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL);
@@ -424,6 +430,7 @@ public:
S32 getZOrder(LLFloater* child);
void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; }
+ void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; }
private:
S32 mColumn;
@@ -431,6 +438,7 @@ private:
S32 mNextTop;
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
+ S32 mSnapOffsetRight;
};
// singleton implementation for floaters
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index af1bfc5ec1..ef2f71ad18 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -29,6 +29,8 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+#ifndef LLFLOATERREG_H
+#define LLFLOATERREG_H
/// llcommon
#include "llboost.h"
@@ -147,3 +149,4 @@ public:
};
+#endif
diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp
index 6b7c174726..8846f2a8c4 100644
--- a/indra/llui/llflyoutbutton.cpp
+++ b/indra/llui/llflyoutbutton.cpp
@@ -35,7 +35,7 @@
// file includes
#include "llflyoutbutton.h"
-static LLRegisterWidget<LLFlyoutButton> r2("flyout_button");
+//static LLDefaultWidgetRegistry::Register<LLFlyoutButton> r2("flyout_button");
const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index d01679cd1c..eddfc71284 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -42,7 +42,7 @@
#include "lluictrlfactory.h"
#include "lluiimage.h"
-static LLRegisterWidget<LLIconCtrl> r("icon");
+static LLDefaultWidgetRegistry::Register<LLIconCtrl> r("icon");
LLIconCtrl::Params::Params()
: image("image_name"),
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index ad0f6f563f..a6cab0e9ee 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -55,7 +55,7 @@ public:
{
Optional<LLUIImage*> image;
Optional<LLUIColor> color;
- Deprecated scale_image;
+ Ignored scale_image;
Params();
};
protected:
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 483c1358ae..39dac296ea 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -38,12 +38,15 @@
#include "llresizebar.h"
#include "llcriticaldamp.h"
+static LLDefaultWidgetRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML);
+
+
//
// LLLayoutStack
//
-struct LLLayoutStack::LLEmbeddedPanel
+struct LLLayoutStack::LayoutPanel
{
- LLEmbeddedPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp),
+ LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp),
mMinWidth(min_width),
mMinHeight(min_height),
mAutoResize(auto_resize),
@@ -68,7 +71,7 @@ struct LLLayoutStack::LLEmbeddedPanel
}
LLResizeBar::Params p;
p.name("resize");
- p.resizing_view(mPanel);
+ p.resizing_view(mPanel);
p.min_size(min_dim);
p.side(side);
p.snapping_enabled(false);
@@ -80,13 +83,13 @@ struct LLLayoutStack::LLEmbeddedPanel
}
}
- ~LLEmbeddedPanel()
+ ~LayoutPanel()
{
// probably not necessary, but...
delete mResizeBar;
mResizeBar = NULL;
}
-
+
F32 getCollapseFactor()
{
if (mOrientation == HORIZONTAL)
@@ -96,7 +99,7 @@ struct LLLayoutStack::LLEmbeddedPanel
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())));
return mVisibleAmt * collapse_amt;
@@ -115,10 +118,9 @@ struct LLLayoutStack::LLEmbeddedPanel
F32 mCollapseAmt;
};
-static LLRegisterWidget<LLLayoutStack> r2("layout_stack", &LLLayoutStack::fromXML);
-
LLLayoutStack::Params::Params()
: orientation("orientation", std::string("vertical")),
+ animate("animate", TRUE),
border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
{
name="stack";
@@ -129,7 +131,8 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
mMinWidth(0),
mMinHeight(0),
mPanelSpacing(p.border_size),
- mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL)
+ mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
+ mAnimate(p.animate)
{}
LLLayoutStack::~LLLayoutStack()
@@ -168,7 +171,7 @@ void LLLayoutStack::draw()
void LLLayoutStack::removeChild(LLView* view)
{
- LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
+ LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
if (embedded_panelp)
{
@@ -222,16 +225,10 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
{
LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack::Params>());
LLXUIParser::instance().readXUI(node, p);
- setupParams(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);
- }
+ // 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);
@@ -242,6 +239,16 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
output_node, output_params, &default_params);
}
+ setupParams(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;
@@ -287,8 +294,9 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
FALSE, output_child);
- LLPanel* panelp = new LLPanel();
- LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, output_child);
+ LLPanel::Params p;
+ LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p);
+ LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, output_child, parent ? parent->getChildRegistry() : LLDefaultWidgetRegistry::instance());
if (new_child)
{
// put child in new embedded panel
@@ -349,7 +357,7 @@ void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL
{
panel->setVisible(FALSE);
}
- LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
+ LayoutPanel* embedded_panel = new LayoutPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
@@ -381,7 +389,7 @@ void LLLayoutStack::removePanel(LLPanel* panel)
void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
{
- LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel);
+ LayoutPanel* panel_container = findEmbeddedPanel(panel);
if (!panel_container) return;
panel_container->mCollapsed = collapsed;
@@ -405,16 +413,30 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
LLPanel* panelp = (*panel_it)->mPanel;
if (panelp->getVisible())
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
- if ((*panel_it)->mVisibleAmt > 0.99f)
+ if (mAnimate)
+ {
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
+ if ((*panel_it)->mVisibleAmt > 0.99f)
+ {
+ (*panel_it)->mVisibleAmt = 1.f;
+ }
+ }
+ else
{
(*panel_it)->mVisibleAmt = 1.f;
}
}
else // not visible
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
- if ((*panel_it)->mVisibleAmt < 0.001f)
+ if (mAnimate)
+ {
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ if ((*panel_it)->mVisibleAmt < 0.001f)
+ {
+ (*panel_it)->mVisibleAmt = 0.f;
+ }
+ }
+ else
{
(*panel_it)->mVisibleAmt = 0.f;
}
@@ -670,7 +692,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
} // end LLLayoutStack::updateLayout
-LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
+LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
{
if (!panelp) return NULL;
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 600690f67d..480bdb5c17 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -43,6 +43,7 @@ public:
{
Optional<std::string> orientation;
Optional<S32> border_size;
+ Optional<bool> animate;
// mMinWidth and mMinHeight are calculated, not set in XML
Params();
@@ -81,7 +82,7 @@ protected:
friend class LLUICtrlFactory;
private:
- struct LLEmbeddedPanel;
+ struct LayoutPanel;
void updateLayout(BOOL force_resize = FALSE);
void calcMinExtents();
@@ -90,13 +91,15 @@ private:
const ELayoutOrientation mOrientation;
- typedef std::vector<LLEmbeddedPanel*> e_panel_list_t;
+ typedef std::vector<LayoutPanel*> e_panel_list_t;
e_panel_list_t mPanels;
- LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp) const;
+ LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
S32 mMinWidth; // calculated by calcMinExtents
S32 mMinHeight; // calculated by calcMinExtents
S32 mPanelSpacing;
+
+ bool mAnimate;
}; // end class LLLayoutStack
#endif
diff --git a/indra/llui/lllazyvalue.h b/indra/llui/lllazyvalue.h
index da0af6f522..cf45214628 100644
--- a/indra/llui/lllazyvalue.h
+++ b/indra/llui/lllazyvalue.h
@@ -75,6 +75,11 @@ public:
return mValue;
}
+ bool isUsingFunction() const
+ {
+ return mValueGetter != NULL;
+ }
+
private:
function_type mValueGetter;
T mValue;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index c03ef7968f..5ea45e13cf 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -70,8 +70,9 @@ const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing
const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing
const F32 AUTO_SCROLL_TIME = 0.05f;
+const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval?
-static LLRegisterWidget<LLLineEditor> r1("line_editor");
+static LLDefaultWidgetRegistry::Register<LLLineEditor> r1("line_editor");
template LLLineEditor* LLView::getChild<LLLineEditor>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
@@ -161,6 +162,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
llassert( mMaxLengthBytes > 0 );
mScrollTimer.reset();
+ mTripleClickTimer.reset();
setText(p.default_text());
// line history support:
@@ -450,6 +452,7 @@ void LLLineEditor::selectAll()
BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
{
setFocus( TRUE );
+ mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL);
if (mSelectionEnd == 0 && mSelectionStart == mText.length())
{
@@ -566,14 +569,25 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
}
else
{
- // Save selection for word/line selecting on double-click
- mLastSelectionStart = mSelectionStart;
- mLastSelectionEnd = mSelectionEnd;
+ if (mTripleClickTimer.hasExpired())
+ {
+ // Save selection for word/line selecting on double-click
+ mLastSelectionStart = mSelectionStart;
+ mLastSelectionEnd = mSelectionEnd;
- // Move cursor and deselect for regular click
- setCursorAtLocalPos( x );
- deselect();
- startSelection();
+ // Move cursor and deselect for regular click
+ setCursorAtLocalPos( x );
+ deselect();
+ startSelection();
+ }
+ else // handle triple click
+ {
+ selectAll();
+ // We don't want handleMouseUp() to "finish" the selection (and thereby
+ // set mSelectionEnd to where the mouse is), so we finish the selection
+ // here.
+ mIsSelecting = FALSE;
+ }
}
gFocusMgr.setMouseCapture( this );
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 4c2a9b77b2..eb021bace9 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -103,7 +103,7 @@ public:
Optional<S32> text_pad_left,
text_pad_right;
- Deprecated is_unicode,
+ Ignored is_unicode,
drop_shadow_visible,
border_drop_shadow_visible,
bg_visible;
@@ -320,6 +320,7 @@ protected:
LLLinePrevalidateFunc mPrevalidateFunc;
LLFrameTimer mKeystrokeTimer;
+ LLTimer mTripleClickTimer;
LLUIColor mCursorColor;
LLUIColor mFgColor;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index fc2e6e163b..4af1c1241b 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -65,8 +65,6 @@
#include <set>
#include <boost/tokenizer.hpp>
-using namespace LLOldEvents;
-
// static
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
@@ -121,6 +119,19 @@ const F32 PIE_SHRINK_TIME = 0.2f; // time of transition between unbounded and bo
const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
+// widget registrars
+struct MenuRegistry : public LLWidgetRegistry<MenuRegistry>
+{};
+
+static MenuRegistry::Register<LLMenuItemSeparatorGL> register_separator("menu_item_separator");
+static MenuRegistry::Register<LLMenuItemCallGL> register_menu_item_call("menu_item_call");
+static MenuRegistry::Register<LLMenuItemCheckGL> register_menu_item_check("menu_item_check");
+static MenuRegistry::Register<LLMenuGL> register_menu("menu");
+
+static LLDefaultWidgetRegistry::Register<LLMenuGL> register_menu_default("menu");
+
+
+
///============================================================================
/// Class LLMenuItemGL
///============================================================================
@@ -395,25 +406,30 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
return FALSE;
}
-BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
onCommit();
make_ui_sound("UISndClickRelease");
- return TRUE;
+ return LLView::handleMouseUp(x, y, mask);
}
-BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
setHighlight(TRUE);
- return TRUE;
+ return LLView::handleMouseDown(x, y, mask);
}
+BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ // If the menu is scrollable let it handle the wheel event.
+ return !getMenu()->isScrollable();
+}
void LLMenuItemGL::draw( void )
{
@@ -516,8 +532,6 @@ void LLMenuItemGL::onVisibilityChange(BOOL new_visibility)
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static LLRegisterWidget<LLMenuItemSeparatorGL> register_separator("menu_item_separator");
-
LLMenuItemSeparatorGL::Params::Params()
{
name = "separator";
@@ -708,7 +722,6 @@ public:
///============================================================================
/// Class LLMenuItemCallGL
///============================================================================
-static LLRegisterWidget<LLMenuItemCallGL> register_menu_item_call_gl("menu_item_call");
LLMenuItemCallGL::LLMenuItemCallGL(const LLMenuItemCallGL::Params& p)
: LLMenuItemGL(p)
@@ -787,8 +800,6 @@ BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask )
///============================================================================
/// Class LLMenuItemCheckGL
///============================================================================
-static LLRegisterWidget<LLMenuItemCheckGL> register_menu_item_check_gl("menu_item_check");
-
LLMenuItemCheckGL::LLMenuItemCheckGL (const LLMenuItemCheckGL::Params& p)
: LLMenuItemCallGL(p)
{
@@ -1446,18 +1457,105 @@ void LLMenuItemBranchDownGL::draw( void )
setHover(FALSE);
}
+class LLMenuScrollItem : public LLMenuItemCallGL
+{
+public:
+ enum EArrowType
+ {
+ ARROW_DOWN,
+ ARROW_UP
+ };
+
+ struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
+ {
+ Optional<EArrowType> arrow_type;
+ Optional<CommitCallbackParam> scroll_callback;
+ };
+
+protected:
+ LLMenuScrollItem(const Params&);
+ friend class LLUICtrlFactory;
+
+public:
+ /*virtual*/ void draw();
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
+ /*virtual*/ void setEnabled(BOOL enabled);
+ virtual void onCommit( void );
+
+private:
+ LLButton* mArrowBtn;
+};
+
+LLMenuScrollItem::LLMenuScrollItem(const Params& p)
+: LLMenuItemCallGL(p)
+{
+ std::string icon;
+ if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP)
+ {
+ icon = "arrow_up.tga";
+ }
+ else
+ {
+ icon = "arrow_down.tga";
+ }
+
+ LLButton::Params bparams;
+ bparams.label("");
+ bparams.label_selected("");
+ bparams.mouse_opaque(true);
+ bparams.scale_image(false);
+ bparams.click_callback(p.scroll_callback);
+ bparams.mouse_held_callback(p.scroll_callback);
+ bparams.follows.flags(FOLLOWS_ALL);
+ std::string background = "transparent.j2c";
+ bparams.image_unselected.name(background);
+ bparams.image_disabled.name(background);
+ bparams.image_selected.name(background);
+ bparams.image_hover_selected.name(background);
+ bparams.image_disabled_selected.name(background);
+ bparams.image_hover_unselected.name(background);
+ bparams.image_overlay.name(icon);
+
+ mArrowBtn = LLUICtrlFactory::create<LLButton>(bparams);
+ addChild(mArrowBtn);
+}
+
+/*virtual*/
+void LLMenuScrollItem::draw()
+{
+ LLUICtrl::draw();
+}
+
+/*virtual*/
+void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ mArrowBtn->reshape(width, height, called_from_parent);
+ LLView::reshape(width, height, called_from_parent);
+}
+
+/*virtual*/
+void LLMenuScrollItem::setEnabled(BOOL enabled)
+{
+ mArrowBtn->setEnabled(enabled);
+ LLView::setEnabled(enabled);
+}
+
+void LLMenuScrollItem::onCommit( void )
+{
+ LLUICtrl::onCommit();
+}
+
///============================================================================
/// Class LLMenuGL
///============================================================================
-static LLRegisterWidget<LLMenuGL> r1("menu");
-
LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
: LLUICtrl(p),
mBackgroundColor( p.bg_color() ),
mBgVisible( p.bg_visible ),
mDropShadowed( p.drop_shadow ),
mHorizontalLayout( p.horizontal_layout ),
+ mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout
mKeepFixedSize( p.keep_fixed_size ),
mLabel (p.label),
mLastMouseX(0),
@@ -1467,6 +1565,9 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
mTornOff(FALSE),
mTearOffItem(NULL),
mSpilloverBranch(NULL),
+ mFirstVisibleItem(NULL),
+ mArrowUpItem(NULL),
+ mArrowDownItem(NULL),
mSpilloverMenu(NULL),
mJumpKey(p.jump_key),
mCreateJumpKeys(p.create_jump_keys),
@@ -1563,6 +1664,11 @@ BOOL LLMenuGL::postBuild()
return LLUICtrl::postBuild();
}
+const widget_registry_t& LLMenuGL::getChildRegistry() const
+{
+ return MenuRegistry::instance();
+}
+
// are we the childmost active menu and hence our jump keys should be enabled?
// or are we a free-standing torn-off menu (which uses jump keys too)
@@ -1609,6 +1715,86 @@ BOOL LLMenuGL::isOpen()
}
}
+void LLMenuGL::scrollItemsUp()
+{
+ // Slowing down the items scrolling when arrow button is held
+ if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
+ {
+ mScrollItemsTimer.setTimerExpirySec(.033f);
+ }
+ else
+ {
+ return;
+ }
+
+ 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++)
+ {
+ if( (*cur_item_iter) == mFirstVisibleItem)
+ {
+ break;
+ }
+ if ((*cur_item_iter)->getVisible())
+ {
+ prev_item_iter = cur_item_iter;
+ }
+ }
+
+ 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
+ {
+ 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)
+ {
+ break;
+ }
+ }
+
+ item_list_t::iterator 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)->getVisible())
+ {
+ mFirstVisibleItem = *next_item_iter;
+ }
+
+ mNeedsArrange = TRUE;
+ arrangeAndClear();
+}
// rearrange the child rects so they fit the shape of the menu.
void LLMenuGL::arrange( void )
@@ -1627,11 +1813,26 @@ void LLMenuGL::arrange( void )
// torn off menus are not constrained to the size of the screen
U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth();
- U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight();
+ U32 max_height = U32_MAX;
+ if (!getTornOff())
+ {
+ max_height = getRect().mTop - menu_region_rect.mBottom;
+ if (menu_region_rect.mTop - getRect().mTop > (S32)max_height)
+ {
+ max_height = menu_region_rect.mTop - getRect().mTop;
+ }
+ }
+
// *FIX: create the item first and then ask for its dimensions?
S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate
S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING;
+ // Scrolling support
+ item_list_t::iterator first_visible_item_iter;
+ item_list_t::iterator first_hidden_item_iter = mItems.end();
+ S32 height_before_first_visible_item = -1;
+ S32 visible_items_height = 0;
+
if (mHorizontalLayout)
{
item_list_t::iterator item_iter;
@@ -1675,11 +1876,13 @@ void LLMenuGL::arrange( void )
else
{
item_list_t::iterator item_iter;
+
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
if (!getTornOff()
+ && !mScrollable
&& *item_iter != mSpilloverBranch
&& height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height)
{
@@ -1710,19 +1913,164 @@ void LLMenuGL::arrange( void )
height += (*item_iter)->getNominalHeight();
width = llmax( width, (*item_iter)->getNominalWidth() );
}
+
+ if (mScrollable)
+ {
+ // Determining visible items boundaries
+ if (NULL == mFirstVisibleItem)
+ {
+ mFirstVisibleItem = *item_iter;
+ }
+
+ if (*item_iter == mFirstVisibleItem)
+ {
+ height_before_first_visible_item = height - (*item_iter)->getNominalHeight();
+ first_visible_item_iter = item_iter;
+ }
+
+ if (-1 != height_before_first_visible_item && 0 == visible_items_height && height - height_before_first_visible_item > max_height - spillover_item_height * 2)
+ {
+ first_hidden_item_iter = item_iter;
+ visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight();
+ }
+ }
}
}
- }
- setRect(LLRect(getRect().mLeft, getRect().mBottom + height, getRect().mLeft + width, getRect().mBottom));
+ if (mScrollable)
+ {
+ S32 max_items_height = max_height - spillover_item_height * 2;
+
+ // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit
+ if (visible_items_height < max_items_height)
+ {
+ if (visible_items_height == 0)
+ {
+ visible_items_height = height - height_before_first_visible_item;
+ }
+
+ item_list_t::iterator tmp_iter(first_visible_item_iter);
+ while (visible_items_height < max_items_height && first_visible_item_iter != mItems.begin())
+ {
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ // It keeps visible item, after first_visible_item_iter
+ tmp_iter = first_visible_item_iter;
+ }
+
+ first_visible_item_iter--;
+
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ visible_items_height += (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight();
+ }
+ }
+
+ // Roll back one item, that doesn't fit
+ if (visible_items_height > max_items_height)
+ {
+ visible_items_height -= (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight();
+ first_visible_item_iter = tmp_iter;
+ }
+ if (!(*first_visible_item_iter)->getVisible())
+ {
+ first_visible_item_iter = tmp_iter;
+ }
+
+ mFirstVisibleItem = *first_visible_item_iter;
+ }
+ }
+ }
S32 cur_height = (S32)llmin(max_height, height);
+
+ if (mScrollable &&
+ (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height))
+ {
+ // Reserving 2 extra slots for arrow items
+ cur_height = visible_items_height + spillover_item_height * 2;
+ }
+
+ setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height));
+
S32 cur_width = 0;
+ S32 offset = 0;
+ if (mScrollable)
+ {
+ // No space for all items, creating arrow items
+ if (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height)
+ {
+ if (NULL == mArrowUpItem)
+ {
+ 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));
+
+ mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowUpItem);
+
+ }
+ if (NULL == mArrowDownItem)
+ {
+ 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));
+
+ mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowDownItem);
+ }
+
+ LLRect rect;
+ mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight()));
+ mArrowUpItem->setVisible(TRUE);
+ mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING);
+ mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight());
+ mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight()));
+ mArrowDownItem->setVisible(TRUE);
+ mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height);
+ mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight());
+
+ cur_height -= mArrowUpItem->getNominalHeight();
+
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ else
+ {
+ if (NULL != mArrowUpItem)
+ {
+ mArrowUpItem->setVisible(FALSE);
+ }
+ if (NULL != mArrowDownItem)
+ {
+ mArrowDownItem->setVisible(FALSE);
+ }
+ }
+
+ }
+
item_list_t::iterator item_iter;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
+ if (mScrollable)
+ {
+ if (item_iter == first_visible_item_iter)
+ {
+ offset = 0;
+ }
+ else if (item_iter == first_hidden_item_iter)
+ {
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ }
+
// setup item rect to hold label
LLRect rect;
if (mHorizontalLayout)
@@ -1732,8 +2080,11 @@ void LLMenuGL::arrange( void )
}
else
{
- rect.setLeftTopAndSize( 0, cur_height, width, (*item_iter)->getNominalHeight());
- cur_height -= (*item_iter)->getNominalHeight();
+ rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight());
+ if (offset == 0)
+ {
+ cur_height -= (*item_iter)->getNominalHeight();
+ }
}
(*item_iter)->setRect( rect );
(*item_iter)->buildDrawLabel();
@@ -1913,9 +2264,11 @@ void LLMenuGL::empty( void )
cleanupSpilloverBranch();
mItems.clear();
+ mFirstVisibleItem = NULL;
+ mArrowUpItem = NULL;
+ mArrowDownItem = NULL;
deleteAllChildren();
-
}
// Adjust rectangle of the menu
@@ -2351,9 +2704,29 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
}
getWindow()->setCursor(UI_CURSOR_ARROW);
- //ProductEngine: what behavior is this addressing?
// *HACK Release the mouse capture
- gFocusMgr.setMouseCapture( NULL );
+ // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button
+ // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events
+ // until the user chooses one of the drop-down menu items.
+
+ return TRUE;
+}
+
+BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ if (!mScrollable)
+ return blockMouseEvent(x, y);
+
+ if( clicks > 0 )
+ {
+ while( clicks-- )
+ scrollItemsDown();
+ }
+ else
+ {
+ while( clicks++ )
+ scrollItemsUp();
+ }
return TRUE;
}
@@ -2458,7 +2831,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
const S32 HPAD = 2;
- menu->arrangeAndClear(); // Fix menu rect if needed.
LLRect rect = menu->getRect();
//LLView* cur_view = spawning_view;
S32 left = x + HPAD;
@@ -2471,6 +2843,15 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
//rect.setLeftTopAndSize(x + HPAD, y, rect.getWidth(), rect.getHeight());
menu->setRect( rect );
+ // Resetting scrolling position
+ if (menu->isScrollable())
+ {
+ menu->mFirstVisibleItem = NULL;
+ menu->needsArrange();
+ }
+ menu->arrangeAndClear(); // Fix menu rect if needed.
+ rect = menu->getRect();
+
S32 bottom;
left = rect.mLeft;
bottom = rect.mBottom;
@@ -2502,7 +2883,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
/// Class LLMenuBarGL
///============================================================================
-static LLRegisterWidget<LLMenuBarGL> r2("menu_bar");
+static LLDefaultWidgetRegistry::Register<LLMenuBarGL> r2("menu_bar");
LLMenuBarGL::LLMenuBarGL( const Params& p )
: LLMenuGL(p),
@@ -2516,7 +2897,6 @@ LLMenuBarGL::~LLMenuBarGL()
mAccelerators.clear();
}
-
BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
{
if (getHighlightedItem() && mask == MASK_NONE)
@@ -3189,7 +3569,9 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )
// class LLContextMenu
// A context menu
//-----------------------------------------------------------------------------
-static LLRegisterWidget<LLContextMenu> context_menu_register("context_menu");
+static LLDefaultWidgetRegistry::Register<LLContextMenu> context_menu_register("context_menu");
+static MenuRegistry::Register<LLContextMenu> context_menu_register2("context_menu");
+
LLContextMenu::LLContextMenu(const Params& p)
: LLMenuGL(p),
@@ -3208,13 +3590,21 @@ void LLContextMenu::setVisible(BOOL visible)
void LLContextMenu::show(S32 x, S32 y,BOOL adjustCursor)
{
+ arrangeAndClear();
+
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
-
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
-
LLView* parent_view = getParent();
+ if(getParentMenuItem())
+ {
+ S32 parent_width = getParentMenuItem()->getRect().getWidth();
+
+ if(x + width > menu_region_rect.getWidth())
+ x -= parent_width + width;
+ }
+
S32 local_x, local_y;
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
@@ -3238,8 +3628,6 @@ void LLContextMenu::hide()
LLView::setVisible(FALSE);
- gFocusMgr.setMouseCapture(NULL);
-
if (mHoverItem)
{
mHoverItem->setHighlight( FALSE );
@@ -3250,9 +3638,11 @@ void LLContextMenu::hide()
BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
{
+ LLMenuGL::handleHover(x,y,mask);
+
BOOL handled = FALSE;
- LLMenuItemGL *item = getItemFromXY( x, y );
+ LLMenuItemGL *item = getHighlightedItem();
if (item && item->getEnabled())
{
@@ -3293,7 +3683,7 @@ BOOL LLContextMenu::handleMouseDown( S32 x, S32 y, MASK mask )
{
BOOL handled = FALSE;
// The click was somewhere within our rectangle
- LLMenuItemGL *item = getItemFromXY( x, y );
+ LLMenuItemGL *item = getHighlightedItem();
if (item)
{
@@ -3315,7 +3705,7 @@ BOOL LLContextMenu::handleMouseUp( S32 x, S32 y, MASK mask )
BOOL handled = FALSE;
// The click was somewhere within our rectangle
- LLMenuItemGL *item = getItemFromXY( x, y );
+ LLMenuItemGL *item = getHighlightedItem();
if (item)
{
@@ -3347,7 +3737,7 @@ BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
// The click was somewhere within our rectangle
- LLMenuItemGL *item = getItemFromXY( x, y );
+ LLMenuItemGL *item = getHighlightedItem();
S32 local_x = x - getRect().mLeft;
S32 local_y = y - getRect().mBottom;
@@ -3383,7 +3773,6 @@ BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
if (!mHoveredAnyItem && !pointInView(local_x, local_y))
{
- gFocusMgr.setMouseCapture(NULL);
sMenuContainer->hideMenus();
return TRUE;
}
@@ -3395,25 +3784,12 @@ BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
return result;
}
-LLMenuItemGL* LLContextMenu::getItemFromXY (S32 x, S32 y)
-{
- item_list_t::iterator item_iter;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- S32 local_x = x - (**item_iter).getRect().mLeft;
- S32 local_y = y - (**item_iter).getRect().mBottom;
- if((**item_iter).pointInView(local_x,local_y))
- return *item_iter;
- }
- return NULL;
-}
-
-void LLContextMenu::draw ()
+void LLContextMenu::draw()
{
LLMenuGL::draw();
}
-BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
+BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
{
if (menu == this)
@@ -3426,7 +3802,11 @@ BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
p.name = menu->getName();
p.label = menu->getLabel();
p.branch = menu;
-
+ p.enabled_color=LLUI::getCachedColorFunctor("MenuItemEnabledColor");
+ p.disabled_color=LLUI::getCachedColorFunctor("MenuItemDisabledColor");
+ p.highlight_bg_color=LLUI::getCachedColorFunctor("MenuItemHighlightBgColor");
+ p.highlight_fg_color=LLUI::getCachedColorFunctor("MenuItemHighlightFgColor");
+
item = LLUICtrlFactory::create<LLContextMenuBranch>(p);
LLMenuGL::sMenuContainer->addChild(item->getBranch());
item->setFont( LLFontGL::getFontSansSerifSmall() );
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index ffaecc2c15..526e1c2583 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -63,7 +63,7 @@ public:
Optional<KEY> jump_key;
Optional<bool> use_mac_ctrl;
- Deprecated rect,
+ Ignored rect,
left,
top,
right,
@@ -175,6 +175,7 @@ public:
virtual BOOL handleKeyHere( KEY key, MASK mask );
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
+ virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
virtual void draw( void );
BOOL getHover() const { return mGotHover; }
@@ -368,7 +369,8 @@ public:
drop_shadow,
bg_visible,
create_jump_keys,
- keep_fixed_size;
+ keep_fixed_size,
+ scrollable;
Optional<LLUIColor> bg_color;
Params()
@@ -377,7 +379,8 @@ public:
drop_shadow("drop_shadow", true),
bg_visible("bg_visible", true),
create_jump_keys("create_jump_keys", false),
- bg_color("bg_color", LLUI::getCachedColorFunctor( "MenuDefaultBgColor" ))
+ bg_color("bg_color", LLUI::getCachedColorFunctor( "MenuDefaultBgColor" )),
+ scrollable("scrollable", false)
{
addSynonym(bg_visible, "opaque");
addSynonym(bg_color, "color");
@@ -400,12 +403,14 @@ public:
// LLView Functionality
/*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char );
/*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask );
+ /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
/*virtual*/ void draw( void );
/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*virtual*/ void removeChild( LLView* ctrl);
/*virtual*/ BOOL postBuild();
+ /*virtual*/ const widget_registry_t& getChildRegistry() const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
@@ -493,6 +498,10 @@ public:
static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; }
static BOOL getKeyboardMode() { return sKeyboardMode; }
+ void scrollItemsUp();
+ void scrollItemsDown();
+ BOOL isScrollable() const { return mScrollable; }
+
static class LLMenuHolderGL* sMenuContainer;
protected:
@@ -507,6 +516,9 @@ protected:
// TODO: create accessor methods for these?
typedef std::list< LLMenuItemGL* > item_list_t;
item_list_t mItems;
+ LLMenuItemGL*mFirstVisibleItem;
+ LLMenuItemGL *mArrowUpItem, *mArrowDownItem;
+
typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t;
navigation_key_map_t mJumpKeys;
S32 mLastMouseX;
@@ -514,6 +526,7 @@ protected:
S32 mMouseVelX;
S32 mMouseVelY;
BOOL mHorizontalLayout;
+ BOOL mScrollable;
BOOL mKeepFixedSize;
BOOL mNeedsArrange;
@@ -530,6 +543,7 @@ private:
BOOL mDropShadowed; // Whether to drop shadow
BOOL mHasSelection;
LLFrameTimer mFadeTimer;
+ LLTimer mScrollItemsTimer;
BOOL mTornOff;
class LLMenuItemTearOffGL* mTearOffItem;
class LLMenuItemBranchGL* mSpilloverBranch;
@@ -653,9 +667,6 @@ public:
BOOL appendContextSubMenu(LLContextMenu *menu);
protected:
- LLMenuItemGL* getItemFromXY (S32 x, S32 y);
-
-protected:
BOOL mHoveredAnyItem;
LLMenuItemGL* mHoverItem;
};
@@ -685,14 +696,14 @@ public:
LLMenuBarGL( const Params& p );
virtual ~LLMenuBarGL();
- virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
- virtual BOOL handleKeyHere(KEY key, MASK mask);
- virtual BOOL handleJumpKey(KEY key);
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask);
+ /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+ /*virtual*/ BOOL handleJumpKey(KEY key);
+ /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
- virtual void draw();
- virtual BOOL jumpKeysActive();
+ /*virtual*/ void draw();
+ /*virtual*/ BOOL jumpKeysActive();
// add a vertical separator to this menu
virtual BOOL addSeparator();
diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h
index ea8a9841e3..7f4c1c040a 100644
--- a/indra/llui/llmultifloater.h
+++ b/indra/llui/llmultifloater.h
@@ -44,7 +44,7 @@
class LLMultiFloater : public LLFloater
{
public:
- LLMultiFloater(const LLFloater::Params& params = LLFloater::Params());
+ LLMultiFloater(const LLFloater::Params& params = LLFloater::getDefaultParams());
virtual ~LLMultiFloater() {};
void buildTabContainer();
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index 24b83b0120..099a79278a 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -45,7 +45,7 @@
#include <sstream>
-static LLRegisterWidget<LLMultiSlider> r("multi_slider_bar");
+static LLDefaultWidgetRegistry::Register<LLMultiSlider> r("multi_slider_bar");
const F32 FLOAT_THRESHOLD = 0.00001f;
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index bc981a9b57..312aceaaa2 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -52,7 +52,7 @@
#include "llresmgr.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLMultiSliderCtrl> r("multi_slider");
+static LLDefaultWidgetRegistry::Register<LLMultiSliderCtrl> r("multi_slider");
const U32 MAX_STRING_LENGTH = 10;
LLMultiSliderCtrl::Params::Params()
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 569112aef1..452f18b40b 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -314,7 +314,7 @@ void LLNotificationForm::addElement(const std::string& type, const std::string&
LLSD element;
element["type"] = type;
element["name"] = name;
- element["label"] = name;
+ element["text"] = name;
element["value"] = value;
element["index"] = mFormData.size();
mFormData.append(element);
@@ -541,8 +541,12 @@ std::string LLNotification::getSelectedOptionName(const LLSD& response)
void LLNotification::respond(const LLSD& response)
{
mRespondedTo = true;
- LLNotificationResponder func = LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
- func(asLLSD(), response);
+ // look up the functor
+ LLNotificationFunctorRegistry::ResponseFunctor functor =
+ LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
+ // and then call it
+ functor(asLLSD(), response);
+
if (mTemporaryResponder)
{
LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 5c8d146e0c..b749724b4e 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -299,8 +299,8 @@ public:
struct Functor : public LLInitParam::Choice<Functor>
{
- Option<std::string> name;
- Option<LLNotificationFunctorRegistry::ResponseFunctor> function;
+ Alternative<std::string> name;
+ Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function;
Functor()
: name("functor_name"),
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 35871dc078..0136a41d61 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -56,7 +56,12 @@
#include "llbutton.h"
#include "lltabcontainer.h"
-static LLRegisterWidget<LLPanel> r1("panel", &LLPanel::fromXML);
+static LLDefaultWidgetRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML);
+
+const LLPanel::Params& LLPanel::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLPanel::Params>();
+}
LLPanel::Params::Params()
: has_border("border", false),
@@ -67,7 +72,8 @@ LLPanel::Params::Params()
min_width("min_width", 100),
min_height("min_height", 100),
strings("string"),
- filename("filename")
+ filename("filename"),
+ class_name("class")
{
name = "panel";
addSynonym(background_visible, "bg_visible");
@@ -85,7 +91,8 @@ LLPanel::LLPanel(const LLPanel::Params& p)
mDefaultBtn(NULL),
mBorder(NULL),
mLabel(p.label),
- mCommitCallbackRegistrar(false)
+ mCommitCallbackRegistrar(false),
+ mEnableCallbackRegistrar(false)
{
setIsChrome(FALSE);
@@ -112,6 +119,14 @@ void LLPanel::addBorder(LLViewBorder::Params p)
addChild( mBorder );
}
+void LLPanel::addBorder()
+{
+ LLViewBorder::Params p;
+ p.border_thickness(LLPANEL_BORDER_WIDTH);
+ addBorder(p);
+}
+
+
void LLPanel::removeBorder()
{
if (mBorder)
@@ -263,29 +278,26 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask )
}
}
}
-
- // If we have a default button, click it when
- // return is pressed, unless current focus is a return-capturing button
- // in which case *that* button will handle the return key
- LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
- if (cur_focus && !(focused_button && focused_button->getCommitOnReturn()))
+
+ // If RETURN was pressed and something has focus, call onCommit()
+ if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE)
{
- // RETURN key means hit default button in this case
- if (key == KEY_RETURN && mask == MASK_NONE
- && mDefaultBtn != NULL
- && mDefaultBtn->getVisible()
- && mDefaultBtn->getEnabled())
+ LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
+ if (focused_button && focused_button->getCommitOnReturn())
{
+ // current focus is a return-capturing button,
+ // let *that* button handle the return key
+ handled = FALSE;
+ }
+ else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled())
+ {
+ // If we have a default button, click it when return is pressed
mDefaultBtn->onCommit();
handled = TRUE;
}
- }
-
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- // set keyboard focus to self to trigger commitOnFocusLost behavior on current ctrl
- if (cur_focus && cur_focus->acceptsTextInput())
+ else if (cur_focus->acceptsTextInput())
{
+ // call onCommit for text input handling control
cur_focus->onCommit();
handled = TRUE;
}
@@ -352,23 +364,49 @@ void LLPanel::setBorderVisible(BOOL b)
}
}
+LLFastTimer::DeclareTimer FTM_PANEL_CONSTRUCTION("Panel Construction");
+
LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node)
{
std::string name("panel");
node->getAttributeString("name", name);
- LLPanel* panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name);
+ std::string class_attr;
+ node->getAttributeString("class", class_attr);
+
+ LLPanel* panelp = NULL;
+
+ {
+ LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
+
+ if(!class_attr.empty())
+ {
+ panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr);
+ if (!panelp)
+ {
+ llwarns << "Panel class \"" << class_attr << "\" not registered." << llendl;
+ }
+ }
+ if (!panelp)
+ {
+ panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name);
+ }
+
+ }
// factory panels may have registered their own factory maps
if (!panelp->getFactoryMap().empty())
{
LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap());
}
- panelp->mCommitCallbackRegistrar.pushScope(); // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ // 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->mCommitCallbackRegistrar.popScope();
+ panelp->mEnableCallbackRegistrar.popScope();
if (panelp && !panelp->getFactoryMap().empty())
{
@@ -422,62 +460,95 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
}
+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)
{
const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel::Params>());
Params params(default_params);
- LLXMLNodePtr referenced_xml;
- std::string xml_filename;
- node->getAttributeString("filename", xml_filename);
-
- if (!xml_filename.empty())
{
- if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
- {
- llwarns << "Couldn't parse panel from: " << xml_filename << llendl;
+ LLFastTimer timer(FTM_PANEL_SETUP);
- return FALSE;
- }
+ LLXMLNodePtr referenced_xml;
+ std::string xml_filename;
+ node->getAttributeString("filename", xml_filename);
- LLXUIParser::instance().readXUI(referenced_xml, params);
+ if (!xml_filename.empty())
+ {
+ LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD);
+ if (output_node)
+ {
+ //if we are exporting, we want to export the current xml
+ //not the referenced xml
+ LLXUIParser::instance().readXUI(node, params);
+ Params output_params(params);
+ setupParamsForExport(output_params, parent);
+ output_node->setName(node->getName()->mString);
+ LLXUIParser::instance().writeXUI(
+ output_node, output_params, &default_params);
+ return TRUE;
+ }
+
+ if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
+ {
+ llwarns << "Couldn't parse panel from: " << xml_filename << llendl;
- // add children using dimensions from referenced xml for consistent layout
- setShape(params.rect);
- addChildren(referenced_xml);
- }
+ return FALSE;
+ }
- LLXUIParser::instance().readXUI(node, params);
+ LLXUIParser::instance().readXUI(referenced_xml, params);
- 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);
- }
-
- setupParams(params, parent);
- initFromParams(params);
+ // add children using dimensions from referenced xml for consistent layout
+ setShape(params.rect);
+ LLUICtrlFactory::createChildren(this, referenced_xml);
+ }
- // add children
- addChildren(node, output_node);
+ LLXUIParser::instance().readXUI(node, params);
- // Connect to parent after children are built, because tab containers
- // do a reshape() on their child panels, which requires that the children
- // be built/added. JC
- if (parent)
- {
- S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
- parent->addChild(this, tab_group);
- }
+ 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);
+ }
+
+ setupParams(params, parent);
+ {
+ LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
+ initFromParams(params);
+ }
+
+ // add children
+ LLUICtrlFactory::createChildren(this, node, output_node);
- postBuild();
+ // Connect to parent after children are built, because tab containers
+ // do a reshape() on their child panels, which requires that the children
+ // be built/added. JC
+ if (parent)
+ {
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+ parent->addChild(this, tab_group);
+ }
+ {
+ LLFastTimer timer(FTM_PANEL_POSTBUILD);
+ postBuild();
+ }
+ }
return TRUE;
}
+const widget_registry_t& LLPanel::getChildRegistry() const
+{
+ // use default widget registry
+ return LLDefaultWidgetRegistry::instance();
+}
+
bool LLPanel::hasString(const std::string& name)
{
return mUIStrings.find(name) != mUIStrings.end();
@@ -827,10 +898,11 @@ LLView* LLPanel::getChildView(const std::string& name, BOOL recurse, BOOL create
}
if (!view && create_if_missing)
{
- view = getDummyWidget<LLView>(name);
+ view = getDefaultWidget<LLView>(name);
if (!view)
{
- view = LLUICtrlFactory::createDummyWidget<LLView>(name);
+ // create LLViews explicitly, as they are not registered widget types
+ view = LLUICtrlFactory::createDefaultWidget<LLView>(name);
}
}
return view;
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 5f4f8d16e7..fc40cd77eb 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -86,17 +86,20 @@ public:
min_height;
Optional<std::string> filename;
+ Optional<std::string> class_name;
Multiple<LocalizedString> strings;
Params();
};
+protected:
+ friend class LLUICtrlFactory;
// RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8
- static const Params& defaultParams() { return LLUICtrlFactory::getDefaultParams<LLPanel::Params>(); }
+ static const LLPanel::Params& getDefaultParams();
// Panels can get constructed directly
- LLPanel(const Params& params = defaultParams());
+ LLPanel(const LLPanel::Params& params = getDefaultParams());
public:
// LLPanel(const std::string& name, const LLRect& rect = LLRect(), BOOL bordered = TRUE);
@@ -119,7 +122,7 @@ public:
// Border controls
void addBorder( LLViewBorder::Params p);
- void addBorder() { LLViewBorder::Params p; p.border_thickness(LLPANEL_BORDER_WIDTH); addBorder(p); }
+ void addBorder();
void removeBorder();
BOOL hasBorder() const { return mBorder != NULL; }
void setBorderVisible( BOOL b );
@@ -158,9 +161,11 @@ public:
const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; }
CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; }
+ EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
void initFromParams(const Params& p);
BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+ /*virtual*/ const widget_registry_t& getChildRegistry() const;
bool hasString(const std::string& name);
std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const;
@@ -238,12 +243,16 @@ public:
void childDisplayNotFound();
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+
+ //call onOpen to let panel know when it's about to be shown or activated
+ virtual void onOpen(const LLSD& key) {}
protected:
// Override to set not found list
LLButton* getDefaultButton() { return mDefaultBtn; }
LLCallbackMap::map_t mFactoryMap;
CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar;
+ EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
private:
// Unified error reporting for the child* functions
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index 693c331797..779967940a 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -46,7 +46,7 @@
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLProgressBar> r("progress_bar");
+static LLDefaultWidgetRegistry::Register<LLProgressBar> r("progress_bar");
LLProgressBar::Params::Params()
: image_bar("image_bar"),
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 7d34841431..70f98bd908 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -44,8 +44,14 @@
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLRadioGroup> r1("radio_group");
-static LLRegisterWidget<LLRadioCtrl> r2("radio_item");
+static LLDefaultWidgetRegistry::Register<LLRadioGroup> r1("radio_group");
+
+struct RadioGroupRegistry : public LLWidgetRegistry<RadioGroupRegistry>
+{};
+
+static RadioGroupRegistry::Register<LLRadioCtrl> register_radio_ctrl("radio_item");
+
+
LLRadioGroup::Params::Params()
: has_border("draw_border")
@@ -76,6 +82,11 @@ LLRadioGroup::~LLRadioGroup()
{
}
+const widget_registry_t& LLRadioGroup::getChildRegistry() const
+{
+ return RadioGroupRegistry::instance();
+}
+
// virtual
BOOL LLRadioGroup::postBuild()
{
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 3dfab9b2b3..850d896e29 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -48,8 +48,8 @@ class LLRadioCtrl : public LLCheckBoxCtrl
public:
struct Params : public LLInitParam::Block<Params, LLCheckBoxCtrl::Params>
{
- Deprecated length;
- Deprecated type;
+ Ignored length;
+ Ignored type;
Params()
: length("length"),
@@ -70,7 +70,6 @@ protected:
friend class LLUICtrlFactory;
};
-
/*
* An invisible view containing multiple mutually exclusive toggling
* buttons (usually radio buttons). Automatically handles the mutex
@@ -80,6 +79,7 @@ class LLRadioGroup
: public LLUICtrl, public LLCtrlSelectionInterface
{
public:
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<bool> has_border;
@@ -118,6 +118,8 @@ public:
// Update the control as needed. Userdata must be a pointer to the button.
void onClickButton(LLUICtrl* clicked_radio);
+ virtual const widget_registry_t& getChildRegistry() const;
+
//========================================================================
LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
@@ -145,5 +147,4 @@ private:
BOOL mHasBorder;
};
-
#endif
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 1a2603420b..3f1ff34419 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -48,7 +48,7 @@
#include "llrender.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLScrollbar> register_scrollbar("scroll_bar");
+static LLDefaultWidgetRegistry::Register<LLScrollbar> register_scrollbar("scroll_bar");
LLScrollbar::Params::Params()
: orientation ("orientation", HORIZONTAL),
@@ -62,7 +62,9 @@ LLScrollbar::Params::Params()
thumb_color("thumb_color"),
thickness("thickness"),
up_button("up_button"),
- down_button("down_button")
+ down_button("down_button"),
+ left_button("left_button"),
+ right_button("right_button")
{
tab_stop = false;
}
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index dfe3ef29fc..2a2e56a92c 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -63,7 +63,7 @@ static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
/// Class LLScrollContainer
///----------------------------------------------------------------------------
-static LLRegisterWidget<LLScrollContainer> r("scroll_container");
+static LLDefaultWidgetRegistry::Register<LLScrollContainer> r("scroll_container");
LLScrollContainer::Params::Params()
: is_opaque("opaque"),
@@ -197,6 +197,15 @@ void LLScrollContainer::reshape(S32 width, S32 height,
BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
{
+ // allow scrolled view to handle keystrokes in case it delegated keyboard focus
+ // to the scroll container.
+ // NOTE: this should not recurse indefinitely as handleKeyHere
+ // should not propagate to parent controls, so mScrolledView should *not*
+ // call LLScrollContainer::handleKeyHere in turn
+ if (mScrolledView->handleKeyHere(key, mask))
+ {
+ return TRUE;
+ }
for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
{
if( mScrollbar[i]->handleKeyHere(key, mask) )
@@ -508,6 +517,11 @@ bool LLScrollContainer::addChild(LLView* view, S32 tab_group)
return ret_val;
}
+const widget_registry_t& LLScrollContainer::getChildRegistry() const
+{
+ // a scroll container can contain any default widget
+ return LLDefaultWidgetRegistry::instance();
+}
void LLScrollContainer::updateScroll()
{
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index 7e207645ff..26d8cc824e 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -104,6 +104,7 @@ public:
virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect);
virtual void draw();
virtual bool addChild(LLView* view, S32 tab_group = 0);
+ virtual const widget_registry_t& getChildRegistry() const;
private:
// internal scrollbar handlers
diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp
index bfeb35704a..1f3a7f9fcf 100644
--- a/indra/llui/llscrollingpanellist.cpp
+++ b/indra/llui/llscrollingpanellist.cpp
@@ -35,7 +35,7 @@
#include "llscrollingpanellist.h"
-static LLRegisterWidget<LLScrollingPanelList> r("scrolling_panel_list");
+static LLDefaultWidgetRegistry::Register<LLScrollingPanelList> r("scrolling_panel_list");
/////////////////////////////////////////////////////////////////////
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index 48fddbfb71..02f09bd9b4 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -285,6 +285,16 @@ void LLScrollListColumn::SortNames::declareValues()
declare("descending", LLScrollListColumn::DESCENDING);
}
+//
+// LLScrollListColumn
+//
+//static
+const LLScrollListColumn::Params& LLScrollListColumn::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLScrollListColumn::Params>();
+}
+
+
LLScrollListColumn::LLScrollListColumn(const Params& p, LLScrollListCtrl* parent)
: mWidth(0),
mIndex (-1),
diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h
index c1bb86577f..712ea56454 100644
--- a/indra/llui/llscrolllistcolumn.h
+++ b/indra/llui/llscrolllistcolumn.h
@@ -116,9 +116,9 @@ public:
struct Width : public LLInitParam::Choice<Width>
{
- Option<bool> dynamic_width;
- Option<S32> pixel_width;
- Option<F32> relative_width;
+ Alternative<bool> dynamic_width;
+ Alternative<S32> pixel_width;
+ Alternative<F32> relative_width;
Width()
: dynamic_width("dynamicwidth", false),
@@ -133,8 +133,8 @@ public:
// either an image or label is used in column header
struct Header : public LLInitParam::Choice<Header>
{
- Option<std::string> label;
- Option<LLUIImage*> image;
+ Alternative<std::string> label;
+ Alternative<LLUIImage*> image;
Header()
: label("label"),
@@ -160,8 +160,10 @@ public:
}
};
+ static const Params& getDefaultParams();
+
//NOTE: this is default constructible so we can store it in a map.
- LLScrollListColumn(const Params& p = Params(), LLScrollListCtrl* = NULL);
+ LLScrollListColumn(const Params& p = getDefaultParams(), LLScrollListCtrl* = NULL);
void setWidth(S32 width);
S32 getWidth() const { return mWidth; }
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 6f484b1875..6d91c784f7 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -62,7 +62,7 @@
template LLScrollListCtrl* LLView::getChild<LLScrollListCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
-static LLRegisterWidget<LLScrollListCtrl> r("scroll_list");
+static LLDefaultWidgetRegistry::Register<LLScrollListCtrl> r("scroll_list");
// local structures & classes.
struct SortScrollListItem
@@ -1246,14 +1246,14 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
// has an associated, unique UUID, and only one of which can be selected at a time.
-LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width)
+LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled)
{
if (getItemCount() < mMaxItemCount)
{
LLScrollListItem::Params item_p;
item_p.enabled(enabled);
item_p.value(id);
- item_p.cells.add().value(item_text).width(column_width).type("text");
+ item_p.cells.add().value(item_text).type("text");
return addRow( item_p, pos );
}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 461df6760f..8d200fb73f 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -222,7 +222,7 @@ public:
// DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue().
// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
// has an associated, unique UUID, and only one of which can be selected at a time.
- LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, S32 column_width = 0);
+ LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
LLUUID getStringUUIDSelectedItem() const;
LLScrollListItem* getFirstSelected() const;
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index 8d87137c3a..4237d5b304 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -64,9 +64,9 @@ public:
Optional<void*> userdata;
Optional<LLSD> value;
- Deprecated name; // use for localization tools
- Deprecated type;
- Deprecated length;
+ Ignored name; // use for localization tools
+ Ignored type;
+ Ignored length;
Multiple<LLScrollListCell::Params> cells;
diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp
index 62b204fd56..9522d32a8b 100644
--- a/indra/llui/llsearcheditor.cpp
+++ b/indra/llui/llsearcheditor.cpp
@@ -36,7 +36,7 @@
#include "llsearcheditor.h"
-static LLRegisterWidget<LLSearchEditor> r2("search_editor");
+//static LLDefaultWidgetRegistry::Register<LLSearchEditor> r2("search_editor");
LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
: LLUICtrl(p)
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index ff2f5d3da0..8070dc4d02 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -43,10 +43,9 @@
#include "llimagegl.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLSlider> r1("slider_bar");
+static LLDefaultWidgetRegistry::Register<LLSlider> r1("slider_bar");
//FIXME: make this into an unregistered template so that code constructed sliders don't
// have ambigious template lookup problem
-static LLRegisterWidget<LLSlider> r2("volume_slider");
LLSlider::Params::Params()
: track_color("track_color"),
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 2c8aed6196..8bdeddcf75 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -53,7 +53,7 @@
const U32 MAX_STRING_LENGTH = 10;
-static LLRegisterWidget<LLSliderCtrl> r("slider");
+static LLDefaultWidgetRegistry::Register<LLSliderCtrl> r("slider");
LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
: LLF32UICtrl(p),
@@ -398,4 +398,3 @@ void LLSliderCtrl::reportInvalidData()
make_ui_sound("UISndBadKeystroke");
}
-
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ac4b528aac..72329a4b32 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -53,7 +53,7 @@
const U32 MAX_STRING_LENGTH = 32;
-static LLRegisterWidget<LLSpinCtrl> r2("spinner");
+static LLDefaultWidgetRegistry::Register<LLSpinCtrl> r2("spinner");
LLSpinCtrl::Params::Params()
: label_width("label_width"),
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index b5383c34ea..bd74b285a7 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -43,8 +43,6 @@
#include "llstat.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLStatBar> r1("stat_bar");
-
///////////////////////////////////////////////////////////////////////////////////
LLStatBar::LLStatBar(const Params& p)
diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp
index e16f2c450e..6691f16c1e 100644
--- a/indra/llui/llstatview.cpp
+++ b/indra/llui/llstatview.cpp
@@ -64,3 +64,17 @@ LLStatView::~LLStatView()
}
}
+
+// widget registrars
+struct StatViewRegistry : public LLWidgetRegistry<StatViewRegistry>
+{};
+
+static StatViewRegistry::Register<LLStatBar> r1("stat_bar");
+
+
+const widget_registry_t& LLStatView::getChildRegistry() const
+{
+ return StatViewRegistry::instance();
+}
+
+
diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h
index 0197c7ceb3..20aba7782b 100644
--- a/indra/llui/llstatview.h
+++ b/indra/llui/llstatview.h
@@ -53,11 +53,14 @@ public:
};
~LLStatView();
+ virtual const widget_registry_t& getChildRegistry() const;
+
protected:
LLStatView(const Params&);
friend class LLUICtrlFactory;
protected:
std::string mSetting;
+
};
#endif // LL_STATVIEW_
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 5b24131c90..3391b1275c 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -99,15 +99,21 @@ struct LLPlaceHolderPanel : public LLPanel
LLPlaceHolderPanel(const Params& p) : LLPanel(p)
{}
};
-static LLRegisterWidget<LLPlaceHolderPanel> r1("placeholder");
-static LLRegisterWidget<LLTabContainer> r2("tab_container");
+static LLDefaultWidgetRegistry::Register<LLPlaceHolderPanel> r1("placeholder");
+static LLDefaultWidgetRegistry::Register<LLTabContainer> r2("tab_container");
LLTabContainer::Params::Params()
: tab_width("tab_width"),
tab_position("tab_position"),
tab_min_width("tab_min_width"),
tab_max_width("tab_max_width"),
- hide_tabs("hide_tabs", false)
+ hide_tabs("hide_tabs", false),
+ tab_top_image_unselected("tab_top_image_unselected"),
+ tab_top_image_selected("tab_top_image_selected"),
+ tab_bottom_image_unselected("tab_bottom_image_unselected"),
+ tab_bottom_image_selected("tab_bottom_image_selected"),
+ tab_left_image_unselected("tab_left_image_unselected"),
+ tab_left_image_selected("tab_left_image_selected")
{
name(std::string("tab_container"));
mouse_opaque = false;
@@ -134,7 +140,13 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mJumpNextArrowBtn(NULL),
mRightTabBtnOffset(p.tab_padding_right),
mTotalTabWidth(0),
- mTabPosition(p.tab_position)
+ mTabPosition(p.tab_position),
+ mImageTopUnselected(p.tab_top_image_unselected),
+ mImageTopSelected(p.tab_top_image_selected),
+ mImageBottomUnselected(p.tab_bottom_image_unselected),
+ mImageBottomSelected(p.tab_bottom_image_selected),
+ mImageLeftUnselected(p.tab_left_image_unselected),
+ mImageLeftSelected(p.tab_left_image_selected)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@@ -817,8 +829,8 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
// Tab button
LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw().
- std::string tab_img;
- std::string tab_selected_img;
+ LLUIImage* tab_img = NULL;
+ LLUIImage* tab_selected_img = NULL;
S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel
if (mIsVertical)
@@ -831,14 +843,14 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
else if( getTabPosition() == LLTabContainer::TOP )
{
btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, tabcntr_tab_height );
- tab_img = "tab_top_blue.tga";
- tab_selected_img = "tab_top_selected_blue.tga";
+ tab_img = mImageTopUnselected.get();
+ tab_selected_img = mImageTopSelected.get();
}
else
{
btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, tabcntr_tab_height );
- tab_img = "tab_bottom_blue.tga";
- tab_selected_img = "tab_bottom_selected_blue.tga";
+ tab_img = mImageBottomUnselected.get();
+ tab_selected_img = mImageBottomSelected.get();
}
LLTextBox* textbox = NULL;
@@ -869,8 +881,8 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
p.font(font);
p.label(trimmed_label);
- p.image_unselected.name("tab_left.tga");
- p.image_selected.name("tab_left_selected.tga");
+ p.image_unselected(mImageLeftUnselected);
+ p.image_selected(mImageLeftSelected);
p.scale_image(true);
p.font_halign = LLFontGL::LEFT;
p.tab_stop(false);
@@ -895,8 +907,8 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.visible(false);
p.tool_tip(tooltip);
p.scale_image(true);
- p.image_unselected.name(tab_img);
- p.image_selected.name(tab_selected_img);
+ p.image_unselected(tab_img);
+ p.image_selected(tab_selected_img);
p.tab_stop(false);
// Try to squeeze in a bit more text
p.pad_left(4);
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 7ed1a0f4bf..ac8232bbb1 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -71,6 +71,13 @@ public:
Optional<bool> hide_tabs;
Optional<S32> tab_padding_right;
+ Optional<LLUIImage*> tab_top_image_unselected,
+ tab_top_image_selected,
+ tab_bottom_image_unselected,
+ tab_bottom_image_selected,
+ tab_left_image_unselected,
+ tab_left_image_selected;
+
Params();
};
@@ -236,6 +243,13 @@ private:
S32 mTotalTabWidth;
LLFrameTimer mDragAndDropDelayTimer;
+
+ LLPointer<LLUIImage> mImageTopUnselected;
+ LLPointer<LLUIImage> mImageTopSelected;
+ LLPointer<LLUIImage> mImageBottomUnselected;
+ LLPointer<LLUIImage> mImageBottomSelected;
+ LLPointer<LLUIImage> mImageLeftUnselected;
+ LLPointer<LLUIImage> mImageLeftSelected;
};
#endif // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 95990bbfc2..464e4be809 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -40,7 +40,7 @@
template LLTextBox* LLView::getChild<LLTextBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
-static LLRegisterWidget<LLTextBox> r("text");
+static LLDefaultWidgetRegistry::Register<LLTextBox> r("text");
LLTextBox::Params::Params()
: text_color("text_color"),
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index aae538a221..dca906decc 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -60,7 +60,7 @@ public:
Optional<LLFontGL::ShadowType> font_shadow;
- Deprecated drop_shadow_visible,
+ Ignored drop_shadow_visible,
type,
length;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 44d98e75c8..34bced064e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -63,7 +63,7 @@
//
// Globals
//
-static LLRegisterWidget<LLTextEditor> r("simple_text_editor");
+static LLDefaultWidgetRegistry::Register<LLTextEditor> r("simple_text_editor");
//
// Constants
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index efedb30f47..f64353555e 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -82,7 +82,7 @@ public:
Optional<LLViewBorder::Params> border;
- Deprecated type,
+ Ignored type,
length,
is_unicode;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 1cb6972370..1d3e5d7a15 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -50,6 +50,7 @@
// Project includes
#include "llcontrol.h"
#include "llui.h"
+#include "lluicolortable.h"
#include "llview.h"
#include "lllineeditor.h"
#include "llfloater.h"
@@ -57,6 +58,10 @@
#include "llmenugl.h"
#include "llwindow.h"
+// for registration
+#include "llsearcheditor.h"
+#include "llflyoutbutton.h"
+
// for XUIParse
#include "llquaternion.h"
#include <boost/tokenizer.hpp>
@@ -84,6 +89,10 @@ std::list<std::string> gUntranslated;
/*static*/ std::vector<std::string> LLUI::sXUIPaths;
+// register searcheditor here
+static LLDefaultWidgetRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
+static LLDefaultWidgetRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
+
//
// Functions
@@ -1697,7 +1706,7 @@ void LLUI::getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y)
// static
std::string LLUI::getLanguage()
{
- std::string language = "en-us";
+ std::string language = "en";
if (sSettingGroups["config"])
{
language = sSettingGroups["config"]->getString("Language");
@@ -1711,7 +1720,7 @@ std::string LLUI::getLanguage()
}
if (language.empty() || language == "default")
{
- language = "en-us";
+ language = "en";
}
}
return language;
@@ -1744,7 +1753,7 @@ void LLUI::setupPaths()
else // parsing failed
{
std::string slash = gDirUtilp->getDirDelimiter();
- std::string dir = "xui" + slash + "en-us";
+ std::string dir = "xui" + slash + "en";
llwarns << "XUI::config file unable to open: " << filename << llendl;
sXUIPaths.push_back(dir);
}
@@ -1771,7 +1780,7 @@ std::string LLUI::locateSkin(const std::string& filename)
}
if (!gDirUtilp->fileExists(found_file))
{
- std::string local_skin = "xui" + slash + "en-us" + slash + filename;
+ std::string local_skin = "xui" + slash + "en" + slash + filename;
found_file = gDirUtilp->findSkinnedFilename(local_skin);
}
if (!gDirUtilp->fileExists(found_file))
@@ -1858,8 +1867,11 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
for (settings_map_t::iterator itor = sSettingGroups.begin();
itor != sSettingGroups.end(); ++itor)
{
- if (sSettingGroups[(itor->first)]->controlExists(controlname))
- return *sSettingGroups[(itor->first)];
+ if(itor->second!= NULL)
+ {
+ if (sSettingGroups[(itor->first)]->controlExists(controlname))
+ return *sSettingGroups[(itor->first)];
+ }
}
return *sSettingGroups["config"]; // default group
@@ -1943,7 +1955,7 @@ namespace LLInitParam
{
if (control.isProvided())
{
- return LLUI::getCachedColorFunctor(control);
+ return LLUIColorTable::instance().getColor(control);
}
else
{
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 71396e10d9..dbd295d4e8 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -183,7 +183,8 @@ public:
static void setupPaths();
static const std::vector<std::string>& getXUIPaths() { return sXUIPaths; }
static std::string getSkinPath() { return sXUIPaths.front(); }
-
+ static std::string getLocalizedSkinPath() { return sXUIPaths.back(); } //all files may not exist at the localized path
+
//helper functions (should probably move free standing rendering helper functions here)
static LLView* getRootView() { return sRootView; }
static void setRootView(LLView* view) { sRootView = view; }
@@ -664,8 +665,8 @@ template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sReg
// useful parameter blocks
struct TimeIntervalParam : public LLInitParam::Choice<TimeIntervalParam>
{
- Option<F32> seconds;
- Option<S32> frames;
+ Alternative<F32> seconds;
+ Alternative<S32> frames;
TimeIntervalParam()
: seconds("seconds"),
frames("frames")
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
new file mode 100644
index 0000000000..27ba6cc8b4
--- /dev/null
+++ b/indra/llui/lluicolortable.cpp
@@ -0,0 +1,155 @@
+/**
+ * @file lluicolortable.cpp
+ * @brief brief LLUIColorTable class implementation file
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include <queue>
+
+#include "lluicolortable.h"
+
+LLUIColorTable::ColorParams::ColorParams()
+: value("value"),
+ reference("reference")
+{
+}
+
+LLUIColorTable::ColorEntryParams::ColorEntryParams()
+: name("name"),
+ color("")
+{
+}
+
+LLUIColorTable::Params::Params()
+: color_entries("color_entries")
+{
+}
+
+void LLUIColorTable::init(const Params& p)
+{
+ // this map will contain all color references after the following loop
+ typedef std::map<std::string, std::string> string_string_map_t;
+ string_string_map_t unresolved_refs;
+
+ mColors.clear();
+ for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries().begin();
+ it != p.color_entries().end();
+ ++it)
+ {
+ ColorEntryParams color_entry = *it;
+ if(color_entry.color.value.isChosen())
+ {
+ mColors.insert(string_color_map_t::value_type(color_entry.name, color_entry.color.value));
+ }
+ else
+ {
+ unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference));
+ }
+ }
+
+ // maintain an in order queue of visited references for better debugging of cycles
+ typedef std::queue<std::string> string_queue_t;
+ string_queue_t ref_chain;
+
+ // maintain a map of the previously visited references in the reference chain for detecting cycles
+ typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t;
+ string_color_ref_iter_map_t visited_refs;
+
+ // loop through the unresolved color references until there are none left
+ while(!unresolved_refs.empty())
+ {
+ // we haven't visited any references yet
+ visited_refs.clear();
+
+ string_string_map_t::iterator it = unresolved_refs.begin();
+ while(true)
+ {
+ if(it != unresolved_refs.end())
+ {
+ // locate the current reference in the previously visited references...
+ string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(it->first);
+ if(visited != visited_refs.end()
+ && !(visited_refs.key_comp()(it->first, visited->first)))
+ {
+ // ...if we find the current reference in the previously visited references
+ // we know that there is a cycle
+ std::string ending_ref = it->first;
+ std::string warning("The following colors form a cycle: ");
+
+ // warn about the references in the chain and remove them from
+ // the unresolved references map because they cannot be resolved
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ if(!ref_chain.empty())
+ {
+ warning += ref_chain.front() + "->";
+ ref_chain.pop();
+ }
+ unresolved_refs.erase(iter->second);
+ }
+
+ llwarns << warning + ending_ref << llendl;
+
+ break;
+ }
+ else
+ {
+ // ...continue along the reference chain
+ ref_chain.push(it->first);
+ visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(it->first, it));
+ }
+ }
+ else
+ {
+ // since this reference does not refer to another reference it must refer to an
+ // actual color, lets find it...
+ string_color_map_t::iterator color_value = mColors.find(it->second);
+
+ if(color_value != mColors.end())
+ {
+ // ...we found the color, and we now add every reference in the reference chain
+ // to the color map
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ mColors.insert(string_color_map_t::value_type(iter->first, color_value->second));
+ unresolved_refs.erase(iter->second);
+ }
+
+ break;
+ }
+ else
+ {
+ // ... we did not find the color which imples that the current reference
+ // references a non-existant color
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ llwarns << iter->first << " references a non-existent color" << llendl;
+ unresolved_refs.erase(iter->second);
+ }
+
+ break;
+ }
+ }
+
+ // find the next color reference in the reference chain
+ it = unresolved_refs.find(it->second);
+ }
+ }
+}
+
+const LLColor4& LLUIColorTable::getColor(const std::string& name) const
+{
+ string_color_map_t::const_iterator iter = mColors.find(name);
+ return (iter != mColors.end() ? iter->second : LLColor4::magenta);
+}
diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h
new file mode 100644
index 0000000000..dcbb1ee5cb
--- /dev/null
+++ b/indra/llui/lluicolortable.h
@@ -0,0 +1,58 @@
+/**
+ * @file lluicolortable.h
+ * @brief brief LLUIColorTable class header file
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLUICOLORTABLE_H_
+#define LL_LLUICOLORTABLE_H_
+
+#include <map>
+
+#include "llinitparam.h"
+#include "llsingleton.h"
+
+#include "v4color.h"
+
+class LLUIColorTable : public LLSingleton<LLUIColorTable>
+{
+public:
+ struct ColorParams : LLInitParam::Choice<ColorParams>
+ {
+ Alternative<LLColor4> value;
+ Alternative<std::string> reference;
+
+ ColorParams();
+ };
+
+ struct ColorEntryParams : LLInitParam::Block<ColorEntryParams>
+ {
+ Mandatory<std::string> name;
+ Mandatory<ColorParams> color;
+
+ ColorEntryParams();
+ };
+
+ struct Params : LLInitParam::Block<Params>
+ {
+ Multiple<ColorEntryParams> color_entries;
+
+ Params();
+ };
+
+ // define colors by passing in a param block that can be generated via XUI file or manually
+ void init(const Params& p);
+
+ // color lookup
+ const LLColor4& getColor(const std::string& name) const;
+
+private:
+ // consider using sorted vector
+ typedef std::map<std::string, LLColor4> string_color_map_t;
+ string_color_map_t mColors;
+};
+
+#endif // LL_LLUICOLORTABLE_H
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 99811809a8..7b378fd9c7 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -38,7 +38,7 @@
#include "llpanel.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLUICtrl> r("ui_ctrl");
+static LLDefaultWidgetRegistry::Register<LLUICtrl> r("ui_ctrl");
LLUICtrl::Params::Params()
: tab_stop("tab_stop", true),
@@ -47,8 +47,8 @@ LLUICtrl::Params::Params()
init_callback("init_callback"),
commit_callback("commit_callback"),
validate_callback("validate_callback"),
- control_name("control_name"),
- enabled_control("enabled_control")
+ rightclick_callback("rightclick_callback"),
+ control_name("control_name")
{
addSynonym(initial_value, "initial_val");
// this is the canonical name for text contents of an xml node
@@ -111,13 +111,21 @@ void LLFocusableElement::setFocus(BOOL b)
{
}
+//static
+const LLUICtrl::Params& LLUICtrl::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLUICtrl::Params>();
+}
+
+
LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
: LLView(p),
mTentative(FALSE),
mIsChrome(FALSE),
mViewModel(viewmodel),
mControlVariable(NULL),
- mEnabledControlVariable(NULL)
+ mEnabledControlVariable(NULL),
+ mDisabledControlVariable(NULL)
{
mUICtrlHandle.bind(this);
}
@@ -127,12 +135,37 @@ void LLUICtrl::initFromParams(const Params& p)
LLView::initFromParams(p);
setControlName(p.control_name);
- if (p.enabled_control.isProvided())
+ if(p.enabled_controls.isProvided())
{
- LLControlVariable* control = findControl(p.enabled_control);
- if (control)
- setEnabledControlVariable(control);
+ if (p.enabled_controls.enabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.enabled);
+ if (control)
+ setEnabledControlVariable(control);
+ }
+ else if(p.enabled_controls.disabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.disabled);
+ if (control)
+ setDisabledControlVariable(control);
+ }
}
+ if(p.controls_visibility.isProvided())
+ {
+ if (p.controls_visibility.visible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.visible);
+ if (control)
+ setMakeVisibleControlVariable(control);
+ }
+ else if (p.controls_visibility.invisible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.invisible);
+ if (control)
+ setMakeInvisibleControlVariable(control);
+ }
+ }
+
setTabStop(p.tab_stop);
setFocusLostCallback(p.focus_lost_callback());
@@ -163,6 +196,10 @@ void LLUICtrl::initFromParams(const Params& p)
}
}
}
+
+ if(p.rightclick_callback.isProvided())
+ initCommitCallback(p.rightclick_callback, mRightClickSignal);
+
}
@@ -326,6 +363,50 @@ void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)
}
}
+void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)
+{
+ if (mDisabledControlVariable)
+ {
+ mDisabledControlConnection.disconnect(); // disconnect current signal
+ mDisabledControlVariable = NULL;
+ }
+ if (control)
+ {
+ mDisabledControlVariable = control;
+ mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("disabled")));
+ setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));
+ }
+}
+
+void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeVisibleControlVariable)
+ {
+ mMakeVisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeVisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeVisibleControlVariable = control;
+ mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("visible")));
+ setVisible(mMakeVisibleControlVariable->getValue().asBoolean());
+ }
+}
+
+void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeInvisibleControlVariable)
+ {
+ mMakeInvisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeInvisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeInvisibleControlVariable = control;
+ mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("invisible")));
+ setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));
+ }
+}
// static
bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
{
@@ -342,11 +423,21 @@ bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle,
ctrl->setEnabled(newvalue.asBoolean());
return true;
}
+ else if(type =="disabled")
+ {
+ ctrl->setEnabled(!newvalue.asBoolean());
+ return true;
+ }
else if (type == "visible")
{
ctrl->setVisible(newvalue.asBoolean());
return true;
}
+ else if (type == "invisible")
+ {
+ ctrl->setVisible(!newvalue.asBoolean());
+ return true;
+ }
}
return false;
}
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 6d310dca22..6dfbd9cf8b 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -87,7 +87,7 @@ public:
struct CallbackParam : public LLInitParam::Block<CallbackParam>
{
- Deprecated name;
+ Ignored name;
Optional<std::string> function_name;
Optional<LLSD> parameter;
@@ -114,6 +114,26 @@ public:
Optional<enable_callback_t> function;
};
+ struct EnableControls : public LLInitParam::Choice<EnableControls>
+ {
+ Alternative<std::string> enabled;
+ Alternative<std::string> disabled;
+
+ EnableControls()
+ : enabled("enabled_control"),
+ disabled("disabled_control")
+ {}
+ };
+ struct ControlVisibility : public LLInitParam::Choice<ControlVisibility>
+ {
+ Alternative<std::string> visible;
+ Alternative<std::string> invisible;
+
+ ControlVisibility()
+ : visible("make_visible_control"),
+ invisible("make_invisible_control")
+ {}
+ };
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<std::string> label;
@@ -124,10 +144,13 @@ public:
commit_callback;
Optional<EnableCallbackParam> validate_callback;
+ Optional<CommitCallbackParam> rightclick_callback;
+
Optional<focus_callback_t> focus_lost_callback;
Optional<std::string> control_name;
- Optional<std::string> enabled_control;
+ Optional<EnableControls> enabled_controls;
+ Optional<ControlVisibility> controls_visibility;
Params();
};
@@ -137,7 +160,8 @@ public:
void initFromParams(const Params& p);
protected:
friend class LLUICtrlFactory;
- LLUICtrl(const Params& p = LLUICtrl::Params(),
+ static const Params& getDefaultParams();
+ LLUICtrl(const Params& p = getDefaultParams(),
const LLViewModelPtr& viewmodel=LLViewModelPtr(new LLViewModel));
void initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig);
@@ -176,6 +200,9 @@ public:
LLControlVariable* getControlVariable() { return mControlVariable; }
void setEnabledControlVariable(LLControlVariable* control);
+ void setDisabledControlVariable(LLControlVariable* control);
+ void setMakeVisibleControlVariable(LLControlVariable* control);
+ void setMakeInvisibleControlVariable(LLControlVariable* control);
virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
@@ -244,8 +271,9 @@ protected:
static bool controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type);
- commit_signal_t mCommitSignal;
- enable_signal_t mValidateSignal;
+ commit_signal_t mCommitSignal;
+ enable_signal_t mValidateSignal;
+ commit_signal_t mRightClickSignal;
LLViewModelPtr mViewModel;
@@ -253,7 +281,12 @@ protected:
boost::signals2::connection mControlConnection;
LLControlVariable* mEnabledControlVariable;
boost::signals2::connection mEnabledControlConnection;
-
+ LLControlVariable* mDisabledControlVariable;
+ boost::signals2::connection mDisabledControlConnection;
+ LLControlVariable* mMakeVisibleControlVariable;
+ boost::signals2::connection mMakeVisibleControlConnection;
+ LLControlVariable* mMakeInvisibleControlVariable;
+ boost::signals2::connection mMakeInvisibleControlConnection;
private:
BOOL mTabStop;
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 1f487bdb7e..24e4ad18e6 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -78,10 +78,14 @@ const S32 VPAD = 4;
const S32 FLOATER_H_MARGIN = 15;
const S32 MIN_WIDGET_HEIGHT = 10;
+LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");
+LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams");
+LLFastTimer::DeclareTimer FTM_WIDGET_SETUP("Widget Setup");
+
//-----------------------------------------------------------------------------
// Register widgets that are purely data driven here so they get linked in
#include "llstatview.h"
-static LLRegisterWidget<LLStatView> register_stat_view("stat_view");
+static LLDefaultWidgetRegistry::Register<LLStatView> register_stat_view("stat_view");
//-----------------------------------------------------------------------------
@@ -103,9 +107,7 @@ public:
};
-//FIXME: this created an ambiguous lookup of template (locate.xml or pad.xml?)
-static LLRegisterWidget<LLUICtrlLocate> r1("locate");
-static LLRegisterWidget<LLUICtrlLocate> r2("pad");
+static LLDefaultWidgetRegistry::Register<LLUICtrlLocate> r1("locate");
//-----------------------------------------------------------------------------
// LLUICtrlFactory()
@@ -132,22 +134,82 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
}
}
+//static
+void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, LLXMLNodePtr output_node)
+{
+ if (node.isNull()) return;
+
+ for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
+ {
+ LLXMLNodePtr outputChild;
+ if (output_node)
+ {
+ outputChild = output_node->createChild("", FALSE);
+ }
+
+ if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, outputChild, viewp->getChildRegistry()))
+ {
+ std::string child_name = std::string(child_node->getName()->mString);
+ llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
+ }
+
+ if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty())
+ {
+ output_node->deleteChild(outputChild);
+ }
+ }
+
+}
+
+LLFastTimer::DeclareTimer FTM_XML_PARSE("XML Reading/Parsing");
//-----------------------------------------------------------------------------
// getLayeredXMLNode()
//-----------------------------------------------------------------------------
bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
{
+ LLFastTimer timer(FTM_XML_PARSE);
return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
}
+
+//-----------------------------------------------------------------------------
+// getLocalizedXMLNode()
+//-----------------------------------------------------------------------------
+bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
+{
+ LLFastTimer timer(FTM_XML_PARSE);
+ std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), xui_filename);
+ if (!LLXMLNode::parseFile(full_filename, root, NULL))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+static LLFastTimer::DeclareTimer BUILD_FLOATERS("Build Floaters");
+
//-----------------------------------------------------------------------------
// buildFloater()
//-----------------------------------------------------------------------------
void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, BOOL open_floater, LLXMLNodePtr output_node)
{
+ LLFastTimer timer(BUILD_FLOATERS);
LLXMLNodePtr root;
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, 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;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
{
llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
return;
@@ -167,8 +229,10 @@ void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filen
{
mFactoryStack.push_front(&floaterp->getFactoryMap());
}
-
- floaterp->getCommitCallbackRegistrar().pushScope(); // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ floaterp->getCommitCallbackRegistrar().pushScope();
+ floaterp->getEnableCallbackRegistrar().pushScope();
floaterp->initFloaterXML(root, floaterp->getParent(), open_floater, output_node);
@@ -178,6 +242,7 @@ void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filen
}
floaterp->getCommitCallbackRegistrar().popScope();
+ floaterp->getEnableCallbackRegistrar().popScope();
if (!floaterp->getFactoryMap().empty())
{
@@ -202,15 +267,28 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
return 0;
}
+static LLFastTimer::DeclareTimer BUILD_PANELS("Build Panels");
+
//-----------------------------------------------------------------------------
// buildPanel()
//-----------------------------------------------------------------------------
BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node)
{
+ LLFastTimer timer(BUILD_PANELS);
BOOL didPost = FALSE;
LLXMLNodePtr root;
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, 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;
@@ -232,7 +310,14 @@ BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, L
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();
if (LLUI::sShowXUINames)
{
@@ -251,13 +336,15 @@ BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, L
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
-LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node)
+LLFastTimer::DeclareTimer FTM_CREATE_FROM_XML("Create child widget");
+
+LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& registry)
{
+ LLFastTimer timer(FTM_CREATE_FROM_XML);
std::string ctrl_type = node->getName()->mString;
LLStringUtil::toLower(ctrl_type);
- LLWidgetCreatorFunc* funcp = LLWidgetCreatorRegistry::getInstance()->getValue(ctrl_type);
-
+ const LLWidgetCreatorFunc* funcp = registry.getValue(ctrl_type);
if (funcp == NULL)
{
return NULL;
@@ -267,7 +354,8 @@ LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const
{
if (mDummyPanel == NULL)
{
- mDummyPanel = new LLPanel();
+ LLPanel::Params p;
+ mDummyPanel = create<LLPanel>(p);
}
parent = mDummyPanel;
}
@@ -299,7 +387,8 @@ LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
return ret;
}
}
- return new LLPanel();
+ LLPanel::Params panel_p;
+ return create<LLPanel>(panel_p);
}
//-----------------------------------------------------------------------------
@@ -359,12 +448,18 @@ void LLUICtrlFactory::popFactoryFunctions()
}
}
+const widget_registry_t& LLUICtrlFactory::getWidgetRegistry(LLView* viewp)
+{
+ return viewp->getChildRegistry();
+}
+
//
// LLXUIParser
//
LLXUIParser::LLXUIParser()
-: mLastWriteGeneration(-1)
+: mLastWriteGeneration(-1),
+ mCurReadDepth(0)
{
registerParserFuncs<bool>(boost::bind(&LLXUIParser::readBoolValue, this, _1),
boost::bind(&LLXUIParser::writeBoolValue, this, _1, _2));
@@ -396,9 +491,13 @@ LLXUIParser::LLXUIParser()
boost::bind(&LLXUIParser::writeSDValue, this, _1, _2));
}
+static LLFastTimer::DeclareTimer PARSE_XUI("XUI Parsing");
+
void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent)
{
+ LLFastTimer timer(PARSE_XUI);
mNameStack.clear();
+ mCurReadDepth = 0;
setParseSilently(silent);
if (node.isNull())
@@ -421,9 +520,21 @@ void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &bloc
// go from a stack of names to a specific XML node
LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack)
{
- if (stack.empty() || mWriteRootNode.isNull()) return NULL;
+ name_stack_t name_stack;
- std::string attribute_name = stack.front().first;
+ for (name_stack_t::const_iterator it = stack.begin();
+ it != stack.end();
+ ++it)
+ {
+ if (!it->first.empty())
+ {
+ name_stack.push_back(*it);
+ }
+ }
+
+ if (name_stack.empty() || mWriteRootNode.isNull()) return NULL;
+
+ std::string attribute_name = name_stack.front().first;
// heuristic to make font always attribute of parent node
bool is_font = (attribute_name == "font");
@@ -444,43 +555,68 @@ LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack)
}
}
- for (name_stack_t::const_iterator it = ++stack.begin();
- it != stack.end();
+ for (name_stack_t::const_iterator it = ++name_stack.begin();
+ it != name_stack.end();
++it)
{
attribute_name += ".";
attribute_name += it->first;
}
+ // *NOTE: <string> elements for translation need to have whitespace
+ // preserved like "initial_value" above, however, the <string> node
+ // becomes an attribute of the containing floater or panel.
+ // Because all <string> elements must have a "name" attribute, and
+ // "name" is parsed first, just put the value into the last written
+ // child.
+ if (attribute_name == "string.value")
+ {
+ // The caller of will shortly call writeStringValue(), which sets
+ // this node's type to string, but we don't want to export type="string".
+ // Set the default for this node to suppress the export.
+ static LLXMLNodePtr default_node;
+ if (default_node.isNull())
+ {
+ default_node = new LLXMLNode();
+ // Force the node to have a string type
+ default_node->setStringValue( std::string() );
+ }
+ mLastWrittenChild->setDefault(default_node);
+ // mLastWrittenChild is the "string" node part of "string.value",
+ // so the caller will call writeStringValue() into that node,
+ // setting the node text contents.
+ return mLastWrittenChild;
+ }
+
LLXMLNodePtr attribute_node;
const char* attribute_cstr = attribute_name.c_str();
- if (stack.size() != 1
+ if (name_stack.size() != 1
&& !is_font)
{
std::string child_node_name(mWriteRootNode->getName()->mString);
child_node_name += ".";
- child_node_name += stack.front().first;
+ child_node_name += name_stack.front().first;
LLXMLNodePtr child_node;
- if (mLastWriteGeneration == stack.front().second)
+ if (mLastWriteGeneration == name_stack.front().second)
{
child_node = mLastWrittenChild;
}
else
{
- mLastWriteGeneration = stack.front().second;
+ mLastWriteGeneration = name_stack.front().second;
child_node = mWriteRootNode->createChild(child_node_name.c_str(), false);
}
mLastWrittenChild = child_node;
- name_stack_t::const_iterator it = ++stack.begin();
+ name_stack_t::const_iterator it = ++name_stack.begin();
std::string short_attribute_name(it->first);
for (++it;
- it != stack.end();
+ it != name_stack.end();
++it)
{
short_attribute_name += ".";
@@ -526,7 +662,10 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLIn
{
mCurReadNode = nodep;
mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration()));
- block.submitValue(mNameStack, *this);
+ // child nodes are not necessarily valid parameters (could be a child widget)
+ // so don't complain once we've recursed
+ bool silent = mCurReadDepth > 0;
+ block.submitValue(mNameStack, *this, silent);
mNameStack.pop_back();
}
@@ -539,6 +678,7 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLIn
// nested_param1
// nested_param2
// nested_param3
+ mCurReadDepth++;
for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();)
{
std::string child_name(childp->getName()->mString);
@@ -550,13 +690,6 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLIn
// since there is no widget named "rect"
if (child_name.find(".") == std::string::npos)
{
- // skip over children with registered names
- if (LLWidgetCreatorRegistry::instance().exists(child_name))
- {
- childp = childp->getNextSibling();
- continue;
- }
-
mNameStack.push_back(std::make_pair(child_name, newParseGeneration()));
num_tokens_pushed++;
}
@@ -611,6 +744,7 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLIn
mNameStack.pop_back();
}
}
+ mCurReadDepth--;
return values_parsed;
}
@@ -637,7 +771,9 @@ bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& blo
num_tokens_pushed++;
}
- any_parsed |= block.submitValue(mNameStack, *this);
+ // child nodes are not necessarily valid attributes, so don't complain once we've recursed
+ bool silent = mCurReadDepth > 0;
+ any_parsed |= block.submitValue(mNameStack, *this, silent);
while(num_tokens_pushed-- > 0)
{
@@ -872,6 +1008,9 @@ bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& sta
if (node.notNull())
{
LLUIColor color = *((LLUIColor*)val_ptr);
+ //RN: don't write out the color that is represented by a function
+ // rely on param block exporting to get the reference to the color settings
+ if (color.isUsingFunction()) return false;
node->setFloatValue(4, color.get().mV);
return true;
}
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 5b04557368..b9c61b1fed 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -36,6 +36,7 @@
#include "llcallbackmap.h"
#include "llinitparam.h"
#include "llxmlnode.h"
+#include "llfasttimer.h"
#include <boost/function.hpp>
#include <iosfwd>
@@ -109,18 +110,37 @@ private:
LLXMLNodePtr mWriteRootNode;
S32 mLastWriteGeneration;
LLXMLNodePtr mLastWrittenChild;
+ S32 mCurReadDepth;
};
// global static instance for registering all widget types
typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc;
-class LLWidgetCreatorRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, LLWidgetCreatorRegistry>
+typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t;
+
+template <typename DERIVED_TYPE>
+class LLWidgetRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>
{
+public:
+ typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t;
+ // local static instance for registering a particular widget
+ template<typename T, typename PARAM_BLOCK = typename T::Params>
+ class Register : public super_t::StaticRegistrar
+ {
+ public:
+ // register with either the provided builder, or the generic templated builder
+ Register(const char* tag, LLWidgetCreatorFunc func = NULL);
+ };
+
protected:
- LLWidgetCreatorRegistry() {}
-
-private:
- friend class LLSingleton<LLWidgetCreatorRegistry>;
+ LLWidgetRegistry() {}
+};
+
+class LLDefaultWidgetRegistry : public LLWidgetRegistry<LLDefaultWidgetRegistry>
+{
+protected:
+ LLDefaultWidgetRegistry() {}
+ friend class LLSingleton<LLDefaultWidgetRegistry>;
};
struct LLCompareTypeID
@@ -134,19 +154,19 @@ struct LLCompareTypeID
class LLWidgetTemplateRegistry
: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetTemplateRegistry, LLCompareTypeID>
-{
+{};
-};
+// function used to create new default widgets via LLView::getChild<T>
+typedef LLView* (*dummy_widget_creator_func_t)(const std::string&);
-// local static instance for registering a particular widget
-template<typename T, typename PARAM_BLOCK = typename T::Params>
-class LLRegisterWidget
-: public LLWidgetCreatorRegistry::StaticRegistrar
-{
-public:
- // register with either the provided builder, or the generic templated builder
- LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func = NULL);
-};
+// used to register factory functions for default widget instances
+class LLDummyWidgetRegistry
+: public LLRegistrySingleton<const std::type_info*, dummy_widget_creator_func_t, LLDummyWidgetRegistry, LLCompareTypeID>
+{};
+
+extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
+extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
+extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS;
class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
{
@@ -232,10 +252,12 @@ public:
return widget;
}
- LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename = LLStringUtil::null, LLXMLNodePtr output_node = NULL);
+ LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& );
+ static const widget_registry_t& getWidgetRegistry(LLView*);
+
template<typename T>
- static T* createFromFile(const std::string &filename, LLView *parent)
+ static T* createFromFile(const std::string &filename, LLView *parent, LLXMLNodePtr output_node = NULL)
{
//#pragma message("Generating LLUICtrlFactory::createFromFile")
T* widget = NULL;
@@ -245,35 +267,50 @@ public:
{
LLXMLNodePtr root_node;
- if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
- {
- LLView* view = getInstance()->createFromXML(root_node, parent, filename);
- if (view)
- {
- widget = dynamic_cast<T*>(view);
- // not of right type, so delete it
- if (!widget)
- {
- delete view;
- view = NULL;
- }
-
+ //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_node))
+ {
+ llwarns << "Couldn't parse XUI file: " << filename << llendl;
+ goto fail;
}
}
- else
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
{
llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
+ goto fail;
+ }
+
+ LLView* view = getInstance()->createFromXML(root_node, parent, filename, output_node, getWidgetRegistry(parent));
+ if (view)
+ {
+ widget = dynamic_cast<T*>(view);
+ // not of right type, so delete it
+ if (!widget)
+ {
+ delete view;
+ view = NULL;
+ }
+
}
}
+fail:
getInstance()->mFileNames.pop_back();
-
return widget;
}
+ template<class T>
+ static T* getDefaultWidget(const std::string& name)
+ {
+ dummy_widget_creator_func_t* dummy_func = LLDummyWidgetRegistry::instance().getValue(&typeid(T));
+ return dynamic_cast<T*>((*dummy_func)(name));
+ }
+
template <class T>
- static T* createDummyWidget(const std::string& name)
+ static LLView* createDefaultWidget(const std::string& name)
{
- //#pragma message("Generating LLUICtrlFactory::createDummyWidget")
typename T::Params params;
params.name(name);
@@ -283,6 +320,8 @@ public:
template<typename T, typename PARAM_BLOCK>
static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
{
+ LLFastTimer timer(FTM_WIDGET_SETUP);
+
//#pragma message("Generating LLUICtrlFactory::defaultBuilder")
PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>());
@@ -307,8 +346,15 @@ public:
{
llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
}
- T* widget = new T(params);
- widget->initFromParams(params);
+ T* widget;
+ {
+ LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
+ widget = new T(params);
+ }
+ {
+ LLFastTimer timer(FTM_INIT_FROM_PARAMS);
+ widget->initFromParams(params);
+ }
if (parent)
{
@@ -316,7 +362,7 @@ public:
setCtrlParent(widget, parent, tab_group);
}
- widget->addChildren(node, output_node);
+ createChildren(widget, node, output_node);
if (!widget->postBuild())
{
@@ -327,7 +373,11 @@ public:
return widget;
}
+ static void createChildren(LLView* viewp, LLXMLNodePtr node, 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);
@@ -346,12 +396,68 @@ private:
};
// this is here to make gcc happy with reference to LLUICtrlFactory
-template<typename T, typename PARAM_BLOCK>
-LLRegisterWidget<T, PARAM_BLOCK>::LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func)
-: LLWidgetCreatorRegistry::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func)
+template<typename DERIVED>
+template<typename T, typename PARAM_BLOCK>
+LLWidgetRegistry<DERIVED>::Register<T, PARAM_BLOCK>::Register(const char* tag, LLWidgetCreatorFunc func)
+: LLWidgetRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func)
{
- //FIXME: inventory_panel will register itself with LLPanel::Params but it does have its own params...:(
+ // associate parameter block type with template .xml file
LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag);
+ // associate widget type with factory function
+ LLDummyWidgetRegistry::instance().defaultRegistrar().add(&typeid(T), &LLUICtrlFactory::createDefaultWidget<T>);
+}
+
+
+typedef boost::function<LLPanel* (void)> LLPannelClassCreatorFunc;
+
+// 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,LLPannelClassCreatorFunc func)
+ {
+ mPannelClassesNames[tag] = func;
+ }
+
+ LLPanel* createPanelClass(const std::string& tag)
+ {
+ param_name_map_t::iterator iT = mPannelClassesNames.find(tag);
+ if(iT == mPannelClassesNames.end())
+ return 0;
+ return iT->second();
+ }
+ template<typename T>
+ static T* defaultPanelClassBuilder()
+ {
+ T* pT = new T();
+ return pT;
+ }
+
+private:
+ typedef std::map< std::string, LLPannelClassCreatorFunc> param_name_map_t;
+
+ param_name_map_t mPannelClassesNames;
+};
+
+
+// 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>);
}
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
index 0ed2283742..8e0de0cb0c 100644
--- a/indra/llui/lluiimage.cpp
+++ b/indra/llui/lluiimage.cpp
@@ -49,6 +49,10 @@ LLUIImage::LLUIImage(const std::string& name, LLPointer<LLImageGL> image) :
{
}
+LLUIImage::~LLUIImage()
+{
+}
+
void LLUIImage::setClipRegion(const LLRectf& region)
{
mClipRegion = region;
@@ -147,12 +151,16 @@ namespace LLInitParam
return imagep;
}
+
template<>
bool ParamCompare<LLUIImage*>::equals(
LLUIImage* const &a,
LLUIImage* const &b)
{
// force all LLUIImages for XML UI export to be "non-default"
- return false;
+ if (!a && !b)
+ return false;
+ else
+ return (a == b);
}
}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index ae43b50172..e35026cd3d 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -33,7 +33,7 @@
#ifndef LL_LLUIIMAGE_H
#define LL_LLUIIMAGE_H
-#include "llgl.h"
+//#include "llgl.h"
#include "llimagegl.h"
#include "llrefcount.h"
#include "llrect.h"
@@ -46,6 +46,7 @@ class LLUIImage : public LLRefCount
{
public:
LLUIImage(const std::string& name, LLPointer<LLImageGL> image);
+ virtual ~LLUIImage();
void setClipRegion(const LLRectf& region);
void setScaleRegion(const LLRectf& region);
@@ -67,8 +68,8 @@ public:
const std::string& getName() const { return mName; }
- S32 getWidth() const;
- S32 getHeight() const;
+ virtual S32 getWidth() const;
+ virtual S32 getHeight() const;
// returns dimensions of underlying textures, which might not be equal to ui image portion
S32 getTextureWidth() const;
diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp
index ce73990d27..7ce0fd7a88 100644
--- a/indra/llui/lluistring.cpp
+++ b/indra/llui/lluistring.cpp
@@ -112,6 +112,13 @@ void LLUIString::clear()
void LLUIString::format()
{
+ // optimize for empty strings (don't attempt string replacement)
+ if (mOrig.empty())
+ {
+ mResult.clear();
+ mWResult.clear();
+ return;
+ }
mResult = mOrig;
// get the defailt args + local args
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 0a28075ed6..d225ad2767 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -56,8 +56,6 @@
#include "lltexteditor.h"
#include "lltextbox.h"
-using namespace LLOldEvents;
-
BOOL LLView::sDebugRects = FALSE;
BOOL LLView::sDebugKeys = FALSE;
S32 LLView::sDepth = 0;
@@ -95,9 +93,10 @@ LLView::Params::Params()
layout("layout"),
rect("rect"),
bottom_delta("bottom_delta", S32_MAX),
+ top_pad("top_pad"),
+ top_delta("top_delta", S32_MAX),
+ left_pad("left_pad"),
left_delta("left_delta", S32_MAX),
- top_delta("top_delta"),
- right_delta("right_delta"),
center_horiz("center_horiz", false),
center_vert("center_vert", false),
serializable("", false),
@@ -124,7 +123,8 @@ LLView::LLView(const LLView::Params& p)
mUseBoundingRect(p.use_bounding_rect),
mDefaultTabGroup(p.default_tab_group),
mLastTabGroup(0),
- mToolTipMsg((LLStringExplicit)p.tool_tip())
+ mToolTipMsg((LLStringExplicit)p.tool_tip()),
+ mDefaultWidgets(NULL)
{
// create rect first, as this will supply initial follows flags
setShape(p.rect);
@@ -157,8 +157,13 @@ LLView::~LLView()
mParentView->removeChild(this);
}
- std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(),
- DeletePairedPointer());
+ if (mDefaultWidgets)
+ {
+ std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
+ DeletePairedPointer());
+ delete mDefaultWidgets;
+ mDefaultWidgets = NULL;
+ }
}
// virtual
@@ -269,34 +274,6 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
}
}
-void LLView::addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node)
-{
- if (node.isNull()) return;
-
- for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
- {
- LLXMLNodePtr outputChild;
- if (output_node)
- {
- outputChild = output_node->createChild("", FALSE);
- }
-
- if (!LLUICtrlFactory::getInstance()->createFromXML(child_node, this, LLStringUtil::null, outputChild))
- {
- std::string child_name = std::string(child_node->getName()->mString);
- if (child_name.find(".") == std::string::npos)
- {
- llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
- }
- }
-
- if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty())
- {
- output_node->deleteChild(outputChild);
- }
- }
-}
-
// virtual
bool LLView::addChild(LLView* child, S32 tab_group)
{
@@ -1733,10 +1710,10 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_
if (create_if_missing)
{
- LLView* view = getDummyWidget<LLView>(name);
+ LLView* view = getDefaultWidget<LLView>(name);
if (!view)
{
- view = LLUICtrlFactory::createDummyWidget<LLView>(name);
+ view = LLUICtrlFactory::createDefaultWidget<LLView>(name);
}
return view;
}
@@ -2305,16 +2282,34 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna
LLControlVariable *LLView::findControl(const std::string& name)
{
- LLControlVariable* control;
- control = LLUI::sSettingGroups["color"]->getControl(name);
- if (control)
+ // parse the name to locate which group it belongs to
+ std::size_t key_pos= name.find(".");
+ if(key_pos!= std::string::npos )
{
- return control;
+ std::string control_group_key = name.substr(0, key_pos);
+ LLControlVariable* control;
+ // check if it's in the control group that name indicated
+ if(LLUI::sSettingGroups[control_group_key])
+ {
+ control = LLUI::sSettingGroups[control_group_key]->getControl(name);
+ if (control)
+ {
+ return control;
+ }
+ }
}
- return LLUI::sSettingGroups["config"]->getControl(name);
+ LLControlGroup& control_group = LLUI::getControlControlGroup(name);
+ return control_group.getControl(name);
+}
+
+const widget_registry_t& LLView::getChildRegistry() const
+{
+ static widget_registry_t empty_registry;
+ return empty_registry;
}
+
const S32 FLOATER_H_MARGIN = 15;
const S32 MIN_WIDGET_HEIGHT = 10;
const S32 VPAD = 4;
@@ -2395,17 +2390,38 @@ void LLView::parseFollowsFlags(const LLView::Params& params)
// static
-LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
+//LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
+//{
+// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
+//
+// if (node->hasAttribute("halign"))
+// {
+// std::string horizontal_align_name;
+// node->getAttributeString("halign", horizontal_align_name);
+// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+// }
+// return gl_hfont_align;
+//}
+
+// Return the rectangle of the last-constructed child,
+// if present and a first-class widget (eg, not a close box or drag handle)
+// Returns true if found
+static bool get_last_child_rect(LLView* parent, LLRect *rect)
{
- LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
+ if (!parent) return false;
- if (node->hasAttribute("halign"))
+ LLView::child_list_t::const_iterator itor =
+ parent->getChildList()->begin();
+ for (;itor != parent->getChildList()->end(); ++itor)
{
- std::string horizontal_align_name;
- node->getAttributeString("halign", horizontal_align_name);
- gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+ LLView *last_view = (*itor);
+ if (last_view->getSaveToXML())
+ {
+ *rect = last_view->getRect();
+ return true;
+ }
}
- return gl_hfont_align;
+ return false;
}
//static
@@ -2416,10 +2432,12 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
p.serializable(true);
- // *NOTE: Do not inherit layout from parent until we re-export
- // all nodes and make topleft the default. JC
- //if (p.layout().empty() && parent)
- // p.layout = parent->getLayout();
+ // *NOTE: This will confuse export of floater/panel coordinates unless
+ // the default is also "topleft". JC
+ if (p.layout().empty() && parent)
+ {
+ p.layout = parent->getLayout();
+ }
if (parent)
{
@@ -2488,20 +2506,11 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
last_rect.translate(0, last_rect.getHeight());
- LLView::child_list_t::const_iterator itor = parent->getChildList()->begin();
- for (;itor != parent->getChildList()->end(); ++itor)
- {
- LLView *last_view = (*itor);
- if (last_view->getSaveToXML())
- {
- last_rect = last_view->getRect();
- break;
- }
- }
+ // If there was a recently constructed child, use its rectangle
+ get_last_child_rect(parent, &last_rect);
if (layout_topleft)
{
- S32 left_delta = 0;
p.bottom_delta.setIfNotProvided(0, false);
// Invert the sense of bottom_delta for topleft layout
@@ -2509,32 +2518,33 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
{
p.bottom_delta = -p.bottom_delta;
}
- else if (p.top_delta.isProvided())
+ else if (p.top_pad.isProvided())
{
- p.bottom_delta = -(p.rect.height + p.top_delta);
+ p.bottom_delta = -(p.rect.height + p.top_pad);
}
- else if (!p.left_delta.isProvided() && !p.right_delta.isProvided() && !p.top_delta.isProvided())
+ else if (p.top_delta.isProvided())
{
- // set default position is just below last rect
- p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
+ p.bottom_delta =
+ -(p.top_delta + p.rect.height - last_rect.getHeight());
}
-
- // *TODO: Add left_pad for padding off the last widget's right edge
- // if (p.left_pad.isProvided())
- //{
- // left_delta = p.left_pad + last_rect.getWidth();
- //}
- //else if ...
- if (p.left_delta.isProvided())
+ else if (!p.bottom_delta.isProvided()
+ && !p.left_delta.isProvided()
+ && !p.top_pad.isProvided()
+ && !p.left_pad.isProvided())
{
- left_delta = p.left_delta;
+ // set default position is just below last rect
+ p.bottom_delta.set(-(p.rect.height + VPAD), false);
}
- else if (p.right_delta.isProvided())
+
+ // default to same left edge
+ p.left_delta.setIfNotProvided(0, false);
+ if (p.left_pad.isProvided())
{
- left_delta = -(p.right_delta + p.rect.width);
+ // left_pad is based on prior widget's right edge
+ p.left_delta.set(p.left_pad + last_rect.getWidth(), false);
}
- last_rect.translate(left_delta, p.bottom_delta);
+ last_rect.translate(p.left_delta, p.bottom_delta);
}
else
{
@@ -2581,27 +2591,103 @@ static S32 invert_vertical(S32 y, LLView* parent)
}
}
-//static
-void LLView::setupParamsForExport(Params& p, LLView* parent)
-{
- // Don't convert if already top-left based
- if (p.layout() == "topleft")
+// Assumes that input is in bottom-left coordinates, hence must call
+// _before_ convert_coords_to_top_left().
+static void convert_to_relative_layout(LLView::Params& p, LLView* parent)
+{
+ // Use setupParams to get the final widget rectangle
+ // according to our wacky layout rules.
+ LLView::Params final = p;
+ LLView::setupParams(final, parent);
+ // Must actually extract the rectangle to get consistent
+ // right = left+width, top = bottom+height
+ LLRect final_rect = final.rect;
+
+ // We prefer to write out top edge instead of bottom, regardless
+ // of whether we use relative positioning
+ bool converted_top = false;
+
+ // Look for a last rectangle
+ LLRect last_rect;
+ if (get_last_child_rect(parent, &last_rect))
+ {
+ // ...we have a previous widget to compare to
+ const S32 EDGE_THRESHOLD_PIXELS = 4;
+ S32 left_pad = final_rect.mLeft - last_rect.mRight;
+ S32 left_delta = final_rect.mLeft - last_rect.mLeft;
+ S32 top_pad = final_rect.mTop - last_rect.mBottom;
+ S32 top_delta = final_rect.mTop - last_rect.mTop;
+ // If my left edge is almost the same, or my top edge is
+ // almost the same...
+ if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS
+ || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS)
+ {
+ // ...use relative positioning
+ // prefer top_pad if widgets are stacking vertically
+ // (coordinate system is still bottom-left here)
+ if (top_pad < 0)
+ {
+ p.top_pad = top_pad;
+ p.top_delta.setProvided(false);
+ }
+ else
+ {
+ p.top_pad.setProvided(false);
+ p.top_delta = top_delta;
+ }
+ // null out other vertical specifiers
+ p.rect.top.setProvided(false);
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ converted_top = true;
+
+ // prefer left_pad if widgets are stacking horizontally
+ if (left_pad > 0)
+ {
+ p.left_pad = left_pad;
+ p.left_delta.setProvided(false);
+ }
+ else
+ {
+ p.left_pad.setProvided(false);
+ p.left_delta = left_delta;
+ }
+ p.rect.left.setProvided(false);
+ p.rect.right.setProvided(false);
+ }
+ }
+
+ if (!converted_top)
{
- return;
+ // ...this is the first widget, or one that wasn't aligned
+ // prefer top/left specification
+ p.rect.top = final_rect.mTop;
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ p.top_pad.setProvided(false);
+ p.top_delta.setProvided(false);
}
+}
+static void convert_coords_to_top_left(LLView::Params& p, LLView* parent)
+{
+ // Convert the coordinate system to be top-left based.
if (p.rect.top.isProvided())
{
p.rect.top = invert_vertical(p.rect.top, parent);
}
- if (p.top_delta.isProvided())
- {
- p.top_delta = -p.top_delta;
- }
if (p.rect.bottom.isProvided())
{
p.rect.bottom = invert_vertical(p.rect.bottom, parent);
}
+ if (p.top_pad.isProvided())
+ {
+ p.top_pad = -p.top_pad;
+ }
+ if (p.top_delta.isProvided())
+ {
+ p.top_delta = -p.top_delta;
+ }
if (p.bottom_delta.isProvided())
{
p.bottom_delta = -p.bottom_delta;
@@ -2609,6 +2695,46 @@ void LLView::setupParamsForExport(Params& p, LLView* parent)
p.layout = "topleft";
}
+//static
+void LLView::setupParamsForExport(Params& p, LLView* parent)
+{
+ // Don't convert if already top-left based
+ if (p.layout() == "topleft")
+ {
+ return;
+ }
+
+ // heuristic: Many of our floaters and panels were bulk-exported.
+ // These specify exactly bottom/left and height/width.
+ // Others were done by hand using bottom_delta and/or left_delta.
+ // Some rely on not specifying left to mean align with left edge.
+ // Try to convert both to use relative layout, but using top-left
+ // coordinates.
+ // Avoid rectangles where top/bottom/left/right was specified.
+ if (p.rect.height.isProvided() && p.rect.width.isProvided())
+ {
+ if (p.rect.bottom.isProvided() && p.rect.left.isProvided())
+ {
+ // standard bulk export, convert it
+ convert_to_relative_layout(p, parent);
+ }
+ else if (p.rect.bottom.isProvided() && p.left_delta.isProvided())
+ {
+ // hand layout with left_delta
+ convert_to_relative_layout(p, parent);
+ }
+ else if (p.bottom_delta.isProvided())
+ {
+ // hand layout with bottom_delta
+ // don't check for p.rect.left or p.left_delta because sometimes
+ // this layout doesn't set it for widgets that are left-aligned
+ convert_to_relative_layout(p, parent);
+ }
+ }
+
+ convert_coords_to_top_left(p, parent);
+}
+
LLView::tree_iterator_t LLView::beginTree()
{
return tree_iterator_t(this,
@@ -2621,3 +2747,14 @@ LLView::tree_iterator_t LLView::endTree()
// an empty iterator is an "end" iterator
return tree_iterator_t();
}
+
+// 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
+{
+ if (!mDefaultWidgets)
+ {
+ mDefaultWidgets = new default_widget_map_t();
+ }
+ return *mDefaultWidgets;
+}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 85e190c7d2..422f62f602 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -37,6 +37,7 @@
// the HUD or a dialog box or a button. It can also contain sub-views
// and child widgets
+#include "stdtypes.h"
#include "llcoord.h"
#include "llfontgl.h"
#include "llmortician.h"
@@ -48,7 +49,6 @@
#include "llui.h"
#include "lluistring.h"
#include "llviewquery.h"
-#include "llxmlnode.h"
#include "stdenums.h"
#include "lluistring.h"
#include "llcursortypes.h"
@@ -143,8 +143,8 @@ class LLView : public LLMouseHandler, public LLMortician
public:
struct Follows : public LLInitParam::Choice<Follows>
{
- Option<std::string> string;
- Option<U32> flags;
+ Alternative<std::string> string;
+ Alternative<U32> flags;
Follows()
: string(""),
@@ -176,17 +176,21 @@ public:
Optional<std::string> layout;
Optional<LLRect> rect;
- Optional<S32> top_delta,
- bottom_delta,
- right_delta,
- left_delta;
-
+ // 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
+
Optional<bool> center_horiz,
center_vert;
// these are nested attributes for LLLayoutPanel
//FIXME: get parent context involved in parsing traversal
- Deprecated user_resize,
+ Ignored user_resize,
auto_resize,
needs_translate;
@@ -285,8 +289,6 @@ public:
void moveChildToFrontOfTabGroup(LLUICtrl* child);
void moveChildToBackOfTabGroup(LLUICtrl* child);
- void addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node = NULL);
-
virtual bool addChild(LLView* view, S32 tab_group = 0);
// implemented in terms of addChild()
@@ -484,20 +486,23 @@ public:
virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
- template <class T> T* getDummyWidget(const std::string& name) const
+ template <class T> T* getDefaultWidget(const std::string& name) const
{
- dummy_widget_map_t::const_iterator found_it = mDummyWidgets.find(name);
- if (found_it == mDummyWidgets.end())
+ 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);
}
+ // determines allowable children when parsing XUI
+ virtual const widget_registry_t& getChildRegistry() const;
+
//////////////////////////////////////////////
// statics
//////////////////////////////////////////////
- static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node);
+ //static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node);
// focuses the item in the list after the currently-focused item, wrapping if necessary
static BOOL focusNext(LLView::child_list_t & result);
@@ -520,13 +525,13 @@ public:
// to be top-left based.
static void setupParamsForExport(Params& p, LLView* parent);
-protected:
//virtual BOOL addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; }
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleUnicodeCharHere(llwchar uni_char);
virtual void handleReshape(const LLRect& rect, bool by_user);
+protected:
void drawDebugRect();
void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
@@ -587,8 +592,11 @@ private:
static LLWindow* sWindow; // All root views must know about their window.
- typedef std::map<std::string, LLView*> dummy_widget_map_t;
- mutable dummy_widget_map_t mDummyWidgets;
+ 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;
+
+ default_widget_map_t& getDefaultWidgetMap() const;
public:
static BOOL sDebugRects; // Draw debug rects behind everything.
@@ -632,10 +640,10 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse, BO
}
if (create_if_missing)
{
- result = getDummyWidget<T>(name);
+ result = getDefaultWidget<T>(name);
if (!result)
{
- result = LLUICtrlFactory::createDummyWidget<T>(name);
+ result = LLUICtrlFactory::getDefaultWidget<T>(name);
if (result)
{
@@ -647,7 +655,7 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse, BO
return NULL;
}
- mDummyWidgets[name] = result;
+ getDefaultWidgetMap()[name] = result;
}
}
}
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index 540a9f7513..a5b09671bb 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -35,7 +35,7 @@
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
-static LLRegisterWidget<LLViewBorder> r("view_border");
+static LLDefaultWidgetRegistry::Register<LLViewBorder> r("view_border");
void LLViewBorder::BevelValues::declareValues()
{