diff options
Diffstat (limited to 'indra/llui/llview.cpp')
-rw-r--r-- | indra/llui/llview.cpp | 319 |
1 files changed, 228 insertions, 91 deletions
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 0a28075ed6..d225ad2767 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -56,8 +56,6 @@ #include "lltexteditor.h" #include "lltextbox.h" -using namespace LLOldEvents; - BOOL LLView::sDebugRects = FALSE; BOOL LLView::sDebugKeys = FALSE; S32 LLView::sDepth = 0; @@ -95,9 +93,10 @@ LLView::Params::Params() layout("layout"), rect("rect"), bottom_delta("bottom_delta", S32_MAX), + top_pad("top_pad"), + top_delta("top_delta", S32_MAX), + left_pad("left_pad"), left_delta("left_delta", S32_MAX), - top_delta("top_delta"), - right_delta("right_delta"), center_horiz("center_horiz", false), center_vert("center_vert", false), serializable("", false), @@ -124,7 +123,8 @@ LLView::LLView(const LLView::Params& p) mUseBoundingRect(p.use_bounding_rect), mDefaultTabGroup(p.default_tab_group), mLastTabGroup(0), - mToolTipMsg((LLStringExplicit)p.tool_tip()) + mToolTipMsg((LLStringExplicit)p.tool_tip()), + mDefaultWidgets(NULL) { // create rect first, as this will supply initial follows flags setShape(p.rect); @@ -157,8 +157,13 @@ LLView::~LLView() mParentView->removeChild(this); } - std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(), - DeletePairedPointer()); + if (mDefaultWidgets) + { + std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(), + DeletePairedPointer()); + delete mDefaultWidgets; + mDefaultWidgets = NULL; + } } // virtual @@ -269,34 +274,6 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child) } } -void LLView::addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node) -{ - if (node.isNull()) return; - - for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) - { - LLXMLNodePtr outputChild; - if (output_node) - { - outputChild = output_node->createChild("", FALSE); - } - - if (!LLUICtrlFactory::getInstance()->createFromXML(child_node, this, LLStringUtil::null, outputChild)) - { - std::string child_name = std::string(child_node->getName()->mString); - if (child_name.find(".") == std::string::npos) - { - llwarns << "Could not create widget named " << child_node->getName()->mString << llendl; - } - } - - if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty()) - { - output_node->deleteChild(outputChild); - } - } -} - // virtual bool LLView::addChild(LLView* child, S32 tab_group) { @@ -1733,10 +1710,10 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ if (create_if_missing) { - LLView* view = getDummyWidget<LLView>(name); + LLView* view = getDefaultWidget<LLView>(name); if (!view) { - view = LLUICtrlFactory::createDummyWidget<LLView>(name); + view = LLUICtrlFactory::createDefaultWidget<LLView>(name); } return view; } @@ -2305,16 +2282,34 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna LLControlVariable *LLView::findControl(const std::string& name) { - LLControlVariable* control; - control = LLUI::sSettingGroups["color"]->getControl(name); - if (control) + // parse the name to locate which group it belongs to + std::size_t key_pos= name.find("."); + if(key_pos!= std::string::npos ) { - return control; + std::string control_group_key = name.substr(0, key_pos); + LLControlVariable* control; + // check if it's in the control group that name indicated + if(LLUI::sSettingGroups[control_group_key]) + { + control = LLUI::sSettingGroups[control_group_key]->getControl(name); + if (control) + { + return control; + } + } } - return LLUI::sSettingGroups["config"]->getControl(name); + LLControlGroup& control_group = LLUI::getControlControlGroup(name); + return control_group.getControl(name); +} + +const widget_registry_t& LLView::getChildRegistry() const +{ + static widget_registry_t empty_registry; + return empty_registry; } + const S32 FLOATER_H_MARGIN = 15; const S32 MIN_WIDGET_HEIGHT = 10; const S32 VPAD = 4; @@ -2395,17 +2390,38 @@ void LLView::parseFollowsFlags(const LLView::Params& params) // static -LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) +//LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) +//{ +// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; +// +// if (node->hasAttribute("halign")) +// { +// std::string horizontal_align_name; +// node->getAttributeString("halign", horizontal_align_name); +// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); +// } +// return gl_hfont_align; +//} + +// Return the rectangle of the last-constructed child, +// if present and a first-class widget (eg, not a close box or drag handle) +// Returns true if found +static bool get_last_child_rect(LLView* parent, LLRect *rect) { - LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; + if (!parent) return false; - if (node->hasAttribute("halign")) + LLView::child_list_t::const_iterator itor = + parent->getChildList()->begin(); + for (;itor != parent->getChildList()->end(); ++itor) { - std::string horizontal_align_name; - node->getAttributeString("halign", horizontal_align_name); - gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); + LLView *last_view = (*itor); + if (last_view->getSaveToXML()) + { + *rect = last_view->getRect(); + return true; + } } - return gl_hfont_align; + return false; } //static @@ -2416,10 +2432,12 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) p.serializable(true); - // *NOTE: Do not inherit layout from parent until we re-export - // all nodes and make topleft the default. JC - //if (p.layout().empty() && parent) - // p.layout = parent->getLayout(); + // *NOTE: This will confuse export of floater/panel coordinates unless + // the default is also "topleft". JC + if (p.layout().empty() && parent) + { + p.layout = parent->getLayout(); + } if (parent) { @@ -2488,20 +2506,11 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) last_rect.translate(0, last_rect.getHeight()); - LLView::child_list_t::const_iterator itor = parent->getChildList()->begin(); - for (;itor != parent->getChildList()->end(); ++itor) - { - LLView *last_view = (*itor); - if (last_view->getSaveToXML()) - { - last_rect = last_view->getRect(); - break; - } - } + // If there was a recently constructed child, use its rectangle + get_last_child_rect(parent, &last_rect); if (layout_topleft) { - S32 left_delta = 0; p.bottom_delta.setIfNotProvided(0, false); // Invert the sense of bottom_delta for topleft layout @@ -2509,32 +2518,33 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) { p.bottom_delta = -p.bottom_delta; } - else if (p.top_delta.isProvided()) + else if (p.top_pad.isProvided()) { - p.bottom_delta = -(p.rect.height + p.top_delta); + p.bottom_delta = -(p.rect.height + p.top_pad); } - else if (!p.left_delta.isProvided() && !p.right_delta.isProvided() && !p.top_delta.isProvided()) + else if (p.top_delta.isProvided()) { - // set default position is just below last rect - p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false); + p.bottom_delta = + -(p.top_delta + p.rect.height - last_rect.getHeight()); } - - // *TODO: Add left_pad for padding off the last widget's right edge - // if (p.left_pad.isProvided()) - //{ - // left_delta = p.left_pad + last_rect.getWidth(); - //} - //else if ... - if (p.left_delta.isProvided()) + else if (!p.bottom_delta.isProvided() + && !p.left_delta.isProvided() + && !p.top_pad.isProvided() + && !p.left_pad.isProvided()) { - left_delta = p.left_delta; + // set default position is just below last rect + p.bottom_delta.set(-(p.rect.height + VPAD), false); } - else if (p.right_delta.isProvided()) + + // default to same left edge + p.left_delta.setIfNotProvided(0, false); + if (p.left_pad.isProvided()) { - left_delta = -(p.right_delta + p.rect.width); + // left_pad is based on prior widget's right edge + p.left_delta.set(p.left_pad + last_rect.getWidth(), false); } - last_rect.translate(left_delta, p.bottom_delta); + last_rect.translate(p.left_delta, p.bottom_delta); } else { @@ -2581,27 +2591,103 @@ static S32 invert_vertical(S32 y, LLView* parent) } } -//static -void LLView::setupParamsForExport(Params& p, LLView* parent) -{ - // Don't convert if already top-left based - if (p.layout() == "topleft") +// Assumes that input is in bottom-left coordinates, hence must call +// _before_ convert_coords_to_top_left(). +static void convert_to_relative_layout(LLView::Params& p, LLView* parent) +{ + // Use setupParams to get the final widget rectangle + // according to our wacky layout rules. + LLView::Params final = p; + LLView::setupParams(final, parent); + // Must actually extract the rectangle to get consistent + // right = left+width, top = bottom+height + LLRect final_rect = final.rect; + + // We prefer to write out top edge instead of bottom, regardless + // of whether we use relative positioning + bool converted_top = false; + + // Look for a last rectangle + LLRect last_rect; + if (get_last_child_rect(parent, &last_rect)) + { + // ...we have a previous widget to compare to + const S32 EDGE_THRESHOLD_PIXELS = 4; + S32 left_pad = final_rect.mLeft - last_rect.mRight; + S32 left_delta = final_rect.mLeft - last_rect.mLeft; + S32 top_pad = final_rect.mTop - last_rect.mBottom; + S32 top_delta = final_rect.mTop - last_rect.mTop; + // If my left edge is almost the same, or my top edge is + // almost the same... + if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS + || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS) + { + // ...use relative positioning + // prefer top_pad if widgets are stacking vertically + // (coordinate system is still bottom-left here) + if (top_pad < 0) + { + p.top_pad = top_pad; + p.top_delta.setProvided(false); + } + else + { + p.top_pad.setProvided(false); + p.top_delta = top_delta; + } + // null out other vertical specifiers + p.rect.top.setProvided(false); + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + converted_top = true; + + // prefer left_pad if widgets are stacking horizontally + if (left_pad > 0) + { + p.left_pad = left_pad; + p.left_delta.setProvided(false); + } + else + { + p.left_pad.setProvided(false); + p.left_delta = left_delta; + } + p.rect.left.setProvided(false); + p.rect.right.setProvided(false); + } + } + + if (!converted_top) { - return; + // ...this is the first widget, or one that wasn't aligned + // prefer top/left specification + p.rect.top = final_rect.mTop; + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + p.top_pad.setProvided(false); + p.top_delta.setProvided(false); } +} +static void convert_coords_to_top_left(LLView::Params& p, LLView* parent) +{ + // Convert the coordinate system to be top-left based. if (p.rect.top.isProvided()) { p.rect.top = invert_vertical(p.rect.top, parent); } - if (p.top_delta.isProvided()) - { - p.top_delta = -p.top_delta; - } if (p.rect.bottom.isProvided()) { p.rect.bottom = invert_vertical(p.rect.bottom, parent); } + if (p.top_pad.isProvided()) + { + p.top_pad = -p.top_pad; + } + if (p.top_delta.isProvided()) + { + p.top_delta = -p.top_delta; + } if (p.bottom_delta.isProvided()) { p.bottom_delta = -p.bottom_delta; @@ -2609,6 +2695,46 @@ void LLView::setupParamsForExport(Params& p, LLView* parent) p.layout = "topleft"; } +//static +void LLView::setupParamsForExport(Params& p, LLView* parent) +{ + // Don't convert if already top-left based + if (p.layout() == "topleft") + { + return; + } + + // heuristic: Many of our floaters and panels were bulk-exported. + // These specify exactly bottom/left and height/width. + // Others were done by hand using bottom_delta and/or left_delta. + // Some rely on not specifying left to mean align with left edge. + // Try to convert both to use relative layout, but using top-left + // coordinates. + // Avoid rectangles where top/bottom/left/right was specified. + if (p.rect.height.isProvided() && p.rect.width.isProvided()) + { + if (p.rect.bottom.isProvided() && p.rect.left.isProvided()) + { + // standard bulk export, convert it + convert_to_relative_layout(p, parent); + } + else if (p.rect.bottom.isProvided() && p.left_delta.isProvided()) + { + // hand layout with left_delta + convert_to_relative_layout(p, parent); + } + else if (p.bottom_delta.isProvided()) + { + // hand layout with bottom_delta + // don't check for p.rect.left or p.left_delta because sometimes + // this layout doesn't set it for widgets that are left-aligned + convert_to_relative_layout(p, parent); + } + } + + convert_coords_to_top_left(p, parent); +} + LLView::tree_iterator_t LLView::beginTree() { return tree_iterator_t(this, @@ -2621,3 +2747,14 @@ LLView::tree_iterator_t LLView::endTree() // an empty iterator is an "end" iterator return tree_iterator_t(); } + +// only create maps on demand, as they incur heap allocation/deallocation cost +// when a view is constructed/deconstructed +LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const +{ + if (!mDefaultWidgets) + { + mDefaultWidgets = new default_widget_map_t(); + } + return *mDefaultWidgets; +} |