diff options
Diffstat (limited to 'indra/llui')
30 files changed, 438 insertions, 291 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 74b49b846e..82ec02d2eb 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -26,7 +26,6 @@ include_directories( ) set(llui_SOURCE_FILES - llalertdialog.cpp llbutton.cpp llcheckboxctrl.cpp llclipboard.cpp @@ -112,7 +111,6 @@ set(llui_SOURCE_FILES set(llui_HEADER_FILES CMakeLists.txt - llalertdialog.h llbutton.h llcallbackmap.h llcheckboxctrl.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 7721137e29..e9f6288f44 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -63,7 +63,6 @@ template class LLButton* LLView::getChild<class LLButton>( // globals loaded from settings.xml S32 LLBUTTON_H_PAD = 0; -S32 LLBUTTON_V_PAD = 0; S32 BTN_HEIGHT_SMALL= 0; S32 BTN_HEIGHT = 0; @@ -93,6 +92,7 @@ LLButton::Params::Params() flash_color("flash_color"), pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + pad_bottom("pad_bottom"), click_callback("click_callback"), mouse_down_callback("mouse_down_callback"), mouse_up_callback("mouse_up_callback"), @@ -148,6 +148,7 @@ LLButton::LLButton(const LLButton::Params& p) mHAlign(p.font_halign), mLeftHPad(p.pad_left), mRightHPad(p.pad_right), + mBottomVPad(p.pad_bottom), mHoverGlowStrength(p.hover_glow_amount), mCommitOnReturn(p.commit_on_return), mFadeWhenDisabled(FALSE), @@ -839,7 +840,9 @@ void LLButton::draw() // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. - mLastDrawCharsCount = mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset), + mLastDrawCharsCount = mGLFont->render(label, 0, + (F32)x, + (F32)(mBottomVPad + y_offset), label_color % alpha, mHAlign, LLFontGL::BOTTOM, LLFontGL::NORMAL, diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 4c7400220d..5e28b8cdff 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -49,7 +49,6 @@ // PLEASE please use these "constants" when building your own buttons. // They are loaded from settings.xml at run time. extern S32 LLBUTTON_H_PAD; -extern S32 LLBUTTON_V_PAD; extern S32 BTN_HEIGHT_SMALL; extern S32 BTN_HEIGHT; @@ -105,6 +104,7 @@ public: // layout Optional<S32> pad_right; Optional<S32> pad_left; + Optional<S32> pad_bottom; // under text label // callbacks Optional<CommitCallbackParam> click_callback, // alias -> commit_callback @@ -310,6 +310,7 @@ private: LLFontGL::HAlign mHAlign; S32 mLeftHPad; S32 mRightHPad; + S32 mBottomVPad; // under text label F32 mHoverGlowStrength; F32 mCurGlowStrength; diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 9c69e4f2b6..63faf44f9d 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -98,8 +98,15 @@ void LLDockableFloater::toggleInstance(const LLSD& sdname) else if (instance != NULL) { instance->setMinimized(FALSE); - instance->setVisible(TRUE); - gFloaterView->bringToFront(instance); + if (instance->getVisible()) + { + instance->setVisible(FALSE); + } + else + { + instance->setVisible(TRUE); + gFloaterView->bringToFront(instance); + } } } diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index d9b98b1c28..a93c666648 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -112,6 +112,7 @@ void LLDragHandleTop::setTitle(const std::string& title) params.font(font); params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); params.font_shadow(LLFontGL::DROP_SHADOW_SOFT); + params.use_ellipses = true; mTitleBox = LLUICtrlFactory::create<LLTextBox> (params); addChild( mTitleBox ); } diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 64a4824a17..09124c3013 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -530,7 +530,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) if ( !selectNextItemPair(true, reset_selection) && reset_selection) { // If case we are in accordion tab notify parent to go to the previous accordion - notifyParent(LLSD().with("action","select_prev")); + if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + resetSelection(); } break; } @@ -539,7 +540,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) if ( !selectNextItemPair(false, reset_selection) && reset_selection) { // If case we are in accordion tab notify parent to go to the next accordion - notifyParent(LLSD().with("action","select_next")); + if( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed + resetSelection(); } break; } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index fd7b64af02..f7fd2dbdfe 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1649,6 +1649,7 @@ void LLFloater::draw() } else { + //FIXME: get rid of this hack // draw children LLView* focused_child = dynamic_cast<LLView*>(gFocusMgr.getKeyboardFocus()); BOOL focused_child_visible = FALSE; @@ -2703,6 +2704,19 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o output_node, output_params, &default_params); } + // Default floater position to top-left corner of screen + // However, some legacy floaters have explicit top or bottom + // coordinates set, so respect their wishes. + if (!params.rect.top.isProvided() && !params.rect.bottom.isProvided()) + { + params.rect.top.set(0); + } + if (!params.rect.left.isProvided() && !params.rect.right.isProvided()) + { + params.rect.left.set(0); + } + + params.from_xui = true; setupParams(params, parent); initFromParams(params); diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 1fb618adee..5e15fa3919 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -246,6 +246,7 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o output_node, output_params, &default_params); } + p.from_xui = true; setupParams(p, parent); LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p); diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index abd5436018..c1af428674 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -45,9 +45,8 @@ public: { Optional<std::string> orientation; Optional<S32> border_size; - Optional<bool> animate; - Optional<bool> clip; - // mMinWidth and mMinHeight are calculated, not set in XML + Optional<bool> animate, + clip; Params(); }; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index fd5c2b7fef..202ed04fbc 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -97,7 +97,7 @@ const U32 SEPARATOR_HEIGHT_PIXELS = 8; const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10; const S32 MENU_ITEM_PADDING = 4; -const std::string BOOLEAN_TRUE_PREFIX( "X" ); +const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK const std::string BRANCH_SUFFIX( ">" ); const std::string ARROW_UP ("^^^^^^^"); const std::string ARROW_DOWN("vvvvvvv"); @@ -3905,7 +3905,7 @@ BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu) item = LLUICtrlFactory::create<LLContextMenuBranch>(p); LLMenuGL::sMenuContainer->addChild(item->getBranch()); - item->setFont( LLFontGL::getFontSansSerifSmall() ); + item->setFont( LLFontGL::getFontSansSerif() ); return append( item ); } diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index 87938c19d4..7323323d8c 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -328,7 +328,7 @@ void LLMultiSliderCtrl::updateText() // static void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata) { - LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl); + LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); if (!ctrl) return; @@ -369,7 +369,7 @@ void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata) // static void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata) { - LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl); + LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); if (!self) return; diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 750b190953..738a96f730 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -37,7 +37,6 @@ #define LLPANEL_CPP #include "llpanel.h" -#include "llalertdialog.h" #include "llfocusmgr.h" #include "llfontgl.h" #include "llrect.h" @@ -542,6 +541,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu output_node, output_params, &default_params); } + params.from_xui = true; setupParams(params, parent); { LLFastTimer timer(FTM_PANEL_CONSTRUCTION); diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index 86bd2f05ce..997b9c13f8 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -43,15 +43,43 @@ #include "llui.h" #include "llfocusmgr.h" #include "lluictrlfactory.h" +#include "llsdutil.h" static LLDefaultChildRegistry::Register<LLRadioGroup> r1("radio_group"); -static RadioGroupRegistry::Register<LLRadioCtrl> register_radio_ctrl("radio_item"); +/* + * An invisible view containing multiple mutually exclusive toggling + * buttons (usually radio buttons). Automatically handles the mutex + * condition by highlighting only one button at a time. + */ +class LLRadioCtrl : public LLCheckBoxCtrl +{ +public: + typedef LLRadioGroup::ItemParams Params; + /*virtual*/ ~LLRadioCtrl(); + /*virtual*/ void setValue(const LLSD& value); + + /*virtual*/ BOOL postBuild(); + + LLSD getPayload() { return mPayload; } + // Ensure label is in an attribute, not the contents + static void setupParamsForExport(Params& p, LLView* parent); + +protected: + LLRadioCtrl(const LLRadioGroup::ItemParams& p); + friend class LLUICtrlFactory; + + LLSD mPayload; // stores data that this item represents in the radio group +}; +static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item"); LLRadioGroup::Params::Params() -: has_border("draw_border") +: has_border("draw_border"), + items("item") { + addSynonym(items, "radio_item"); + name = "radio_group"; mouse_opaque = true; follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP; @@ -76,6 +104,25 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p) } } +void LLRadioGroup::initFromParams(const Params& p) +{ + LLUICtrl::initFromParams(p); + for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin(); + it != p.items().end(); + ++it) + { + LLRadioGroup::ItemParams item_params(*it); + + item_params.font.setIfNotProvided(mFont); // apply radio group font by default + item_params.commit_callback.function = boost::bind(&LLRadioGroup::onClickButton, this, _1); + item_params.from_xui = p.from_xui; + + LLRadioCtrl* item = LLUICtrlFactory::create<LLRadioCtrl>(item_params, this); + mRadioButtons.push_back(item); + } +} + + LLRadioGroup::~LLRadioGroup() { } @@ -141,7 +188,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled) BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) { - if (index < 0 || index >= (S32)mRadioButtons.size()) + if (index < 0 || (S32)mRadioButtons.size() <= index ) { return FALSE; } @@ -170,7 +217,7 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) if (!from_event) { - setControlValue(getSelectedIndex()); + setControlValue(getValue()); } return TRUE; @@ -235,27 +282,6 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask) return handled; } - -// When adding a child button, we need to ensure that the radio -// group gets a message when the button is clicked. - -/*virtual*/ -bool LLRadioGroup::addChild(LLView* view, S32 tab_group) -{ - bool res = LLView::addChild(view, tab_group); - if (res) - { - LLRadioCtrl* radio_ctrl = dynamic_cast<LLRadioCtrl*>(view); - if (radio_ctrl) - { - radio_ctrl->setFont(mFont); - radio_ctrl->setCommitCallback(boost::bind(&LLRadioGroup::onClickButton, this, _1)); - mRadioButtons.push_back(radio_ctrl); - } - } - return res; -} - BOOL LLRadioGroup::handleMouseDown(S32 x, S32 y, MASK mask) { // grab focus preemptively, before child button takes mousecapture @@ -302,13 +328,12 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl) void LLRadioGroup::setValue( const LLSD& value ) { - std::string value_name = value.asString(); int idx = 0; for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { LLRadioCtrl* radio = *iter; - if (radio->getName() == value_name) + if (radio->getPayload().asString() == value.asString()) { setSelectedIndex(idx); idx = -1; @@ -325,7 +350,7 @@ void LLRadioGroup::setValue( const LLSD& value ) } else { - llwarns << "LLRadioGroup::setValue: value not found: " << value_name << llendl; + llwarns << "LLRadioGroup::setValue: value not found: " << value.asString() << llendl; } } } @@ -337,7 +362,7 @@ LLSD LLRadioGroup::getValue() const for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if (idx == index) return LLSD((*iter)->getName()); + if (idx == index) return LLSD((*iter)->getPayload()); ++idx; } return LLSD(); @@ -357,11 +382,10 @@ LLUUID LLRadioGroup::getCurrentID() const BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected) { S32 idx = 0; - std::string value_string = value.asString(); for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if((*iter)->getName() == value_string) + if((*iter)->getPayload().asString() == value.asString()) { setSelectedIndex(idx); return TRUE; @@ -380,11 +404,10 @@ LLSD LLRadioGroup::getSelectedValue() BOOL LLRadioGroup::isSelected(const LLSD& value) const { S32 idx = 0; - std::string value_string = value.asString(); for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if((*iter)->getName() == value_string) + if((*iter)->getPayload().asString() == value.asString()) { if (idx == mSelectedIndex) { @@ -406,9 +429,21 @@ BOOL LLRadioGroup::operateOnAll(EOperation op) return FALSE; } -LLRadioCtrl::LLRadioCtrl(const LLRadioCtrl::Params& p) - : LLCheckBoxCtrl(p) +LLRadioGroup::ItemParams::ItemParams() +: value("value") { + addSynonym(value, "initial_value"); +} + +LLRadioCtrl::LLRadioCtrl(const LLRadioGroup::ItemParams& p) +: LLCheckBoxCtrl(p), + mPayload(p.value) +{ + // use name as default "Value" for backwards compatibility + if (!p.value.isProvided()) + { + mPayload = p.name(); + } } BOOL LLRadioCtrl::postBuild() diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h index 1e9b5115f8..b178bb36ca 100644 --- a/indra/llui/llradiogroup.h +++ b/indra/llui/llradiogroup.h @@ -37,35 +37,6 @@ #include "llcheckboxctrl.h" #include "llctrlselectioninterface.h" - -/* - * An invisible view containing multiple mutually exclusive toggling - * buttons (usually radio buttons). Automatically handles the mutex - * condition by highlighting only one button at a time. - */ -class LLRadioCtrl : public LLCheckBoxCtrl -{ -public: - struct Params : public LLInitParam::Block<Params, LLCheckBoxCtrl::Params> - {}; - - /*virtual*/ ~LLRadioCtrl(); - /*virtual*/ void setValue(const LLSD& value); - - /*virtual*/ BOOL postBuild(); - - // Ensure label is in an attribute, not the contents - static void setupParamsForExport(Params& p, LLView* parent); - -protected: - LLRadioCtrl(const Params& p); - friend class LLUICtrlFactory; -}; - - -struct RadioGroupRegistry : public LLChildRegistry<RadioGroupRegistry> -{}; - /* * An invisible view containing multiple mutually exclusive toggling * buttons (usually radio buttons). Automatically handles the mutex @@ -76,25 +47,31 @@ class LLRadioGroup { public: + struct ItemParams : public LLInitParam::Block<ItemParams, LLCheckBoxCtrl::Params> + { + Optional<LLSD> value; + ItemParams(); + }; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<bool> has_border; + Optional<bool> has_border; + Multiple<ItemParams, AtLeast<1> > items; Params(); }; - // my valid children are stored in this registry - typedef RadioGroupRegistry child_registry_t; - protected: LLRadioGroup(const Params&); friend class LLUICtrlFactory; public: + + /*virtual*/ void initFromParams(const Params&); + virtual ~LLRadioGroup(); virtual BOOL postBuild(); - virtual bool addChild(LLView* view, S32 tab_group = 0); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -134,7 +111,7 @@ public: private: const LLFontGL* mFont; S32 mSelectedIndex; - typedef std::vector<LLRadioCtrl*> button_list_t; + typedef std::vector<class LLRadioCtrl*> button_list_t; button_list_t mRadioButtons; BOOL mHasBorder; diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index bd2d595174..714aca9337 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -50,15 +50,17 @@ class LLSearchEditor : public LLUICtrl public: struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> { - Optional<LLButton::Params> search_button, clear_button; - Optional<bool> search_button_visible, clear_button_visible; + Optional<LLButton::Params> search_button, + clear_button; + Optional<bool> search_button_visible, + clear_button_visible; Optional<commit_callback_t> keystroke_callback; Params() - : search_button("search_button") - , search_button_visible("search_button_visible") - , clear_button("clear_button") - , clear_button_visible("clear_button_visible") + : search_button("search_button"), + search_button_visible("search_button_visible"), + clear_button("clear_button"), + clear_button_visible("clear_button_visible") { name = "search_editor"; } diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index d7d61cf6cb..83e2e3db50 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -120,6 +120,8 @@ LLTabContainer::Params::Params() tab_min_width("tab_min_width"), tab_max_width("tab_max_width"), tab_height("tab_height"), + label_pad_bottom("label_pad_bottom"), + label_pad_left("label_pad_left"), tab_position("tab_position"), hide_tabs("hide_tabs", false), tab_padding_right("tab_padding_right"), @@ -145,6 +147,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mMinTabWidth(0), mMaxTabWidth(p.tab_max_width), mTabHeight(p.tab_height), + mLabelPadBottom(p.label_pad_bottom), + mLabelPadLeft(p.label_pad_left), mPrevArrowBtn(NULL), mNextArrowBtn(NULL), mIsVertical( p.tab_position == LEFT ), @@ -906,7 +910,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) if (placeholder) { - btn_rect.translate(0, -LLBUTTON_V_PAD-2); + btn_rect.translate(0, -6); // *TODO: make configurable LLTextBox::Params params; params.name(trimmed_label); params.rect(btn_rect); @@ -933,6 +937,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.image_selected(mMiddleTabParams.tab_left_image_selected); p.scale_image(true); p.font_halign = mFontHalign; + p.pad_bottom( mLabelPadBottom ); p.tab_stop(false); p.label_shadow(false); if (indent) @@ -956,8 +961,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.tab_stop(false); p.label_shadow(false); // Try to squeeze in a bit more text - p.pad_left(4); + p.pad_left( mLabelPadLeft ); p.pad_right(2); + p.pad_bottom( mLabelPadBottom ); p.font_halign = mFontHalign; p.follows.flags = FOLLOWS_LEFT; p.follows.flags = FOLLOWS_LEFT; @@ -1897,6 +1903,3 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y) } } } - - - diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index be9c6c7d06..5d0f194bf9 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -79,7 +79,9 @@ public: Optional<S32> tab_width, tab_min_width, tab_max_width, - tab_height; + tab_height, + label_pad_bottom, + label_pad_left; Optional<bool> hide_tabs; Optional<S32> tab_padding_right; @@ -261,6 +263,11 @@ private: S32 mTotalTabWidth; S32 mTabHeight; + // Padding under the text labels of tab buttons + S32 mLabelPadBottom; + // Padding to the left of text labels of tab buttons + S32 mLabelPadLeft; + LLFrameTimer mDragAndDropDelayTimer; LLFontGL::HAlign mFontHalign; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e0503a0844..cb0907a771 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -312,7 +312,7 @@ void LLTextBase::drawSelectionBackground() S32 selection_left = llmin( mSelectionStart, mSelectionEnd ); S32 selection_right = llmax( mSelectionStart, mSelectionEnd ); - LLRect selection_rect = mTextRect; + LLRect selection_rect = mVisibleTextRect; // Skip through the lines we aren't drawing. LLRect content_display_rect = getVisibleDocumentRect(); @@ -391,7 +391,7 @@ void LLTextBase::drawSelectionBackground() ++rect_it) { LLRect selection_rect = *rect_it; - selection_rect.translate(mTextRect.mLeft - content_display_rect.mLeft, mTextRect.mBottom - content_display_rect.mBottom); + selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); gl_rect_2d(selection_rect, selection_color); } } @@ -538,10 +538,10 @@ void LLTextBase::drawText() line_end = next_start; } - LLRect text_rect(line.mRect.mLeft + mTextRect.mLeft - scrolled_view_rect.mLeft, - line.mRect.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom, + LLRect text_rect(line.mRect.mLeft + mVisibleTextRect.mLeft - scrolled_view_rect.mLeft, + line.mRect.mTop - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom, llmin(mDocumentView->getRect().getWidth(), line.mRect.mRight) - scrolled_view_rect.mLeft, - line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom); + line.mRect.mBottom - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom); // draw a single line of text S32 seg_start = line_start; @@ -561,14 +561,14 @@ void LLTextBase::drawText() S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart(); - if (mUseEllipses - && clipped_end == line_end - && next_line == last_line - && last_line < (S32)mLineInfoList.size()) + if (mUseEllipses // using ellipses + && clipped_end == line_end // last segment on line + && next_line == last_line // this is the last visible line + && last_line < (S32)mLineInfoList.size()) // and there is more text to display { - // more text to go, but we can't fit it - // so attempt to draw one extra character to force ellipses - clipped_end++; + // more lines of text to go, but we can't fit them + // so shrink text rect to force ellipses + text_rect.mRight -= 2; } text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect)); @@ -949,7 +949,7 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) LLUICtrl::reshape( width, height, called_from_parent ); // do this first after reshape, because other things depend on - // up-to-date mTextRect + // up-to-date mVisibleTextRect updateRects(); needsReflow(); @@ -984,7 +984,7 @@ void LLTextBase::draw() : hasFocus() ? mFocusBgColor.get() : mWriteableBgColor.get(); - gl_rect_2d(mTextRect, bg_color, TRUE); + gl_rect_2d(mVisibleTextRect, bg_color, TRUE); } // draw document view @@ -1053,9 +1053,9 @@ S32 LLTextBase::getLeftOffset(S32 width) case LLFontGL::LEFT: return mHPad; case LLFontGL::HCENTER: - return mHPad + (mTextRect.getWidth() - width - mHPad) / 2; + return mHPad + (mVisibleTextRect.getWidth() - width - mHPad) / 2; case LLFontGL::RIGHT: - return mTextRect.getWidth() - width; + return mVisibleTextRect.getWidth() - width; default: return mHPad; } @@ -1071,17 +1071,17 @@ void LLTextBase::reflow(S32 start_index) while(mReflowNeeded) { - mReflowNeeded = FALSE; + mReflowNeeded = false; // shrink document to minimum size (visible portion of text widget) // to force inlined widgets with follows set to shrink - mDocumentView->setShape(mTextRect); + mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos); - bool follow_selection = mTextRect.overlaps(old_cursor_rect); // cursor is visible - old_cursor_rect.translate(-mTextRect.mLeft, -mTextRect.mBottom); + bool follow_selection = mVisibleTextRect.overlaps(old_cursor_rect); // cursor is visible + old_cursor_rect.translate(-mVisibleTextRect.mLeft, -mVisibleTextRect.mBottom); S32 first_line = getFirstVisibleLine(); @@ -1094,15 +1094,15 @@ void LLTextBase::reflow(S32 start_index) } LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex); // subtract off effect of horizontal scrollbar from local position of first char - first_char_rect.translate(-mTextRect.mLeft, -mTextRect.mBottom); + first_char_rect.translate(-mVisibleTextRect.mLeft, -mVisibleTextRect.mBottom); S32 cur_top = 0; segment_set_t::iterator seg_iter = mSegments.begin(); S32 seg_offset = 0; S32 line_start_index = 0; - const S32 text_width = mTextRect.getWidth() - mHPad; // reserve room for margin - S32 remaining_pixels = text_width; + const S32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin + S32 remaining_pixels = text_available_width; LLWString text(getWText()); S32 line_count = 0; @@ -1137,15 +1137,21 @@ void LLTextBase::reflow(S32 start_index) // grow line height as necessary based on reported height of this segment line_height = llmax(line_height, segment_height); remaining_pixels -= segment_width; + if (remaining_pixels < 0) + { + // getNumChars() and getDimensions() should return consistent results + remaining_pixels = 0; + } seg_offset += character_count; S32 last_segment_char_on_line = segment->getStart() + seg_offset; - S32 text_left = getLeftOffset(text_width - remaining_pixels); + S32 text_actual_width = text_available_width - remaining_pixels; + S32 text_left = getLeftOffset(text_actual_width); LLRect line_rect(text_left, cur_top, - text_left + (text_width - remaining_pixels), + text_left + text_actual_width, cur_top - line_height); // if we didn't finish the current segment... @@ -1160,7 +1166,7 @@ void LLTextBase::reflow(S32 start_index) line_start_index = segment->getStart() + seg_offset; cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - remaining_pixels = text_width; + remaining_pixels = text_available_width; line_height = 0; } // ...just consumed last segment.. @@ -1188,7 +1194,7 @@ void LLTextBase::reflow(S32 start_index) line_start_index = segment->getStart() + seg_offset; cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; line_height = 0; - remaining_pixels = text_width; + remaining_pixels = text_available_width; } ++seg_iter; seg_offset = 0; @@ -1238,10 +1244,10 @@ void LLTextBase::reflow(S32 start_index) } } -LLRect LLTextBase::getContentsRect() +LLRect LLTextBase::getTextBoundingRect() { reflow(); - return mContentsRect; + return mTextBoundingRect; } @@ -1760,7 +1766,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round LLRect visible_region = getVisibleDocumentRect(); // binary search for line that starts before local_y - line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mTextRect.mBottom + visible_region.mBottom, compare_bottom()); + line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mVisibleTextRect.mBottom + visible_region.mBottom, compare_bottom()); if (line_iter == mLineInfoList.end()) { @@ -1768,7 +1774,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round } S32 pos = getLength(); - S32 start_x = mTextRect.mLeft + line_iter->mRect.mLeft; + S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft; segment_set_t::iterator line_seg_iter; S32 line_seg_offset; @@ -1879,7 +1885,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const if (mLineInfoList.empty()) { // return default height rect in upper left - local_rect = mTextRect; + local_rect = mVisibleTextRect; local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight()); return local_rect; } @@ -1890,8 +1896,8 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const // compensate for scrolled, inset view of doc LLRect scrolled_view_rect = getVisibleDocumentRect(); local_rect = doc_rect; - local_rect.translate(mTextRect.mLeft - scrolled_view_rect.mLeft, - mTextRect.mBottom - scrolled_view_rect.mBottom); + local_rect.translate(mVisibleTextRect.mLeft - scrolled_view_rect.mLeft, + mVisibleTextRect.mBottom - scrolled_view_rect.mBottom); return local_rect; } @@ -1991,7 +1997,7 @@ void LLTextBase::changeLine( S32 delta ) LLRect visible_region = getVisibleDocumentRect(); - S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mRect.mBottom + mTextRect.mBottom - visible_region.mBottom, TRUE); + S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mRect.mBottom + mVisibleTextRect.mBottom - visible_region.mBottom, TRUE); setCursorPos(new_cursor_pos, true); } @@ -2067,56 +2073,64 @@ void LLTextBase::updateRects() { if (mLineInfoList.empty()) { - mContentsRect = LLRect(0, mVPad, mHPad, 0); + mTextBoundingRect = LLRect(0, mVPad, mHPad, 0); } else { - mContentsRect = mLineInfoList.begin()->mRect; + mTextBoundingRect = mLineInfoList.begin()->mRect; for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin(); line_iter != mLineInfoList.end(); ++line_iter) { - mContentsRect.unionWith(line_iter->mRect); + mTextBoundingRect.unionWith(line_iter->mRect); } - mContentsRect.mTop += mVPad; + mTextBoundingRect.mTop += mVPad; // subtract a pixel off the bottom to deal with rounding errors in measuring font height - mContentsRect.mBottom -= 1; + mTextBoundingRect.mBottom -= 1; - S32 delta_pos = -mContentsRect.mBottom; + S32 delta_pos = -mTextBoundingRect.mBottom; // move line segments to fit new document rect for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) { it->mRect.translate(0, delta_pos); } - mContentsRect.translate(0, delta_pos); + mTextBoundingRect.translate(0, delta_pos); } // update document container dimensions according to text contents - LLRect doc_rect = mContentsRect; - // use old mTextRect constraint document to width of viewable region + LLRect doc_rect = mTextBoundingRect; + // use old mVisibleTextRect constraint document to width of viewable region doc_rect.mLeft = 0; - doc_rect.mRight = llmax(mTextRect.getWidth(), mContentsRect.mRight); + + // allow horizontal scrolling? + // if so, use entire width of text contents + // otherwise, stop at width of mVisibleTextRect + doc_rect.mRight = mScroller + ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) + : mVisibleTextRect.getWidth(); mDocumentView->setShape(doc_rect); - //update mTextRect *after* mDocumentView has been resized + //update mVisibleTextRect *after* mDocumentView has been resized // so that scrollbars are added if document needs to scroll - // since mTextRect does not include scrollbars - LLRect old_text_rect = mTextRect; - mTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + // since mVisibleTextRect does not include scrollbars + LLRect old_text_rect = mVisibleTextRect; + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); //FIXME: replace border with image? if (mBorderVisible) { - mTextRect.stretch(-1); + mVisibleTextRect.stretch(-1); } - if (mTextRect != old_text_rect) + if (mVisibleTextRect != old_text_rect) { needsReflow(); } - // update document container again, using new mTextRect - doc_rect.mRight = llmax(mTextRect.getWidth(), mContentsRect.mRight); + // update document container again, using new mVisibleTextRect (that has scrollbars enabled as needed) + doc_rect.mRight = mScroller + ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) + : mVisibleTextRect.getWidth(); mDocumentView->setShape(doc_rect); } @@ -2154,7 +2168,7 @@ LLRect LLTextBase::getVisibleDocumentRect() const LLRect doc_rect = mDocumentView->getLocalRect(); doc_rect.mLeft -= mDocumentView->getRect().mLeft; // adjust for height of text above widget baseline - doc_rect.mBottom = doc_rect.getHeight() - mTextRect.getHeight(); + doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); return doc_rect; } } @@ -2413,10 +2427,18 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt if (num_chars > 0) { LLWString text = mEditor.getWText(); - width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); // if last character is a newline, then return true, forcing line break llwchar last_char = text[mStart + first_char + num_chars - 1]; - force_newline = (last_char == '\n'); + if (last_char == '\n') + { + force_newline = true; + // don't count newline in font width + width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars - 1); + } + else + { + width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); + } } else { @@ -2447,6 +2469,12 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin { LLWString text = mEditor.getWText(); + LLUIImagePtr image = mStyle->getImage(); + if( image.notNull()) + { + num_pixels -= image->getWidth(); + } + // search for newline and if found, truncate there S32 last_char = mStart + segment_offset; for (; last_char != mEnd; ++last_char) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 0138ca3704..a1f8ba39ae 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -156,8 +156,8 @@ public: void addDocumentChild(LLView* view); void removeDocumentChild(LLView* view); const LLView* getDocumentView() const { return mDocumentView; } - LLRect getTextRect() { return mTextRect; } - LLRect getContentsRect(); + LLRect getVisibleTextRect() { return mVisibleTextRect; } + LLRect getTextBoundingRect(); LLRect getVisibleDocumentRect() const; S32 getVPad() { return mVPad; } @@ -311,8 +311,8 @@ protected: // text segmentation and flow segment_set_t mSegments; line_list_t mLineInfoList; - LLRect mTextRect; // The rect in which text is drawn. Excludes borders. - LLRect mContentsRect; + LLRect mVisibleTextRect; // The rect in which text is drawn. Excludes borders. + LLRect mTextBoundingRect; // colors LLUIColor mCursorColor; diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 0bd0ab59fb..a1f5b5726b 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -134,12 +134,12 @@ void LLTextBox::setClickedCallback( boost::function<void (void*)> cb, void* user S32 LLTextBox::getTextPixelWidth() { - return getContentsRect().getWidth(); + return getTextBoundingRect().getWidth(); } S32 LLTextBox::getTextPixelHeight() { - return getContentsRect().getHeight(); + return getTextBoundingRect().getHeight(); } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index faf9ccbeb8..e8fc9475a5 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -758,8 +758,8 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { mScroller->autoScroll(x, y); } - S32 clamped_x = llclamp(x, mTextRect.mLeft, mTextRect.mRight); - S32 clamped_y = llclamp(y, mTextRect.mBottom, mTextRect.mTop); + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); setCursorAtLocalPos( clamped_x, clamped_y, true ); mSelectionEnd = mCursorPos; } @@ -809,8 +809,8 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { mScroller->autoScroll(x, y); } - S32 clamped_x = llclamp(x, mTextRect.mLeft, mTextRect.mRight); - S32 clamped_y = llclamp(y, mTextRect.mBottom, mTextRect.mTop); + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); setCursorAtLocalPos( clamped_x, clamped_y, true ); endSelection(); } @@ -2075,8 +2075,8 @@ void LLTextEditor::drawPreeditMarker() const S32 line_height = llround( mDefaultFont->getLineHeight() ); S32 line_start = getLineStart(cur_line); - S32 line_y = mTextRect.mTop - line_height; - while((mTextRect.mBottom <= line_y) && (num_lines > cur_line)) + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) { S32 next_start = -1; S32 line_end = text_len; @@ -2108,12 +2108,12 @@ void LLTextEditor::drawPreeditMarker() continue; } - S32 preedit_left = mTextRect.mLeft; + S32 preedit_left = mVisibleTextRect.mLeft; if (left > line_start) { preedit_left += mDefaultFont->getWidth(text, line_start, left - line_start); } - S32 preedit_right = mTextRect.mLeft; + S32 preedit_right = mVisibleTextRect.mLeft; if (right < line_end) { preedit_right += mDefaultFont->getWidth(text, line_start, right - line_start); @@ -2154,7 +2154,7 @@ void LLTextEditor::drawLineNumbers() { LLGLSUIDefault gls_ui; LLRect scrolled_view_rect = getVisibleDocumentRect(); - LLRect content_rect = getTextRect(); + LLRect content_rect = getVisibleTextRect(); LLLocalClipRect clip(content_rect); S32 first_line = getFirstVisibleLine(); S32 num_lines = getLineCount(); @@ -2180,12 +2180,12 @@ void LLTextEditor::drawLineNumbers() { line_info& line = mLineInfoList[cur_line]; - if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) + if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mVisibleTextRect.mBottom) { break; } - S32 line_bottom = line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom; + S32 line_bottom = line.mRect.mBottom - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom; // draw the line numbers if(line.mLineNum != last_line_num && line.mRect.mTop <= scrolled_view_rect.mTop) { @@ -2216,8 +2216,8 @@ void LLTextEditor::draw() { { // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mTextRect - LLRect clip_rect(mTextRect); + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); clip_rect.stretch(1); LLLocalClipRect clip(clip_rect); drawPreeditMarker(); @@ -2781,7 +2781,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect if (control) { LLRect control_rect_screen; - localRectToScreen(mTextRect, &control_rect_screen); + localRectToScreen(mVisibleTextRect, &control_rect_screen); LLUI::screenRectToGL(control_rect_screen, control); } @@ -2832,8 +2832,8 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect if (coord) { - const S32 query_x = mTextRect.mLeft + mDefaultFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + const S32 query_x = mVisibleTextRect.mLeft + mDefaultFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; S32 query_screen_x, query_screen_y; localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); @@ -2841,13 +2841,13 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect if (bounds) { - S32 preedit_left = mTextRect.mLeft; + S32 preedit_left = mVisibleTextRect.mLeft; if (preedit_left_position > current_line_start) { preedit_left += mDefaultFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); } - S32 preedit_right = mTextRect.mLeft; + S32 preedit_right = mVisibleTextRect.mLeft; if (preedit_right_position < current_line_end) { preedit_right += mDefaultFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); @@ -2857,7 +2857,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect preedit_right += mDefaultFont->getWidth(text, current_line_start, current_line_end - current_line_start); } - const S32 preedit_top = mTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; const S32 preedit_bottom = preedit_top - line_height; const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 6603887905..1ea6b66a93 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1896,17 +1896,26 @@ namespace LLInitParam control("") {} - LLUIColor TypedParam<LLUIColor>::getValueFromBlock() const + void TypedParam<LLUIColor>::setValueFromBlock() const { if (control.isProvided()) { - return LLUIColorTable::instance().getColor(control); + mData.mValue = LLUIColorTable::instance().getColor(control); } else { - return LLColor4(red, green, blue, alpha); + mData.mValue = LLColor4(red, green, blue, alpha); } } + + void TypedParam<LLUIColor>::setBlockFromValue() + { + LLColor4 color = mData.mValue.get(); + red = color.mV[VRED]; + green = color.mV[VGREEN]; + blue = color.mV[VBLUE]; + alpha = color.mV[VALPHA]; + } void TypeValues<LLUIColor>::declareValues() { @@ -1932,28 +1941,33 @@ namespace LLInitParam addSynonym(name, ""); } - const LLFontGL* TypedParam<const LLFontGL*>::getValueFromBlock() const + void TypedParam<const LLFontGL*>::setValueFromBlock() const { - if (name.isProvided()) + const LLFontGL* res_fontp = LLFontGL::getFontByName(name); + if (res_fontp) { - const LLFontGL* res_fontp = LLFontGL::getFontByName(name); - if (res_fontp) - { - return res_fontp; - } + mData.mValue = res_fontp; + return; + } - U8 fontstyle = 0; - fontstyle = LLFontGL::getStyleFromString(style()); - LLFontDescriptor desc(name(), size(), fontstyle); - const LLFontGL* fontp = LLFontGL::getFont(desc); - if (fontp) - { - return fontp; - } + U8 fontstyle = 0; + fontstyle = LLFontGL::getStyleFromString(style()); + LLFontDescriptor desc(name(), size(), fontstyle); + const LLFontGL* fontp = LLFontGL::getFont(desc); + if (fontp) + { + mData.mValue = fontp; + } + } + + void TypedParam<const LLFontGL*>::setBlockFromValue() + { + if (mData.mValue) + { + name = LLFontGL::nameFromFont(mData.mValue); + size = LLFontGL::sizeFromFont(mData.mValue); + style = LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()); } - - // default to current value - return mData.mValue; } TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) @@ -1966,7 +1980,7 @@ namespace LLInitParam height("height") {} - LLRect TypedParam<LLRect>::getValueFromBlock() const + void TypedParam<LLRect>::setValueFromBlock() const { LLRect rect; @@ -2027,7 +2041,17 @@ namespace LLInitParam rect.mBottom = bottom; rect.mTop = top; } - return rect; + mData.mValue = rect; + } + + void TypedParam<LLRect>::setBlockFromValue() + { + left = mData.mValue.mLeft; + right = mData.mValue.mRight; + bottom = mData.mValue.mBottom; + top = mData.mValue.mTop; + width.setProvided(false); + height.setProvided(false); } TypedParam<LLCoordGL>::TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) @@ -2037,9 +2061,15 @@ namespace LLInitParam { } - LLCoordGL TypedParam<LLCoordGL>::getValueFromBlock() const + void TypedParam<LLCoordGL>::setValueFromBlock() const + { + mData.mValue.set(x, y); + } + + void TypedParam<LLCoordGL>::setBlockFromValue() { - return LLCoordGL(x, y); + x = mData.mValue.mX; + y = mData.mValue.mY; } diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 5ec07f1941..5840e76f5c 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -379,7 +379,8 @@ namespace LLInitParam TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count); - LLRect getValueFromBlock() const; + void setValueFromBlock() const; + void setBlockFromValue(); }; template<> @@ -401,7 +402,8 @@ namespace LLInitParam Optional<std::string> control; TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count); - LLUIColor getValueFromBlock() const; + void setValueFromBlock() const; + void setBlockFromValue(); }; // provide a better default for Optional<const LLFontGL*> than NULL @@ -429,7 +431,8 @@ namespace LLInitParam style; TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count); - const LLFontGL* getValueFromBlock() const; + void setValueFromBlock() const; + void setBlockFromValue(); }; template<> @@ -467,7 +470,8 @@ namespace LLInitParam y; TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count); - LLCoordGL getValueFromBlock() const; + void setValueFromBlock() const; + void setBlockFromValue(); }; } diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 3643bf44f7..27237800d4 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -105,9 +105,12 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa } } +static LLFastTimer::DeclareTimer FTM_CREATE_CHILDREN("Create XUI Children"); + //static void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node) { + LLFastTimer ft(FTM_CREATE_CHILDREN); if (node.isNull()) return; for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) @@ -393,7 +396,7 @@ BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& na //static void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group) { - if (tab_group < 0) tab_group = parent->getLastTabGroup(); + if (tab_group == S32_MAX) tab_group = parent->getLastTabGroup(); parent->addChild(view, tab_group); } @@ -454,8 +457,3 @@ const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_ty return LLWidgetNameRegistry::instance().getValue(widget_type); } -// static -void LLUICtrlFactory::connect(LLView* parent, LLView* child) -{ - parent->addChild(child); -} diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 55d7d745eb..6788f29ba9 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -180,34 +180,54 @@ public: void popFactoryFunctions(); template<typename T> - static T* create(typename T::Params& params, LLView* parent = NULL) + static T* createWidget(typename T::Params& params, LLView* parent = NULL) { - //#pragma message("Generating LLUICtrlFactory::create") - params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get()); - //S32 foo = "test"; + T* widget = NULL; + + T::setupParams(params, parent); if (!params.validateBlock()) { llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; + //return NULL; + } + + { + LLFastTimer timer(FTM_WIDGET_CONSTRUCTION); + widget = new T(params); + } + { + LLFastTimer timer(FTM_INIT_FROM_PARAMS); + widget->initFromParams(params); } - T* widget = new T(params); - widget->initFromParams(params); + if (parent) { - connect(parent, widget); + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX; + setCtrlParent(widget, parent, tab_group); } return widget; } - // fix for gcc template instantiation annoyance - static void connect(LLView* parent, LLView* child); - + template<typename T> + static T* create(typename T::Params& params, LLView* parent = NULL) + { + params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get()); + + T* widget = createWidget<T>(params, parent); + if (widget) + { + widget->postBuild(); + } + + return widget; + } + LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t&, LLXMLNodePtr output_node ); template<typename T> static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry, LLXMLNodePtr output_node = NULL) { - //#pragma message("Generating LLUICtrlFactory::createFromFile") T* widget = NULL; std::string skinned_filename = findSkinnedFilename(filename); @@ -272,7 +292,6 @@ fail: { LLFastTimer timer(FTM_WIDGET_SETUP); - //#pragma message("Generating LLUICtrlFactory::defaultBuilder") typename T::Params params(getDefaultParams<T>()); LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); @@ -290,36 +309,17 @@ fail: } // Apply layout transformations, usually munging rect - T::setupParams(params, parent); + params.from_xui = true; + T* widget = createWidget<T>(params, parent); - if (!params.validateBlock()) - { - llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; - } - T* widget; - { - LLFastTimer timer(FTM_WIDGET_CONSTRUCTION); - widget = new T(params); - } - { - LLFastTimer timer(FTM_INIT_FROM_PARAMS); - widget->initFromParams(params); - } - - if (parent) - { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; - setCtrlParent(widget, parent, tab_group); - } - typedef typename T::child_registry_t registry_t; createChildren(widget, node, registry_t::instance(), output_node); - if (!widget->postBuild()) + if (widget && !widget->postBuild()) { delete widget; - return NULL; + widget = NULL; } return widget; diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp index f941f391eb..1dfc281d93 100644 --- a/indra/llui/lluiimage.cpp +++ b/indra/llui/lluiimage.cpp @@ -161,22 +161,32 @@ void LLUIImage::onImageLoaded() namespace LLInitParam { - LLUIImage* TypedParam<LLUIImage*>::getValueFromBlock() const + void TypedParam<LLUIImage*>::setValueFromBlock() const { // The keyword "none" is specifically requesting a null image // do not default to current value. Used to overwrite template images. if (name() == "none") { - return NULL; + mData.mValue = NULL; } LLUIImage* imagep = LLUI::getUIImage(name()); - if (!imagep) + if (imagep) { - // default to current value - imagep = mData.mValue; + mData.mValue = imagep; + } + } + + void TypedParam<LLUIImage*>::setBlockFromValue() + { + if (mData.mValue == NULL) + { + name = "none"; + } + else + { + name = mData.mValue->getName(); } - return imagep; } diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h index 5fa9610ab2..bdfc44262d 100644 --- a/indra/llui/lluiimage.h +++ b/indra/llui/lluiimage.h @@ -111,7 +111,8 @@ namespace LLInitParam { } - LLUIImage* getValueFromBlock() const; + void setValueFromBlock() const; + void setBlockFromValue(); }; // Need custom comparison function for our test app, which only loads diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 3a1e656364..f7a53e87de 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -39,22 +39,23 @@ LLFastTimer::DeclareTimer FTM_UI_STRING("UI String"); LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args) - : mOrig(instring), - mArgs(args) +: mOrig(instring), + mArgs(args) { - format(); + dirty(); } void LLUIString::assign(const std::string& s) { mOrig = s; - format(); + dirty(); } void LLUIString::setArgList(const LLStringUtil::format_map_t& args) + { mArgs = args; - format(); + dirty(); } void LLUIString::setArgs(const LLSD& sd) @@ -68,40 +69,40 @@ void LLUIString::setArgs(const LLSD& sd) { setArg(sd_it->first, sd_it->second.asString()); } - format(); + dirty(); } void LLUIString::setArg(const std::string& key, const std::string& replacement) { mArgs[key] = replacement; - format(); + dirty(); } void LLUIString::truncate(S32 maxchars) { - if (mWResult.size() > (size_t)maxchars) + if (getUpdatedWResult().size() > (size_t)maxchars) { - LLWStringUtil::truncate(mWResult, maxchars); - mResult = wstring_to_utf8str(mWResult); + LLWStringUtil::truncate(getUpdatedWResult(), maxchars); + mResult = wstring_to_utf8str(getUpdatedWResult()); } } void LLUIString::erase(S32 charidx, S32 len) { - mWResult.erase(charidx, len); - mResult = wstring_to_utf8str(mWResult); + getUpdatedWResult().erase(charidx, len); + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::insert(S32 charidx, const LLWString& wchars) { - mWResult.insert(charidx, wchars); - mResult = wstring_to_utf8str(mWResult); + getUpdatedWResult().insert(charidx, wchars); + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::replace(S32 charidx, llwchar wc) { - mWResult[charidx] = wc; - mResult = wstring_to_utf8str(mWResult); + getUpdatedWResult()[charidx] = wc; + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::clear() @@ -112,8 +113,16 @@ void LLUIString::clear() mWResult.clear(); } -void LLUIString::format() +void LLUIString::dirty() { + mNeedsResult = true; + mNeedsWResult = true; +} + +void LLUIString::updateResult() const +{ + mNeedsResult = false; + LLFastTimer timer(FTM_UI_STRING); // optimize for empty strings (don't attempt string replacement) @@ -129,5 +138,11 @@ void LLUIString::format() LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); combined_args.insert(mArgs.begin(), mArgs.end()); LLStringUtil::format(mResult, combined_args); - mWResult = utf8str_to_wstring(mResult); +} + +void LLUIString::updateWResult() const +{ + mNeedsWResult = false; + + mWResult = utf8str_to_wstring(getUpdatedResult()); } diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 763de4d6a3..7ec0fd603a 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -76,19 +76,19 @@ public: void setArgs(const class LLSD& sd); void setArg(const std::string& key, const std::string& replacement); - const std::string& getString() const { return mResult; } - operator std::string() const { return mResult; } + const std::string& getString() const { return getUpdatedResult(); } + operator std::string() const { return getUpdatedResult(); } - const LLWString& getWString() const { return mWResult; } - operator LLWString() const { return mWResult; } + const LLWString& getWString() const { return getUpdatedWResult(); } + operator LLWString() const { return getUpdatedWResult(); } - bool empty() const { return mWResult.empty(); } - S32 length() const { return mWResult.size(); } + bool empty() const { return getUpdatedResult().empty(); } + S32 length() const { return getUpdatedWResult().size(); } void clear(); void clearArgs() { mArgs.clear(); } - // These utuilty functions are included for text editing. + // These utility functions are included for text editing. // They do not affect mOrig and do not perform argument substitution void truncate(S32 maxchars); void erase(S32 charidx, S32 len); @@ -96,12 +96,24 @@ public: void replace(S32 charidx, llwchar wc); private: - void format(); + // something changed, requiring reformatting of strings + void dirty(); + + std::string& getUpdatedResult() const { if (mNeedsResult) { updateResult(); } return mResult; } + LLWString& getUpdatedWResult() const{ if (mNeedsWResult) { updateWResult(); } return mWResult; } + + // do actual work of updating strings (non-inlined) + void updateResult() const; + void updateWResult() const; std::string mOrig; - std::string mResult; - LLWString mWResult; // for displaying + mutable std::string mResult; + mutable LLWString mWResult; // for displaying LLStringUtil::format_map_t mArgs; + + // controls lazy evaluation + mutable bool mNeedsResult; + mutable bool mNeedsWResult; }; #endif // LL_LLUISTRING_H diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 8917e4b813..a8d8626e49 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -2494,8 +2494,6 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) const S32 VPAD = 4; const S32 MIN_WIDGET_HEIGHT = 10; - p.from_xui(true); - // *NOTE: This will confuse export of floater/panel coordinates unless // the default is also "topleft". JC if (p.layout().empty() && parent) @@ -2503,6 +2501,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) p.layout = parent->getLayout(); } + if (parent) { LLRect parent_rect = parent->getLocalRect(); @@ -2510,7 +2509,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) LLRect last_rect = parent->getLocalRect(); bool layout_topleft = (p.layout() == "topleft"); - if (layout_topleft) + if (layout_topleft && p.from_xui) { //invert top to bottom if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; @@ -2518,7 +2517,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) } // convert negative or centered coordinates to parent relative values - // Note: some of this logic matches the logic in TypedParam<LLRect>::getValueFromBlock() + // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() if (p.center_horiz) { @@ -2536,7 +2535,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) p.rect.right.setProvided(false); // recalculate the right } } - else + else if (p.from_xui) // only do negative coordinate magic for XUI { if (p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth(); if (p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth(); @@ -2557,7 +2556,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) p.rect.top.setProvided(false); // recalculate the top } } - else + else if (p.from_xui) { if (p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight(); if (p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight(); |