diff options
Diffstat (limited to 'indra/llui')
33 files changed, 1398 insertions, 387 deletions
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index d93748d069..bdf1c12b79 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -197,6 +197,9 @@ void LLButton::init(void (*click_callback)(void*), void *callback_data, const LL mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) ); mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) ); mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) ); + + mImageOverlayAlignment = LLFontGL::HCENTER; + mImageOverlayColor = LLColor4::white; } LLButton::~LLButton() @@ -607,7 +610,7 @@ void LLButton::draw() // draw overlay image if (mImageOverlay.notNull()) { - const S32 IMG_PAD = 4; + const S32 IMG_PAD = 5; // get max width and height (discard level 0) S32 overlay_width = mImageOverlay->getWidth(0); S32 overlay_height = mImageOverlay->getHeight(0); @@ -628,7 +631,7 @@ void LLButton::draw() overlay_width, overlay_height, mImageOverlay, - LLColor4::white); + mImageOverlayColor); break; case LLFontGL::HCENTER: gl_draw_scaled_image( @@ -637,7 +640,7 @@ void LLButton::draw() overlay_width, overlay_height, mImageOverlay, - LLColor4::white); + mImageOverlayColor); break; case LLFontGL::RIGHT: gl_draw_scaled_image( @@ -646,7 +649,7 @@ void LLButton::draw() overlay_width, overlay_height, mImageOverlay, - LLColor4::white); + mImageOverlayColor); break; default: // draw nothing @@ -866,7 +869,7 @@ void LLButton::setHoverImages( const LLString& image_name, const LLString& selec setImageHoverSelected(selected_name); } -void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment) +void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment, const LLColor4& color) { if (image_name.empty()) { @@ -877,6 +880,7 @@ void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alig LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name); mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id); mImageOverlayAlignment = alignment; + mImageOverlayColor = color; } } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index ba77220a7b..a638b5be49 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -124,7 +124,7 @@ public: void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } - void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER); + void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; } @@ -190,6 +190,7 @@ protected: LLPointer<LLImageGL> mImageOverlay; LLFontGL::HAlign mImageOverlayAlignment; + LLColor4 mImageOverlayColor; LLPointer<LLImageGL> mImageUnselected; LLUIString mUnselectedLabel; diff --git a/indra/llui/llctrlselectioninterface.h b/indra/llui/llctrlselectioninterface.h index 698d609593..9df7475a6c 100644 --- a/indra/llui/llctrlselectioninterface.h +++ b/indra/llui/llctrlselectioninterface.h @@ -31,6 +31,8 @@ public: virtual BOOL getCanSelect() const = 0; + virtual S32 getItemCount() const = 0; + virtual BOOL selectFirstItem() = 0; virtual BOOL selectNthItem( S32 index ) = 0; @@ -56,7 +58,6 @@ class LLCtrlListInterface : public LLCtrlSelectionInterface public: virtual ~LLCtrlListInterface(); - virtual S32 getItemCount() const = 0; virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; virtual void clearColumns() = 0; virtual void setColumnLabel(const LLString& column, const LLString& label) = 0; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 22acf46125..17b4dffa3f 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -292,28 +292,32 @@ void LLFloater::init(const LLString& title, { // Resize bars (sides) const S32 RESIZE_BAR_THICKNESS = 3; - mResizeBar[0] = new LLResizeBar( + mResizeBar[LLResizeBar::LEFT] = new LLResizeBar( "resizebar_left", + this, LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), - min_width, min_height, LLResizeBar::LEFT ); + min_width, S32_MAX, LLResizeBar::LEFT ); addChild( mResizeBar[0] ); - mResizeBar[1] = new LLResizeBar( + mResizeBar[LLResizeBar::TOP] = new LLResizeBar( "resizebar_top", + this, LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), - min_width, min_height, LLResizeBar::TOP ); + min_height, S32_MAX, LLResizeBar::TOP ); addChild( mResizeBar[1] ); - mResizeBar[2] = new LLResizeBar( + mResizeBar[LLResizeBar::RIGHT] = new LLResizeBar( "resizebar_right", + this, LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), - min_width, min_height, LLResizeBar::RIGHT ); + min_width, S32_MAX, LLResizeBar::RIGHT ); addChild( mResizeBar[2] ); - mResizeBar[3] = new LLResizeBar( + mResizeBar[LLResizeBar::BOTTOM] = new LLResizeBar( "resizebar_bottom", + this, LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), - min_width, min_height, LLResizeBar::BOTTOM ); + min_height, S32_MAX, LLResizeBar::BOTTOM ); addChild( mResizeBar[3] ); @@ -601,7 +605,14 @@ void LLFloater::setResizeLimits( S32 min_width, S32 min_height ) { if( mResizeBar[i] ) { - mResizeBar[i]->setResizeLimits( min_width, min_height ); + if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT) + { + mResizeBar[i]->setResizeLimits( min_width, S32_MAX ); + } + else + { + mResizeBar[i]->setResizeLimits( min_height, S32_MAX ); + } } if( mResizeHandle[i] ) { @@ -653,6 +664,25 @@ const LLString& LLFloater::getTitle() const return mDragHandle ? mDragHandle->getTitle() : LLString::null; } +void LLFloater::setShortTitle( const LLString& short_title ) +{ + mShortTitle = short_title; +} + +LLString LLFloater::getShortTitle() +{ + if (mShortTitle.empty()) + { + return mDragHandle ? mDragHandle->getTitle() : LLString::null; + } + else + { + return mShortTitle; + } +} + + + BOOL LLFloater::canSnapTo(LLView* other_view) { if (NULL == other_view) @@ -991,12 +1021,22 @@ void LLFloater::setHost(LLMultiFloater* host) } } -void LLFloater::moveResizeHandleToFront() +void LLFloater::moveResizeHandlesToFront() { - // 0 is the bottom right - if( mResizeHandle[0] ) + for( S32 i = 0; i < 4; i++ ) { - sendChildToFront(mResizeHandle[0]); + if( mResizeBar[i] ) + { + sendChildToFront(mResizeBar[i]); + } + } + + for( S32 i = 0; i < 4; i++ ) + { + if( mResizeHandle[i] ) + { + sendChildToFront(mResizeHandle[i]); + } } } @@ -1193,6 +1233,10 @@ BOOL LLFloater::getEditModeEnabled() void LLFloater::show(LLFloater* floaterp) { if (floaterp) floaterp->open(); + if (floaterp->getHost()) + { + floaterp->getHost()->open(); + } } //static @@ -1206,7 +1250,7 @@ BOOL LLFloater::visible(LLFloater* floaterp) { if (floaterp) { - return floaterp->isInVisibleChain(); + return !floaterp->isMinimized() && floaterp->isInVisibleChain(); } return FALSE; } @@ -1233,12 +1277,15 @@ void LLFloater::onClickTearOff(void *userdata) // reparent to floater view gFloaterView->addChild(self); - new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->mRect.getWidth(), self->mRect.getHeight()); - self->open(); /* Flawfinder: ignore */ - self->setRect(new_rect); + + // only force position for floaters that don't have that data saved + if (self->mRectControl.empty()) + { + new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->mRect.getWidth(), self->mRect.getHeight()); + self->setRect(new_rect); + } gFloaterView->adjustToFitScreen(self, FALSE); - self->setCanDrag(TRUE); // give focus to new window to keep continuity for the user self->setFocus(TRUE); } @@ -1248,6 +1295,8 @@ void LLFloater::onClickTearOff(void *userdata) if (new_host) { new_host->showFloater(self); + // make sure host is visible + new_host->open(); } } } @@ -1499,26 +1548,30 @@ void LLFloater::setCanResize(BOOL can_resize) const S32 RESIZE_BAR_THICKNESS = 3; mResizeBar[0] = new LLResizeBar( "resizebar_left", + this, LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), - mMinWidth, mMinHeight, LLResizeBar::LEFT ); + mMinWidth, S32_MAX, LLResizeBar::LEFT ); addChild( mResizeBar[0] ); mResizeBar[1] = new LLResizeBar( "resizebar_top", + this, LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), - mMinWidth, mMinHeight, LLResizeBar::TOP ); + mMinHeight, S32_MAX, LLResizeBar::TOP ); addChild( mResizeBar[1] ); mResizeBar[2] = new LLResizeBar( "resizebar_right", + this, LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), - mMinWidth, mMinHeight, LLResizeBar::RIGHT ); + mMinWidth, S32_MAX, LLResizeBar::RIGHT ); addChild( mResizeBar[2] ); mResizeBar[3] = new LLResizeBar( "resizebar_bottom", + this, LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), - mMinWidth, mMinHeight, LLResizeBar::BOTTOM ); + mMinHeight, S32_MAX, LLResizeBar::BOTTOM ); addChild( mResizeBar[3] ); @@ -1855,7 +1908,7 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF sibling->getVisible() && expanded_base_rect.rectInRect(&sibling->getRect())) { - base_rect |= sibling->getRect(); + base_rect.unionWith(sibling->getRect()); } } @@ -2550,18 +2603,22 @@ BOOL LLMultiFloater::closeAllFloaters() return TRUE; //else all tabs were successfully closed... } -void LLMultiFloater::growToFit(LLFloater* floaterp, S32 width, S32 height) +void LLMultiFloater::growToFit(S32 content_width, S32 content_height) { - floater_data_map_t::iterator found_data_it; - found_data_it = mFloaterDataMap.find(floaterp->getHandle()); - if (found_data_it != mFloaterDataMap.end()) + S32 new_width = llmax(mRect.getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2); + S32 new_height = llmax(mRect.getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); + + if (isMinimized()) { - // store new width and height with this floater so that it will keep its size when detached - found_data_it->second.mWidth = width; - found_data_it->second.mHeight = height; + mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, new_width, new_height); + } + else + { + S32 old_height = mRect.getHeight(); + reshape(new_width, new_height); + // keep top left corner in same position + translate(0, old_height - new_height); } - - resizeToContents(); } /** @@ -2618,12 +2675,18 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, floaterp->setCanMinimize(FALSE); floaterp->setCanResize(FALSE); floaterp->setCanDrag(FALSE); + floaterp->storeRectControl(); + + if (mAutoResize) + { + growToFit(floater_data.mWidth, floater_data.mHeight); + } //add the panel, add it to proper maps - mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); + mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); mFloaterDataMap[floaterp->getHandle()] = floater_data; - resizeToContents(); + updateResizeLimits(); if ( select_added_floater ) { @@ -2673,7 +2736,6 @@ void LLMultiFloater::showFloater(LLFloater* floaterp) { addFloater(floaterp, TRUE); } - setVisibleAndFrontmost(); } void LLMultiFloater::removeFloater(LLFloater* floaterp) @@ -2696,9 +2758,11 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp) } mTabContainer->removeTabPanel(floaterp); floaterp->setBackgroundVisible(TRUE); + floaterp->setCanDrag(TRUE); floaterp->setHost(NULL); + floaterp->applyRectControl(); - resizeToContents(); + updateResizeLimits(); tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); } @@ -2840,18 +2904,8 @@ BOOL LLMultiFloater::postBuild() return FALSE; } -void LLMultiFloater::resizeToContents() +void LLMultiFloater::updateResizeLimits() { - // we're already in the middle of a reshape, don't interrupt it - floater_data_map_t::iterator floater_it; - S32 new_width = 0; - S32 new_height = 0; - for (floater_it = mFloaterDataMap.begin(); floater_it != mFloaterDataMap.end(); ++floater_it) - { - new_width = llmax(new_width, floater_it->second.mWidth + LLPANEL_BORDER_WIDTH * 2); - new_height = llmax(new_height, floater_it->second.mHeight + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - } - S32 new_min_width = 0; S32 new_min_height = 0; S32 tab_idx; @@ -2867,21 +2921,23 @@ void LLMultiFloater::resizeToContents() setResizeLimits(new_min_width, new_min_height); S32 cur_height = mRect.getHeight(); + S32 new_width = llmax(mRect.getWidth(), new_min_width); + S32 new_height = llmax(mRect.getHeight(), new_min_height); - if (mAutoResize) + if (isMinimized()) { - reshape(new_width, new_height); + mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, llmax(mPreviousRect.getWidth(), new_width), llmax(mPreviousRect.getHeight(), new_height)); } else { - reshape(llmax(new_min_width, mRect.getWidth()), llmax(new_min_height, mRect.getHeight())); - } + reshape(new_width, new_height); - // make sure upper left corner doesn't move - translate(0, cur_height - mRect.getHeight()); + // make sure upper left corner doesn't move + translate(0, cur_height - mRect.getHeight()); - // Try to keep whole view onscreen, don't allow partial offscreen. - gFloaterView->adjustToFitScreen(this, FALSE); + // Try to keep whole view onscreen, don't allow partial offscreen. + gFloaterView->adjustToFitScreen(this, FALSE); + } } // virtual @@ -2937,6 +2993,7 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor { LLString name(getName()); LLString title(getTitle()); + LLString short_title(getShortTitle()); LLString rect_control(""); BOOL resizable = isResizable(); S32 min_width = getMinWidth(); @@ -2948,6 +3005,7 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor node->getAttributeString("name", name); node->getAttributeString("title", title); + node->getAttributeString("short_title", short_title); node->getAttributeString("rect_control", rect_control); node->getAttributeBOOL("can_resize", resizable); node->getAttributeBOOL("can_minimize", minimizable); @@ -2974,6 +3032,8 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor minimizable, close_btn); + setShortTitle(short_title); + BOOL can_tear_off; if (node->getAttributeBOOL("can_tear_off", can_tear_off)) { @@ -2988,17 +3048,13 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor LLFloater::setFloaterHost((LLMultiFloater*) this); } - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - factory->createWidget(this, child); - } + initChildrenXML(node, factory); + if (node->hasName("multi_floater")) { LLFloater::setFloaterHost(last_host); } - BOOL result = postBuild(); if (!result) @@ -3011,4 +3067,6 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor { this->open(); /* Flawfinder: ignore */ } + + moveResizeHandlesToFront(); } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 1491f75683..942ae34d27 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -123,8 +123,10 @@ public: void setTitle( const LLString& title ); const LLString& getTitle() const; + void setShortTitle( const LLString& short_title ); + LLString getShortTitle(); virtual void setMinimized(BOOL b); - void moveResizeHandleToFront(); + void moveResizeHandlesToFront(); void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE); void addDependentFloater(LLViewHandle dependent_handle, BOOL reposition = TRUE); LLFloater* getDependee() { return (LLFloater*)LLFloater::getFloaterByHandle(mDependeeHandle); } @@ -222,6 +224,7 @@ protected: LLRect mPreviousRect; BOOL mForeground; LLViewHandle mDependeeHandle; + LLString mShortTitle; BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. @@ -351,12 +354,11 @@ public: /*virtual*/ void draw(); /*virtual*/ void setVisible(BOOL visible); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent); - /*virtual*/ EWidgetType getWidgetType() const; /*virtual*/ LLString getWidgetTag() const; virtual void setCanResize(BOOL can_resize); - virtual void growToFit(LLFloater* floaterp, S32 width, S32 height); + virtual void growToFit(S32 content_width, S32 content_height); virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainerCommon::eInsertionPoint insertion_point = LLTabContainerCommon::END); virtual void showFloater(LLFloater* floaterp); @@ -378,7 +380,7 @@ public: void setTabContainer(LLTabContainerCommon* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } static void onTabSelected(void* userdata, bool); - virtual void resizeToContents(); + virtual void updateResizeLimits(); protected: struct LLFloaterData diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index da53e3d104..5c8eb8b4af 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -132,8 +132,7 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu if (lock) { - mLockedView = mKeyboardFocus; - mKeyboardLockedFocusLostCallback = on_focus_lost; + lockFocus(); } } @@ -292,6 +291,12 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( LLUICtrl* top_view ) } } +void LLFocusMgr::lockFocus() +{ + mLockedView = mKeyboardFocus; + mKeyboardLockedFocusLostCallback = mKeyboardFocusLostCallback; +} + void LLFocusMgr::unlockFocus() { mLockedView = NULL; diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index dc8025d4c0..e764f5459c 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -61,6 +61,7 @@ public: // All Three void releaseFocusIfNeeded( LLView* top_view ); + void lockFocus(); void unlockFocus(); BOOL focusLocked() { return mLockedView != NULL; } diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index d7ccfe1daa..52fdf3cd5a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1391,9 +1391,9 @@ void LLMenuItemBranchGL::updateBranchParent(LLView* parentp) } } -void LLMenuItemBranchGL::onVisibilityChange( BOOL curVisibilityIn ) +void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility ) { - if (curVisibilityIn == FALSE && mBranch->getVisible() && !mBranch->getTornOff()) + if (new_visibility == FALSE && !mBranch->getTornOff()) { mBranch->setVisible(FALSE); } diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 37feffd4b0..c130214b99 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -31,9 +31,18 @@ #include "llviewborder.h" #include "llbutton.h" +// LLLayoutStack +#include "llgl.h" +#include "llglheaders.h" +#include "llresizebar.h" +#include "llcriticaldamp.h" + LLPanel::panel_map_t LLPanel::sPanelMap; LLPanel::alert_queue_t LLPanel::sAlertQueue; +const S32 RESIZE_BAR_OVERLAP = 1; +const S32 PANEL_STACK_GAP = RESIZE_BAR_HEIGHT; + void LLPanel::init() { // mRectControl @@ -99,13 +108,16 @@ void LLPanel::addBorder(LLViewBorder::EBevel border_bevel, addChild( mBorder ); } +void LLPanel::removeBorder() +{ + delete mBorder; + mBorder = NULL; +} + LLPanel::~LLPanel() { - if( !mRectControl.empty() ) - { - LLUI::sConfigGroup->setRect( mRectControl, mRect ); - } + storeRectControl(); sPanelMap.erase(mViewHandle); } @@ -159,44 +171,41 @@ void LLPanel::setCtrlsEnabled( BOOL b ) void LLPanel::draw() { - if( getVisible() ) + // draw background + if( mBgVisible ) { - // draw background - if( mBgVisible ) - { - //RN: I don't see the point of this - S32 left = 0;//LLPANEL_BORDER_WIDTH; - S32 top = mRect.getHeight();// - LLPANEL_BORDER_WIDTH; - S32 right = mRect.getWidth();// - LLPANEL_BORDER_WIDTH; - S32 bottom = 0;//LLPANEL_BORDER_WIDTH; + //RN: I don't see the point of this + S32 left = 0;//LLPANEL_BORDER_WIDTH; + S32 top = mRect.getHeight();// - LLPANEL_BORDER_WIDTH; + S32 right = mRect.getWidth();// - LLPANEL_BORDER_WIDTH; + S32 bottom = 0;//LLPANEL_BORDER_WIDTH; - if (mBgOpaque ) - { - gl_rect_2d( left, top, right, bottom, mBgColorOpaque ); - } - else - { - gl_rect_2d( left, top, right, bottom, mBgColorAlpha ); - } + if (mBgOpaque ) + { + gl_rect_2d( left, top, right, bottom, mBgColorOpaque ); } - - if( mDefaultBtn) + else { - if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) - { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); - BOOL focus_is_child_button = focus_ctrl->getWidgetType() == WIDGET_TYPE_BUTTON && static_cast<LLButton *>(focus_ctrl)->getCommitOnReturn(); - // only enable default button when current focus is not a return-capturing button - mDefaultBtn->setBorderEnabled(!focus_is_child_button); - } - else - { - mDefaultBtn->setBorderEnabled(FALSE); - } + gl_rect_2d( left, top, right, bottom, mBgColorAlpha ); } + } - LLView::draw(); + if( mDefaultBtn) + { + if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) + { + LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + BOOL focus_is_child_button = focus_ctrl->getWidgetType() == WIDGET_TYPE_BUTTON && static_cast<LLButton *>(focus_ctrl)->getCommitOnReturn(); + // only enable default button when current focus is not a return-capturing button + mDefaultBtn->setBorderEnabled(!focus_is_child_button); + } + else + { + mDefaultBtn->setBorderEnabled(FALSE); + } } + + LLView::draw(); } void LLPanel::refresh() @@ -552,7 +561,7 @@ LLXMLNodePtr LLPanel::getXML(bool save_children) const return node; } -LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *factory) +LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *factory) { LLString name("panel"); node->getAttributeString("name", name); @@ -561,11 +570,21 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *fa // Fall back on a default panel, if there was no special factory. if (!panelp) { - panelp = new LLPanel("tab panel"); + LLRect rect; + createRect(node, rect, parent, LLRect()); + panelp = new LLPanel(name, rect); + panelp->initPanelXML(node, parent, factory); + // preserve panel's width and height, but override the location + const LLRect& panelrect = panelp->getRect(); + S32 w = panelrect.getWidth(); + S32 h = panelrect.getHeight(); + rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h); + panelp->setRect(rect); + } + else + { + panelp->initPanelXML(node, parent, factory); } - - panelp->initPanelXML(node, parentp, factory); - return panelp; } @@ -577,11 +596,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f setPanelParameters(node, parent); - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - factory->createWidget(this, child); - } + initChildrenXML(node, factory); LLString xml_filename; node->getAttributeString("filename", xml_filename); @@ -590,8 +605,16 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f if (!xml_filename.empty()) { + // Preserve postion of embedded panel but allow panel to dictate width/height + LLRect rect(getRect()); didPost = factory->buildPanel(this, xml_filename, NULL); - } else { + S32 w = getRect().getWidth(); + S32 h = getRect().getHeight(); + rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h); + setRect(rect); + } + else + { didPost = FALSE; } @@ -604,10 +627,32 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f return didPost; } -void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) +void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory) +{ + LLXMLNodePtr child; + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) + { + // look for string declarations for programmatic text + if (child->hasName("string")) + { + LLString string_name; + child->getAttributeString("name", string_name); + if (!string_name.empty()) + { + mUIStrings[string_name] = LLUIString(child->getTextContents()); + } + } + else + { + factory->createWidget(this, child); + } + } +} + +void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent) { /////// Rect, follows, tool_tip, enabled, visible attributes /////// - initFromXML(node, parentp); + initFromXML(node, parent); /////// Border attributes /////// BOOL border = FALSE; @@ -632,6 +677,10 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) addBorder(bevel_style, border_style, border_thickness); } + else + { + removeBorder(); + } /////// Background attributes /////// BOOL background_visible = FALSE; @@ -656,6 +705,30 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) setLabel(label); } +LLString LLPanel::getFormattedUIString(const LLString& name, const LLString::format_map_t& args) const +{ + ui_string_map_t::const_iterator found_it = mUIStrings.find(name); + if (found_it != mUIStrings.end()) + { + // make a copy as format works in place + LLUIString formatted_string = found_it->second; + formatted_string.setArgList(args); + return formatted_string.getString(); + } + return LLString::null; +} + +LLUIString LLPanel::getUIString(const LLString& name) const +{ + ui_string_map_t::const_iterator found_it = mUIStrings.find(name); + if (found_it != mUIStrings.end()) + { + return found_it->second; + } + return LLUIString(LLString::null); +} + + void LLPanel::childSetVisible(const LLString& id, bool visible) { LLView* child = getChildByName(id, true); @@ -1045,3 +1118,493 @@ void LLPanel::childDisplayNotFound() LLAlertDialog::showXml("FloaterNotFound", args); } +void LLPanel::storeRectControl() +{ + if( !mRectControl.empty() ) + { + LLUI::sConfigGroup->setRect( mRectControl, mRect ); + } +} + + +// +// LLLayoutStack +// +struct LLLayoutStack::LLEmbeddedPanel +{ + LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize) : + mPanel(panelp), + mMinWidth(min_width), + mMinHeight(min_height), + mAutoResize(auto_resize), + mOrientation(orientation), + mVisibleAmt(1.f) // default to fully visible + { + LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; + LLRect resize_bar_rect = panelp->getRect(); + + S32 min_dim; + if (orientation == HORIZONTAL) + { + min_dim = mMinHeight; + } + else + { + min_dim = mMinWidth; + } + mResizeBar = new LLResizeBar("resizer", mPanel, LLRect(), min_dim, S32_MAX, side); + mResizeBar->setEnableSnapping(FALSE); + // panels initialized as hidden should not start out partially visible + if (!mPanel->getVisible()) + { + mVisibleAmt = 0.f; + } + } + + LLPanel* mPanel; + S32 mMinWidth; + S32 mMinHeight; + BOOL mAutoResize; + LLResizeBar* mResizeBar; + eLayoutOrientation mOrientation; + F32 mVisibleAmt; +}; + +LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) : + mOrientation(orientation), + mMinWidth(0), + mMinHeight(0) +{ +} + +LLLayoutStack::~LLLayoutStack() +{ +} + +void LLLayoutStack::draw() +{ + updateLayout(); + { + // clip if outside nominal bounds + LLLocalClipRect clip(getLocalRect(), mRect.getWidth() > mMinWidth || mRect.getHeight() > mMinHeight); + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + LLRect clip_rect = (*panel_it)->mPanel->getRect(); + // scale clipping rectangle by visible amount + if (mOrientation == HORIZONTAL) + { + clip_rect.mRight = clip_rect.mLeft + llround(clip_rect.getWidth() * (*panel_it)->mVisibleAmt); + } + else + { + clip_rect.mBottom = clip_rect.mTop - llround(clip_rect.getHeight() * (*panel_it)->mVisibleAmt); + } + LLLocalClipRect clip(clip_rect, (*panel_it)->mVisibleAmt < 1.f); + // only force drawing invisible children if visible amount is non-zero + drawChild((*panel_it)->mPanel, 0, 0, (*panel_it)->mVisibleAmt > 0.f); + } + } +} + +void LLLayoutStack::removeCtrl(LLUICtrl* ctrl) +{ + LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel((LLPanel*)ctrl); + + if (embedded_panelp) + { + mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); + delete embedded_panelp; + } + + calcMinExtents(); + + LLView::removeCtrl(ctrl); +} + +void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLView::reshape(width, height, called_from_parent); + //updateLayout(); +} + +LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLView::getXML(); + return node; +} + +//static +LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLString orientation_string("vertical"); + node->getAttributeString("orientation", orientation_string); + + eLayoutOrientation orientation = VERTICAL; + + if (orientation_string == "horizontal") + { + orientation = HORIZONTAL; + } + else if (orientation_string == "vertical") + { + orientation = VERTICAL; + } + else + { + llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl; + } + + LLLayoutStack* layout_stackp = new LLLayoutStack(orientation); + + layout_stackp->initFromXML(node, parent); + + LLXMLNodePtr child; + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) + { + if (child->hasName("layout_panel")) + { + S32 min_width = 0; + S32 min_height = 0; + BOOL auto_resize = TRUE; + + child->getAttributeS32("min_width", min_width); + child->getAttributeS32("min_height", min_height); + child->getAttributeBOOL("auto_resize", auto_resize); + + LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory); + panelp->setFollowsNone(); + if (panelp) + { + layout_stackp->addPanel(panelp, min_width, min_height, auto_resize); + } + } + } + + return layout_stackp; +} + +S32 LLLayoutStack::getMinWidth() +{ + return mMinWidth; +} + +S32 LLLayoutStack::getMinHeight() +{ + return mMinHeight; +} + +void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index) +{ + LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize); + + mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel); + addChild(panel); + addChild(embedded_panel->mResizeBar); + + // 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) + { + e_panel_list_t::iterator next_it = panel_it; + ++next_it; + + LLResizeBar* resize_barp = (*panel_it)->mResizeBar; + sendChildToFront(resize_barp); + // last resize bar is disabled, since its not between any two panels + if ( next_it == mPanels.end() ) + { + resize_barp->setEnabled(FALSE); + } + else + { + resize_barp->setEnabled(TRUE); + } + } + + //updateLayout(); +} + +void LLLayoutStack::removePanel(LLPanel* panel) +{ + removeChild(panel); + //updateLayout(); +} + +void LLLayoutStack::updateLayout(BOOL force_resize) +{ + calcMinExtents(); + + // calculate current extents + S32 cur_width = 0; + S32 cur_height = 0; + + const F32 ANIM_OPEN_TIME = 0.02f; + const F32 ANIM_CLOSE_TIME = 0.02f; + + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + LLPanel* panelp = (*panel_it)->mPanel; + if (panelp->getVisible()) + { + (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME)); + if ((*panel_it)->mVisibleAmt > 0.99f) + { + (*panel_it)->mVisibleAmt = 1.f; + } + } + else // not visible + { + (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); + if ((*panel_it)->mVisibleAmt < 0.001f) + { + (*panel_it)->mVisibleAmt = 0.f; + } + } + if (mOrientation == HORIZONTAL) + { + // all panels get expanded to max of all the minimum dimensions + cur_height = llmax(mMinHeight, panelp->getRect().getHeight()); + cur_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt); + if (panel_it != mPanels.end()) + { + cur_width += PANEL_STACK_GAP; + } + } + else //VERTICAL + { + cur_width = llmax(mMinWidth, panelp->getRect().getWidth()); + cur_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt); + if (panel_it != mPanels.end()) + { + cur_height += PANEL_STACK_GAP; + } + } + } + + S32 num_resizable_panels = 0; + S32 shrink_headroom_available = 0; + S32 shrink_headroom_total = 0; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + // panels that are not fully visible do not count towards shrink headroom + if ((*panel_it)->mVisibleAmt < 1.f) + continue; + // 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 ((*panel_it)->mResizeBar->hasMouseCapture() || (!(*panel_it)->mAutoResize && !force_resize)) + { + if (mOrientation == HORIZONTAL) + { + shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; + } + else //VERTICAL + { + shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; + } + } + else + { + num_resizable_panels++; + if (mOrientation == HORIZONTAL) + { + shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; + shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; + } + else //VERTICAL + { + shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; + shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; + } + } + } + + // positive means panels need to grow, negative means shrink + S32 pixels_to_distribute; + if (mOrientation == HORIZONTAL) + { + pixels_to_distribute = mRect.getWidth() - cur_width; + } + else //VERTICAL + { + pixels_to_distribute = mRect.getHeight() - cur_height; + } + + S32 cur_x = 0; + S32 cur_y = mRect.getHeight(); + + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + LLPanel* panelp = (*panel_it)->mPanel; + + S32 cur_width = panelp->getRect().getWidth(); + S32 cur_height = panelp->getRect().getHeight(); + S32 new_width = llmax((*panel_it)->mMinWidth, cur_width); + S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); + + S32 delta_size = 0; + + // if panel can automatically resize (not animating, and resize flag set)... + if ((*panel_it)->mVisibleAmt == 1.f && (force_resize || (*panel_it)->mAutoResize) && !(*panel_it)->mResizeBar->hasMouseCapture()) + { + if (mOrientation == HORIZONTAL) + { + // if we're shrinking + if (pixels_to_distribute < 0) + { + // shrink proportionally to amount over minimum + delta_size = llround((F32)pixels_to_distribute * (F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available); + } + else + { + // grow all elements equally + delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels); + } + new_width = llmax((*panel_it)->mMinWidth, panelp->getRect().getWidth() + delta_size); + } + else + { + new_width = llmax(mMinWidth, mRect.getWidth()); + } + + if (mOrientation == VERTICAL) + { + if (pixels_to_distribute < 0) + { + // shrink proportionally to amount over minimum + delta_size = llround((F32)pixels_to_distribute * (F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available); + } + else + { + delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels); + } + new_height = llmax((*panel_it)->mMinHeight, panelp->getRect().getHeight() + delta_size); + } + else + { + new_height = llmax(mMinHeight, mRect.getHeight()); + } + } + else // don't resize + { + if (mOrientation == HORIZONTAL) + { + new_height = llmax(mMinHeight, mRect.getHeight()); + } + else // VERTICAL + { + new_width = llmax(mMinWidth, mRect.getWidth()); + } + } + + // adjust running headroom count based on new sizes + shrink_headroom_total += delta_size; + + panelp->reshape(new_width, new_height); + panelp->setOrigin(cur_x, cur_y - new_height); + + LLRect panel_rect = panelp->getRect(); + 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 + PANEL_STACK_GAP + RESIZE_BAR_OVERLAP; + } + else + { + resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP; + resize_bar_rect.mBottom = panel_rect.mBottom - PANEL_STACK_GAP - RESIZE_BAR_OVERLAP; + } + (*panel_it)->mResizeBar->setRect(resize_bar_rect); + + if (mOrientation == HORIZONTAL) + { + cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP; + } + else //VERTICAL + { + cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP; + } + } + + // update resize bars with new limits + LLResizeBar* last_resize_bar = NULL; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + LLPanel* panelp = (*panel_it)->mPanel; + + if (mOrientation == HORIZONTAL) + { + (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinWidth, (*panel_it)->mMinWidth + shrink_headroom_total); + } + else //VERTICAL + { + (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinHeight, (*panel_it)->mMinHeight + shrink_headroom_total); + } + // hide resize bars for invisible panels + (*panel_it)->mResizeBar->setVisible(panelp->getVisible()); + if (panelp->getVisible()) + { + last_resize_bar = (*panel_it)->mResizeBar; + } + } + + // hide last resize bar as there is nothing past it + if (last_resize_bar) + { + last_resize_bar->setVisible(FALSE); + } + + // not enough room to fit existing contents + if (!force_resize && + ((cur_y != -PANEL_STACK_GAP) || (cur_x != mRect.getWidth() + PANEL_STACK_GAP))) + { + // do another layout pass with all stacked elements contributing + // even those that don't usually resize + llassert_always(force_resize == FALSE); + updateLayout(TRUE); + } +} + +LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) +{ + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + if ((*panel_it)->mPanel == panelp) + { + return *panel_it; + } + } + return NULL; +} + +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) + { + mMinHeight = llmax(mMinHeight, (*panel_it)->mMinHeight); + mMinWidth += (*panel_it)->mMinWidth; + if (panel_it != mPanels.begin()) + { + mMinWidth += PANEL_STACK_GAP; + } + } + else //VERTICAL + { + mMinWidth = llmax(mMinWidth, (*panel_it)->mMinWidth); + mMinHeight += (*panel_it)->mMinHeight; + if (panel_it != mPanels.begin()) + { + mMinHeight += PANEL_STACK_GAP; + } + } + } +} diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index f06797a7f8..aa5f6e314f 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -15,6 +15,7 @@ #include "llcallbackmap.h" #include "lluictrl.h" #include "llviewborder.h" +#include "lluistring.h" #include "v4color.h" #include <list> #include <queue> @@ -71,6 +72,8 @@ public: LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE, S32 border_thickness = LLPANEL_BORDER_WIDTH ); + void removeBorder(); + virtual ~LLPanel(); virtual void draw(); virtual void refresh(); // called in setFocus() @@ -97,6 +100,7 @@ public: LLString getLabel() const { return mLabel; } void setRectControl(const LLString& rect_control) { mRectControl.assign(rect_control); } + void storeRectControl(); void setBorderVisible( BOOL b ); @@ -116,8 +120,12 @@ public: virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory); void setPanelParameters(LLXMLNodePtr node, LLView *parentp); + LLString getFormattedUIString(const LLString& name, const LLString::format_map_t& args = LLUIString::sNullArgs) const; + LLUIString getUIString(const LLString& name) const; + // ** Wrappers for setting child properties by name ** -TomY // Override to set not found list @@ -196,6 +204,8 @@ public: typedef std::queue<LLAlertInfo> alert_queue_t; static alert_queue_t sAlertQueue; + typedef std::map<LLString, LLUIString> ui_string_map_t; + private: // common constructor void init(); @@ -221,6 +231,8 @@ protected: LLString mLabel; S32 mLastTabGroup; + ui_string_map_t mUIStrings; + typedef std::map<LLString, EWidgetType> requirements_map_t; requirements_map_t mRequirements; @@ -228,4 +240,50 @@ protected: static panel_map_t sPanelMap; }; +class LLLayoutStack : public LLView +{ +public: + typedef enum e_layout_orientation + { + HORIZONTAL, + VERTICAL + } eLayoutOrientation; + + LLLayoutStack(eLayoutOrientation orientation); + virtual ~LLLayoutStack(); + + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); + /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const; + /*virtual*/ void removeCtrl(LLUICtrl* ctrl); + virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LAYOUT_STACK; } + virtual LLString getWidgetTag() const { return LL_LAYOUT_STACK_TAG; } + + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + + S32 getMinWidth(); + S32 getMinHeight(); + + void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index = S32_MAX); + void removePanel(LLPanel* panel); + void updateLayout(BOOL force_resize = FALSE); + +protected: + struct LLEmbeddedPanel; + + LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp); + void calcMinExtents(); + S32 getMinStackSize(); + S32 getCurStackSize(); + +protected: + eLayoutOrientation mOrientation; + + typedef std::vector<LLEmbeddedPanel*> e_panel_list_t; + e_panel_list_t mPanels; + + S32 mMinWidth; + S32 mMinHeight; +}; + #endif diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index 69c0da6933..b58ae09b5d 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -149,7 +149,7 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) { BOOL handled = FALSE; // do any of the tab buttons have keyboard focus? - if (getEnabled() && !called_from_parent) + if (getEnabled() && !called_from_parent && mask == MASK_NONE) { switch(key) { @@ -421,6 +421,69 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory return radio_group; } +// LLCtrlSelectionInterface functions +BOOL LLRadioGroup::setCurrentByID( const LLUUID& id ) +{ + return FALSE; +} + +LLUUID LLRadioGroup::getCurrentID() +{ + return LLUUID::null; +} + +BOOL LLRadioGroup::setSelectedByValue(LLSD value, BOOL selected) +{ + S32 idx = 0; + std::string value_string = value.asString(); + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + if((*iter)->getName() == value_string) + { + setSelectedIndex(idx); + return TRUE; + } + idx++; + } + + return FALSE; +} + +LLSD LLRadioGroup::getSimpleSelectedValue() +{ + return getValue(); +} + +BOOL LLRadioGroup::isSelected(LLSD value) +{ + S32 idx = 0; + std::string value_string = value.asString(); + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + if((*iter)->getName() == value_string) + { + if (idx == mSelectedIndex) + { + return TRUE; + } + } + idx++; + } + return FALSE; +} + +BOOL LLRadioGroup::operateOnSelection(EOperation op) +{ + return FALSE; +} + +BOOL LLRadioGroup::operateOnAll(EOperation op) +{ + return FALSE; +} + LLRadioCtrl::LLRadioCtrl(const LLString& name, const LLRect& rect, const LLString& label, const LLFontGL* font, void (*commit_callback)(LLUICtrl*, void*), void* callback_userdata) : @@ -438,3 +501,4 @@ void LLRadioCtrl::setValue(const LLSD& value) LLCheckBoxCtrl::setValue(value); mButton->setTabStop(value.asBoolean()); } + diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h index 01b4a61b82..2a856ee6cf 100644 --- a/indra/llui/llradiogroup.h +++ b/indra/llui/llradiogroup.h @@ -15,6 +15,7 @@ #include "lluictrl.h" #include "llcheckboxctrl.h" +#include "llctrlselectioninterface.h" class LLFontGL; @@ -32,7 +33,7 @@ public: }; class LLRadioGroup -: public LLUICtrl +: public LLUICtrl, public LLCtrlSelectionInterface { public: // Build a radio group. The number (0...n-1) of the currently selected @@ -63,7 +64,6 @@ public: static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void setIndexEnabled(S32 index, BOOL enabled); - S32 getItemCount() { return mRadioButtons.size(); } // return the index value of the selected item S32 getSelectedIndex() const; @@ -87,6 +87,23 @@ public: // button. static void onClickButton(LLUICtrl* radio, void* userdata); + //======================================================================== + LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; + + // LLCtrlSelectionInterface functions + /*virtual*/ S32 getItemCount() const { return mRadioButtons.size(); } + /*virtual*/ BOOL getCanSelect() const { return TRUE; } + /*virtual*/ BOOL selectFirstItem() { return setSelectedIndex(0); } + /*virtual*/ BOOL selectNthItem( S32 index ) { return setSelectedIndex(index); } + /*virtual*/ S32 getFirstSelectedIndex() { return getSelectedIndex(); } + /*virtual*/ BOOL setCurrentByID( const LLUUID& id ); + /*virtual*/ LLUUID getCurrentID(); // LLUUID::null if no items in menu + /*virtual*/ BOOL setSelectedByValue(LLSD value, BOOL selected); + /*virtual*/ LLSD getSimpleSelectedValue(); + /*virtual*/ BOOL isSelected(LLSD value); + /*virtual*/ BOOL operateOnSelection(EOperation op); + /*virtual*/ BOOL operateOnAll(EOperation op); + protected: // protected function shared by the two constructors. void init(BOOL border); diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index 0128b4ebbc..b3bce755b1 100644 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -18,16 +18,18 @@ #include "llfocusmgr.h" #include "llwindow.h" -LLResizeBar::LLResizeBar( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, Side side ) +LLResizeBar::LLResizeBar( const LLString& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side ) : LLView( name, rect, TRUE ), mDragLastScreenX( 0 ), mDragLastScreenY( 0 ), mLastMouseScreenX( 0 ), mLastMouseScreenY( 0 ), - mMinWidth( min_width ), - mMinHeight( min_height ), - mSide( side ) + mMinSize( min_size ), + mMaxSize( max_size ), + mSide( side ), + mSnappingEnabled(TRUE), + mResizingView(resizing_view) { // set up some generically good follow code. switch( side ) @@ -129,12 +131,11 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask) // Make sure the mouse in still over the application. We don't want to make the parent // so big that we can't see the resize handle any more. LLRect valid_rect = getRootView()->getRect(); - LLView* resizing_view = getParent(); - if( valid_rect.localPointInRect( screen_x, screen_y ) && resizing_view ) + if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView ) { // Resize the parent - LLRect orig_rect = resizing_view->getRect(); + LLRect orig_rect = mResizingView->getRect(); LLRect scaled_rect = orig_rect; S32 new_width = orig_rect.getWidth(); @@ -143,76 +144,63 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask) switch( mSide ) { case LEFT: - new_width = orig_rect.getWidth() - delta_x; - if( new_width < mMinWidth ) - { - new_width = mMinWidth; - delta_x = orig_rect.getWidth() - mMinWidth; - } + new_width = llclamp(orig_rect.getWidth() - delta_x, mMinSize, mMaxSize); + delta_x = orig_rect.getWidth() - new_width; scaled_rect.translate(delta_x, 0); break; case TOP: - new_height = orig_rect.getHeight() + delta_y; - if( new_height < mMinHeight ) - { - new_height = mMinHeight; - delta_y = mMinHeight - orig_rect.getHeight(); - } + new_height = llclamp(orig_rect.getHeight() + delta_y, mMinSize, mMaxSize); + delta_y = new_height - orig_rect.getHeight(); break; case RIGHT: - new_width = orig_rect.getWidth() + delta_x; - if( new_width < mMinWidth ) - { - new_width = mMinWidth; - delta_x = mMinWidth - orig_rect.getWidth(); - } + new_width = llclamp(orig_rect.getWidth() + delta_x, mMinSize, mMaxSize); + delta_x = new_width - orig_rect.getWidth(); break; case BOTTOM: - new_height = orig_rect.getHeight() - delta_y; - if( new_height < mMinHeight ) - { - new_height = mMinHeight; - delta_y = orig_rect.getHeight() - mMinHeight; - } + new_height = llclamp(orig_rect.getHeight() - delta_y, mMinSize, mMaxSize); + delta_y = orig_rect.getHeight() - new_height; scaled_rect.translate(0, delta_y); break; } scaled_rect.mTop = scaled_rect.mBottom + new_height; scaled_rect.mRight = scaled_rect.mLeft + new_width; - resizing_view->setRect(scaled_rect); + mResizingView->setRect(scaled_rect); LLView* snap_view = NULL; - switch( mSide ) + if (mSnappingEnabled) { - case LEFT: - snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); - break; - case TOP: - snap_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); - break; - case RIGHT: - snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); - break; - case BOTTOM: - snap_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); - break; + switch( mSide ) + { + case LEFT: + snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); + break; + case TOP: + snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); + break; + case RIGHT: + snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); + break; + case BOTTOM: + snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); + break; + } } // register "snap" behavior with snapped view - resizing_view->snappedTo(snap_view); + mResizingView->snappedTo(snap_view); // restore original rectangle so the appropriate changes are detected - resizing_view->setRect(orig_rect); + mResizingView->setRect(orig_rect); // change view shape as user operation - resizing_view->userSetShape(scaled_rect); + mResizingView->userSetShape(scaled_rect); // update last valid mouse cursor position based on resized view's actual size - LLRect new_rect = resizing_view->getRect(); + LLRect new_rect = mResizingView->getRect(); switch(mSide) { case LEFT: diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 7a77cce8a6..cf78879cba 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -17,7 +17,7 @@ class LLResizeBar : public LLView public: enum Side { LEFT, TOP, RIGHT, BOTTOM }; - LLResizeBar(const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, Side side ); + LLResizeBar(const LLString& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side ); virtual EWidgetType getWidgetType() const; virtual LLString getWidgetTag() const; @@ -27,7 +27,8 @@ public: virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } + void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; } + void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; } protected: S32 mDragLastScreenX; @@ -35,9 +36,11 @@ protected: S32 mLastMouseScreenX; S32 mLastMouseScreenY; LLCoordGL mLastMouseDir; - S32 mMinWidth; - S32 mMinHeight; + S32 mMinSize; + S32 mMaxSize; Side mSide; + BOOL mSnappingEnabled; + LLView* mResizingView; }; const S32 RESIZE_BAR_HEIGHT = 3; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 0e3c73f633..589afb114a 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -485,8 +485,7 @@ void LLScrollableContainerView::draw() BOOL show_h_scrollbar = FALSE; calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - LLGLEnable scissor_test(GL_SCISSOR_TEST); - LLUI::setScissorRegionLocal(LLRect(mInnerRect.mLeft, + LLLocalClipRect clip(LLRect(mInnerRect.mLeft, mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height, visible_width, mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 1d07d3f36b..e802b3426b 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -31,7 +31,7 @@ #include "llkeyboard.h" #include "llresizebar.h" -const S32 LIST_BORDER_PAD = 2; // white space inside the border and to the left of the scrollbar +const S32 LIST_BORDER_PAD = 0; // white space inside the border and to the left of the scrollbar const S32 MIN_COLUMN_WIDTH = 20; const S32 LIST_SNAP_PADDING = 5; @@ -397,6 +397,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect, mCommitOnKeyboardMovement(TRUE), mCommitOnSelectionChange(FALSE), mSelectionChanged(FALSE), + mNeedsScroll(FALSE), mCanSelect(TRUE), mDisplayColumnHeaders(FALSE), mCollapseEmptyColumns(FALSE), @@ -1419,14 +1420,16 @@ void LLScrollListCtrl::drawItems() S32 x = mItemListRect.mLeft; S32 y = mItemListRect.mTop - mLineHeight; - S32 num_page_lines = mPageLines; + // allow for partial line at bottom + S32 num_page_lines = mPageLines + 1; LLRect item_rect; LLGLSUIDefault gls_ui; { - + LLLocalClipRect clip(mItemListRect); + S32 cur_x = x; S32 cur_y = y; @@ -1538,6 +1541,11 @@ void LLScrollListCtrl::draw() { if( getVisible() ) { + if (mNeedsScroll) + { + scrollToShowSelected(); + mNeedsScroll = FALSE; + } LLRect background(0, mRect.getHeight(), mRect.getWidth(), 0); // Draw background if (mBackgroundVisible) @@ -1690,6 +1698,7 @@ BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask) gFocusMgr.setMouseCapture(this); selectItemAt(x, y, mask); + mNeedsScroll = TRUE; } return TRUE; @@ -1699,17 +1708,16 @@ BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask) { if (hasMouseCapture()) { + // release mouse capture immediately so + // scroll to show selected logic will work + gFocusMgr.setMouseCapture(NULL); if(mask == MASK_NONE) { selectItemAt(x, y, mask); + mNeedsScroll = TRUE; } } - if (hasMouseCapture()) - { - gFocusMgr.setMouseCapture(NULL); - } - // always commit when mouse operation is completed inside list if (mItemListRect.pointInRect(x,y)) { @@ -1750,7 +1758,8 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) mItemListRect.getWidth(), mLineHeight ); - int num_page_lines = mPageLines; + // allow for partial line at bottom + S32 num_page_lines = mPageLines + 1; S32 line = 0; item_list::iterator iter; @@ -1783,6 +1792,7 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) if(mask == MASK_NONE) { selectItemAt(x, y, mask); + mNeedsScroll = TRUE; } } else if (mCanSelect) @@ -1830,7 +1840,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent { // commit implicit in call selectPrevItem(FALSE); - scrollToShowSelected(); + mNeedsScroll = TRUE; handled = TRUE; } break; @@ -1839,7 +1849,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent { // commit implicit in call selectNextItem(FALSE); - scrollToShowSelected(); + mNeedsScroll = TRUE; handled = TRUE; } break; @@ -1847,7 +1857,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent if (mAllowKeyboardMovement || hasFocus()) { selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1)); - scrollToShowSelected(); + mNeedsScroll = TRUE; if (mCommitOnKeyboardMovement && !mCommitOnSelectionChange) { @@ -1860,7 +1870,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent if (mAllowKeyboardMovement || hasFocus()) { selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1)); - scrollToShowSelected(); + mNeedsScroll = TRUE; if (mCommitOnKeyboardMovement && !mCommitOnSelectionChange) { @@ -1873,7 +1883,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent if (mAllowKeyboardMovement || hasFocus()) { selectFirstItem(); - scrollToShowSelected(); + mNeedsScroll = TRUE; if (mCommitOnKeyboardMovement && !mCommitOnSelectionChange) { @@ -1886,7 +1896,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent if (mAllowKeyboardMovement || hasFocus()) { selectNthItem(getItemCount() - 1); - scrollToShowSelected(); + mNeedsScroll = TRUE; if (mCommitOnKeyboardMovement && !mCommitOnSelectionChange) { @@ -1925,6 +1935,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent } else if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString), FALSE)) { + mNeedsScroll = TRUE; // update search string only on successful match mSearchTimer.reset(); @@ -1964,6 +1975,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_ if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE)) { // update search string only on successful match + mNeedsScroll = TRUE; mSearchString += uni_char; mSearchTimer.reset(); @@ -2009,6 +2021,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_ if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) { selectItem(item); + mNeedsScroll = TRUE; cellp->highlightText(0, 1); mSearchTimer.reset(); @@ -2030,8 +2043,6 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_ } } - // make sure selected item is on screen - scrollToShowSelected(); return TRUE; } @@ -2183,6 +2194,13 @@ void LLScrollListCtrl::setScrollPos( S32 pos ) void LLScrollListCtrl::scrollToShowSelected() { + // don't scroll automatically when capturing mouse input + // as that will change what is currently under the mouse cursor + if (hasMouseCapture()) + { + return; + } + S32 index = getFirstSelectedIndex(); if (index < 0) { @@ -3013,8 +3031,9 @@ LLColumnHeader::LLColumnHeader(const LLString& label, const LLRect &rect, LLScro const S32 RESIZE_BAR_THICKNESS = 3; mResizeBar = new LLResizeBar( "resizebar", + this, LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), - MIN_COLUMN_WIDTH, mRect.getHeight(), LLResizeBar::RIGHT ); + MIN_COLUMN_WIDTH, S32_MAX, LLResizeBar::RIGHT ); addChild(mResizeBar); mResizeBar->setEnabled(FALSE); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 793f97dc64..9604b0569c 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -585,6 +585,7 @@ protected: BOOL mCommitOnKeyboardMovement; BOOL mCommitOnSelectionChange; BOOL mSelectionChanged; + BOOL mNeedsScroll; BOOL mCanSelect; BOOL mDisplayColumnHeaders; BOOL mCollapseEmptyColumns; diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index 3a01013943..06fd2830a3 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -30,6 +30,7 @@ LLSlider::LLSlider( F32 min_value, F32 max_value, F32 increment, + BOOL volume, const LLString& control_name) : LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata, @@ -39,6 +40,7 @@ LLSlider::LLSlider( mMinValue( min_value ), mMaxValue( max_value ), mIncrement( increment ), + mVolumeSlider( volume ), mMouseOffset( 0 ), mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ), mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ), @@ -49,7 +51,7 @@ LLSlider::LLSlider( mMouseDownCallback( NULL ), mMouseUpCallback( NULL ) { - // prperly handle setting the starting thumb rect + // properly handle setting the starting thumb rect // do it this way to handle both the operating-on-settings // and standalone ways of using this setControlName(control_name, NULL); @@ -74,13 +76,15 @@ void LLSlider::setValue(F32 value, BOOL from_event) value -= mMinValue; value += mIncrement/2.0001f; value -= fmod(value, mIncrement); - mValue = mMinValue + value; + value += mMinValue; - if (!from_event) + if (!from_event && mValue != value) { - setControlValue(mValue); + setControlValue(value); } - + + mValue = value; + F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue); S32 left_edge = THUMB_WIDTH/2; @@ -91,6 +95,18 @@ void LLSlider::setValue(F32 value, BOOL from_event) mThumbRect.mRight = x + (THUMB_WIDTH/2); } +void LLSlider::setValueAndCommit(F32 value) +{ + F32 old_value = mValue; + setValue(value); + + if (mValue != old_value) + { + onCommit(); + } +} + + F32 LLSlider::getValueF32() const { return mValue; @@ -107,8 +123,7 @@ BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask) x = llclamp( x, left_edge, right_edge ); F32 t = F32(x - left_edge) / (right_edge - left_edge); - setValue(t * (mMaxValue - mMinValue) + mMinValue ); - onCommit(); + setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); getWindow()->setCursor(UI_CURSOR_ARROW); lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; @@ -158,8 +173,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask) if (MASK_CONTROL & mask) // if CTRL is modifying { - setValue(mInitialValue); - onCommit(); + setValueAndCommit(mInitialValue); } else { @@ -196,13 +210,11 @@ BOOL LLSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) handled = TRUE; break; case KEY_LEFT: - setValue(getValueF32() - getIncrement()); - onCommit(); + setValueAndCommit(getValueF32() - getIncrement()); handled = TRUE; break; case KEY_RIGHT: - setValue(getValueF32() + getIncrement()); - onCommit(); + setValueAndCommit(getValueF32() + getIncrement()); handled = TRUE; break; default: @@ -224,33 +236,93 @@ void LLSlider::draw() LLRect rect(mDragStartThumbRect); F32 opacity = mEnabled ? 1.f : 0.3f; + LLColor4 center_color = (mThumbCenterColor % opacity); + LLColor4 outline_color = (mThumbOutlineColor % opacity); + LLColor4 track_color = (mTrackColor % opacity); + LLImageGL* thumb_imagep = NULL; + // Track + if (mVolumeSlider) + { + LLRect track(0, mRect.getHeight(), mRect.getWidth(), 0); + + track.mBottom += 3; + track.mTop -= 1; + track.mRight -= 1; + + gl_triangle_2d(track.mLeft, track.mBottom, + track.mRight, track.mBottom, + track.mRight, track.mTop, + center_color, + TRUE); + gl_triangle_2d(track.mLeft, track.mBottom, + track.mRight, track.mBottom, + track.mRight, track.mTop, + outline_color, + FALSE); + } + else + { + LLUUID thumb_image_id; + thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga")); + thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id); - LLUUID thumb_image_id; - thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga")); - LLImageGL* thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id); - - S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2; - LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset ); + S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2; + LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset ); - track_rect.stretch(-1); - gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(), - thumb_imagep, mTrackColor % opacity); - //gl_rect_2d( track_rect, mThumbOutlineColor % opacity ); + track_rect.stretch(-1); + gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(), + thumb_imagep, track_color); + } + // Thumb if (!thumb_imagep) { - gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE); - if (hasMouseCapture()) + if (mVolumeSlider) + { + if (hasMouseCapture()) + { + LLRect rect(mDragStartThumbRect); + gl_rect_2d( rect, outline_color ); + rect.stretch(-1); + gl_rect_2d( rect, mThumbCenterColor % 0.3f ); + + if (hasFocus()) + { + LLRect thumb_rect = mThumbRect; + thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt()))); + gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor()); + } + gl_rect_2d( mThumbRect, mThumbOutlineColor ); + } + else + { + if (hasFocus()) + { + LLRect thumb_rect = mThumbRect; + thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt()))); + gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor()); + } + LLRect rect(mThumbRect); + gl_rect_2d(rect, outline_color); + rect.stretch(-1); + gl_rect_2d( rect, center_color); + } + } + else { - gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE); + gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE); + if (hasMouseCapture()) + { + gl_rect_2d(mDragStartThumbRect, center_color, FALSE); + } } } else if( hasMouseCapture() ) { gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(), - thumb_imagep, mThumbCenterColor % 0.3f, TRUE); + thumb_imagep, mThumbCenterColor % 0.3f, TRUE); if (hasFocus()) { @@ -258,20 +330,12 @@ void LLSlider::draw() LLRect highlight_rect = mThumbRect; highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(), - thumb_imagep, gFocusMgr.getFocusColor()); + thumb_imagep, gFocusMgr.getFocusColor()); } - gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), - thumb_imagep, mThumbOutlineColor, TRUE); - - //// Start Thumb - //gl_rect_2d( mDragStartThumbRect, mThumbOutlineColor % 0.3f ); - //rect.stretch(-1); - //gl_rect_2d( rect, mThumbCenterColor % 0.3f ); + thumb_imagep, mThumbOutlineColor, TRUE); - //// Thumb - //gl_rect_2d( mThumbRect, mThumbOutlineColor ); } else { @@ -281,22 +345,12 @@ void LLSlider::draw() LLRect highlight_rect = mThumbRect; highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(), - thumb_imagep, gFocusMgr.getFocusColor()); + thumb_imagep, gFocusMgr.getFocusColor()); } gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), - thumb_imagep, mThumbCenterColor % opacity, TRUE); - //rect = mThumbRect; - - //gl_rect_2d( mThumbRect, mThumbOutlineColor % opacity ); - // - //rect.stretch(-1); - - //// Thumb - //gl_rect_2d( rect, mThumbCenterColor % opacity ); - + thumb_imagep, center_color, TRUE); } - LLUICtrl::draw(); } } @@ -310,6 +364,7 @@ LLXMLNodePtr LLSlider::getXML(bool save_children) const node->createChild("min_val", TRUE)->setFloatValue(getMinValue()); node->createChild("max_val", TRUE)->setFloatValue(getMaxValue()); node->createChild("increment", TRUE)->setFloatValue(getIncrement()); + node->createChild("volume", TRUE)->setBoolValue(getVolumeSlider()); return node; } @@ -336,6 +391,8 @@ LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa F32 increment = 0.1f; node->getAttributeF32("increment", increment); + BOOL volume = node->hasName("volume_slider") ? TRUE : FALSE; + node->getAttributeBOOL("volume", volume); LLSlider* slider = new LLSlider(name, rect, @@ -344,7 +401,8 @@ LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa initial_value, min_value, max_value, - increment); + increment, + volume); slider->initFromXML(node, parent); diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index d88da42064..d9cdf11d5d 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -26,6 +26,7 @@ public: F32 min_value, F32 max_value, F32 increment, + BOOL volume, const LLString& control_name = LLString::null ); virtual EWidgetType getWidgetType() const; @@ -46,6 +47,7 @@ public: F32 getMinValue() const { return mMinValue; } F32 getMaxValue() const { return mMaxValue; } F32 getIncrement() const { return mIncrement; } + BOOL getVolumeSlider() const { return mVolumeSlider; } void setMinValue(F32 min_value) {mMinValue = min_value;} void setMaxValue(F32 max_value) {mMaxValue = max_value;} void setIncrement(F32 increment) {mIncrement = increment;} @@ -59,12 +61,16 @@ public: virtual void draw(); protected: + void setValueAndCommit(F32 value); + +protected: F32 mValue; F32 mInitialValue; F32 mMinValue; F32 mMaxValue; F32 mIncrement; + BOOL mVolumeSlider; S32 mMouseOffset; LLRect mDragStartThumbRect; diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 8b5cd4690e..4ae8c5d222 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -37,6 +37,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect, S32 text_left, BOOL show_text, BOOL can_edit_text, + BOOL volume, void (*commit_callback)(LLUICtrl*, void*), void* callback_user_data, F32 initial_value, F32 min_value, F32 max_value, F32 increment, @@ -45,6 +46,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect, mFont(font), mShowText( show_text ), mCanEditText( can_edit_text ), + mVolumeSlider( volume ), mPrecision( 3 ), mLabelBox( NULL ), mLabelWidth( label_width ), @@ -84,7 +86,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect, "slider", slider_rect, LLSliderCtrl::onSliderCommit, this, - initial_value, min_value, max_value, increment, + initial_value, min_value, max_value, increment, volume, control_which ); addChild( mSlider ); @@ -423,6 +425,8 @@ LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText); + node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider); + node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision); if (mLabelBox) @@ -474,6 +478,9 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory BOOL can_edit_text = FALSE; node->getAttributeBOOL("can_edit_text", can_edit_text); + BOOL volume = FALSE; + node->getAttributeBOOL("volume", volume); + F32 initial_value = 0.f; node->getAttributeF32("initial_val", initial_value); @@ -521,6 +528,7 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory rect.getWidth() - text_left, show_text, can_edit_text, + volume, callback, NULL, initial_value, diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 2185e42eb1..0780350462 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -40,6 +40,7 @@ public: S32 text_left, BOOL show_text, BOOL can_edit_text, + BOOL volume, void (*commit_callback)(LLUICtrl*, void*), void* callback_userdata, F32 initial_value, F32 min_value, F32 max_value, F32 increment, @@ -104,7 +105,8 @@ private: const LLFontGL* mFont; BOOL mShowText; BOOL mCanEditText; - + BOOL mVolumeSlider; + S32 mPrecision; LLTextBox* mLabelBox; S32 mLabelWidth; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index ef527b32c2..65551e5c48 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -50,6 +50,7 @@ LLTabContainerCommon::LLTabContainerCommon( : LLPanel(name, rect, bordered), mCurrentTabIdx(-1), + mTabsHidden(FALSE), mScrolled(FALSE), mScrollPos(0), mScrollPosPixels(0), @@ -75,6 +76,7 @@ LLTabContainerCommon::LLTabContainerCommon( : LLPanel(name, rect_control, bordered), mCurrentTabIdx(-1), + mTabsHidden(FALSE), mScrolled(FALSE), mScrollPos(0), mScrollPosPixels(0), @@ -127,11 +129,11 @@ void LLTabContainerCommon::addPlaceholder(LLPanel* child, const LLString& label) addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); } -void LLTabContainerCommon::lockTabs() +void LLTabContainerCommon::lockTabs(S32 num_tabs) { - // count current tabs and ensure no new tabs get + // count current tabs or use supplied value and ensure no new tabs get // inserted between them - mLockedTabCount = getTabCount(); + mLockedTabCount = num_tabs > 0 ? num_tabs : getTabCount(); } void LLTabContainerCommon::removeTabPanel(LLPanel* child) @@ -522,12 +524,12 @@ void LLTabContainerCommon::setTabPanelFlashing(LLPanel* child, BOOL state ) } } -void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name) +void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name, const LLColor4& color) { LLTabTuple* tuple = getTabByPanel(child); if( tuple ) { - tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT); + tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT, color); } } @@ -647,6 +649,8 @@ LLView* LLTabContainerCommon::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtr } } + node->getAttributeBOOL("hide_tabs", tab_container->mTabsHidden); + tab_container->setPanelParameters(node, parent); if (LLFloater::getFloaterHost()) @@ -1016,10 +1020,11 @@ void LLTabContainer::setPanelTitle(S32 index, const LLString& title) { if (index >= 0 && index < (S32)mTabList.size()) { - LLButton* tab_button = mTabList[index]->mButton; + LLTabTuple* tuple = mTabList[index]; + LLButton* tab_button = tuple->mButton; const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); mTotalTabWidth -= tab_button->getRect().getWidth(); - tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); + tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); mTotalTabWidth += tab_button->getRect().getWidth(); tab_button->setLabelSelected(title); tab_button->setLabelUnselected(title); @@ -1225,63 +1230,60 @@ void LLTabContainer::draw() LLPanel::draw(); - // Show all the buttons - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + // if tabs are hidden, don't draw them and leave them in the invisible state + if (!mTabsHidden) { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - } - - // Draw some of the buttons... + // Show all the buttons + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( TRUE ); + } - LLGLEnable scissor_test(has_scroll_arrows ? GL_SCISSOR_TEST : GL_FALSE); - if( has_scroll_arrows ) - { - // ...but clip them. - S32 x1 = mLeftArrowBtn->getRect().mRight; - S32 y1 = 0; - S32 x2 = mRightArrowBtn->getRect().mLeft; - S32 y2 = 1; - if (mTabList.size() > 0) + // Draw some of the buttons... + LLRect clip_rect = getLocalRect(); + if (has_scroll_arrows) { - y2 = mTabList[0]->mButton->getRect().mTop; + // ...but clip them. + clip_rect.mLeft = mLeftArrowBtn->getRect().mRight; + clip_rect.mRight = mRightArrowBtn->getRect().mLeft; } - LLUI::setScissorRegionLocal(LLRect(x1, y2, x2, y1)); - } + LLLocalClipRect clip(clip_rect); - S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos; - S32 idx = 0; - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; + S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos; + S32 idx = 0; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; - tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); - left += tuple->mButton->getRect().getWidth(); + tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); + left += tuple->mButton->getRect().getWidth(); - if( idx < mScrollPos ) - { - if( tuple->mButton->getFlashing() ) + if( idx < mScrollPos ) { - mLeftArrowBtn->setFlashing( TRUE ); + if( tuple->mButton->getFlashing() ) + { + mLeftArrowBtn->setFlashing( TRUE ); + } } - } - else - if( max_scroll_visible < idx ) - { - if( tuple->mButton->getFlashing() ) + else + if( max_scroll_visible < idx ) { - mRightArrowBtn->setFlashing( TRUE ); + if( tuple->mButton->getFlashing() ) + { + mRightArrowBtn->setFlashing( TRUE ); + } } - } - LLUI::pushMatrix(); - { - LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); - tuple->mButton->draw(); + LLUI::pushMatrix(); + { + LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); + tuple->mButton->draw(); + } + LLUI::popMatrix(); + + idx++; } - LLUI::popMatrix(); - - idx++; } mLeftArrowBtn->setFlashing(FALSE); @@ -1608,12 +1610,12 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); } -void LLTabContainer::setTabImage(LLPanel* child, std::string image_name) +void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) { LLTabTuple* tuple = getTabByPanel(child); if( tuple ) { - tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT); + tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color); const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); // remove current width from total tab strip width @@ -1622,7 +1624,11 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name) S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? tuple->mButton->getImageOverlay()->getWidth(0) : 0; - tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + image_overlay_width, mMinTabWidth, mMaxTabWidth), + + tuple->mPadding = image_overlay_width; + + tuple->mButton->setRightHPad(tuple->mPadding + LLBUTTON_H_PAD); + tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tuple->mButton->getRect().getHeight()); // add back in button width to total tab strip width mTotalTabWidth += tuple->mButton->getRect().getWidth(); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index a395fd94af..4665983402 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -67,7 +67,7 @@ public: BOOL placeholder = FALSE, eInsertionPoint insertion_point = END) = 0; virtual void addPlaceholder(LLPanel* child, const LLString& label); - virtual void lockTabs(); + virtual void lockTabs(S32 num_tabs = 0); virtual void enableTabButton(S32 which, BOOL enable); @@ -94,7 +94,7 @@ public: BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); - virtual void setTabImage(LLPanel* child, std::string img_name); + virtual void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); void setTitle( const LLString& title ); const LLString getPanelTitle(S32 index); @@ -135,7 +135,8 @@ protected: mOnChangeCallback( cb ), mUserData( userdata ), mOldState(FALSE), - mPlaceholderText(placeholder) + mPlaceholderText(placeholder), + mPadding(0) {} LLTabContainerCommon* mTabContainer; @@ -145,11 +146,13 @@ protected: void* mUserData; BOOL mOldState; LLTextBox* mPlaceholderText; + S32 mPadding; }; typedef std::vector<LLTabTuple*> tuple_list_t; tuple_list_t mTabList; S32 mCurrentTabIdx; + BOOL mTabsHidden; BOOL mScrolled; LLFrameTimer mScrollTimer; @@ -208,7 +211,7 @@ public: /*virtual*/ void removeTabPanel( LLPanel* child ); /*virtual*/ void setPanelTitle(S32 index, const LLString& title); - /*virtual*/ void setTabImage(LLPanel* child, std::string img_name); + /*virtual*/ void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); /*virtual*/ void setRightTabBtnOffset( S32 offset ); /*virtual*/ void setMinTabWidth(S32 width); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index eb59765927..ea5897e28e 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2993,8 +2993,7 @@ void LLTextEditor::draw() if( getVisible() ) { { - LLGLEnable scissor_test(GL_SCISSOR_TEST); - LLUI::setScissorRegionLocal(LLRect(0, mRect.getHeight(), mRect.getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); + LLLocalClipRect clip(LLRect(0, mRect.getHeight(), mRect.getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); bindEmbeddedChars( mGLFont ); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index c65500b56c..696be050ce 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -57,6 +57,8 @@ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f); LLWindow* LLUI::sWindow = NULL; LLHtmlHelp* LLUI::sHtmlHelp = NULL; BOOL LLUI::sShowXUINames = FALSE; +std::stack<LLRect> LLUI::sClipRectStack; + // // Functions // @@ -90,7 +92,7 @@ void make_ui_sound(const LLString& name) { llinfos << "ui sound name: " << name << llendl; } - LLUI::sAudioCallback(uuid, LLUI::sConfigGroup->getF32("AudioLevelUI")); + LLUI::sAudioCallback(uuid); } } } @@ -1791,3 +1793,59 @@ void LLUI::setHtmlHelp(LLHtmlHelp* html_help) { LLUI::sHtmlHelp = html_help; } + +//static +void LLUI::pushClipRect(const LLRect& rect) +{ + LLRect combined_clip_rect = rect; + if (!sClipRectStack.empty()) + { + combined_clip_rect.intersectWith(sClipRectStack.top()); + } + sClipRectStack.push(combined_clip_rect); + setScissorRegionScreen(combined_clip_rect); +} + +//static +void LLUI::popClipRect() +{ + sClipRectStack.pop(); + if (!sClipRectStack.empty()) + { + setScissorRegionScreen(sClipRectStack.top()); + } +} + +LLClipRect::LLClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled) +{ + if (mEnabled) + { + LLUI::pushClipRect(rect); + } +} + +LLClipRect::~LLClipRect() +{ + if (mEnabled) + { + LLUI::popClipRect(); + } +} + +LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled) +{ + if (mEnabled) + { + LLRect scissor_rect = rect; + scissor_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY); + LLUI::pushClipRect(scissor_rect); + } +} + +LLLocalClipRect::~LLLocalClipRect() +{ + if (mEnabled) + { + LLUI::popClipRect(); + } +} diff --git a/indra/llui/llui.h b/indra/llui/llui.h index dbe79338e5..fefe75f43e 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -16,6 +16,8 @@ #include "llrect.h" #include "llcoord.h" #include "llhtmlhelp.h" +#include "llgl.h" +#include <stack> class LLColor4; class LLVector3; @@ -123,7 +125,7 @@ extern BOOL gShowTextEditCursor; extern LLString gLanguage; class LLImageProviderInterface; -typedef void (*LLUIAudioCallback)(const LLUUID& uuid, F32 volume); +typedef void (*LLUIAudioCallback)(const LLUUID& uuid); class LLUI { @@ -144,8 +146,8 @@ public: //helper functions (should probably move free standing rendering helper functions here) static LLString locateSkin(const LLString& filename); - static void setScissorRegionScreen(const LLRect& rect); - static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called + static void pushClipRect(const LLRect& rect); + static void popClipRect(); static void setCursorPositionScreen(S32 x, S32 y); static void setCursorPositionLocal(LLView* viewp, S32 x, S32 y); static void setScaleFactor(const LLVector2& scale_factor); @@ -153,6 +155,11 @@ public: static LLUUID findAssetUUIDByName(const LLString& name); static LLVector2 getWindowSize(); static void setHtmlHelp(LLHtmlHelp* html_help); + +private: + static void setScissorRegionScreen(const LLRect& rect); + static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called + public: static LLControlGroup* sConfigGroup; static LLControlGroup* sColorsGroup; @@ -163,6 +170,8 @@ public: static LLWindow* sWindow; static BOOL sShowXUINames; static LLHtmlHelp* sHtmlHelp; + static std::stack<LLRect> sClipRectStack; + }; // UI widgets @@ -251,6 +260,7 @@ typedef enum e_widget_type WIDGET_TYPE_TEXTURE_VIEW, WIDGET_TYPE_MEMORY_VIEW, WIDGET_TYPE_FRAME_STAT_VIEW, + WIDGET_TYPE_LAYOUT_STACK, WIDGET_TYPE_DONTCARE, WIDGET_TYPE_COUNT } EWidgetType; @@ -272,38 +282,38 @@ public: } // default show and hide methods - static T* showInstance(const LLSD& seed) + static T* showInstance(const LLSD& seed = LLSD()) { T* instance = INSTANCE_ADAPTOR::getInstance(seed); INSTANCE_ADAPTOR::show(instance); return instance; } - static void hideInstance(const LLSD& seed) + static void hideInstance(const LLSD& seed = LLSD()) { T* instance = INSTANCE_ADAPTOR::getInstance(seed); INSTANCE_ADAPTOR::hide(instance); } - static void toggleInstance(const LLSD& seed) + static void toggleInstance(const LLSD& seed = LLSD()) { - if (!INSTANCE_ADAPTOR::instanceVisible(seed)) + if (INSTANCE_ADAPTOR::instanceVisible(seed)) { - INSTANCE_ADAPTOR::showInstance(seed); + INSTANCE_ADAPTOR::hideInstance(seed); } else { - INSTANCE_ADAPTOR::hideInstance(seed); + INSTANCE_ADAPTOR::showInstance(seed); } } - static BOOL instanceVisible(const LLSD& seed) + static BOOL instanceVisible(const LLSD& seed = LLSD()) { T* instance = INSTANCE_ADAPTOR::findInstance(seed); return instance != NULL && INSTANCE_ADAPTOR::visible(instance); } - static T* getInstance(const LLSD& seed) + static T* getInstance(const LLSD& seed = LLSD()) { T* instance = INSTANCE_ADAPTOR::findInstance(seed); if (instance == NULL) @@ -312,6 +322,7 @@ public: } return instance; } + }; // Creates a UI singleton by ignoring the identifying parameter @@ -326,12 +337,12 @@ public: LLUISingleton() : LLUIInstanceMgr<T, INSTANCE_ADAPTOR>() { sInstance = (T*)this; } ~LLUISingleton() { sInstance = NULL; } - static T* findInstance(const LLSD& seed) + static T* findInstance(const LLSD& seed = LLSD()) { return sInstance; } - static T* createInstance(const LLSD& seed) + static T* createInstance(const LLSD& seed = LLSD()) { if (sInstance == NULL) { @@ -346,4 +357,24 @@ protected: template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL; +class LLClipRect +{ +public: + LLClipRect(const LLRect& rect, BOOL enabled = TRUE); + virtual ~LLClipRect(); +protected: + LLGLState mScissorState; + BOOL mEnabled; +}; + +class LLLocalClipRect +{ +public: + LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); + virtual ~LLLocalClipRect(); +protected: + LLGLState mScissorState; + BOOL mEnabled; +}; + #endif diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index abf796fde0..46bb977f7e 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -236,7 +236,7 @@ public: /*virtual*/ void operator() (LLView * parent, viewList_t &children) const { children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup())); - } + } }; BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields) diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 1d149b63e2..b4551c1852 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -69,7 +69,7 @@ const LLString LLUICtrlFactory::sUICtrlNames[WIDGET_TYPE_COUNT] = LLString("web_browser"), //WIDGET_TYPE_WEBBROWSER LLString("slider"), //WIDGET_TYPE_SLIDER, actually LLSliderCtrl LLString("slider_bar"), //WIDGET_TYPE_SLIDER_BAR, actually LLSlider - LLString("volume_slider"), //WIDGET_TYPE_VOLUME_SLIDER, actually LLVolumeSliderCtrl + LLString("volume_slider"), //WIDGET_TYPE_VOLUME_SLIDER, actually LLSlider + "volume" param LLString("spinner"), //WIDGET_TYPE_SPINNER, actually LLSpinCtrl LLString("text_editor"), //WIDGET_TYPE_TEXT_EDITOR LLString("texture_picker"),//WIDGET_TYPE_TEXTURE_PICKER @@ -135,6 +135,7 @@ const LLString LLUICtrlFactory::sUICtrlNames[WIDGET_TYPE_COUNT] = LLString("texture_view"), //WIDGET_TYPE_TEXTURE_VIEW LLString("memory_view"), //WIDGET_TYPE_MEMORY_VIEW LLString("frame_stat_view"), //WIDGET_TYPE_FRAME_STAT_VIEW + LLString("layout_stack"), //WIDGET_TYPE_LAYOUT_STACK LLString("DONT_CARE"), //WIDGET_TYPE_DONTCARE }; @@ -177,6 +178,7 @@ LLUICtrlFactory::LLUICtrlFactory() LLUICtrlCreator<LLScrollListCtrl>::registerCreator(LL_SCROLL_LIST_CTRL_TAG, this); LLUICtrlCreator<LLSliderCtrl>::registerCreator(LL_SLIDER_CTRL_TAG, this); LLUICtrlCreator<LLSlider>::registerCreator(LL_SLIDER_TAG, this); + LLUICtrlCreator<LLSlider>::registerCreator(LL_VOLUME_SLIDER_CTRL_TAG, this); LLUICtrlCreator<LLSpinCtrl>::registerCreator(LL_SPIN_CTRL_TAG, this); LLUICtrlCreator<LLTextBox>::registerCreator(LL_TEXT_BOX_TAG, this); LLUICtrlCreator<LLRadioGroup>::registerCreator(LL_RADIO_GROUP_TAG, this); @@ -190,6 +192,7 @@ LLUICtrlFactory::LLUICtrlFactory() LLUICtrlCreator<LLMenuGL>::registerCreator(LL_MENU_GL_TAG, this); LLUICtrlCreator<LLMenuBarGL>::registerCreator(LL_MENU_BAR_GL_TAG, this); LLUICtrlCreator<LLScrollingPanelList>::registerCreator(LL_SCROLLING_PANEL_LIST_TAG, this); + LLUICtrlCreator<LLLayoutStack>::registerCreator(LL_LAYOUT_STACK_TAG, this); setupPaths(); @@ -745,6 +748,37 @@ LLScrollingPanelList* LLUICtrlFactory::getScrollingPanelList(LLPanel* panelp, co return (LLScrollingPanelList*)panelp->getCtrlByNameAndType(name, WIDGET_TYPE_SCROLLING_PANEL_LIST); } + +LLCtrlListInterface* LLUICtrlFactory::getListInterfaceByName(LLPanel* panelp, const LLString& name) +{ + LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE); + if (viewp && viewp->isCtrl()) + { + return ((LLUICtrl*)viewp)->getListInterface(); + } + return NULL; +} + +LLCtrlSelectionInterface* LLUICtrlFactory::getSelectionInterfaceByName(LLPanel* panelp, const LLString& name) +{ + LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE); + if (viewp && viewp->isCtrl()) + { + return ((LLUICtrl*)viewp)->getSelectionInterface(); + } + return NULL; +} + +LLCtrlScrollInterface* LLUICtrlFactory::getScrollInterfaceByName(LLPanel* panelp, const LLString& name) +{ + LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE); + if (viewp && viewp->isCtrl()) + { + return ((LLUICtrl*)viewp)->getScrollInterface(); + } + return NULL; +} + void LLUICtrlFactory::registerCreator(LLString ctrlname, creator_function_t function) { LLString::toLower(ctrlname); diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index c7280aa4a2..04a8a83cfa 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -45,6 +45,9 @@ class LLWebBrowserCtrl; class LLViewBorder; class LLColorSwatchCtrl; class LLScrollingPanelList; +class LLCtrlListInterface; +class LLCtrlSelectionInterface; +class LLCtrlScrollInterface; // Widget @@ -103,6 +106,11 @@ public: static LLMenuItemCallGL* getMenuItemCallByName(LLPanel* panelp, const LLString& name); static LLScrollingPanelList* getScrollingPanelList(LLPanel* panelp, const LLString& name); + // interface getters + static LLCtrlListInterface* getListInterfaceByName(LLPanel* panelp, const LLString& name); + static LLCtrlSelectionInterface* getSelectionInterfaceByName(LLPanel* panelp, const LLString& name); + static LLCtrlScrollInterface* getScrollInterfaceByName(LLPanel* panelp, const LLString& name); + LLPanel* createFactoryPanel(LLString name); virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node); diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 8c5b587158..900a867164 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -10,6 +10,9 @@ #include "lluistring.h" +const LLString::format_map_t LLUIString::sNullArgs; + + // public LLUIString::LLUIString(const LLString& instring, const LLString::format_map_t& args) diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 8c2e3c481c..c3113cbe74 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -75,6 +75,8 @@ public: void insert(S32 charidx, const LLWString& wchars); void replace(S32 charidx, llwchar wc); + static const LLString::format_map_t sNullArgs; + private: void format(); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index dbc635830b..b87d82653a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -305,6 +305,10 @@ void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child) void LLView::addChild(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) { @@ -328,6 +332,10 @@ void LLView::addChild(LLView* child, S32 tab_group) void LLView::addChildAtEnd(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) { @@ -732,18 +740,22 @@ void LLView::setEnabled(BOOL enabled) // virtual void LLView::setVisible(BOOL visible) { - if( !visible && (gFocusMgr.getTopCtrl() == this) ) - { - gFocusMgr.setTopCtrl( NULL ); - } - if ( mVisible != visible ) { - // tell all children of this view that the visibility may have changed - onVisibilityChange ( visible ); - } + if( !visible && (gFocusMgr.getTopCtrl() == this) ) + { + gFocusMgr.setTopCtrl( NULL ); + } - mVisible = visible; + mVisible = visible; + + // notify children of visibility change if root, or part of visible hierarchy + if (!getParent() || getParent()->isInVisibleChain()) + { + // tell all children of this view that the visibility may have changed + onVisibilityChange( visible ); + } + } } // virtual @@ -758,7 +770,7 @@ BOOL LLView::setLabelArg(const LLString& key, const LLString& text) return FALSE; } -void LLView::onVisibilityChange ( BOOL curVisibilityIn ) +void LLView::onVisibilityChange ( BOOL new_visibility ) { for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { @@ -766,7 +778,7 @@ void LLView::onVisibilityChange ( BOOL curVisibilityIn ) // only views that are themselves visible will have their overall visibility affected by their ancestors if (viewp->getVisible()) { - viewp->onVisibilityChange ( curVisibilityIn ); + viewp->onVisibilityChange ( new_visibility ); } } } @@ -1370,64 +1382,61 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask) void LLView::draw() { - if (getVisible()) + if (sDebugRects) { - if (sDebugRects) - { - drawDebugRect(); + drawDebugRect(); - // Check for bogus rectangle - if (mRect.mRight <= mRect.mLeft - || mRect.mTop <= mRect.mBottom) - { - llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; - } + // Check for bogus rectangle + if (mRect.mRight <= mRect.mLeft + || mRect.mTop <= mRect.mBottom) + { + llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; } + } - LLRect rootRect = getRootView()->getRect(); - LLRect screenRect; + 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; - } + // draw focused control on top of everything else + LLView* focus_view = gFocusMgr.getKeyboardFocus(); + if (focus_view && focus_view->getParent() != this) + { + focus_view = NULL; + } - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) - { - LLView *viewp = *child_iter; - ++sDepth; + for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) + { + LLView *viewp = *child_iter; + ++sDepth; - if (viewp->getVisible() && viewp != focus_view) + if (viewp->getVisible() && viewp != focus_view) + { + // Only draw views that are within the root view + localRectToScreen(viewp->getRect(),&screenRect); + if ( rootRect.rectInRect(&screenRect) ) { - // Only draw views that are within the root view - localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.rectInRect(&screenRect) ) + glMatrixMode(GL_MODELVIEW); + LLUI::pushMatrix(); { - glMatrixMode(GL_MODELVIEW); - LLUI::pushMatrix(); - { - LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); - viewp->draw(); - } - LLUI::popMatrix(); + LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); + viewp->draw(); } + LLUI::popMatrix(); } - - --sDepth; } - if (focus_view && focus_view->getVisible()) - { - drawChild(focus_view); - } + --sDepth; + } - // HACK - if (sEditingUI && this == sEditingUIView) - { - drawDebugRect(); - } + if (focus_view && focus_view->getVisible()) + { + drawChild(focus_view); + } + + // HACK + if (sEditingUI && this == sEditingUIView) + { + drawDebugRect(); } } @@ -1480,13 +1489,13 @@ void LLView::drawDebugRect() } } -void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset) +void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw) { if (childp && childp->getParent() == this) { ++sDepth; - if (childp->getVisible()) + if (childp->getVisible() || force_draw) { glMatrixMode(GL_MODELVIEW); LLUI::pushMatrix(); @@ -1616,7 +1625,7 @@ void LLView::updateRect() LLView* viewp = *child_it; if (viewp->getVisible()) { - child_spanning_rect |= viewp->mRect; + child_spanning_rect.unionWith(viewp->mRect); } } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index f9875e8cca..18f453f621 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -359,7 +359,7 @@ public: virtual void draw(); void drawDebugRect(); - void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0); + void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); virtual const LLString& getName() const; |