From 9ec432034dc3c45d7ce763eb02dae4cc7f6b8da8 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Sun, 21 Jun 2009 08:04:56 +0000 Subject: merge -r 122421-124917 viewer-2.0.0-2 -> viewer-2.0.0-3 ignore-dead-branch --- indra/llui/llview.cpp | 1350 ++++++++++++++++++++++--------------------------- 1 file changed, 598 insertions(+), 752 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 8ec681fcaf..2e2ef4d79f 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -56,19 +56,18 @@ #include "lltexteditor.h" #include "lltextbox.h" -using namespace LLOldEvents; - -//HACK: this allows you to instantiate LLView from xml with "" which we don't want -static LLRegisterWidget r("view"); - BOOL LLView::sDebugRects = FALSE; BOOL LLView::sDebugKeys = FALSE; S32 LLView::sDepth = 0; BOOL LLView::sDebugMouseHandling = FALSE; std::string LLView::sMouseHandlerMessage; -BOOL LLView::sEditingUI = FALSE; +//BOOL LLView::sEditingUI = FALSE; BOOL LLView::sForceReshape = FALSE; -LLView* LLView::sEditingUIView = NULL; +//LLView* LLView::sEditingUIView = NULL; +std::set LLView::sPreviewHighlightedElements; +BOOL LLView::sHighlightingDiffs = FALSE; +LLView* LLView::sPreviewClickedElement = NULL; +BOOL LLView::sDrawPreviewHighlights = FALSE; S32 LLView::sLastLeftXML = S32_MIN; S32 LLView::sLastBottomXML = S32_MIN; @@ -76,77 +75,78 @@ S32 LLView::sLastBottomXML = S32_MIN; BOOL LLView::sIsDrawing = FALSE; #endif -LLView::LLView() : - mParentView(NULL), - mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(TRUE), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) -{ -} - -LLView::LLView(const std::string& name, BOOL mouse_opaque) : +LLView::Params::Params() +: name("name", std::string("unnamed")), + enabled("enabled", true), + visible("visible", true), + mouse_opaque("mouse_opaque", true), + follows("follows"), + hover_cursor("hover_cursor", "UI_CURSOR_ARROW"), + use_bounding_rect("use_bounding_rect", false), + tab_group("tab_group", 0), + default_tab_group("default_tab_group"), + tool_tip("tool_tip"), + sound_flags("sound_flags", MOUSE_UP), + font("font", LLFontGL::getFontSansSerif()), + font_halign("halign"), + font_valign("valign"), + layout("layout"), + rect("rect"), + bottom_delta("bottom_delta", S32_MAX), + top_pad("top_pad"), + top_delta("top_delta", S32_MAX), + left_pad("left_pad"), + left_delta("left_delta", S32_MAX), + center_horiz("center_horiz", false), + center_vert("center_vert", false), + serializable("", false), + user_resize("user_resize"), + auto_resize("auto_resize"), + needs_translate("translate") +{ + addSynonym(rect, ""); +} + +LLView::LLView(const LLView::Params& p) +: mName(p.name), mParentView(NULL), - mName(name), mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) -{ -} - - -LLView::LLView( - const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) : - mParentView(NULL), - mName(name), - mRect(rect), - mBoundingRect(rect), - mReshapeFlags(reshape), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), + mSaveToXML(p.serializable), mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), + mLastVisible(FALSE), mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) + mHoverCursor(getCursorFromString(p.hover_cursor)), + mEnabled(p.enabled), + mVisible(p.visible), + mMouseOpaque(p.mouse_opaque), + mSoundFlags(p.sound_flags), + mUseBoundingRect(p.use_bounding_rect), + mDefaultTabGroup(p.default_tab_group), + mLastTabGroup(0), + mToolTipMsg((LLStringExplicit)p.tool_tip()), + mDummyWidgets(NULL) { + // create rect first, as this will supply initial follows flags + setShape(p.rect); + parseFollowsFlags(p); } - LLView::~LLView() { //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl; // llassert(LLView::sIsDrawing == FALSE); + +// llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators + if( gFocusMgr.getKeyboardFocus() == this ) { - llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; + //llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; gFocusMgr.removeKeyboardFocusWithoutCallback( this ); } if( hasMouseCapture() ) { - llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; + //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; gFocusMgr.removeMouseCaptureWithoutCallback( this ); } @@ -157,16 +157,13 @@ LLView::~LLView() mParentView->removeChild(this); } - dispatch_list_t::iterator itor; - for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) + if (mDummyWidgets) { - (*itor).second->clearDispatchers(); + std::for_each(mDummyWidgets->begin(), mDummyWidgets->end(), + DeletePairedPointer()); + delete mDummyWidgets; + mDummyWidgets = NULL; } - - std::for_each(mFloaterControls.begin(), mFloaterControls.end(), - DeletePairedPointer()); - std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(), - DeletePairedPointer()); } // virtual @@ -187,7 +184,6 @@ BOOL LLView::isPanel() const return FALSE; } -// virtual void LLView::setToolTip(const LLStringExplicit& msg) { mToolTipMsg = msg; @@ -234,19 +230,31 @@ const std::string& LLView::getName() const void LLView::sendChildToFront(LLView* child) { +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child && child->getParent() == this) { - mChildList.remove( child ); - mChildList.push_front(child); + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.front()) + { + mChildList.remove( child ); + mChildList.push_front(child); + } } } void LLView::sendChildToBack(LLView* child) { +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child && child->getParent() == this) { - mChildList.remove( child ); - mChildList.push_back(child); + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.back()) + { + mChildList.remove( child ); + mChildList.push_back(child); + } } } @@ -266,12 +274,18 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child) } } -void LLView::addChild(LLView* child, S32 tab_group) +// virtual +bool LLView::addChild(LLView* child, S32 tab_group) { + if (!child) + { + return false; + } if (mParentView == child) { llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; } + // remove from current parent if (child->mParentView) { @@ -284,55 +298,46 @@ void LLView::addChild(LLView* child, S32 tab_group) // add to ctrl list if is LLUICtrl if (child->isCtrl()) { - // controls are stored in reverse order from render order - addCtrlAtEnd((LLUICtrl*) child, tab_group); + LLUICtrl* ctrl = static_cast(child); + mCtrlOrder.insert(tab_order_pair_t(ctrl, + tab_order_t(tab_group, mNextInsertionOrdinal))); + + mNextInsertionOrdinal++; } child->mParentView = this; updateBoundingRect(); + mLastTabGroup = tab_group; + return true; } -void LLView::addChildAtEnd(LLView* child, S32 tab_group) +bool LLView::addChildInBack(LLView* child, S32 tab_group) { - if (mParentView == child) - { - llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; - } - // remove from current parent - if (child->mParentView) + if(addChild(child, tab_group)) { - child->mParentView->removeChild(child); + sendChildToBack(child); + return true; } - // add to back of child list - mChildList.push_back(child); - - // add to ctrl list if is LLUICtrl - if (child->isCtrl()) - { - // controls are stored in reverse order from render order - addCtrl((LLUICtrl*) child, tab_group); - } - - child->mParentView = this; - updateBoundingRect(); + return false; } // remove the specified child from the view, and set it's parent to NULL. -void LLView::removeChild(LLView* child, BOOL deleteIt) +void LLView::removeChild(LLView* child) { + //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child->mParentView == this) { mChildList.remove( child ); child->mParentView = NULL; if (child->isCtrl()) { - removeCtrl((LLUICtrl*)child); - } - if (deleteIt) - { - delete child; + child_tab_order_t::iterator found = mCtrlOrder.find(static_cast(child)); + if(found != mCtrlOrder.end()) + { + mCtrlOrder.erase(found); + } } } else @@ -342,28 +347,6 @@ void LLView::removeChild(LLView* child, BOOL deleteIt) updateBoundingRect(); } -void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group) -{ - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, mNextInsertionOrdinal++))); -} - -void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group) -{ - // add to front of list by using negative ordinal, which monotonically increases - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, -1 * mNextInsertionOrdinal++))); -} - -void LLView::removeCtrl(LLUICtrl* ctrl) -{ - child_tab_order_t::iterator found = mCtrlOrder.find(ctrl); - if(found != mCtrlOrder.end()) - { - mCtrlOrder.erase(found); - } -} - LLView::ctrl_list_t LLView::getCtrlList() const { ctrl_list_t controls; @@ -653,7 +636,7 @@ BOOL LLView::canSnapTo(const LLView* other_view) } // virtual -void LLView::snappedTo(const LLView* snap_view) +void LLView::setSnappedTo(const LLView* snap_view) { } @@ -671,6 +654,17 @@ BOOL LLView::handleHover(S32 x, S32 y, MASK mask) return handled; } +void LLView::onMouseEnter(S32 x, S32 y, MASK mask) +{ + //llinfos << "Mouse entered " << getName() << llendl; +} + +void LLView::onMouseLeave(S32 x, S32 y, MASK mask) +{ + //llinfos << "Mouse left " << getName() << llendl; +} + + std::string LLView::getShowNamesToolTip() { LLView* view = getParent(); @@ -731,23 +725,14 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s // get our own tooltip tool_tip = mToolTipMsg.getString(); - if ( - LLUI::sShowXUINames + + if (LLUI::sShowXUINames && (tool_tip.find(".xml", 0) == std::string::npos) && (mName.find("Drag", 0) == std::string::npos)) { tool_tip = getShowNamesToolTip(); } - BOOL show_names_text_box = LLUI::sShowXUINames && dynamic_cast(this) != NULL; - - // don't allow any siblings to handle this event - // even if we don't have a tooltip - if (getMouseOpaque() || show_names_text_box) - { - handled = TRUE; - } - if(!tool_tip.empty()) { msg = tool_tip; @@ -759,7 +744,13 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s localPointToScreen( mRect.getWidth(), mRect.getHeight(), &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); - + } + // don't allow any siblings to handle this event + // even if we don't have a tooltip + if (getMouseOpaque() || + (!tool_tip.empty() && + (!LLUI::sShowXUINames || dynamic_cast(this)))) + { handled = TRUE; } @@ -925,22 +916,22 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask) handled_view = this; } - // HACK If we're editing UI, select the leaf view that ate the click. - if (sEditingUI && handled_view) - { - // need to find leaf views, big hack - LLButton* buttonp = dynamic_cast(handled_view); - LLLineEditor* line_editorp = dynamic_cast(handled_view); - LLTextEditor* text_editorp = dynamic_cast(handled_view); - LLTextBox* text_boxp = dynamic_cast(handled_view); - if (buttonp - || line_editorp - || text_editorp - || text_boxp) - { - sEditingUIView = handled_view; - } - } + //// HACK If we're editing UI, select the leaf view that ate the click. + //if (sEditingUI && handled_view) + //{ + // // need to find leaf views, big hack + // LLButton* buttonp = dynamic_cast(handled_view); + // LLLineEditor* line_editorp = dynamic_cast(handled_view); + // LLTextEditor* text_editorp = dynamic_cast(handled_view); + // LLTextBox* text_boxp = dynamic_cast(handled_view); + // if (buttonp + // || line_editorp + // || text_editorp + // || text_boxp) + // { + // sEditingUIView = handled_view; + // } + //} return handled; } @@ -1166,6 +1157,7 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask) { sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage; } + handled_view = viewp; break; } @@ -1328,55 +1320,58 @@ void LLView::draw() } } - LLRect rootRect = getRootView()->getRect(); - LLRect screenRect; - - // draw focused control on top of everything else - LLView* focus_view = gFocusMgr.getKeyboardFocus(); - if (focus_view && focus_view->getParent() != this) + if (!mChildList.empty()) { - focus_view = NULL; - } + LLRect rootRect = getRootView()->getRect(); + LLRect screenRect; - ++sDepth; - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) - { - LLView *viewp = *child_iter; + // draw focused control on top of everything else + LLView* focus_view = gFocusMgr.getKeyboardFocus(); + if (focus_view && focus_view->getParent() != this) + { + focus_view = NULL; + } - if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) + ++sDepth; + + for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) { - // Only draw views that are within the root view - localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.rectInRect(&screenRect) ) + child_list_reverse_iter_t child = child_iter++; + LLView *viewp = *child; + + if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) { - glMatrixMode(GL_MODELVIEW); - LLUI::pushMatrix(); + // Only draw views that are within the root view + localRectToScreen(viewp->getRect(),&screenRect); + if ( rootRect.rectInRect(&screenRect) ) { - LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); - viewp->draw(); + glMatrixMode(GL_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); + viewp->draw(); + } + LLUI::popMatrix(); } - LLUI::popMatrix(); } - } - } - --sDepth; + } + --sDepth; - if (focus_view && focus_view->getVisible()) - { - drawChild(focus_view); + if (focus_view && focus_view->getVisible()) + { + drawChild(focus_view); + } } - // HACK - if (sEditingUI && this == sEditingUIView) - { - drawDebugRect(); - } + gGL.getTexUnit(0)->disable(); } //Draw a box for debugging. void LLView::drawDebugRect() { + std::set::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element + LLUI::pushMatrix(); { // drawing solids requires texturing be disabled @@ -1391,9 +1386,21 @@ void LLView::drawDebugRect() // draw red rectangle for the border LLColor4 border_color(0.f, 0.f, 0.f, 1.f); - if (sEditingUI) + //if (sEditingUI) + //{ + // border_color.mV[0] = 1.f; + //} + if(preview_iter != sPreviewHighlightedElements.end()) { - border_color.mV[0] = 1.f; + if(LLView::sPreviewClickedElement && this == sPreviewClickedElement) + { + border_color = LLColor4::red; + } + else + { + static LLUICachedControl scroll_highlighted_color ("ScrollHighlightedColor", *(new LLColor4)); + border_color = scroll_highlighted_color; + } } else { @@ -1416,8 +1423,8 @@ void LLView::drawDebugRect() gGL.vertex2i(0, debug_rect.getHeight() - 1); gGL.end(); - // Draw the name if it's not a leaf node - if (mChildList.size() && !sEditingUI) + // Draw the name if it's not a leaf node or not in editing or preview mode + if (mChildList.size() && preview_iter == sPreviewHighlightedElements.end()) { //char temp[256]; S32 x, y; @@ -1427,7 +1434,7 @@ void LLView::drawDebugRect() std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), debug_rect.getWidth(), debug_rect.getHeight()); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, - LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, + LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); } } @@ -1583,15 +1590,28 @@ void LLView::updateBoundingRect() } } -LLRect LLView::getScreenRect() const +LLRect LLView::calcScreenRect() const { - // *FIX: check for one-off error LLRect screen_rect; localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom); localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop); return screen_rect; } +LLRect LLView::calcScreenBoundingRect() const +{ + LLRect screen_rect; + // get bounding rect, if used + LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect; + + // convert to local coordinates, as defined by mRect + bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); + + localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom); + localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop); + return screen_rect; +} + LLRect LLView::getLocalBoundingRect() const { LLRect local_bounding_rect = getBoundingRect(); @@ -1690,7 +1710,12 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ if (create_if_missing) { - return createDummyWidget(name); + LLView* view = getDummyWidget(name); + if (!view) + { + view = LLUICtrlFactory::createDummyWidget(name); + } + return view; } return NULL; } @@ -1779,12 +1804,32 @@ LLView* LLView::getRootView() return view; } -BOOL LLView::deleteViewByHandle(LLHandle handle) +LLView* LLView::findPrevSibling(LLView* child) +{ + child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child); + if (prev_it != mChildList.end() && prev_it != mChildList.begin()) + { + return *(--prev_it); + } + return NULL; +} + +LLView* LLView::findNextSibling(LLView* child) +{ + child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child); + if (next_it != mChildList.end()) + { + next_it++; + } + + return (next_it != mChildList.end()) ? *next_it : NULL; +} + +void LLView::deleteViewByHandle(LLHandle handle) { LLView* viewp = handle.get(); delete viewp; - return viewp != NULL; } @@ -1945,132 +1990,6 @@ BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* o return FALSE; } -// virtual -LLXMLNodePtr LLView::getXML(bool save_children) const -{ - //FIXME: need to provide actual derived type tag, probably outside this method - LLXMLNodePtr node = new LLXMLNode("view", FALSE); - - node->createChild("name", TRUE)->setStringValue(getName()); - node->createChild("width", TRUE)->setIntValue(getRect().getWidth()); - node->createChild("height", TRUE)->setIntValue(getRect().getHeight()); - - LLView* parent = getParent(); - S32 left = getRect().mLeft; - S32 bottom = getRect().mBottom; - if (parent) bottom -= parent->getRect().getHeight(); - - node->createChild("left", TRUE)->setIntValue(left); - node->createChild("bottom", TRUE)->setIntValue(bottom); - - U32 follows_flags = getFollows(); - if (follows_flags) - { - std::stringstream buffer; - bool pipe = false; - if (followsLeft()) - { - buffer << "left"; - pipe = true; - } - if (followsTop()) - { - if (pipe) buffer << "|"; - buffer << "top"; - pipe = true; - } - if (followsRight()) - { - if (pipe) buffer << "|"; - buffer << "right"; - pipe = true; - } - if (followsBottom()) - { - if (pipe) buffer << "|"; - buffer << "bottom"; - } - node->createChild("follows", TRUE)->setStringValue(buffer.str()); - } - // Export all widgets as enabled and visible - code must disable. - node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque ); - if (!mToolTipMsg.getString().empty()) - { - node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString()); - } - if (mSoundFlags != MOUSE_UP) - { - node->createChild("sound_flags", TRUE)->setIntValue((S32)mSoundFlags); - } - - node->createChild("enabled", TRUE)->setBoolValue(getEnabled()); - - if (!mControlName.empty()) - { - node->createChild("control_name", TRUE)->setStringValue(mControlName); - } - return node; -} - -//static -LLView* LLView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - LLView* viewp = new LLView(); - viewp->initFromXML(node, parent); - return viewp; -} - -// static -void LLView::addColorXML(LLXMLNodePtr node, const LLColor4& color, - const char* xml_name, const char* control_name) -{ - if (color != LLUI::sColorsGroup->getColor(ll_safe_string(control_name))) - { - node->createChild(xml_name, TRUE)->setFloatValue(4, color.mV); - } -} - -//static -std::string LLView::escapeXML(const std::string& xml, std::string& indent) -{ - std::string ret = indent + "\"" + LLXMLNode::escapeXML(xml); - - //replace every newline with a close quote, new line, indent, open quote - size_t index = ret.size()-1; - size_t fnd; - - while ((fnd = ret.rfind("\n", index)) != std::string::npos) - { - ret.replace(fnd, 1, "\"\n" + indent + "\""); - index = fnd-1; - } - - //append close quote - ret.append("\""); - - return ret; -} - -// static -LLWString LLView::escapeXML(const LLWString& xml) -{ - LLWString out; - for (LLWString::size_type i = 0; i < xml.size(); ++i) - { - llwchar c = xml[i]; - switch(c) - { - case '"': out.append(utf8string_to_wstring(""")); break; - case '\'': out.append(utf8string_to_wstring("'")); break; - case '&': out.append(utf8string_to_wstring("&")); break; - case '<': out.append(utf8string_to_wstring("<")); break; - case '>': out.append(utf8string_to_wstring(">")); break; - default: out.push_back(c); break; - } - } - return out; -} - // static const LLCtrlQuery & LLView::getTabOrderQuery() { @@ -2107,7 +2026,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery() } -void LLView::userSetShape(const LLRect& new_rect) +void LLView::setShape(const LLRect& new_rect, bool by_user) +{ + handleReshape(new_rect, by_user); +} + +void LLView::handleReshape(const LLRect& new_rect, bool by_user) { reshape(new_rect.getWidth(), new_rect.getHeight()); translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom); @@ -2355,560 +2279,482 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna // Listener dispatch functions //----------------------------------------------------------------------------- -void LLView::registerEventListener(std::string name, LLSimpleListener* function) -{ - mDispatchList.insert(std::pair(name, function)); -} -void LLView::deregisterEventListener(std::string name) +LLControlVariable *LLView::findControl(const std::string& name) { - dispatch_list_t::iterator itor = mDispatchList.find(name); - if (itor != mDispatchList.end()) + // parse the name to locate which group it belongs to + std::size_t key_pos= name.find("."); + if(key_pos!= std::string::npos ) { - mDispatchList.erase(itor); + std::string control_group_key = name.substr(0, key_pos); + LLControlVariable* control; + // check if it's in the control group that name indicated + if(LLUI::sSettingGroups[control_group_key]) + { + control = LLUI::sSettingGroups[control_group_key]->getControl(name); + if (control) + { + return control; + } + } } + + LLControlGroup& control_group = LLUI::getControlControlGroup(name); + return control_group.getControl(name); } -std::string LLView::findEventListener(LLSimpleListener *listener) const +const widget_registry_t& LLView::getChildRegistry() const { - dispatch_list_t::const_iterator itor; - for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) - { - if (itor->second == listener) - { - return itor->first; - } - } - if (mParentView) - { - return mParentView->findEventListener(listener); - } - return LLStringUtil::null; + static widget_registry_t empty_registry; + return empty_registry; } -LLSimpleListener* LLView::getListenerByName(const std::string& callback_name) + +const S32 FLOATER_H_MARGIN = 15; +const S32 MIN_WIDGET_HEIGHT = 10; +const S32 VPAD = 4; + +void LLView::initFromParams(const LLView::Params& params) { - LLSimpleListener* callback = NULL; - dispatch_list_t::iterator itor = mDispatchList.find(callback_name); - if (itor != mDispatchList.end()) - { - callback = itor->second; - } - else if (mParentView) + LLRect required_rect = getRequiredRect(); + + S32 width = llmax(getRect().getWidth(), required_rect.getWidth()); + S32 height = llmax(getRect().getHeight(), required_rect.getHeight()); + + reshape(width, height); + + // call virtual methods with most recent data + // use getters because these values might not come through parameter block + setEnabled(getEnabled()); + setVisible(getVisible()); + + if (!params.name().empty()) { - callback = mParentView->getListenerByName(callback_name); + setName(params.name()); } - return callback; + + mLayout = params.layout(); } -LLControlVariable *LLView::findControl(const std::string& name) +void LLView::parseFollowsFlags(const LLView::Params& params) { - control_map_t::iterator itor = mFloaterControls.find(name); - if (itor != mFloaterControls.end()) + // preserve follows flags set by code if user did not override + if (!params.follows.isProvided()) { - return itor->second; + return; } - if (mParentView) + + // interpret either string or bitfield version of follows + if (params.follows.string.isChosen()) { - return mParentView->findControl(name); - } - return LLUI::sConfigGroup->getControl(name); -} + setFollows(FOLLOWS_NONE); -const S32 FLOATER_H_MARGIN = 15; -const S32 MIN_WIDGET_HEIGHT = 10; -const S32 VPAD = 4; + std::string follows = params.follows.string; -// static -U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect) -{ - U32 follows = 0; - S32 x = rect.mLeft; - S32 y = rect.mBottom; - S32 w = rect.getWidth(); - S32 h = rect.getHeight(); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|"); + tokenizer tokens(follows, sep); + tokenizer::iterator token_iter = tokens.begin(); - U32 last_x = 0; - U32 last_y = 0; - if (parent_view) - { - last_y = parent_view->getRect().getHeight(); - child_list_t::const_iterator itor = parent_view->getChildList()->begin(); - if (itor != parent_view->getChildList()->end()) + while(token_iter != tokens.end()) { - LLView *last_view = (*itor); - if (last_view->getSaveToXML()) + const std::string& token_str = *token_iter; + if (token_str == "left") + { + setFollowsLeft(); + } + else if (token_str == "right") + { + setFollowsRight(); + } + else if (token_str == "top") { - last_x = last_view->getRect().mLeft; - last_y = last_view->getRect().mBottom; + setFollowsTop(); } + else if (token_str == "bottom") + { + setFollowsBottom(); + } + else if (token_str == "all") + { + setFollowsAll(); + } + ++token_iter; } } - - std::string rect_control; - node->getAttributeString("rect_control", rect_control); - if (! rect_control.empty()) - { - LLRect rect = LLUI::sConfigGroup->getRect(rect_control); - x = rect.mLeft; - y = rect.mBottom; - w = rect.getWidth(); - h = rect.getHeight(); - } - - if (node->hasAttribute("left")) - { - node->getAttributeS32("left", x); - } - if (node->hasAttribute("bottom")) + else if (params.follows.flags.isChosen()) { - node->getAttributeS32("bottom", y); + setFollows(params.follows.flags); } +} - // Make your width the width of the containing - // view if you don't specify a width. - if (parent_view) - { - if(w == 0) - { - w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x); - } - if(h == 0) - { - h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight()); +// static +//LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) +//{ +// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; +// +// if (node->hasAttribute("halign")) +// { +// std::string horizontal_align_name; +// node->getAttributeString("halign", horizontal_align_name); +// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); +// } +// return gl_hfont_align; +//} + +// Return the rectangle of the last-constructed child, +// if present and a first-class widget (eg, not a close box or drag handle) +// Returns true if found +static bool get_last_child_rect(LLView* parent, LLRect *rect) +{ + if (!parent) return false; + + LLView::child_list_t::const_iterator itor = + parent->getChildList()->begin(); + for (;itor != parent->getChildList()->end(); ++itor) + { + LLView *last_view = (*itor); + if (last_view->getSaveToXML()) + { + *rect = last_view->getRect(); + return true; } } + return false; +} - if (node->hasAttribute("width")) - { - node->getAttributeS32("width", w); - } - if (node->hasAttribute("height")) +//static +void LLView::setupParams(LLView::Params& p, LLView* parent) +{ + const S32 VPAD = 4; + const S32 MIN_WIDGET_HEIGHT = 10; + + p.serializable(true); + + // *NOTE: This will confuse export of floater/panel coordinates unless + // the default is also "topleft". JC + if (p.layout().empty() && parent) { - node->getAttributeS32("height", h); + p.layout = parent->getLayout(); } - if (parent_view) + if (parent) { - if (node->hasAttribute("left_delta")) - { - S32 left_delta = 0; - node->getAttributeS32("left_delta", left_delta); - x = last_x + left_delta; - } - else if (node->hasAttribute("left") && node->hasAttribute("right")) + LLRect parent_rect = parent->getLocalRect(); + // overwrite uninitialized rect params, using context + LLRect last_rect = parent->getLocalRect(); + + bool layout_topleft = (p.layout() == "topleft"); + if (layout_topleft) { - // compute width based on left and right - S32 right = 0; - node->getAttributeS32("right", right); - if (right < 0) - { - right = parent_view->getRect().getWidth() + right; - } - w = right - x; + //invert top to bottom + if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; + if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom; } - else if (node->hasAttribute("left")) + + // convert negative or centered coordinates to parent relative values + // Note: some of this logic matches the logic in TypedParam::getValueFromBlock() + + if (p.center_horiz) { - if (x < 0) + if (p.rect.left.isProvided() && p.rect.right.isProvided()) { - x = parent_view->getRect().getWidth() + x; - follows |= FOLLOWS_RIGHT; + S32 width = p.rect.right - p.rect.left; + width = llmax(width, 0); + S32 offset = parent_rect.getWidth()/2 - width/2; + p.rect.left = p.rect.left + offset; + p.rect.right = p.rect.right + offset; } else { - follows |= FOLLOWS_LEFT; + p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2; } } - else if (node->hasAttribute("width") && node->hasAttribute("right")) + else + { + 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(); + } + if (p.center_vert) { - S32 right = 0; - node->getAttributeS32("right", right); - if (right < 0) + if (p.rect.bottom.isProvided() && p.rect.top.isProvided()) { - right = parent_view->getRect().getWidth() + right; + S32 height = p.rect.top - p.rect.bottom; + height = llmax(height, 0); + S32 offset = parent_rect.getHeight()/2 - height/2; + p.rect.bottom = p.rect.bottom + offset; + p.rect.top = p.rect.top + offset; + } + else + { + p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2; } - x = right - w; } else { - // left not specified, same as last - x = last_x; + 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(); } - if (node->hasAttribute("bottom_delta")) + + // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels + if (!p.rect.height.isProvided() && !p.rect.top.isProvided()) { - S32 bottom_delta = 0; - node->getAttributeS32("bottom_delta", bottom_delta); - y = last_y + bottom_delta; + p.rect.height = MIN_WIDGET_HEIGHT; } - else if (node->hasAttribute("top")) + + last_rect.translate(0, last_rect.getHeight()); + + // If there was a recently constructed child, use its rectangle + get_last_child_rect(parent, &last_rect); + + if (layout_topleft) { - // compute height based on top - S32 top = 0; - node->getAttributeS32("top", top); - if (top < 0) + p.bottom_delta.setIfNotProvided(0, false); + + // Invert the sense of bottom_delta for topleft layout + if (p.bottom_delta.isProvided()) { - top = parent_view->getRect().getHeight() + top; + p.bottom_delta = -p.bottom_delta; } - h = top - y; - } - else if (node->hasAttribute("bottom")) - { - if (y < 0) + else if (p.top_pad.isProvided()) { - y = parent_view->getRect().getHeight() + y; - follows |= FOLLOWS_TOP; + p.bottom_delta = -(p.rect.height + p.top_pad); } - else + else if (p.top_delta.isProvided()) { - follows |= FOLLOWS_BOTTOM; + p.bottom_delta = + -(p.top_delta + p.rect.height - last_rect.getHeight()); } - } - else - { - // if bottom not specified, generate automatically - if (last_y == 0) + else if (!p.bottom_delta.isProvided() + && !p.left_delta.isProvided() + && !p.top_pad.isProvided() + && !p.left_pad.isProvided()) { - // treat first child as "bottom" - y = parent_view->getRect().getHeight() - (h + VPAD); - follows |= FOLLOWS_TOP; + // set default position is just below last rect + p.bottom_delta.set(-(p.rect.height + VPAD), false); } - else + + // default to same left edge + p.left_delta.setIfNotProvided(0, false); + if (p.left_pad.isProvided()) { - // treat subsequent children as "bottom_delta" - y = last_y - (h + VPAD); + // left_pad is based on prior widget's right edge + p.left_delta.set(p.left_pad + last_rect.getWidth(), false); } + + last_rect.translate(p.left_delta, p.bottom_delta); + } + else + { + // set default position is just below last rect + p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false); + p.left_delta.setIfNotProvided(0, false); + last_rect.translate(p.left_delta, p.bottom_delta); } - } - else - { - x = llmax(x, 0); - y = llmax(y, 0); - follows = FOLLOWS_LEFT | FOLLOWS_TOP; - } - rect.setOriginAndSize(x, y, w, h); - - return follows; -} - -void LLView::initFromXML(LLXMLNodePtr node, LLView* parent) -{ - // create rect first, as this will supply initial follows flags - LLRect view_rect; - U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect()); - // call reshape in case there are any child elements that need to be layed out - reshape(view_rect.getWidth(), view_rect.getHeight()); - setRect(view_rect); - setFollows(follows_flags); - - parseFollowsFlags(node); - if (node->hasAttribute("control_name")) - { - std::string control_name; - node->getAttributeString("control_name", control_name); - setControlName(control_name, NULL); - } + // this handles case where *both* x and x_delta are provided + // ignore x in favor of default x + x_delta + if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); + if (p.left_delta.isProvided()) p.rect.left.set(0, false); - if (node->hasAttribute("tool_tip")) - { - std::string tool_tip_msg; - node->getAttributeString("tool_tip", tool_tip_msg); - setToolTip(tool_tip_msg); + // selectively apply rectangle defaults, making sure that + // params are not flagged as having been "provided" + // as rect params are overconstrained and rely on provided flags + p.rect.left.setIfNotProvided(last_rect.mLeft, false); + p.rect.bottom.setIfNotProvided(last_rect.mBottom, false); + p.rect.top.setIfNotProvided(last_rect.mTop, false); + p.rect.right.setIfNotProvided(last_rect.mRight, false); + p.rect.width.setIfNotProvided(last_rect.getWidth(), false); + p.rect.height.setIfNotProvided(last_rect.getHeight(), false); } +} - if (node->hasAttribute("enabled")) - { - BOOL enabled; - node->getAttributeBOOL("enabled", enabled); - setEnabled(enabled); - } - - if (node->hasAttribute("visible")) +static S32 invert_vertical(S32 y, LLView* parent) +{ + if (y < 0) { - BOOL visible; - node->getAttributeBOOL("visible", visible); - setVisible(visible); + // already based on top-left, just invert + return -y; } - - if (node->hasAttribute("hover_cursor")) + else if (parent) { - std::string cursor_string; - node->getAttributeString("hover_cursor", cursor_string); - mHoverCursor = getCursorFromString(cursor_string); + // use parent to flip coordinate + S32 parent_height = parent->getRect().getHeight(); + return parent_height - y; } - - node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect); - node->getAttributeBOOL("mouse_opaque", mMouseOpaque); - - node->getAttributeS32("default_tab_group", mDefaultTabGroup); - - reshape(view_rect.getWidth(), view_rect.getHeight()); -} - -void LLView::parseFollowsFlags(LLXMLNodePtr node) -{ - if (node->hasAttribute("follows")) + else { - setFollowsNone(); - - std::string follows; - node->getAttributeString("follows", follows); - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|"); - tokenizer tokens(follows, sep); - tokenizer::iterator token_iter = tokens.begin(); - - while(token_iter != tokens.end()) - { - const std::string& token_str = *token_iter; - if (token_str == "left") + llwarns << "Attempting to convert layout to top-left with no parent" << llendl; + return y; + } +} + +// Assumes that input is in bottom-left coordinates, hence must call +// _before_ convert_coords_to_top_left(). +static void convert_to_relative_layout(LLView::Params& p, LLView* parent) +{ + // Use setupParams to get the final widget rectangle + // according to our wacky layout rules. + LLView::Params final = p; + LLView::setupParams(final, parent); + // Must actually extract the rectangle to get consistent + // right = left+width, top = bottom+height + LLRect final_rect = final.rect; + + // We prefer to write out top edge instead of bottom, regardless + // of whether we use relative positioning + bool converted_top = false; + + // Look for a last rectangle + LLRect last_rect; + if (get_last_child_rect(parent, &last_rect)) + { + // ...we have a previous widget to compare to + const S32 EDGE_THRESHOLD_PIXELS = 4; + S32 left_pad = final_rect.mLeft - last_rect.mRight; + S32 left_delta = final_rect.mLeft - last_rect.mLeft; + S32 top_pad = final_rect.mTop - last_rect.mBottom; + S32 top_delta = final_rect.mTop - last_rect.mTop; + // If my left edge is almost the same, or my top edge is + // almost the same... + if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS + || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS) + { + // ...use relative positioning + // prefer top_pad if widgets are stacking vertically + // (coordinate system is still bottom-left here) + if (top_pad < 0) { - setFollowsLeft(); + p.top_pad = top_pad; + p.top_delta.setProvided(false); } - else if (token_str == "right") - { - setFollowsRight(); - } - else if (token_str == "top") + else { - setFollowsTop(); + p.top_pad.setProvided(false); + p.top_delta = top_delta; } - else if (token_str == "bottom") + // null out other vertical specifiers + p.rect.top.setProvided(false); + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + converted_top = true; + + // prefer left_pad if widgets are stacking horizontally + if (left_pad > 0) { - setFollowsBottom(); + p.left_pad = left_pad; + p.left_delta.setProvided(false); } - else if (token_str == "all") + else { - setFollowsAll(); + p.left_pad.setProvided(false); + p.left_delta = left_delta; } - ++token_iter; + p.rect.left.setProvided(false); + p.rect.right.setProvided(false); } } -} -// static -LLFontGL* LLView::selectFont(LLXMLNodePtr node) -{ - std::string font_name, font_size, font_style; - U8 style = 0; - - if (node->hasAttribute("font")) - { - node->getAttributeString("font", font_name); - } - - if (node->hasAttribute("font_size")) + if (!converted_top) { - node->getAttributeString("font_size", font_size); + // ...this is the first widget, or one that wasn't aligned + // prefer top/left specification + p.rect.top = final_rect.mTop; + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + p.top_pad.setProvided(false); + p.top_delta.setProvided(false); } - - if (node->hasAttribute("font_style")) - { - node->getAttributeString("font_style", font_style); - style = LLFontGL::getStyleFromString(font_style); - } - - if (node->hasAttribute("font-style")) - { - node->getAttributeString("font-style", font_style); - style = LLFontGL::getStyleFromString(font_style); - } - - if (font_name.empty()) - return NULL; - - LLFontDescriptor desc(font_name, font_size, style); - LLFontGL* gl_font = LLFontGL::getFont(desc); - - return gl_font; } -// static -LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) +static void convert_coords_to_top_left(LLView::Params& p, LLView* parent) { - LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; - - if (node->hasAttribute("halign")) + // Convert the coordinate system to be top-left based. + if (p.rect.top.isProvided()) { - std::string horizontal_align_name; - node->getAttributeString("halign", horizontal_align_name); - gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); + p.rect.top = invert_vertical(p.rect.top, parent); } - return gl_hfont_align; -} - -// static -LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node) -{ - LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE; - - if (node->hasAttribute("valign")) + if (p.rect.bottom.isProvided()) { - std::string vert_align_name; - node->getAttributeString("valign", vert_align_name); - gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name); + p.rect.bottom = invert_vertical(p.rect.bottom, parent); } - return gl_vfont_align; -} - -// static -LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node) -{ - LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL; - - if (node->hasAttribute("style")) + if (p.top_pad.isProvided()) { - std::string style_flags_name; - node->getAttributeString("style", style_flags_name); - - if (style_flags_name == "normal") - { - gl_font_style = LLFontGL::NORMAL; - } - else if (style_flags_name == "bold") - { - gl_font_style = LLFontGL::BOLD; - } - else if (style_flags_name == "italic") - { - gl_font_style = LLFontGL::ITALIC; - } - else if (style_flags_name == "underline") - { - gl_font_style = LLFontGL::UNDERLINE; - } - //else leave left + p.top_pad = -p.top_pad; } - return gl_font_style; -} - -bool LLView::setControlValue(const LLSD& value) -{ - std::string ctrlname = getControlName(); - if (!ctrlname.empty()) + if (p.top_delta.isProvided()) { - LLUI::sConfigGroup->setValue(ctrlname, value); - return true; + p.top_delta = -p.top_delta; } - return false; -} - -//virtual -void LLView::setControlName(const std::string& control_name, LLView *context) -{ - if (context == NULL) + if (p.bottom_delta.isProvided()) { - context = this; + p.bottom_delta = -p.bottom_delta; } + p.layout = "topleft"; +} - if (!mControlName.empty()) +//static +void LLView::setupParamsForExport(Params& p, LLView* parent) +{ + // Don't convert if already top-left based + if (p.layout() == "topleft") { - llwarns << "setControlName called twice on same control!" << llendl; - mControlConnection.disconnect(); // disconnect current signal - mControlName.clear(); + return; } - - // Register new listener - if (!control_name.empty()) - { - LLControlVariable *control = context->findControl(control_name); - if (control) - { - mControlName = control_name; - mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value"))); - setValue(control->getValue()); - } - } -} -// static -bool LLView::controlListener(const LLSD& newvalue, LLHandle handle, std::string type) -{ - LLView* view = handle.get(); - if (view) + // heuristic: Many of our floaters and panels were bulk-exported. + // These specify exactly bottom/left and height/width. + // Others were done by hand using bottom_delta and/or left_delta. + // Some rely on not specifying left to mean align with left edge. + // Try to convert both to use relative layout, but using top-left + // coordinates. + // Avoid rectangles where top/bottom/left/right was specified. + if (p.rect.height.isProvided() && p.rect.width.isProvided()) { - if (type == "value") + if (p.rect.bottom.isProvided() && p.rect.left.isProvided()) { - view->setValue(newvalue); - return true; + // standard bulk export, convert it + convert_to_relative_layout(p, parent); } - else if (type == "enabled") + else if (p.rect.bottom.isProvided() && p.left_delta.isProvided()) { - view->setEnabled(newvalue.asBoolean()); - return true; + // hand layout with left_delta + convert_to_relative_layout(p, parent); } - else if (type == "visible") + else if (p.bottom_delta.isProvided()) { - view->setVisible(newvalue.asBoolean()); - return true; + // hand layout with bottom_delta + // don't check for p.rect.left or p.left_delta because sometimes + // this layout doesn't set it for widgets that are left-aligned + convert_to_relative_layout(p, parent); } } - return false; -} -void LLView::addBoolControl(const std::string& name, bool initial_value) -{ - mFloaterControls[name] = new LLControlVariable(name, TYPE_BOOLEAN, initial_value, std::string("Internal floater control")); -} - -LLControlVariable *LLView::getControl(const std::string& name) -{ - control_map_t::iterator itor = mFloaterControls.find(name); - if (itor != mFloaterControls.end()) - { - return itor->second; - } - return NULL; + convert_coords_to_top_left(p, parent); } -//virtual -void LLView::setValue(const LLSD& value) -{ -} - -//virtual -LLSD LLView::getValue() const -{ - return LLSD(); -} - -LLView* LLView::createWidget(LLXMLNodePtr xml_node) const -{ - // forward requests to ui ctrl factory - return LLUICtrlFactory::getInstance()->createCtrlWidget(NULL, xml_node); -} - -// -// LLWidgetClassRegistry -// - -LLWidgetClassRegistry::LLWidgetClassRegistry() +LLView::tree_iterator_t LLView::beginTree() { + return tree_iterator_t(this, + boost::bind(boost::mem_fn(&LLView::beginChild), _1), + boost::bind(boost::mem_fn(&LLView::endChild), _1)); } -void LLWidgetClassRegistry::registerCtrl(const std::string& tag, LLWidgetClassRegistry::factory_func_t function) +LLView::tree_iterator_t LLView::endTree() { - std::string lower_case_tag = tag; - LLStringUtil::toLower(lower_case_tag); - - mCreatorFunctions[lower_case_tag] = function; + // an empty iterator is an "end" iterator + return tree_iterator_t(); } -BOOL LLWidgetClassRegistry::isTagRegistered(const std::string &tag) -{ - return mCreatorFunctions.find(tag) != mCreatorFunctions.end(); -} - -LLWidgetClassRegistry::factory_func_t LLWidgetClassRegistry::getCreatorFunc(const std::string& ctrl_type) -{ - factory_map_t::const_iterator found_it = mCreatorFunctions.find(ctrl_type); - if (found_it == mCreatorFunctions.end()) +// only create maps on demand, as they incur heap allocation/deallocation cost +// when a view is constructed/deconstructed +LLView::dummy_widget_map_t& LLView::getDummyWidgetMap() const +{ + if (!mDummyWidgets) { - return NULL; + mDummyWidgets = new dummy_widget_map_t(); } - return found_it->second; + return *mDummyWidgets; } - -- cgit v1.2.3 From ade6bbb06c6a842f39a3fe32decf7c66682df092 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Sun, 21 Jun 2009 17:16:27 +0000 Subject: merge -r 124105-124625 skinning-13 -> viewer-2.0.0-3 --- indra/llui/llview.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 2e2ef4d79f..d225ad2767 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -124,7 +124,7 @@ LLView::LLView(const LLView::Params& p) mDefaultTabGroup(p.default_tab_group), mLastTabGroup(0), mToolTipMsg((LLStringExplicit)p.tool_tip()), - mDummyWidgets(NULL) + mDefaultWidgets(NULL) { // create rect first, as this will supply initial follows flags setShape(p.rect); @@ -157,12 +157,12 @@ LLView::~LLView() mParentView->removeChild(this); } - if (mDummyWidgets) + if (mDefaultWidgets) { - std::for_each(mDummyWidgets->begin(), mDummyWidgets->end(), + std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(), DeletePairedPointer()); - delete mDummyWidgets; - mDummyWidgets = NULL; + delete mDefaultWidgets; + mDefaultWidgets = NULL; } } @@ -1710,10 +1710,10 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ if (create_if_missing) { - LLView* view = getDummyWidget(name); + LLView* view = getDefaultWidget(name); if (!view) { - view = LLUICtrlFactory::createDummyWidget(name); + view = LLUICtrlFactory::createDefaultWidget(name); } return view; } @@ -2750,11 +2750,11 @@ LLView::tree_iterator_t LLView::endTree() // only create maps on demand, as they incur heap allocation/deallocation cost // when a view is constructed/deconstructed -LLView::dummy_widget_map_t& LLView::getDummyWidgetMap() const +LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const { - if (!mDummyWidgets) + if (!mDefaultWidgets) { - mDummyWidgets = new dummy_widget_map_t(); + mDefaultWidgets = new default_widget_map_t(); } - return *mDummyWidgets; + return *mDefaultWidgets; } -- cgit v1.2.3 From d6101558a171dbd2390792ac1e78d09fc2c27711 Mon Sep 17 00:00:00 2001 From: James Cook Date: Mon, 6 Jul 2009 21:58:04 +0000 Subject: Merge xui-army-5 to viewer-2, includes layout, art, and color changes, also UI color refactoring and new FreeType font library on Linux. svn merge -r126038:126164 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/xui-army-5 --- indra/llui/llview.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index d225ad2767..29d0f6a168 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1325,13 +1325,6 @@ void LLView::draw() LLRect rootRect = getRootView()->getRect(); LLRect screenRect; - // draw focused control on top of everything else - LLView* focus_view = gFocusMgr.getKeyboardFocus(); - if (focus_view && focus_view->getParent() != this) - { - focus_view = NULL; - } - ++sDepth; for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) @@ -1339,7 +1332,7 @@ void LLView::draw() child_list_reverse_iter_t child = child_iter++; LLView *viewp = *child; - if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) + if (viewp->getVisible() && viewp->getRect().isValid()) { // Only draw views that are within the root view localRectToScreen(viewp->getRect(),&screenRect); @@ -1357,11 +1350,6 @@ void LLView::draw() } --sDepth; - - if (focus_view && focus_view->getVisible()) - { - drawChild(focus_view); - } } gGL.getTexUnit(0)->disable(); @@ -1398,7 +1386,7 @@ void LLView::drawDebugRect() } else { - static LLUICachedControl scroll_highlighted_color ("ScrollHighlightedColor", *(new LLColor4)); + static LLUIColor scroll_highlighted_color = LLUIColorTable::instance().getColor("ScrollHighlightedColor"); border_color = scroll_highlighted_color; } } -- cgit v1.2.3 From 52aeaa32841e7d0b37abab0a2a2540c2be2f16b7 Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 7 Jul 2009 00:53:05 +0000 Subject: Merge skinning-14 to viewer-2, including refactoring many floaters to register them with LLFloaterReg, support for introspection of ParamBlock based UI widgets to dump XML schema, splitting llfolderview.cpp into three separate files to unravel dependencies and skeleton for for LLListView widget. Resolved conflicts in these files: lldraghandle.h, lluictrl.h, llchiclet.cpp, llfolderview.h/cpp, lliinventorybridge.cpp, llpanelpicks.cpp, llviewermenu.cpp, floater_mute.xml, floater_preferences.xml, notifications.xml, panel_preferences_audio.xml, panel_preferences_graphics1.xml, panel_region_general.xml svn merge -r124961:126284 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-14 --- indra/llui/llview.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 29d0f6a168..777cf096ac 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -99,10 +99,15 @@ LLView::Params::Params() left_delta("left_delta", S32_MAX), center_horiz("center_horiz", false), center_vert("center_vert", false), - serializable("", false), + from_xui("from_xui", false), user_resize("user_resize"), auto_resize("auto_resize"), - needs_translate("translate") + needs_translate("translate"), + xmlns("xmlns"), + xmlns_xsi("xmlns:xsi"), + xsi_schemaLocation("xsi:schemaLocation"), + xsi_type("xsi:type") + { addSynonym(rect, ""); } @@ -111,7 +116,7 @@ LLView::LLView(const LLView::Params& p) : mName(p.name), mParentView(NULL), mReshapeFlags(FOLLOWS_NONE), - mSaveToXML(p.serializable), + mSaveToXML(p.from_xui), mIsFocusRoot(FALSE), mLastVisible(FALSE), mNextInsertionOrdinal(0), @@ -2291,13 +2296,6 @@ LLControlVariable *LLView::findControl(const std::string& name) return control_group.getControl(name); } -const widget_registry_t& LLView::getChildRegistry() const -{ - static widget_registry_t empty_registry; - return empty_registry; -} - - const S32 FLOATER_H_MARGIN = 15; const S32 MIN_WIDGET_HEIGHT = 10; const S32 VPAD = 4; @@ -2418,7 +2416,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) const S32 VPAD = 4; const S32 MIN_WIDGET_HEIGHT = 10; - p.serializable(true); + p.from_xui(true); // *NOTE: This will confuse export of floater/panel coordinates unless // the default is also "topleft". JC -- cgit v1.2.3 From 923d84d08f98b33657d6bd861c34b985125db757 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Fri, 10 Jul 2009 20:43:08 +0000 Subject: EXT-127: Tooltips don't disappear immediately after moving mouse out of object reviewed by Austin --- indra/llui/llview.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 777cf096ac..f01aacb797 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -743,12 +743,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s msg = tool_tip; // Convert rect local to screen coordinates - localPointToScreen( - 0, 0, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - localPointToScreen( - mRect.getWidth(), mRect.getHeight(), - &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); + *sticky_rect_screen = calcScreenRect(); } // don't allow any siblings to handle this event // even if we don't have a tooltip -- cgit v1.2.3 From 83a6ea234f32bf30d1f16b276d128debb2aeea02 Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 14 Jul 2009 19:06:17 +0000 Subject: Merge skinning-15 to viewer-2. Fixes include: DEV-35175 Spawning context menu should not move mouse cursor (Note: introduces regression where menu can fall off bottom of screen, will fix shortly) DEV-35143 Modal alerts appear behind side tray DEV-35141 Landmarks image and description outside of landmarks Merging revisions 126418-126419,126726-126727,126856-126857,127010-127011,127014-127016 of svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-15 into G:\viewer-2.0.0-3, respecting ancestry --- indra/llui/llview.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index f01aacb797..2f9a6e7d46 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -401,32 +401,28 @@ bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const return (a_score == b_score) ? a < b : a_score < b_score; } -BOOL LLView::isInVisibleChain() const +bool LLView::trueToRoot(const boost::function& predicate) const { const LLView* cur_view = this; while(cur_view) { - if (!cur_view->getVisible()) + if(!predicate(cur_view)) { - return FALSE; + return false; } cur_view = cur_view->getParent(); } - return TRUE; + return true; +} + +BOOL LLView::isInVisibleChain() const +{ + return trueToRoot(&LLView::getVisible); } BOOL LLView::isInEnabledChain() const { - const LLView* cur_view = this; - while(cur_view) - { - if (!cur_view->getEnabled()) - { - return FALSE; - } - cur_view = cur_view->getParent(); - } - return TRUE; + return trueToRoot(&LLView::getEnabled); } // virtual -- cgit v1.2.3 From eb853f55c07ae4a3c3f2aa05fbabcf2e4b4dc115 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Tue, 4 Aug 2009 01:12:59 +0000 Subject: svn merge -r 128442:129343 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-18 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3 --- indra/llui/llview.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 2f9a6e7d46..d94472a8e5 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -603,14 +603,14 @@ void LLView::setVisible(BOOL visible) if (!getParent() || getParent()->isInVisibleChain()) { // tell all children of this view that the visibility may have changed - onVisibilityChange( visible ); + handleVisibilityChange( visible ); } updateBoundingRect(); } } // virtual -void LLView::onVisibilityChange ( BOOL new_visibility ) +void LLView::handleVisibilityChange ( BOOL new_visibility ) { for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { @@ -618,7 +618,7 @@ void LLView::onVisibilityChange ( BOOL new_visibility ) // only views that are themselves visible will have their overall visibility affected by their ancestors if (viewp->getVisible()) { - viewp->onVisibilityChange ( new_visibility ); + viewp->handleVisibilityChange ( new_visibility ); } } } -- cgit v1.2.3 From 0bf4b5f2222ffb8171be094613363427f3b8470a Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Wed, 12 Aug 2009 01:12:27 +0000 Subject: merge https://svn.aws.productengine.com/secondlife/export-from-ll@1277 https://svn.aws.productengine.com/secondlife/pe/stable-1@1297 -> viewer-2-0 Fixes: EXT 208 EXT 366 EXT-211 EXT-245 EXT-246 EXT-278 EXT-279 EXT-280 EXT-298 EXT-301 EXT-304 EXT-311 EXT-317 EXT-318 EXT-319 EXT-339 EXT-343 EXT-344 EXT-346 EXT-349 EXT-350 EXT-351 EXT-354 EXT-355 EXT-358 EXT-360 EXT-362 EXT-369 EXT-372 EXT-374 EXT-381 EXT-382 EXT-383 EXT-395 EXT-396 EXT-412 Other changes: Movement & Caemra controls work Profile and Me panel refactoring Notification refactoring --- indra/llui/llview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index d94472a8e5..e3b61dfaa2 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -75,6 +75,8 @@ S32 LLView::sLastBottomXML = S32_MIN; BOOL LLView::sIsDrawing = FALSE; #endif +static LLDefaultChildRegistry::Register r("view"); + LLView::Params::Params() : name("name", std::string("unnamed")), enabled("enabled", true), -- cgit v1.2.3 From 73caee4208a4e05f66583de099502012fd8415ea Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Fri, 14 Aug 2009 21:50:02 +0000 Subject: svn merge https://svn.aws.productengine.com/secondlife/export-from-ll/viewer-2-0@1331 https://svn.aws.productengine.com/secondlife/pe/stable-1@1340 -> viewer-2.0.0-3 EXT-269 EXT-274 EXT-276 EXT-277 EXT-282 EXT-296 EXT-342 EXT-370 EXT-379 EXT-394 EXT-398 EXT-405 EXT-407 EXT-410 EXT-413 EXT-414 EXT-450 EXT-456 EXT-477 EXT-482 EXT-496 --- indra/llui/llview.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index e3b61dfaa2..0ba028e1c8 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -947,16 +947,11 @@ BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask) BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks) { - BOOL handled = FALSE; if( getVisible() && getEnabled() ) { - handled = childrenHandleScrollWheel( x, y, clicks ) != NULL; - if( !handled && blockMouseEvent(x, y) ) - { - handled = TRUE; - } + return childrenHandleScrollWheel( x, y, clicks ) != NULL; } - return handled; + return FALSE; } BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask) -- cgit v1.2.3 From 138bf1132262c479dbbd5c95195db46b1efd065f Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Mon, 24 Aug 2009 20:04:52 +0000 Subject: merge -r 130399-131510 skinning-21 -> viewer-2.0.0-3 DEV-11254 DEV-11254 DEV-2003: DEV-21567 DEV-37301 EXT-104 EXT-138 EXT-217 EXT-256 EXT-259 EXT-259 EXT-328 EXT-348 EXT-386 EXT-399 EXT-403 EXT-460 EXT-492 EXT-492 EXT-531 EXT-537 EXT-684 improved text editor (handles multiple fonts simultaneously as well as inline widgets) --- indra/llui/llview.cpp | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 0ba028e1c8..e2dc85d03f 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1300,6 +1300,11 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask) } void LLView::draw() +{ + drawChildren(); +} + +void LLView::drawChildren() { if (sDebugRects) { @@ -1329,7 +1334,7 @@ void LLView::draw() { // Only draw views that are within the root view localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.rectInRect(&screenRect) ) + if ( rootRect.overlaps(screenRect) ) { glMatrixMode(GL_MODELVIEW); LLUI::pushMatrix(); @@ -1540,7 +1545,7 @@ void LLView::updateBoundingRect() LLRect child_bounding_rect = childp->getBoundingRect(); - if (local_bounding_rect.isNull()) + if (local_bounding_rect.isEmpty()) { // start out with bounding rect equal to first visible child's bounding rect local_bounding_rect = child_bounding_rect; @@ -1548,7 +1553,7 @@ void LLView::updateBoundingRect() else { // accumulate non-null children rectangles - if (!child_bounding_rect.isNull()) + if (!child_bounding_rect.isEmpty()) { local_bounding_rect.unionWith(child_bounding_rect); } @@ -1639,7 +1644,7 @@ BOOL LLView::hasAncestor(const LLView* parentp) const BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const { - LLView *child = getChildView(childname, TRUE, FALSE); + LLView *child = findChildView(childname, TRUE); if (child) { return gFocusMgr.childHasKeyboardFocus(child); @@ -1654,13 +1659,27 @@ BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const { - return getChildView(childname, recurse, FALSE) != NULL; + return findChildView(childname, recurse) != NULL; } //----------------------------------------------------------------------------- // getChildView() //----------------------------------------------------------------------------- -LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const +LLView* LLView::getChildView(const std::string& name, BOOL recurse) const +{ + LLView* child = findChildView(name, recurse); + if (!child) + { + child = getDefaultWidget(name); + if (!child) + { + child = LLUICtrlFactory::createDefaultWidget(name); + } + } + return child; +} + +LLView* LLView::findChildView(const std::string& name, BOOL recurse) const { //richard: should we allow empty names? //if(name.empty()) @@ -1681,23 +1700,13 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { LLView* childp = *child_it; - LLView* viewp = childp->getChildView(name, recurse, FALSE); + LLView* viewp = childp->findChildView(name, recurse); if ( viewp ) { return viewp; } } } - - if (create_if_missing) - { - LLView* view = getDefaultWidget(name); - if (!view) - { - view = LLUICtrlFactory::createDefaultWidget(name); - } - return view; - } return NULL; } -- cgit v1.2.3 From 745845f79987e4b4ab7f5728746a0eda8898930f Mon Sep 17 00:00:00 2001 From: Monroe Williams Date: Thu, 27 Aug 2009 19:00:18 +0000 Subject: svn merge -r 129841:129910 svn+ssh://svn.lindenlab.com/svn/linden/branches/moss/pluginapi_05-merge@129910 svn merge -r 129913:131718 svn+ssh://svn.lindenlab.com/svn/linden/branches/pluginapi/pluginapi_05 Some branch shenannigans in the pluginapi_05 branch caused this to become a two-part merge. --- indra/llui/llview.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'indra/llui/llview.cpp') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index e2dc85d03f..4770807ac7 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -145,12 +145,6 @@ LLView::~LLView() // llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators - if( gFocusMgr.getKeyboardFocus() == this ) - { - //llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; - gFocusMgr.removeKeyboardFocusWithoutCallback( this ); - } - if( hasMouseCapture() ) { //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; -- cgit v1.2.3