diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/lllayoutstack.cpp | 829 | ||||
-rw-r--r-- | indra/llui/lllayoutstack.h | 95 | ||||
-rw-r--r-- | indra/llui/lllineeditor.cpp | 4 | ||||
-rw-r--r-- | indra/llui/llresizebar.cpp | 4 | ||||
-rw-r--r-- | indra/llui/llresizebar.h | 1 | ||||
-rw-r--r-- | indra/llui/llscrollcontainer.cpp | 99 | ||||
-rw-r--r-- | indra/llui/llspellcheck.cpp | 26 | ||||
-rw-r--r-- | indra/llui/llspellcheck.h | 14 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 10 | ||||
-rw-r--r-- | indra/llui/llview.cpp | 5 | ||||
-rw-r--r-- | indra/llui/llwindowshade.cpp | 11 | ||||
-rw-r--r-- | indra/llui/llwindowshade.h | 3 |
12 files changed, 632 insertions, 469 deletions
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 0e7060e22c..2f1c2a47c9 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -34,6 +34,10 @@ #include "llpanel.h" #include "llresizebar.h" #include "llcriticaldamp.h" +#include "boost/foreach.hpp" + +static const F32 MIN_FRACTIONAL_SIZE = 0.0001f; +static const F32 MAX_FRACTIONAL_SIZE = 1.f; static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack"); static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel"); @@ -49,39 +53,29 @@ void LLLayoutStack::OrientationNames::declareValues() // LLLayoutPanel::Params::Params() : expanded_min_dim("expanded_min_dim", 0), - min_dim("min_dim", 0), - max_dim("max_dim", S32_MAX), - user_resize("user_resize", true), + min_dim("min_dim", -1), + user_resize("user_resize", false), auto_resize("auto_resize", true) { addSynonym(min_dim, "min_width"); addSynonym(min_dim, "min_height"); - addSynonym(max_dim, "max_width"); - addSynonym(max_dim, "max_height"); } LLLayoutPanel::LLLayoutPanel(const Params& p) : LLPanel(p), - mExpandedMinDimSpecified(false), - mExpandedMinDim(p.min_dim), + mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim), mMinDim(p.min_dim), - mMaxDim(p.max_dim), mAutoResize(p.auto_resize), mUserResize(p.user_resize), mCollapsed(FALSE), mCollapseAmt(0.f), mVisibleAmt(1.f), // default to fully visible mResizeBar(NULL), - mFractionalSize(0.f), + mFractionalSize(MIN_FRACTIONAL_SIZE), + mTargetDim(0), + mIgnoreReshape(false), mOrientation(LLLayoutStack::HORIZONTAL) { - // Set the expanded min dim if it is provided, otherwise it gets the p.min_dim value - if (p.expanded_min_dim.isProvided()) - { - mExpandedMinDimSpecified = true; - mExpandedMinDim = p.expanded_min_dim(); - } - // panels initialized as hidden should not start out partially visible if (!getVisible()) { @@ -103,33 +97,83 @@ LLLayoutPanel::~LLLayoutPanel() mResizeBar = NULL; } -void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent) +F32 LLLayoutPanel::getAutoResizeFactor() const +{ + return mVisibleAmt * (1.f - mCollapseAmt); +} + +F32 LLLayoutPanel::getVisibleAmount() const +{ + return mVisibleAmt; +} + +S32 LLLayoutPanel::getLayoutDim() const +{ + return llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight())); +} + +S32 LLLayoutPanel::getVisibleDim() const +{ + F32 min_dim = getRelevantMinDim(); + return llround(mVisibleAmt + * (min_dim + + (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt)))); +} + +void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientation ) +{ + mOrientation = orientation; + S32 layout_dim = llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight())); + + mTargetDim = llmax(layout_dim, getMinDim()); +} + +void LLLayoutPanel::setVisible( BOOL visible ) { - if (mOrientation == LLLayoutStack::HORIZONTAL) + if (visible != getVisible()) { - mFractionalSize += width - llround(mFractionalSize); + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) + { + stackp->mNeedsLayout = true; + } } - else + LLPanel::setVisible(visible); +} + +void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ ) +{ + if (width == getRect().getWidth() && height == getRect().getHeight()) return; + + if (!mIgnoreReshape && mAutoResize == false) { - mFractionalSize += height - llround(mFractionalSize); + mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height; + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) + { + stackp->mNeedsLayout = true; + } } LLPanel::reshape(width, height, called_from_parent); } -F32 LLLayoutPanel::getCollapseFactor() +void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user) { - if (mOrientation == LLLayoutStack::HORIZONTAL) + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) { - F32 collapse_amt = - clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth())); - return mVisibleAmt * collapse_amt; - } - else - { - F32 collapse_amt = - clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getHeight()))); - return mVisibleAmt * collapse_amt; + stackp->mNeedsLayout = true; + if (by_user) + { + // tell layout stack to account for new shape + stackp->updatePanelRect(this, new_rect); + } } + LLPanel::handleReshape(new_rect, by_user); } // @@ -142,20 +186,21 @@ LLLayoutStack::Params::Params() clip("clip", true), open_time_constant("open_time_constant", 0.02f), close_time_constant("close_time_constant", 0.03f), + resize_bar_overlap("resize_bar_overlap", 1), border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) {} LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) : LLView(p), - mMinWidth(0), - mMinHeight(0), mPanelSpacing(p.border_size), mOrientation(p.orientation), mAnimate(p.animate), mAnimatedThisFrame(false), + mNeedsLayout(true), mClip(p.clip), mOpenTimeConstant(p.open_time_constant), - mCloseTimeConstant(p.close_time_constant) + mCloseTimeConstant(p.close_time_constant), + mResizeBarOverlap(p.resize_bar_overlap) {} LLLayoutStack::~LLLayoutStack() @@ -169,26 +214,26 @@ void LLLayoutStack::draw() { updateLayout(); - e_panel_list_t::iterator panel_it; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + // always clip to stack itself + LLLocalClipRect clip(getLocalRect()); + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) { // clip to layout rectangle, not bounding rectangle - LLRect clip_rect = (*panel_it)->getRect(); + LLRect clip_rect = panelp->getRect(); // scale clipping rectangle by visible amount if (mOrientation == HORIZONTAL) { - clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); + clip_rect.mRight = clip_rect.mLeft + panelp->getVisibleDim(); } else { - clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); + clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim(); } - LLPanel* panelp = (*panel_it); - - LLLocalClipRect clip(clip_rect, mClip); - // only force drawing invisible children if visible amount is non-zero - drawChild(panelp, 0, 0, !clip_rect.isEmpty()); + {LLLocalClipRect clip(clip_rect, mClip); + // only force drawing invisible children if visible amount is non-zero + drawChild(panelp, 0, 0, !clip_rect.isEmpty()); + } } mAnimatedThisFrame = false; } @@ -201,12 +246,10 @@ void LLLayoutStack::removeChild(LLView* view) { mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); delete embedded_panelp; + updateFractionalSizes(); + mNeedsLayout = true; } - // need to update resizebars - - calcMinExtents(); - LLView::removeChild(view); } @@ -221,29 +264,15 @@ bool LLLayoutStack::addChild(LLView* child, S32 tab_group) LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child); if (panelp) { - panelp->mFractionalSize = (mOrientation == HORIZONTAL) - ? panelp->getRect().getWidth() - : panelp->getRect().getHeight(); panelp->setOrientation(mOrientation); mPanels.push_back(panelp); + createResizeBar(panelp); + mNeedsLayout = true; } - return LLView::addChild(child, tab_group); -} + BOOL result = LLView::addChild(child, tab_group); -void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front) -{ - LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move); - LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel); - - if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel) - { - llwarns << "One of the panels was not found in stack or NULL was passed instead of valid panel" << llendl; - return; - } - e_panel_list_t::iterator it = std::find(mPanels.begin(), mPanels.end(), embedded_panel_to_move); - mPanels.erase(it); - it = move_to_front ? mPanels.begin() : std::find(mPanels.begin(), mPanels.end(), embedded_target_panel); - mPanels.insert(it, embedded_panel_to_move); + updateFractionalSizes(); + return result; } void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate) @@ -258,84 +287,274 @@ void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate) } } -void LLLayoutStack::removePanel(LLPanel* panel) -{ - removeChild(panel); -} - void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed) { LLLayoutPanel* panel_container = findEmbeddedPanel(panel); if (!panel_container) return; panel_container->mCollapsed = collapsed; + mNeedsLayout = true; } -void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize) -{ - LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); +static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks"); - if (panel) +void LLLayoutStack::updateLayout() +{ + LLFastTimer ft(FTM_UPDATE_LAYOUT); + + if (!mNeedsLayout) return; + + bool animation_in_progress = animatePanels(); + F32 total_visible_fraction = 0.f; + F32 total_open_fraction = 0.f; + S32 space_to_distribute = (mOrientation == HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight(); + + // first, assign minimum dimensions + LLLayoutPanel* panelp = NULL; + BOOST_FOREACH(panelp, mPanels) { - panel->mAutoResize = auto_resize; + if (panelp->mAutoResize) + { + panelp->mTargetDim = panelp->getRelevantMinDim(); + if (!panelp->mCollapsed && panelp->getVisible()) + { + total_open_fraction += panelp->mFractionalSize; + } + } + space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount()); + total_visible_fraction += panelp->mFractionalSize; } -} -void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize) + llassert(total_visible_fraction < 1.01f); + + // don't need spacing after last panel + space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; + + F32 fraction_distributed = 0.f; + if (space_to_distribute > 0 && total_visible_fraction > 0.f) + { // give space proportionally to visible auto resize panels + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) + { + F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction); + S32 delta = llround((F32)space_to_distribute * fraction_to_distribute); + fraction_distributed += fraction_to_distribute; + panelp->mTargetDim += delta; + } + } + } + + if (fraction_distributed < total_visible_fraction) + { // distribute any left over pixels to non-collapsed, visible panels + F32 fraction_left = total_visible_fraction - fraction_distributed; + S32 space_left = llround((F32)space_to_distribute * (fraction_left / total_visible_fraction)); + + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize + && !panelp->mCollapsed + && panelp->getVisible()) + { + S32 space_for_panel = llmax(0, llround((F32)space_left * (panelp->mFractionalSize / total_open_fraction))); + panelp->mTargetDim += space_for_panel; + space_left -= space_for_panel; + total_open_fraction -= panelp->mFractionalSize; + } + } + } + + F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight(); + + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); + F32 panel_visible_dim = panelp->getVisibleDim(); + + LLRect panel_rect; + if (mOrientation == HORIZONTAL) + { + panel_rect.setLeftTopAndSize(llround(cur_pos), + getRect().getHeight(), + llround(panel_dim), + getRect().getHeight()); + } + else + { + panel_rect.setLeftTopAndSize(0, + llround(cur_pos), + getRect().getWidth(), + llround(panel_dim)); + } + panelp->setIgnoreReshape(true); + panelp->setShape(panel_rect); + panelp->setIgnoreReshape(false); + + LLRect resize_bar_rect(panel_rect); + + F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount(); + if (mOrientation == HORIZONTAL) + { + resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; + resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap; + + cur_pos += panel_visible_dim + panel_spacing; + } + else //VERTICAL + { + resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; + resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap; + + cur_pos -= panel_visible_dim + panel_spacing; + } + panelp->mResizeBar->setShape(resize_bar_rect); + } + + updateResizeBarLimits(); + + // clear animation flag at end, since panel resizes will set it + // and leave it set if there is any animation in progress + mNeedsLayout = animation_in_progress; +} // end LLLayoutStack::updateLayout + +LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const { - LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); + if (!panelp) return NULL; - if (panel) + e_panel_list_t::const_iterator panel_it; + BOOST_FOREACH(LLLayoutPanel* p, mPanels) { - panel->mUserResize = user_resize; + if (p == panelp) + { + return p; + } } + return NULL; } -bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp) +LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const { - LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); + LLLayoutPanel* result = NULL; - if (panel && min_dimp) + BOOST_FOREACH(LLLayoutPanel* p, mPanels) { - *min_dimp = panel->getRelevantMinDim(); + if (p->getName() == name) + { + result = p; + break; + } } - return NULL != panel; + return result; } -bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp) +void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) { - LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); + BOOST_FOREACH(LLLayoutPanel* lp, mPanels) + { + if (lp->mResizeBar == NULL) + { + LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; + LLRect resize_bar_rect = getRect(); - if (panel) + LLResizeBar::Params resize_params; + resize_params.name("resize"); + resize_params.resizing_view(lp); + resize_params.min_size(lp->getRelevantMinDim()); + resize_params.side(side); + resize_params.snapping_enabled(false); + LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); + lp->mResizeBar = resize_bar; + LLView::addChild(resize_bar, 0); + } + } + // bring all resize bars to the front so that they are clickable even over the panels + // with a bit of overlap + for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { - if (max_dimp) *max_dimp = panel->mMaxDim; + LLResizeBar* resize_barp = (*panel_it)->mResizeBar; + sendChildToFront(resize_barp); } +} - return NULL != panel; +// update layout stack animations, etc. once per frame +// NOTE: we use this to size world view based on animating UI, *before* we draw the UI +// we might still need to call updateLayout during UI draw phase, in case UI elements +// are resizing themselves dynamically +//static +void LLLayoutStack::updateClass() +{ + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + it->updateLayout(); + } } -static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks"); -void LLLayoutStack::updateLayout(BOOL force_resize) +void LLLayoutStack::updateFractionalSizes() { - LLFastTimer ft(FTM_UPDATE_LAYOUT); - static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0); - calcMinExtents(); - createResizeBars(); + F32 total_resizable_dim = 0; + S32 num_auto_resize_panels = 0; - // calculate current extents - F32 total_size = 0.f; + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) + { + total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim()); + num_auto_resize_panels++; + } + } + F32 total_fractional_size = 0.f; + + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) + { + F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); + panelp->mFractionalSize = panel_resizable_dim > 0.f + ? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) + : MIN_FRACTIONAL_SIZE; + total_fractional_size += panelp->mFractionalSize; + llassert(!llisnan(panelp->mFractionalSize)); + } + } + + if (total_fractional_size == 0.f) + { // equal distribution + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) + { + panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels; + } + } + } + else + { // renormalize + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) + { + panelp->mFractionalSize /= total_fractional_size; + } + } + } +} + +bool LLLayoutStack::animatePanels() +{ + bool animation_in_progress = false; + // // animate visibility // - e_panel_list_t::iterator panel_it; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) { - LLLayoutPanel* panelp = (*panel_it); - if (panelp->getVisible()) + if (panelp->getVisible()) { - if (mAnimate) + if (mAnimate && panelp->mVisibleAmt < 1.f) { if (!mAnimatedThisFrame) { @@ -345,15 +564,21 @@ void LLLayoutStack::updateLayout(BOOL force_resize) panelp->mVisibleAmt = 1.f; } } + + animation_in_progress = true; } else { - panelp->mVisibleAmt = 1.f; + if (panelp->mVisibleAmt != 1.f) + { + panelp->mVisibleAmt = 1.f; + animation_in_progress = true; + } } } else // not visible { - if (mAnimate) + if (mAnimate && panelp->mVisibleAmt > 0.f) { if (!mAnimatedThisFrame) { @@ -363,297 +588,213 @@ void LLLayoutStack::updateLayout(BOOL force_resize) panelp->mVisibleAmt = 0.f; } } + + animation_in_progress = true; } else { - panelp->mVisibleAmt = 0.f; + if (panelp->mVisibleAmt != 0.f) + { + panelp->mVisibleAmt = 0.f; + animation_in_progress = true; + } } } F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f; - panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); - - total_size += panelp->mFractionalSize * panelp->getCollapseFactor(); - // want n-1 panel gaps for n panels - if (panel_it != mPanels.begin()) - { - total_size += mPanelSpacing; - } - } - - S32 num_resizable_panels = 0; - F32 shrink_headroom_available = 0.f; - F32 shrink_headroom_total = 0.f; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - LLLayoutPanel* panelp = (*panel_it); - - // panels that are not fully visible do not count towards shrink headroom - if (panelp->getCollapseFactor() < 1.f) - { - continue; - } - - F32 cur_size = panelp->mFractionalSize; - F32 min_size = (F32)panelp->getRelevantMinDim(); - - // if currently resizing a panel or the panel is flagged as not automatically resizing - // only track total available headroom, but don't use it for automatic resize logic - if (panelp->mResizeBar->hasMouseCapture() - || (!panelp->mAutoResize - && !force_resize)) - { - shrink_headroom_total += cur_size - min_size; - } - else - { - num_resizable_panels++; - - shrink_headroom_available += cur_size - min_size; - shrink_headroom_total += cur_size - min_size; - } - } - - // calculate how many pixels need to be distributed among layout panels - // positive means panels need to grow, negative means shrink - F32 pixels_to_distribute = (mOrientation == HORIZONTAL) - ? getRect().getWidth() - total_size - : getRect().getHeight() - total_size; - - // now we distribute the pixels... - F32 cur_x = 0.f; - F32 cur_y = (F32)getRect().getHeight(); - - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - LLLayoutPanel* panelp = (*panel_it); - - F32 min_size = panelp->getRelevantMinDim(); - F32 delta_size = 0.f; - - // if panel can automatically resize (not animating, and resize flag set)... - if (panelp->getCollapseFactor() == 1.f - && (force_resize || panelp->mAutoResize) - && !panelp->mResizeBar->hasMouseCapture()) + if (panelp->mCollapseAmt != collapse_state) { - if (pixels_to_distribute < 0.f) + if (!mAnimatedThisFrame) { - // shrink proportionally to amount over minimum - // so we can do this in one pass - delta_size = (shrink_headroom_available > 0.f) - ? pixels_to_distribute * ((F32)(panelp->mFractionalSize - min_size) / shrink_headroom_available) - : 0.f; - shrink_headroom_available -= (panelp->mFractionalSize - min_size); + panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); } - else + animation_in_progress = true; + + if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) { - // grow all elements equally - delta_size = pixels_to_distribute / (F32)num_resizable_panels; - num_resizable_panels--; + panelp->mCollapseAmt = collapse_state; } - - panelp->mFractionalSize = llmax(min_size, panelp->mFractionalSize + delta_size); - pixels_to_distribute -= delta_size; } + } - // adjust running headroom count based on new sizes - shrink_headroom_total += delta_size; + mAnimatedThisFrame = true; - LLRect panel_rect; - if (mOrientation == HORIZONTAL) - { - panel_rect.setLeftTopAndSize(llround(cur_x), - llround(cur_y), - llround(panelp->mFractionalSize), - getRect().getHeight()); - } - else - { - panel_rect.setLeftTopAndSize(llround(cur_x), - llround(cur_y), - getRect().getWidth(), - llround(panelp->mFractionalSize)); - } - panelp->setShape(panel_rect); + return animation_in_progress; +} - LLRect resize_bar_rect = panel_rect; - if (mOrientation == HORIZONTAL) - { - resize_bar_rect.mLeft = panel_rect.mRight - resize_bar_overlap; - resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + resize_bar_overlap; - } - else - { - resize_bar_rect.mTop = panel_rect.mBottom + resize_bar_overlap; - resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - resize_bar_overlap; - } - (*panel_it)->mResizeBar->setRect(resize_bar_rect); +void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect ) +{ + S32 new_dim = (mOrientation == HORIZONTAL) + ? new_rect.getWidth() + : new_rect.getHeight(); + S32 delta_dim = new_dim - resized_panel->getVisibleDim(); + if (delta_dim == 0) return; - F32 size = ((*panel_it)->mFractionalSize * (*panel_it)->getCollapseFactor()) + (F32)mPanelSpacing; - if (mOrientation == HORIZONTAL) - { - cur_x += size; - } - else //VERTICAL - { - cur_y -= size; - } - } + F32 total_visible_fraction = 0.f; + F32 delta_auto_resize_headroom = 0.f; + F32 total_auto_resize_headroom = 0.f; - // update resize bars with new limits - LLLayoutPanel* last_resizeable_panel = NULL; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - LLLayoutPanel* panelp = (*panel_it); - S32 relevant_min = panelp->getRelevantMinDim(); + LLLayoutPanel* other_resize_panel = NULL; + LLLayoutPanel* following_panel = NULL; - if (mOrientation == HORIZONTAL) + BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) + { + if (panelp->mAutoResize) { - (*panel_it)->mResizeBar->setResizeLimits( - relevant_min, - relevant_min + llround(shrink_headroom_total)); + total_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); + total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); } - else //VERTICAL + + if (panelp == resized_panel) { - (*panel_it)->mResizeBar->setResizeLimits( - relevant_min, - relevant_min + llround(shrink_headroom_total)); + other_resize_panel = following_panel; } - // toggle resize bars based on panel visibility, resizability, etc - BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize; - (*panel_it)->mResizeBar->setVisible(resize_bar_enabled); - - if ((*panel_it)->mUserResize || (*panel_it)->mAutoResize) + if (panelp->getVisible() && !panelp->mCollapsed) { - last_resizeable_panel = (*panel_it); + following_panel = panelp; } } - // hide last resize bar as there is nothing past it - // resize bars need to be in between two resizable panels - if (last_resizeable_panel) + if (resized_panel->mAutoResize == FALSE) { - last_resizeable_panel->mResizeBar->setVisible(FALSE); + delta_auto_resize_headroom += -delta_dim; } - - // not enough room to fit existing contents - if (force_resize == FALSE - // layout did not complete by reaching target position - && ((mOrientation == VERTICAL && llround(cur_y) != -mPanelSpacing) - || (mOrientation == HORIZONTAL && llround(cur_x) != getRect().getWidth() + mPanelSpacing))) + if (other_resize_panel && other_resize_panel->mAutoResize == FALSE) { - // do another layout pass with all stacked elements contributing - // even those that don't usually resize - llassert_always(force_resize == FALSE); - updateLayout(TRUE); + delta_auto_resize_headroom += delta_dim; } - mAnimatedThisFrame = true; -} // end LLLayoutStack::updateLayout + F32 fraction_given_up = 0.f; + F32 fraction_remaining = 1.f; + F32 updated_auto_resize_headroom = total_auto_resize_headroom + delta_auto_resize_headroom; - -LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const -{ - if (!panelp) return NULL; - - e_panel_list_t::const_iterator panel_it; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + enum { - if ((*panel_it) == panelp) - { - return *panel_it; - } - } - return NULL; -} + BEFORE_RESIZED_PANEL, + RESIZED_PANEL, + NEXT_PANEL, + AFTER_RESIZED_PANEL + } which_panel = BEFORE_RESIZED_PANEL; -LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const -{ - LLLayoutPanel* result = NULL; - - for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) { - LLLayoutPanel* p = *panel_it; + if (!panelp->getVisible() || panelp->mCollapsed) continue; - if (p->getName() == name) + if (panelp == resized_panel) { - result = p; - break; + which_panel = RESIZED_PANEL; } - } - - return result; -} - -// Compute sum of min_width or min_height of children -void LLLayoutStack::calcMinExtents() -{ - mMinWidth = 0; - mMinHeight = 0; - e_panel_list_t::iterator panel_it; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - if (mOrientation == HORIZONTAL) + switch(which_panel) { - mMinWidth += (*panel_it)->getRelevantMinDim(); - if (panel_it != mPanels.begin()) + case BEFORE_RESIZED_PANEL: + if (panelp->mAutoResize) + { // freeze current size as fraction of overall auto_resize space + F32 fractional_adjustment_factor = total_auto_resize_headroom / updated_auto_resize_headroom; + F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); + F32 fraction_delta = (new_fractional_size - panelp->mFractionalSize); + fraction_given_up -= fraction_delta; + fraction_remaining -= panelp->mFractionalSize; + panelp->mFractionalSize += fraction_delta; + llassert(!llisnan(panelp->mFractionalSize)); + } + else { - mMinWidth += mPanelSpacing; + // leave non auto-resize panels alone } - } - else //VERTICAL - { - mMinHeight += (*panel_it)->getRelevantMinDim(); - if (panel_it != mPanels.begin()) + break; + case RESIZED_PANEL: + if (panelp->mAutoResize) + { // freeze new size as fraction + F32 new_fractional_size = (updated_auto_resize_headroom == 0.f) + ? MAX_FRACTIONAL_SIZE + : llclamp((F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); + fraction_given_up -= new_fractional_size - panelp->mFractionalSize; + fraction_remaining -= panelp->mFractionalSize; + panelp->mFractionalSize = new_fractional_size; + llassert(!llisnan(panelp->mFractionalSize)); + } + else + { // freeze new size as original size + panelp->mTargetDim = new_dim; + fraction_remaining -= fraction_given_up; + } + which_panel = NEXT_PANEL; + break; + case NEXT_PANEL: + if (panelp->mAutoResize) + { + fraction_remaining -= panelp->mFractionalSize; + if (fraction_given_up != 0.f) + { + panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); + fraction_given_up = 0.f; + } + else + { + F32 new_fractional_size = llclamp((F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom) + / updated_auto_resize_headroom, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); + fraction_given_up -= new_fractional_size - panelp->mFractionalSize; + panelp->mFractionalSize = new_fractional_size; + } + } + else + { + panelp->mTargetDim -= delta_dim; + } + which_panel = AFTER_RESIZED_PANEL; + break; + case AFTER_RESIZED_PANEL: + if (panelp->mAutoResize) { - mMinHeight += mPanelSpacing; + panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); } + default: + break; } } } -void LLLayoutStack::createResizeBars() +void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) { - for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + mNeedsLayout = true; + LLView::reshape(width, height, called_from_parent); +} + +void LLLayoutStack::updateResizeBarLimits() +{ + LLLayoutPanel* previous_visible_panelp = NULL; + BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) { - LLLayoutPanel* lp = (*panel_it); - if (lp->mResizeBar == NULL) + if (!visible_panelp->getVisible() || visible_panelp->mCollapsed) { - LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; - LLRect resize_bar_rect = getRect(); - - LLResizeBar::Params resize_params; - resize_params.name("resize"); - resize_params.resizing_view(lp); - resize_params.min_size(lp->getRelevantMinDim()); - resize_params.side(side); - resize_params.snapping_enabled(false); - LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); - lp->mResizeBar = resize_bar; - LLView::addChild(resize_bar, 0); + visible_panelp->mResizeBar->setVisible(FALSE); + continue; + } - // bring all resize bars to the front so that they are clickable even over the panels - // with a bit of overlap - for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - LLResizeBar* resize_barp = (*panel_it)->mResizeBar; - sendChildToFront(resize_barp); - } + // toggle resize bars based on panel visibility, resizability, etc + if (previous_visible_panelp + && (visible_panelp->mUserResize || previous_visible_panelp->mUserResize) // one of the pair is user resizable + && (visible_panelp->mAutoResize || visible_panelp->mUserResize) // current panel is resizable + && (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize)) // previous panel is resizable + { + visible_panelp->mResizeBar->setVisible(TRUE); + S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim(); + visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(), + visible_panelp->getVisibleDim() + previous_panel_headroom); + } + else + { + visible_panelp->mResizeBar->setVisible(FALSE); } - } -} -// update layout stack animations, etc. once per frame -// NOTE: we use this to size world view based on animating UI, *before* we draw the UI -// we might still need to call updateLayout during UI draw phase, in case UI elements -// are resizing themselves dynamically -//static -void LLLayoutStack::updateClass() -{ - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - it->updateLayout(); + previous_visible_panelp = visible_panelp; } } diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 3b308a359d..efe93f6def 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2010, Linden Reshasearch, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -60,6 +60,7 @@ public: clip; Optional<F32> open_time_constant, close_time_constant; + Optional<S32> resize_bar_overlap; Params(); }; @@ -72,12 +73,11 @@ public: /*virtual*/ void removeChild(LLView*); /*virtual*/ BOOL postBuild(); /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); - S32 getMinWidth() const { return mMinWidth; } - S32 getMinHeight() const { return mMinHeight; } - typedef enum e_animate { NO_ANIMATE, @@ -85,47 +85,24 @@ public: } EAnimate; void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE); - void removePanel(LLPanel* panel); void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE); S32 getNumPanels() { return mPanels.size(); } - /** - * Moves panel_to_move before target_panel inside layout stack (both panels should already be there). - * If move_to_front is true target_panel is ignored and panel_to_move is moved to the beginning of mPanels - */ - void movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front = false); - - void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize); - void setPanelUserResize(const std::string& panel_name, BOOL user_resize); - - /** - * Gets minimal dimension along layout_stack axis of the specified by name panel. - * - * @returns true if specified by panel_name internal panel exists, false otherwise. - */ - bool getPanelMinSize(const std::string& panel_name, S32* min_dimp); - - /** - * Gets maximal dimension along layout_stack axis of the specified by name panel. - * - * @returns true if specified by panel_name internal panel exists, false otherwise. - */ - bool getPanelMaxSize(const std::string& panel_name, S32* max_dim); - - void updateLayout(BOOL force_resize = FALSE); - + + void updateLayout(); + S32 getPanelSpacing() const { return mPanelSpacing; } - BOOL getAnimate () const { return mAnimate; } - void setAnimate (BOOL animate) { mAnimate = animate; } static void updateClass(); protected: LLLayoutStack(const Params&); friend class LLUICtrlFactory; + friend class LLLayoutPanel; private: - void createResizeBars(); - void calcMinExtents(); + void updateResizeBarLimits(); + bool animatePanels(); + void createResizeBar(LLLayoutPanel* panel); const ELayoutOrientation mOrientation; @@ -134,17 +111,19 @@ private: LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const; LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const; + void updateFractionalSizes(); + void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect ); - S32 mMinWidth; // calculated by calcMinExtents - S32 mMinHeight; // calculated by calcMinExtents S32 mPanelSpacing; // true if we already applied animation this frame bool mAnimatedThisFrame; bool mAnimate; bool mClip; - F32 mOpenTimeConstant; - F32 mCloseTimeConstant; + F32 mOpenTimeConstant; + F32 mCloseTimeConstant; + bool mNeedsLayout; + S32 mResizeBarOverlap; }; // end class LLLayoutStack @@ -156,8 +135,7 @@ public: struct Params : public LLInitParam::Block<Params, LLPanel::Params> { Optional<S32> expanded_min_dim, - min_dim, - max_dim; + min_dim; Optional<bool> user_resize, auto_resize; @@ -168,16 +146,19 @@ public: void initFromParams(const Params& p); + void handleReshape(const LLRect& new_rect, bool by_user); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + - S32 getMinDim() const { return mMinDim; } - void setMinDim(S32 value) { mMinDim = value; if (!mExpandedMinDimSpecified) mExpandedMinDim = value; } + void setVisible(BOOL visible); - S32 getMaxDim() const { return mMaxDim; } - void setMaxDim(S32 value) { mMaxDim = value; } + S32 getLayoutDim() const; + S32 getMinDim() const { return (mMinDim >= 0 || mAutoResize) ? llmax(0, mMinDim) : getLayoutDim(); } + void setMinDim(S32 value) { mMinDim = value; } - S32 getExpandedMinDim() const { return mExpandedMinDim; } - void setExpandedMinDim(S32 value) { mExpandedMinDim = value; mExpandedMinDimSpecified = true; } + S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : mMinDim; } + void setExpandedMinDim(S32 value) { mExpandedMinDim = value; } S32 getRelevantMinDim() const { @@ -185,29 +166,35 @@ public: if (!mCollapsed) { - min_dim = mExpandedMinDim; + min_dim = getExpandedMinDim(); } return min_dim; } - F32 getCollapseFactor(); - void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; } + F32 getAutoResizeFactor() const; + F32 getVisibleAmount() const; + S32 getVisibleDim() const; + + void setOrientation(LLLayoutStack::ELayoutOrientation orientation); + void storeOriginalDim(); + + void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; } protected: LLLayoutPanel(const Params& p); - bool mExpandedMinDimSpecified; + const bool mAutoResize; + const bool mUserResize; + S32 mExpandedMinDim; - S32 mMinDim; - S32 mMaxDim; - bool mAutoResize; - bool mUserResize; bool mCollapsed; F32 mVisibleAmt; F32 mCollapseAmt; F32 mFractionalSize; + S32 mTargetDim; + bool mIgnoreReshape; LLLayoutStack::ELayoutOrientation mOrientation; class LLResizeBar* mResizeBar; }; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 42cfc4cae9..0dc381231d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1948,8 +1948,8 @@ void LLLineEditor::draw() gGL.color4ub(255, 0, 0, 200); while (pxStart < pxEnd) { - gl_line_2d(pxStart, text_bottom - 2, pxStart + 3, text_bottom + 1); - gl_line_2d(pxStart + 3, text_bottom + 1, pxStart + 6, text_bottom - 2); + gl_line_2d(pxStart, (S32)text_bottom - 2, pxStart + 3, (S32)text_bottom + 1); + gl_line_2d(pxStart + 3, (S32)text_bottom + 1, pxStart + 6, (S32)text_bottom - 2); pxStart += 6; } } diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index 02f60c76fa..87aeb4d7a7 100644 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -79,6 +79,8 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p) BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask) { + if (!canResize()) return FALSE; + // Route future Mouse messages here preemptively. (Release on mouse up.) // No handler needed for focus lost since this clas has no state that depends on it. gFocusMgr.setMouseCapture( this ); @@ -243,7 +245,7 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask) handled = TRUE; } - if( handled ) + if( handled && canResize() ) { switch( mSide ) { diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 0725fbd846..6daf191918 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -70,6 +70,7 @@ public: void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; } void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; } void setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; } + bool canResize() { return getEnabled() && mMaxSize > mMinSize; } private: S32 mDragLastScreenX; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index fe3f688fc5..ad4cc20d9a 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -424,63 +424,66 @@ void LLScrollContainer::draw() focusFirstItem(); } - // Draw background - if( mIsOpaque ) + if (getRect().isValid()) { - F32 alpha = getCurrentTransparency(); + // Draw background + if( mIsOpaque ) + { + F32 alpha = getCurrentTransparency(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); - } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); + } - // Draw mScrolledViews and update scroll bars. - // get a scissor region ready, and draw the scrolling view. The - // scissor region ensures that we don't draw outside of the bounds - // of the rectangle. - if( mScrolledView ) - { - updateScroll(); - - // Draw the scrolled area. + // Draw mScrolledViews and update scroll bars. + // get a scissor region ready, and draw the scrolling view. The + // scissor region ensures that we don't draw outside of the bounds + // of the rectangle. + if( mScrolledView ) { - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - - LLLocalClipRect clip(LLRect(mInnerRect.mLeft, - mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, - mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), - mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) - )); - drawChild(mScrolledView); - } - } - - // Highlight border if a child of this container has keyboard focus - if( mBorder->getVisible() ) - { - mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); - } + updateScroll(); - // Draw all children except mScrolledView - // Note: scrollbars have been adjusted by above drawing code - for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); - child_iter != getChildList()->rend(); ++child_iter) - { - LLView *viewp = *child_iter; - if( sDebugRects ) - { - sDepth++; + // Draw the scrolled area. + { + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_v_scrollbar = FALSE; + BOOL show_h_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + + LLLocalClipRect clip(LLRect(mInnerRect.mLeft, + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, + mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + )); + drawChild(mScrolledView); + } } - if( (viewp != mScrolledView) && viewp->getVisible() ) + + // Highlight border if a child of this container has keyboard focus + if( mBorder->getVisible() ) { - drawChild(viewp); + mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); } - if( sDebugRects ) + + // Draw all children except mScrolledView + // Note: scrollbars have been adjusted by above drawing code + for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); + child_iter != getChildList()->rend(); ++child_iter) { - sDepth--; + LLView *viewp = *child_iter; + if( sDebugRects ) + { + sDepth++; + } + if( (viewp != mScrolledView) && viewp->getVisible() ) + { + drawChild(viewp); + } + if( sDebugRects ) + { + sDepth--; + } } } } // end draw diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 65207144f8..aa39e21a96 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -41,6 +41,7 @@ static const std::string DICT_DIR = "dictionaries"; static const std::string DICT_CUSTOM_SUFFIX = "_custom"; static const std::string DICT_IGNORE_SUFFIX = "_ignore"; +LLSD LLSpellChecker::sDictMap; LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; LLSpellChecker::LLSpellChecker() @@ -86,9 +87,10 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str return suggestions.size(); } -const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) const +// static +const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) { - for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) { const LLSD& dict_entry = *it; if (dict_name == dict_entry["language"].asString()) @@ -97,6 +99,7 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) const return LLSD(); } +// static void LLSpellChecker::refreshDictionaryMap() { const std::string app_path = getDictionaryAppPath(); @@ -104,24 +107,22 @@ void LLSpellChecker::refreshDictionaryMap() // Load dictionary information (file name, friendly name, ...) llifstream user_map(user_path + "dictionaries.xml", std::ios::binary); - if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(mDictMap, user_map)) || (0 == mDictMap.size()) ) + if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_map)) || (0 == sDictMap.size()) ) { llifstream app_map(app_path + "dictionaries.xml", std::ios::binary); - if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(mDictMap, app_map)) || (0 == mDictMap.size()) ) + if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_map)) || (0 == sDictMap.size()) ) return; } // Look for installed dictionaries std::string tmp_app_path, tmp_user_path; - for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) { LLSD& sdDict = *it; tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; sdDict["installed"] = - (!tmp_app_path.empty()) && - ( ((gDirUtilp->fileExists(tmp_user_path + ".aff")) && (gDirUtilp->fileExists(tmp_user_path + ".dic"))) || - ((gDirUtilp->fileExists(tmp_app_path + ".aff")) && (gDirUtilp->fileExists(tmp_app_path + ".dic"))) ); + (!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic"))); sdDict["has_custom"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_CUSTOM_SUFFIX + ".dic")); sdDict["has_ignore"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_IGNORE_SUFFIX + ".dic")); } @@ -240,7 +241,7 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) } const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD(); - if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) { sSettingsChangeSignal(); return; @@ -343,3 +344,10 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_name) LLSpellChecker::instance().initHunspell(dict_name); } } + +// static +void LLSpellChecker::initClass() +{ + if (sDictMap.isUndefined()) + refreshDictionaryMap(); +} diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index 8351655b49..d736a7f082 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -28,13 +28,15 @@ #define LLSPELLCHECK_H #include "llsingleton.h" +#include "llui.h" #include <boost/signals2.hpp> class Hunspell; -class LLSpellChecker : public LLSingleton<LLSpellChecker> +class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker> { friend class LLSingleton<LLSpellChecker>; + friend class LLInitClass<LLSpellChecker>; protected: LLSpellChecker(); ~LLSpellChecker(); @@ -52,28 +54,30 @@ public: typedef std::list<std::string> dict_list_t; const std::string& getActiveDictionary() const { return mDictName; } - const LLSD getDictionaryData(const std::string& dict_name) const; - const LLSD& getDictionaryMap() const { return mDictMap; } const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } - void refreshDictionaryMap(); void setSecondaryDictionaries(dict_list_t dict_list); static const std::string getDictionaryAppPath(); static const std::string getDictionaryUserPath(); + static const LLSD getDictionaryData(const std::string& dict_name); + static const LLSD& getDictionaryMap() { return sDictMap; } static bool getUseSpellCheck(); + static void refreshDictionaryMap(); static void setUseSpellCheck(const std::string& dict_name); typedef boost::signals2::signal<void()> settings_change_signal_t; static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); +protected: + static void initClass(); protected: Hunspell* mHunspell; std::string mDictName; std::string mDictFile; - LLSD mDictMap; dict_list_t mDictSecondary; std::vector<std::string> mIgnoreList; + static LLSD sDictMap; static settings_change_signal_t sSettingsChangeSignal; }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 2231d9b983..ce405cd4a4 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -552,7 +552,7 @@ void LLTextBase::drawText() const LLWString& wstrText = getWText(); mMisspellRanges.clear(); - segment_set_t::iterator seg_it = getSegIterContaining(start); + segment_set_t::const_iterator seg_it = getSegIterContaining(start); while (mSegments.end() != seg_it) { LLTextSegmentPtr text_segment = *seg_it; @@ -673,11 +673,15 @@ void LLTextBase::drawText() { // Skip the current word if the user is still busy editing it if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) + { + ++misspell_it; continue; + } + U32 misspell_start = llmax<U32>(misspell_it->first, seg_start), misspell_end = llmin<U32>(misspell_it->second, seg_end); S32 squiggle_start = 0, squiggle_end = 0, pony = 0; - cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_it->first - seg_start, squiggle_start, pony); - cur_segment->getDimensions(misspell_it->first - cur_segment->getStart(), misspell_it->second - misspell_it->first, squiggle_end, pony); + cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony); + cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony); squiggle_start += text_rect.mLeft; pony = (squiggle_end + 3) / 6; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 004681325f..e1ee0a5b14 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1093,6 +1093,11 @@ void LLView::drawChildren() { child_list_reverse_iter_t child = child_iter++; LLView *viewp = *child; + + if (viewp == NULL) + { + continue; + } if (viewp->getVisible() && viewp->getRect().isValid()) { diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp index ae8b30b1ba..f5c463c961 100644 --- a/indra/llui/llwindowshade.cpp +++ b/indra/llui/llwindowshade.cpp @@ -160,7 +160,7 @@ void LLWindowShade::draw() notification_area->reshape(notification_area->getRect().getWidth(), llclamp(message_rect.getHeight() + 15, - llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT), + llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT), MAX_NOTIFICATION_AREA_HEIGHT)); LLUICtrl::draw(); @@ -176,12 +176,12 @@ void LLWindowShade::draw() { hide(); } - else if (notification_area->getCollapseFactor() < 0.01f) + else if (notification_area->getVisibleAmount() < 0.01f) { displayLatestNotification(); } - if (!notification_area->getVisible() && (notification_area->getCollapseFactor() < 0.001f)) + if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f)) { getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); setMouseOpaque(false); @@ -371,6 +371,11 @@ void LLWindowShade::setTextColor(LLColor4 color) getChild<LLTextBox>("notification_text")->setColor(color); } +bool LLWindowShade::isShown() const +{ + return getChildRef<LLLayoutPanel>("notification_area").getVisible(); +} + void LLWindowShade::setCanClose(bool can_close) { getChildView("close_panel")->setVisible(can_close); diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index 1ae84028dd..6d753d1161 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -48,6 +48,9 @@ public: void show(LLNotificationPtr); /*virtual*/ void draw(); void hide(); + + bool isShown() const; + void setBackgroundImage(LLUIImage* image); void setTextColor(LLColor4 color); void setCanClose(bool can_close); |