diff options
author | Bryan O'Sullivan <bos@lindenlab.com> | 2009-06-22 15:02:19 -0700 |
---|---|---|
committer | Bryan O'Sullivan <bos@lindenlab.com> | 2009-06-22 15:02:19 -0700 |
commit | baa73fddd9287ddafd2d31551cb253b355ed910a (patch) | |
tree | e3f0986617fe6c0ee0a14df6aac13c6bb6f92507 /indra/llui | |
parent | dc3833f31b8a20220ddb1775e1625c016c397435 (diff) | |
parent | fcaa1ad46fd1df4cfec9dee12caf6e7b5bf32136 (diff) |
Merge with viewer-2.0.0-3 branch
Diffstat (limited to 'indra/llui')
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() { |