From 089fc07d207c71ce1401e72f09c31ad8c45872e2 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:58 -0500 Subject: Second Life viewer sources 1.17.0.12 --- linden/indra/llui/llalertdialog.cpp | 9 ++-- linden/indra/llui/llbutton.cpp | 78 +++++++++++++++++++++++++++++ linden/indra/llui/llbutton.h | 7 +++ linden/indra/llui/llfloater.cpp | 73 ++++++++++++++++++--------- linden/indra/llui/llfloater.h | 10 ++-- linden/indra/llui/lllineeditor.cpp | 81 ++++++++++++++++++++++++++++++ linden/indra/llui/lllineeditor.h | 10 ++++ linden/indra/llui/llmemberlistener.h | 1 - linden/indra/llui/llpanel.cpp | 17 +++++-- linden/indra/llui/llpanel.h | 2 +- linden/indra/llui/llscrolllistctrl.cpp | 51 +++++++++++++++++-- linden/indra/llui/llscrolllistctrl.h | 8 ++- linden/indra/llui/lltabcontainer.cpp | 54 ++++++++++++++++++-- linden/indra/llui/lltabcontainer.h | 7 ++- linden/indra/llui/lltexteditor.cpp | 57 ++++++++++++++------- linden/indra/llui/lltexteditor.h | 3 +- linden/indra/llui/llui.h | 91 ++++++++++++++++++++++++++++++++++ linden/indra/llui/lluictrlfactory.cpp | 11 ++-- linden/indra/llui/lluictrlfactory.h | 4 +- linden/indra/llui/llview.cpp | 20 +++++--- linden/indra/llui/llview.h | 4 +- 21 files changed, 517 insertions(+), 81 deletions(-) (limited to 'linden/indra/llui') diff --git a/linden/indra/llui/llalertdialog.cpp b/linden/indra/llui/llalertdialog.cpp index 547efae..8950fcd 100644 --- a/linden/indra/llui/llalertdialog.cpp +++ b/linden/indra/llui/llalertdialog.cpp @@ -783,10 +783,11 @@ bool LLAlertDialog::parseAlerts(const LLString& xml_filename, LLControlGroup* se // label= LLString name; child->getAttributeString("name", name); - if (name.empty()) - { - name = alert_name; - } + + //always set to alert_name for the sake of i18n + //if (name.empty()) + name = alert_name; + if (xml_template) { xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_DEFAULT; diff --git a/linden/indra/llui/llbutton.cpp b/linden/indra/llui/llbutton.cpp index 1d44537..de8b82e 100644 --- a/linden/indra/llui/llbutton.cpp +++ b/linden/indra/llui/llbutton.cpp @@ -615,6 +615,56 @@ void LLButton::draw() gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE); } + // draw overlay image + if (mImageOverlay.notNull()) + { + const S32 IMG_PAD = 4; + // get max width and height (discard level 0) + S32 overlay_width = mImageOverlay->getWidth(0); + S32 overlay_height = mImageOverlay->getHeight(0); + + F32 scale_factor = llmin((F32)mRect.getWidth() / (F32)overlay_width, (F32)mRect.getHeight() / (F32)overlay_height, 1.f); + overlay_width = llround((F32)overlay_width * scale_factor); + overlay_height = llround((F32)overlay_height * scale_factor); + + S32 center_x = getLocalRect().getCenterX(); + S32 center_y = getLocalRect().getCenterY(); + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + gl_draw_scaled_image( + IMG_PAD, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + mImageOverlay, + LLColor4::white); + break; + case LLFontGL::HCENTER: + gl_draw_scaled_image( + center_x - (overlay_width / 2), + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + mImageOverlay, + LLColor4::white); + break; + case LLFontGL::RIGHT: + gl_draw_scaled_image( + mRect.getWidth() - IMG_PAD - overlay_width, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + mImageOverlay, + LLColor4::white); + break; + default: + // draw nothing + break; + } + } + // Draw label if( !label.empty() ) { @@ -826,6 +876,21 @@ void LLButton::setHoverImages( const LLString& image_name, const LLString& selec setImageHoverSelected(selected_name); } +void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment) +{ + if (image_name.empty()) + { + mImageOverlay = NULL; + } + else + { + LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name); + mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id); + mImageOverlayAlignment = alignment; + } +} + + void LLButton::onMouseCaptureLost() { mMouseDownTimer.stop(); @@ -998,6 +1063,18 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa LLString image_disabled; if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled); + LLString image_overlay; + node->getAttributeString("image_overlay", image_overlay); + + LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER; + LLString image_overlay_alignment_string; + if (node->hasAttribute("image_overlay_alignment")) + { + node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string); + image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string); + } + + LLButton *button = new LLButton(name, LLRect(), image_unselected, @@ -1020,6 +1097,7 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa if(image_disabled != LLString::null) button->setImageDisabled(image_disabled); + if(image_overlay != LLString::null) button->setImageOverlay(image_overlay, image_overlay_alignment); if (node->hasAttribute("halign")) { diff --git a/linden/indra/llui/llbutton.h b/linden/indra/llui/llbutton.h index 44e8776..6e11779 100644 --- a/linden/indra/llui/llbutton.h +++ b/linden/indra/llui/llbutton.h @@ -142,6 +142,10 @@ public: void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } + void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER); + LLPointer getImageOverlay() { return mImageOverlay; } + + virtual void setValue(const LLSD& value ); virtual LLSD getValue() const; @@ -202,6 +206,9 @@ protected: F32 mHeldDownDelay; // seconds, after which held-down callbacks get called S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called + LLPointer mImageOverlay; + LLFontGL::HAlign mImageOverlayAlignment; + LLPointer mImageUnselected; LLUIString mUnselectedLabel; LLColor4 mUnselectedLabelColor; diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp index df44a58..6ab182f 100644 --- a/linden/indra/llui/llfloater.cpp +++ b/linden/indra/llui/llfloater.cpp @@ -575,17 +575,20 @@ void LLFloater::close(bool app_quitting) cleanupHandles(); gFocusMgr.clearLastFocusForGroup(this); - // Do this early, so UI controls will commit before the - // window is taken down. - releaseFocus(); - - // give focus to dependee floater if it exists, and we had focus first - if (isDependent()) + if (hasFocus()) { - LLFloater* dependee = LLFloater::getFloaterByHandle(mDependeeHandle); - if (dependee && !dependee->isDead()) + // Do this early, so UI controls will commit before the + // window is taken down. + releaseFocus(); + + // give focus to dependee floater if it exists, and we had focus first + if (isDependent()) { - dependee->setFocus(TRUE); + LLFloater* dependee = LLFloater::getFloaterByHandle(mDependeeHandle); + if (dependee && !dependee->isDead()) + { + dependee->setFocus(TRUE); + } } } @@ -1170,6 +1173,28 @@ BOOL LLFloater::getEditModeEnabled() return sEditModeEnabled; } +//static +void LLFloater::show(LLFloater* floaterp) +{ + if (floaterp) floaterp->open(); +} + +//static +void LLFloater::hide(LLFloater* floaterp) +{ + if (floaterp) floaterp->close(); +} + +//static +BOOL LLFloater::visible(LLFloater* floaterp) +{ + if (floaterp) + { + return floaterp->isInVisibleChain(); + } + return FALSE; +} + // static void LLFloater::onClickMinimize(void *userdata) { @@ -2372,7 +2397,7 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) LLMultiFloater::LLMultiFloater() : mTabContainer(NULL), mTabPos(LLTabContainerCommon::TOP), - mAutoResize(FALSE) + mAutoResize(TRUE) { } @@ -2380,7 +2405,7 @@ LLMultiFloater::LLMultiFloater() : LLMultiFloater::LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos) : mTabContainer(NULL), mTabPos(tab_pos), - mAutoResize(FALSE) + mAutoResize(TRUE) { } @@ -2594,15 +2619,12 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, floaterp->setCanResize(FALSE); floaterp->setCanDrag(FALSE); - S32 new_width = llmax(mRect.getWidth(), floaterp->getRect().getWidth()); - S32 new_height = llmax(mRect.getHeight(), floaterp->getRect().getHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - - reshape(new_width, new_height); - //add the panel, add it to proper maps mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); mFloaterDataMap[floaterp->getHandle()] = floater_data; + resizeToContents(); + if ( select_added_floater ) { mTabContainer->selectLastTab(); @@ -2676,10 +2698,7 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp) floaterp->setBackgroundVisible(TRUE); floaterp->setHost(NULL); - if (mAutoResize) - { - resizeToContents(); - } + resizeToContents(); tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); } @@ -2729,7 +2748,8 @@ BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) if (key == 'W') { LLFloater* floater = getActiveFloater(); - if (floater && floater->canClose()) + // is user closeable and is system closeable + if (floater && floater->canClose() && floater->isCloseable()) { floater->close(); } @@ -2848,10 +2868,17 @@ void LLMultiFloater::resizeToContents() S32 cur_height = mRect.getHeight(); - reshape(new_width, new_height); + if (mAutoResize) + { + reshape(new_width, new_height); + } + else + { + reshape(llmax(new_min_width, mRect.getWidth()), llmax(new_min_height, mRect.getHeight())); + } // make sure upper left corner doesn't move - translate(0, cur_height - new_height); + translate(0, cur_height - mRect.getHeight()); // Try to keep whole view onscreen, don't allow partial offscreen. gFloaterView->adjustToFitScreen(this, FALSE); diff --git a/linden/indra/llui/llfloater.h b/linden/indra/llui/llfloater.h index cd45762..8b610e3 100644 --- a/linden/indra/llui/llfloater.h +++ b/linden/indra/llui/llfloater.h @@ -212,6 +212,10 @@ public: static BOOL getEditModeEnabled(); static LLMultiFloater* getFloaterHost() {return sHostp; } + static void show(LLFloater* floaterp); + static void hide(LLFloater* floaterp); + static BOOL visible(LLFloater* floaterp); + static LLFloater* getFloaterByHandle(LLViewHandle handle); protected: @@ -279,7 +283,6 @@ protected: std::vector mMinimizedHiddenChildren; }; - ///////////////////////////////////////////////////////////// // LLFloaterView // Parent of all floating panels @@ -354,8 +357,8 @@ public: LLMultiFloater(); LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos); LLMultiFloater(const LLString& name); - LLMultiFloater(const LLString& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = FALSE); - LLMultiFloater(const LLString& name, const LLString& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = FALSE); + LLMultiFloater(const LLString& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); + LLMultiFloater(const LLString& name, const LLString& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); virtual ~LLMultiFloater(); virtual BOOL postBuild(); @@ -416,3 +419,4 @@ extern LLFloaterView* gFloaterView; #endif // LL_FLOATER_H + diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp index a2cd9af..44616b9 100644 --- a/linden/indra/llui/lllineeditor.cpp +++ b/linden/indra/llui/lllineeditor.cpp @@ -157,6 +157,14 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect, { llassert( max_length_bytes > 0 ); + // line history support: + // - initialize line history list + mLineHistory.insert( mLineHistory.end(), "" ); + // - disable line history by default + mHaveHistory = FALSE; + // - reset current history line pointer + mCurrentHistoryLine = 0; + if (font) { mGLFont = font; @@ -229,10 +237,33 @@ void LLLineEditor::onFocusLost() void LLLineEditor::onCommit() { + // put current line into the line history + updateHistory(); + LLUICtrl::onCommit(); selectAll(); } +// line history support +void LLLineEditor::updateHistory() +{ + // On history enabled line editors, remember committed line and + // reset current history line number. + // Be sure only to remember lines that are not empty and that are + // different from the last on the list. + if( mHaveHistory && mText.length() && ( mLineHistory.empty() || getText() != mLineHistory.back() ) ) + { + // discard possible empty line at the end of the history + // inserted by setText() + if( !mLineHistory.back().length() ) + { + mLineHistory.pop_back(); + } + mLineHistory.insert( mLineHistory.end(), getText() ); + mCurrentHistoryLine = mLineHistory.size() - 1; + } +} + void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent) { LLUICtrl::reshape(width, height, called_from_parent ); @@ -240,6 +271,10 @@ void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent) mMaxHPixels = mRect.getWidth() - 2 * (mBorderThickness + UI_LINEEDITOR_H_PAD) + 1 - mBorderRight; } +void LLLineEditor::setEnableLineHistory( BOOL enabled ) +{ + mHaveHistory = enabled; +} void LLLineEditor::setEnabled(BOOL enabled) { @@ -300,6 +335,13 @@ void LLLineEditor::setText(const LLString &new_text) deselect(); } setCursor(llmin((S32)mText.length(), getCursor())); + + // Newly set text goes always in the last line of history. + // Possible empty strings (as with chat line) will be deleted later. + mLineHistory.insert( mLineHistory.end(), new_text ); + // Set current history line to end of history. + mCurrentHistoryLine = mLineHistory.size() - 1; + mPrevText = mText; } @@ -1086,6 +1128,45 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } break; + // handle ctrl-uparrow if we have a history enabled line editor. + case KEY_UP: + if( mHaveHistory && ( MASK_CONTROL & mask ) ) + { + if( mCurrentHistoryLine > 0 ) + { + mText.assign( mLineHistory[ --mCurrentHistoryLine ] ); + setCursor(llmin((S32)mText.length(), getCursor())); + } + else + { + reportBadKeystroke(); + } + handled = TRUE; + } + break; + + // handle ctrl-downarrow if we have a history enabled line editor + case KEY_DOWN: + if( mHaveHistory && ( MASK_CONTROL & mask ) ) + { + if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.size() - 1 ) + { + mText.assign( mLineHistory[ ++mCurrentHistoryLine ] ); + setCursor(llmin((S32)mText.length(), getCursor())); + } + else + { + reportBadKeystroke(); + } + handled = TRUE; + } + break; + + case KEY_RETURN: + // store sent line in history + updateHistory(); + break; + case KEY_ESCAPE: if (mRevertOnEsc && mText.getString() != mPrevText) { diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h index 65c75ab..e715737 100644 --- a/linden/indra/llui/lllineeditor.h +++ b/linden/indra/llui/lllineeditor.h @@ -36,6 +36,7 @@ // Clipboard (cut, copy, and paste) // Horizontal scrolling to allow strings longer than widget size allows // Pre-validation (limit which keys can be used) +// Optional line history so previous entries can be recalled by CTRL UP/DOWN #ifndef LL_LLLINEEDITOR_H @@ -206,6 +207,10 @@ public: static BOOL postvalidateFloat(const LLString &str); + // line history support: + void setEnableLineHistory( BOOL enabled ); // switches line history on or off + void updateHistory(); // stores current line in history + protected: void removeChar(); void addChar(const llwchar c); @@ -224,6 +229,11 @@ protected: LLString mPrevText; // Saved string for 'ESC' revert LLUIString mLabel; // text label that is visible when no user text provided + // line history support: + BOOL mHaveHistory; // flag for enabled line history + std::vector mLineHistory; // line history storage + U32 mCurrentHistoryLine; // currently browsed history line + LLViewBorder* mBorder; const LLFontGL* mGLFont; S32 mMaxLengthChars; // Max number of characters diff --git a/linden/indra/llui/llmemberlistener.h b/linden/indra/llui/llmemberlistener.h index 92e7278..bc67519 100644 --- a/linden/indra/llui/llmemberlistener.h +++ b/linden/indra/llui/llmemberlistener.h @@ -37,7 +37,6 @@ class LLMemberListener : public LLSimpleListener { public: LLMemberListener() : mPtr(NULL), mRegisteredName("") { } - ~LLMemberListener() { } void registerListener(T *pointer, const LLString& register_name) { diff --git a/linden/indra/llui/llpanel.cpp b/linden/indra/llui/llpanel.cpp index f0b5b25..dfa3f8a 100644 --- a/linden/indra/llui/llpanel.cpp +++ b/linden/indra/llui/llpanel.cpp @@ -589,7 +589,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *fa return panelp; } -void LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { LLString name("panel"); node->getAttributeString("name", name); @@ -605,12 +605,23 @@ void LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f LLString xml_filename; node->getAttributeString("filename", xml_filename); + + BOOL didPost; + if (!xml_filename.empty()) { - factory->buildPanel(this, xml_filename, NULL); + didPost = factory->buildPanel(this, xml_filename, NULL); + } else { + didPost = FALSE; } - postBuild(); + if (!didPost) + { + postBuild(); + didPost = TRUE; + } + + return didPost; } void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) diff --git a/linden/indra/llui/llpanel.h b/linden/indra/llui/llpanel.h index 9da942e..fea3eee 100644 --- a/linden/indra/llui/llpanel.h +++ b/linden/indra/llui/llpanel.h @@ -135,7 +135,7 @@ public: virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - void initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void setPanelParameters(LLXMLNodePtr node, LLView *parentp); // ** Wrappers for setting child properties by name ** -TomY diff --git a/linden/indra/llui/llscrolllistctrl.cpp b/linden/indra/llui/llscrolllistctrl.cpp index 22987dc..fd98bd5 100644 --- a/linden/indra/llui/llscrolllistctrl.cpp +++ b/linden/indra/llui/llscrolllistctrl.cpp @@ -99,7 +99,7 @@ protected: // LLScrollListIcon // LLScrollListIcon::LLScrollListIcon(LLImageGL* icon, S32 width, LLUUID image_id) : -mIcon(icon), mImageUUID(image_id.asString()) +mIcon(icon), mColor(LLColor4::white), mImageUUID(image_id.asString()) { if (width) { @@ -115,6 +115,16 @@ LLScrollListIcon::~LLScrollListIcon() { } +void LLScrollListIcon::setColor(const LLColor4& color) +{ + mColor = color; +} + +void LLScrollListIcon::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const +{ + gl_draw_image(0, 0, mIcon, mColor); +} + // // LLScrollListCheck // @@ -208,6 +218,15 @@ LLScrollListText::~LLScrollListText() delete mColor; } +void LLScrollListText::setColor(const LLColor4& color) +{ + if (!mColor) + { + mColor = new LLColor4(); + } + *mColor = color; +} + void LLScrollListText::setText(const LLString& text) { mText = text; @@ -2809,6 +2828,8 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p LLString fontname = (*itor)["font"].asString(); LLString fontstyle = (*itor)["font-style"].asString(); LLString type = (*itor)["type"].asString(); + BOOL has_color = (*itor).has("color"); + LLColor4 color = ((*itor)["color"]); const LLFontGL *font = gResMgr->getRes(fontname); if (!font) @@ -2821,21 +2842,41 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p { LLUUID image_id = value.asUUID(); LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id); - new_item->setColumn(index, new LLScrollListIcon(icon, width, image_id)); + LLScrollListIcon* cell = new LLScrollListIcon(icon, width, image_id); + if (has_color) + { + cell->setColor(color); + } + new_item->setColumn(index, cell); } else if (type == "checkbox") { LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(), LLRect(0, 0, width, width), "label"); - new_item->setColumn(index, new LLScrollListCheck(ctrl,width)); + LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width); + if (has_color) + { + cell->setColor(color); + } + new_item->setColumn(index, cell); } else if (type == "separator") { - new_item->setColumn(index, new LLScrollListSeparator(width)); + LLScrollListSeparator* cell = new LLScrollListSeparator(width); + if (has_color) + { + cell->setColor(color); + } + new_item->setColumn(index, cell); } else { - new_item->setColumn(index, new LLScrollListText(value.asString(), font, width, font_style, font_alignment)); + LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment); + if (has_color) + { + cell->setColor(color); + } + new_item->setColumn(index, cell); if (columnp->mHeader && !value.asString().empty()) { columnp->mHeader->setHasResizableElement(TRUE); diff --git a/linden/indra/llui/llscrolllistctrl.h b/linden/indra/llui/llscrolllistctrl.h index eed07b8..429985b 100644 --- a/linden/indra/llui/llscrolllistctrl.h +++ b/linden/indra/llui/llscrolllistctrl.h @@ -63,6 +63,7 @@ public: virtual void setWidth(S32 width) = 0; virtual void highlightText(S32 offset, S32 num_chars) {} virtual BOOL isText() = 0; + virtual void setColor(const LLColor4&) = 0; virtual BOOL handleClick() { return FALSE; } virtual void setEnabled(BOOL enable) { } @@ -77,6 +78,7 @@ public: virtual S32 getWidth() const {return mWidth;} virtual S32 getHeight() const { return 5; }; virtual void setWidth(S32 width) {mWidth = width; } + virtual void setColor(const LLColor4&) {}; virtual BOOL isText() { return FALSE; } protected: @@ -97,6 +99,7 @@ public: virtual const BOOL getVisible() const { return mVisible; } virtual void highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;} void setText(const LLString& text); + virtual void setColor(const LLColor4&); virtual BOOL isText() { return TRUE; } private: @@ -120,18 +123,20 @@ class LLScrollListIcon : public LLScrollListCell public: LLScrollListIcon( LLImageGL* icon, S32 width = 0, LLUUID image_id = LLUUID::null); /*virtual*/ ~LLScrollListIcon(); - virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const { gl_draw_image(0, 0, mIcon); } + virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const; virtual S32 getWidth() const { return mWidth; } virtual S32 getHeight() const { return mIcon->getHeight(); } virtual const LLString& getText() const { return mImageUUID; } virtual const LLString& getTextLower() const { return mImageUUID; } virtual void setWidth(S32 width) { mWidth = width; } + virtual void setColor(const LLColor4&); virtual BOOL isText() { return FALSE; } private: LLPointer mIcon; LLString mImageUUID; S32 mWidth; + LLColor4 mColor; }; class LLScrollListCheck : public LLScrollListCell @@ -146,6 +151,7 @@ public: virtual BOOL handleClick(); virtual void setEnabled(BOOL enable) { if (mCheckBox) mCheckBox->setEnabled(enable); } + virtual void setColor(const LLColor4& color) {}; LLCheckBoxCtrl* getCheckBox() { return mCheckBox; } virtual BOOL isText() { return FALSE; } diff --git a/linden/indra/llui/lltabcontainer.cpp b/linden/indra/llui/lltabcontainer.cpp index 61cfde4..44940ae 100644 --- a/linden/indra/llui/lltabcontainer.cpp +++ b/linden/indra/llui/lltabcontainer.cpp @@ -77,7 +77,8 @@ LLTabContainerCommon::LLTabContainerCommon( mCallbackUserdata( callback_userdata ), mTitleBox(NULL), mTopBorderHeight(LLPANEL_BORDER_WIDTH), - mTabPosition(pos) + mTabPosition(pos), + mLockedTabCount(0) { setMouseOpaque(FALSE); } @@ -142,6 +143,13 @@ void LLTabContainerCommon::addPlaceholder(LLPanel* child, const LLString& label) addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); } +void LLTabContainerCommon::lockTabs() +{ + // count current tabs and ensure no new tabs get + // inserted between them + mLockedTabCount = getTabCount(); +} + void LLTabContainerCommon::removeTabPanel(LLPanel* child) { BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); @@ -164,6 +172,10 @@ void LLTabContainerCommon::removeTabPanel(LLPanel* child) break; } } + + // make sure we don't have more locked tabs than we have tabs + mLockedTabCount = llmin(getTabCount(), mLockedTabCount); + if (mCurrentTabIdx >= (S32)mTabList.size()) { mCurrentTabIdx = mTabList.size()-1; @@ -526,6 +538,15 @@ void LLTabContainerCommon::setTabPanelFlashing(LLPanel* child, BOOL state ) } } +void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name) +{ + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT); + } +} + void LLTabContainerCommon::setTitle(const LLString& title) { if (mTitleBox) @@ -687,12 +708,12 @@ void LLTabContainerCommon::insertTuple(LLTabTuple * tuple, eInsertionPoint inser { case START: // insert the new tab in the front of the list - mTabList.insert(mTabList.begin(), tuple); + mTabList.insert(mTabList.begin() + mLockedTabCount, tuple); break; case RIGHT_OF_CURRENT: - // insert the new tab after the current tab + // insert the new tab after the current tab (but not before mLockedTabCount) { - tuple_list_t::iterator current_iter = mTabList.begin() + mCurrentTabIdx + 1; + tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1); mTabList.insert(current_iter, tuple); } break; @@ -1249,6 +1270,7 @@ void LLTabContainer::draw() for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { LLTabTuple* tuple = *iter; + tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); left += tuple->mButton->getRect().getWidth(); @@ -1596,3 +1618,27 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); } + +void LLTabContainer::setTabImage(LLPanel* child, std::string image_name) +{ + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT); + + const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); + // remove current width from total tab strip width + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + + S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + tuple->mButton->getImageOverlay()->getWidth(0) : + 0; + tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + image_overlay_width, mMinTabWidth, mMaxTabWidth), + tuple->mButton->getRect().getHeight()); + // add back in button width to total tab strip width + mTotalTabWidth += tuple->mButton->getRect().getWidth(); + + // tabs have changed size, might need to scroll to see current tab + updateMaxScrollPos(); + } +} \ No newline at end of file diff --git a/linden/indra/llui/lltabcontainer.h b/linden/indra/llui/lltabcontainer.h index 5fe6bc5..7d501d2 100644 --- a/linden/indra/llui/lltabcontainer.h +++ b/linden/indra/llui/lltabcontainer.h @@ -87,7 +87,8 @@ public: BOOL placeholder = FALSE, eInsertionPoint insertion_point = END) = 0; virtual void addPlaceholder(LLPanel* child, const LLString& label); - + virtual void lockTabs(); + virtual void enableTabButton(S32 which, BOOL enable); virtual void removeTabPanel( LLPanel* child ); @@ -113,6 +114,7 @@ public: BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); + virtual void setTabImage(LLPanel* child, std::string img_name); void setTitle( const LLString& title ); const LLString getPanelTitle(S32 index); @@ -180,6 +182,7 @@ protected: S32 mTopBorderHeight; TabPosition mTabPosition; + S32 mLockedTabCount; protected: void scrollPrev(); @@ -221,7 +224,7 @@ public: /*virtual*/ void removeTabPanel( LLPanel* child ); /*virtual*/ void setPanelTitle(S32 index, const LLString& title); - + /*virtual*/ void setTabImage(LLPanel* child, std::string img_name); /*virtual*/ void setRightTabBtnOffset( S32 offset ); /*virtual*/ void setMinTabWidth(S32 width); diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp index ba991c2..80205d3 100644 --- a/linden/indra/llui/lltexteditor.cpp +++ b/linden/indra/llui/lltexteditor.cpp @@ -309,6 +309,9 @@ LLTextEditor::LLTextEditor( { mSourceID.generate(); + // reset desired x cursor position + mDesiredXPixel = -1; + if (font) { mGLFont = font; @@ -348,7 +351,7 @@ LLTextEditor::LLTextEditor( mBorder = new LLViewBorder( "text ed border", LLRect(0, mRect.getHeight(), mRect.getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); addChild( mBorder ); - setText(default_text); + appendText(default_text, FALSE, FALSE); mParseHTML=FALSE; mHTML=""; @@ -914,6 +917,8 @@ void LLTextEditor::setCursorPos(S32 offset) { mCursorPos = llclamp(offset, 0, (S32)getLength()); updateScrollFromCursor(); + // reset desired x cursor position + mDesiredXPixel = -1; } @@ -2645,7 +2650,8 @@ void LLTextEditor::drawSelectionBackground() { LLGLSNoTexture no_texture; const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; - glColor3f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2] ); + F32 alpha = hasFocus() ? 1.f : 0.5f; + glColor4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); if( selection_left_y == selection_right_y ) { @@ -3098,6 +3104,9 @@ void LLTextEditor::changePage( S32 delta ) S32 line, offset; getLineAndOffset( mCursorPos, &line, &offset ); + // get desired x position to remember previous position + S32 desired_x_pixel = mDesiredXPixel; + // allow one line overlap S32 page_size = mScrollbar->getPageSize() - 1; if( delta == -1 ) @@ -3112,6 +3121,10 @@ void LLTextEditor::changePage( S32 delta ) setCursorPos(getPos( line + page_size, offset )); mScrollbar->setDocPos( mScrollbar->getDocPos() + page_size ); } + + // put desired position into remember-buffer after setCursorPos() + mDesiredXPixel = desired_x_pixel; + if (mOnScrollEndCallback && mOnScrollEndData && (mScrollbar->getDocPos() == mScrollbar->getDocPosMax())) { mOnScrollEndCallback(mOnScrollEndData); @@ -3127,9 +3140,13 @@ void LLTextEditor::changeLine( S32 delta ) S32 line_start = getLineStart(line); - S32 desired_x_pixel; - - desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems ); + // set desired x position to remembered previous position + S32 desired_x_pixel = mDesiredXPixel; + // if remembered position was reset (thus -1), calculate new one here + if( desired_x_pixel == -1 ) + { + desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems ); + } S32 new_line = 0; if( (delta < 0) && (line > 0 ) ) @@ -3165,6 +3182,9 @@ void LLTextEditor::changeLine( S32 delta ) mAllowEmbeddedItems); setCursorPos (getPos( new_line, new_offset )); + + // put desired position into remember-buffer after setCursorPos() + mDesiredXPixel = desired_x_pixel; unbindEmbeddedChars( mGLFont ); } @@ -3358,6 +3378,14 @@ void LLTextEditor::appendColoredText(const LLString &new_text, style.setVisible(true); style.setColor(color); style.setFontName(font_name); + appendStyledText(new_text, allow_undo, prepend_newline, &style); +} + +void LLTextEditor::appendStyledText(const LLString &new_text, + bool allow_undo, + bool prepend_newline, + const LLStyle* style) +{ if(mParseHTML) { @@ -3368,10 +3396,13 @@ void LLTextEditor::appendColoredText(const LLString &new_text, LLStyle html; html.setVisible(true); html.setColor(mLinkColor); - html.setFontName(font_name); + if (style) + { + html.setFontName(style->getFontString()); + } html.mUnderline = TRUE; - if (start > 0) appendText(text.substr(0,start),allow_undo, prepend_newline, &style); + if (start > 0) appendText(text.substr(0,start),allow_undo, prepend_newline, style); html.setLinkHREF(text.substr(start,end-start)); appendText(text.substr(start, end-start),allow_undo, prepend_newline, &html); if (end < (S32)text.length()) @@ -3384,22 +3415,14 @@ void LLTextEditor::appendColoredText(const LLString &new_text, break; } } - if (end < (S32)text.length()) appendText(text,allow_undo, prepend_newline, &style); + if (end < (S32)text.length()) appendText(text,allow_undo, prepend_newline, style); } else { - appendText(new_text, allow_undo, prepend_newline, &style); + appendText(new_text, allow_undo, prepend_newline, style); } } -void LLTextEditor::appendStyledText(const LLString &new_text, - bool allow_undo, - bool prepend_newline, - const LLStyle &style) -{ - appendText(new_text, allow_undo, prepend_newline, &style); -} - // Appends new text to end of document void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool prepend_newline, const LLStyle* segment_style) diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h index 32375be..ebe8ac3 100644 --- a/linden/indra/llui/lltexteditor.h +++ b/linden/indra/llui/lltexteditor.h @@ -159,7 +159,7 @@ public: // if styled text starts a line, you need to prepend a newline. void appendStyledText(const LLString &new_text, bool allow_undo, bool prepend_newline, - const LLStyle &style); + const LLStyle* style); // Removes text from the end of document // Does not change highlight or cursor position. @@ -359,6 +359,7 @@ protected: undo_stack_t mUndoStack; S32 mCursorPos; // I-beam is just after the mCursorPos-th character. + S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be LLRect mTextRect; // The rect in which text is drawn. Excludes borders. // List of offsets and segment index of the start of each line. Always has at least one node (0). struct line_info diff --git a/linden/indra/llui/llui.h b/linden/indra/llui/llui.h index 6b8a86a..3085bd9 100644 --- a/linden/indra/llui/llui.h +++ b/linden/indra/llui/llui.h @@ -275,4 +275,95 @@ typedef enum e_widget_type WIDGET_TYPE_COUNT } EWidgetType; +// Manages generation of UI elements by LLSD, such that there is +// only one instance per uniquely identified LLSD parameter +// Class T is the instance type being managed, and INSTANCE_ADDAPTOR +// wraps an instance of the class with handlers for show/hide semantics, etc. +template +class LLUIInstanceMgr +{ +public: + LLUIInstanceMgr() + { + } + + virtual ~LLUIInstanceMgr() + { + } + + // default show and hide methods + static T* showInstance(const LLSD& seed) + { + T* instance = INSTANCE_ADAPTOR::getInstance(seed); + INSTANCE_ADAPTOR::show(instance); + return instance; + } + + static void hideInstance(const LLSD& seed) + { + T* instance = INSTANCE_ADAPTOR::getInstance(seed); + INSTANCE_ADAPTOR::hide(instance); + } + + static void toggleInstance(const LLSD& seed) + { + if (!INSTANCE_ADAPTOR::instanceVisible(seed)) + { + INSTANCE_ADAPTOR::showInstance(seed); + } + else + { + INSTANCE_ADAPTOR::hideInstance(seed); + } + } + + static BOOL instanceVisible(const LLSD& seed) + { + T* instance = INSTANCE_ADAPTOR::findInstance(seed); + return instance != NULL && INSTANCE_ADAPTOR::visible(instance); + } + + static T* getInstance(const LLSD& seed) + { + T* instance = INSTANCE_ADAPTOR::findInstance(seed); + if (instance == NULL) + { + instance = INSTANCE_ADAPTOR::createInstance(seed); + } + return instance; + } +}; + +// Creates a UI singleton by ignoring the identifying parameter +// and always generating the same instance via the LLUIInstanceMgr interface. +// Note that since UI elements can be destroyed by their hierarchy, this singleton +// pattern uses a static pointer to an instance that will be re-created as needed. +template +class LLUISingleton: public LLUIInstanceMgr +{ +public: + // default constructor assumes T is derived from LLUISingleton (a true singleton) + LLUISingleton() : LLUIInstanceMgr() { sInstance = (T*)this; } + ~LLUISingleton() { sInstance = NULL; } + + static T* findInstance(const LLSD& seed) + { + return sInstance; + } + + static T* createInstance(const LLSD& seed) + { + if (sInstance == NULL) + { + sInstance = new T(seed); + } + return sInstance; + } + +protected: + static T* sInstance; +}; + +template T* LLUISingleton::sInstance = NULL; + #endif diff --git a/linden/indra/llui/lluictrlfactory.cpp b/linden/indra/llui/lluictrlfactory.cpp index 475ef2e..79f7313 100644 --- a/linden/indra/llui/lluictrlfactory.cpp +++ b/linden/indra/llui/lluictrlfactory.cpp @@ -370,21 +370,22 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const LLString& filename) //----------------------------------------------------------------------------- // buildPanel() //----------------------------------------------------------------------------- -void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename, +BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename, const LLCallbackMap::map_t* factory_map) { + BOOL didPost = FALSE; LLXMLNodePtr root; if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) { - return; + return didPost; } // root must be called panel if( !root->hasName("panel" ) ) { llwarns << "Root node should be named panel in : " << filename << llendl; - return; + return didPost; } if (factory_map) @@ -392,7 +393,7 @@ void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename, mFactoryStack.push_front(factory_map); } - panelp->initPanelXML(root, NULL, this); + didPost = panelp->initPanelXML(root, NULL, this); if (LLUI::sShowXUINames) { @@ -406,6 +407,8 @@ void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename, { mFactoryStack.pop_front(); } + + return didPost; } //----------------------------------------------------------------------------- diff --git a/linden/indra/llui/lluictrlfactory.h b/linden/indra/llui/lluictrlfactory.h index 18b0ba9..eaae754 100644 --- a/linden/indra/llui/lluictrlfactory.h +++ b/linden/indra/llui/lluictrlfactory.h @@ -80,8 +80,8 @@ public: void buildFloater(LLFloater* floaterp, const LLString &filename, const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); - void buildPanel(LLPanel* panelp, const LLString &filename, - const LLCallbackMap::map_t* factory_map = NULL); + BOOL buildPanel(LLPanel* panelp, const LLString &filename, + const LLCallbackMap::map_t* factory_map = NULL); LLMenuGL *buildMenu(const LLString &filename, LLView* parentp); diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp index d150e10..22d426a 100644 --- a/linden/indra/llui/llview.cpp +++ b/linden/indra/llui/llview.cpp @@ -194,8 +194,10 @@ LLView::~LLView() for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) { (*itor).second->clearDispatchers(); - delete (*itor).second; } + + std::for_each(mFloaterControls.begin(), mFloaterControls.end(), + DeletePairedPointer()); } // virtual @@ -367,22 +369,25 @@ void LLView::addChildAtEnd(LLView* child, S32 tab_group) } // remove the specified child from the view, and set it's parent to NULL. -void LLView::removeChild( LLView* child ) +void LLView::removeChild(LLView* child, BOOL deleteIt) { if (child->mParentView == this) { mChildList.remove( child ); child->mParentView = NULL; + if (child->isCtrl()) + { + removeCtrl((LLUICtrl*)child); + } + if (deleteIt) + { + delete child; + } } else { llerrs << "LLView::removeChild called with non-child" << llendl; } - - if (child->isCtrl()) - { - removeCtrl((LLUICtrl*)child); - } } void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group) @@ -2507,7 +2512,6 @@ void LLView::deregisterEventListener(LLString name) dispatch_list_t::iterator itor = mDispatchList.find(name); if (itor != mDispatchList.end()) { - delete itor->second; mDispatchList.erase(itor); } } diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h index cb9a35c..c7664eb 100644 --- a/linden/indra/llui/llview.h +++ b/linden/indra/llui/llview.h @@ -241,7 +241,7 @@ public: void addChild(LLView* view, S32 tab_group = 0); void addChildAtEnd(LLView* view, S32 tab_group = 0); // remove the specified child from the view, and set it's parent to NULL. - void removeChild( LLView* view ); + void removeChild(LLView* view, BOOL deleteIt = FALSE); virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); @@ -484,7 +484,7 @@ protected: LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); - typedef std::map dispatch_list_t; + typedef std::map > dispatch_list_t; dispatch_list_t mDispatchList; protected: -- cgit v1.1