diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llui/lldockablefloater.cpp | 48 | ||||
-rw-r--r-- | indra/llui/lldockablefloater.h | 23 | ||||
-rw-r--r-- | indra/llui/lldockcontrol.cpp | 124 | ||||
-rw-r--r-- | indra/llui/lldockcontrol.h | 16 | ||||
-rw-r--r-- | indra/llui/llflatlistview.cpp | 195 | ||||
-rw-r--r-- | indra/llui/llflatlistview.h | 142 | ||||
-rw-r--r-- | indra/llui/llfocusmgr.cpp | 4 | ||||
-rw-r--r-- | indra/llui/llfocusmgr.h | 7 | ||||
-rw-r--r-- | indra/llui/llnotifications.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llscrollbar.cpp | 13 | ||||
-rw-r--r-- | indra/llui/llscrollbar.h | 14 | ||||
-rw-r--r-- | indra/llui/llscrollcontainer.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llscrolllistctrl.cpp | 6 | ||||
-rw-r--r-- | indra/llui/llscrolllistctrl.h | 6 | ||||
-rw-r--r-- | indra/llui/lltextbox.h | 1 |
16 files changed, 520 insertions, 85 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index fce6b759a4..1e6b216a61 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -50,7 +50,6 @@ set(llui_SOURCE_FILES llkeywords.cpp lllayoutstack.cpp lllineeditor.cpp - lllistctrl.cpp lllocalcliprect.cpp llmenugl.cpp llmodaldialog.cpp @@ -136,7 +135,6 @@ set(llui_HEADER_FILES lllayoutstack.h lllazyvalue.h lllineeditor.h - lllistctrl.h lllocalcliprect.h llmenugl.h llmodaldialog.h diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index ed15d9d922..93d62fd7c2 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -35,12 +35,21 @@ #include "lldockablefloater.h" //static -LLHandle<LLFloater> LLDockableFloater::instanceHandle; +LLHandle<LLFloater> LLDockableFloater::sInstanceHandle; LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, const LLSD& key, const Params& params) : - LLFloater(key, params), mDockControl(dockControl) + LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true) { + setDocked(mDockControl.get() != NULL && mDockControl.get()->isDockVisible()); + resetInstance(); +} + +LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, + const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(uniqueDocking) +{ + setDocked(mDockControl.get() != NULL && mDockControl.get()->isDockVisible()); resetInstance(); } @@ -57,22 +66,14 @@ BOOL LLDockableFloater::postBuild() void LLDockableFloater::resetInstance() { - if (instanceHandle.get() != this) + if (mUniqueDocking && sInstanceHandle.get() != this) { - if (instanceHandle.get() != NULL && instanceHandle.get()->isDocked()) + if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked()) { - //closeFloater() is not virtual - if (instanceHandle.get()->canClose()) - { - instanceHandle.get()->closeFloater(); + sInstanceHandle.get()->setVisible(FALSE); } - else - { - instanceHandle.get()->setVisible(FALSE); + sInstanceHandle = getHandle(); } - } - instanceHandle = getHandle(); - } } void LLDockableFloater::setVisible(BOOL visible) @@ -81,12 +82,18 @@ void LLDockableFloater::setVisible(BOOL visible) { resetInstance(); } + + if (visible && mDockControl.get() != NULL) + { + mDockControl.get()->repositionDockable(); + } + LLFloater::setVisible(visible); } void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) { - if (mDockControl.get() != NULL) + if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible()) { if (docked) { @@ -97,13 +104,17 @@ void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) { mDockControl.get()->off(); } - } if (!docked && pop_on_undock) { // visually pop up a little bit to emphasize the undocking translate(0, UNDOCK_LEAP_HEIGHT); } + } + else + { + docked = false; + } LLFloater::setDocked(docked, pop_on_undock); } @@ -113,15 +124,20 @@ void LLDockableFloater::draw() if (mDockControl.get() != NULL) { mDockControl.get()->repositionDockable(); + if (isDocked()) + { mDockControl.get()->drawToungue(); } + } LLFloater::draw(); } void LLDockableFloater::setDockControl(LLDockControl* dockControl) { mDockControl.reset(dockControl); + setDocked(mDockControl.get() != NULL && mDockControl.get()->isDockVisible()); } + const LLUIImagePtr& LLDockableFloater::getDockTongue() { return mDockTongue; diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 1d0e89cef5..ed90567ad3 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -46,12 +46,26 @@ class LLDockableFloater : public LLFloater static const U32 UNDOCK_LEAP_HEIGHT = 12; public: LOG_CLASS(LLDockableFloater); - LLDockableFloater(LLDockControl* dockControl, const LLSD& key, const Params& params = getDefaultParams()); + LLDockableFloater(LLDockControl* dockControl, const LLSD& key, + const Params& params = getDefaultParams()); + LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, + const LLSD& key, const Params& params = getDefaultParams()); virtual ~LLDockableFloater(); + static LLHandle<LLFloater> getInstanceHandle() { return sInstanceHandle; } + + /** + * If descendant class overrides postBuild() in order to perform specific + * construction then it must still invoke its superclass' implementation. + */ /* virtula */BOOL postBuild(); /* virtual */void setDocked(bool docked, bool pop_on_undock = true); /* virtual */void draw(); + + /** + * If descendant class overrides setVisible() then it must still invoke its + * superclass' implementation. + */ /*virtual*/ void setVisible(BOOL visible); private: @@ -69,7 +83,12 @@ protected: private: std::auto_ptr<LLDockControl> mDockControl; LLUIImagePtr mDockTongue; - static LLHandle<LLFloater> instanceHandle; + static LLHandle<LLFloater> sInstanceHandle; + /** + * Provides possibility to define that dockable floaters can be docked + * non exclusively. + */ + bool mUniqueDocking; }; #endif /* LL_DOCKABLEFLOATER_H */ diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index d666f2be56..0b16b2554c 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -35,12 +35,12 @@ #include "lldockcontrol.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, bool enabled) : - mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue( - dockTongue) + const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback) : + mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue) { mDockAt = dockAt; - if (enabled) + + if (dockableFloater->isDocked()) { on(); } @@ -49,7 +49,17 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, off(); } - if (dockWidget != NULL) { + if (!(get_rect_callback)) + { + mGetRectCallback = boost::bind(&LLDockControl::getEnabledRect, this, _1); + } + else + { + mGetRectCallback = get_rect_callback; + } + + if (dockWidget != NULL) + { repositionDockable(); } } @@ -67,24 +77,80 @@ void LLDockControl::setDock(LLView* dockWidget) } } +void LLDockControl::getEnabledRect(LLRect& rect) +{ + rect = mDockableFloater->getRootView()->getRect(); +} + void LLDockControl::repositionDockable() { - if (mEnabled) + LLRect dockRect = mDockWidget->calcScreenRect(); + LLRect rootRect; + mGetRectCallback(rootRect); + static BOOL prev_visibility = !mDockWidget->getVisible(); + + // recalculate dockable position if dock position changed, dock visibility changed, + // root view rect changed or recalculation is forced + if (mEnabled && (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible() + || mRootRect != rootRect || mRecalculateDocablePosition)) { - calculateDockablePosition(); + // undock dockable and off() if dock not visible + if (!isDockVisible()) + { + mDockableFloater->setDocked(false); + // force off() since dockable may not have dockControll at this time + off(); + } + else + { + moveDockable(); + } + + mPrevDockRect = dockRect; + mRootRect = rootRect; + mRecalculateDocablePosition = false; + prev_visibility = mDockWidget->getVisible(); } } -void LLDockControl::calculateDockablePosition() +bool LLDockControl::isDockVisible() { + bool res = true; + + if (mDockWidget != NULL) + { + //we should check all hierarchy + res = mDockWidget->isInVisibleChain(); + if (res) + { LLRect dockRect = mDockWidget->calcScreenRect(); - LLRect rootRect = mDockableFloater->getRootView()->getRect(); - // recalculate dockable position if dock position changed - // or root view rect changed or recalculation is forced - if (mPrevDockRect != dockRect || mRootRect != rootRect - || mRecalculateDocablePosition) + switch (mDockAt) { + case TOP: + // check is dock inside parent rect + LLRect dockParentRect = + mDockWidget->getParent()->calcScreenRect(); + if (dockRect.mRight <= dockParentRect.mLeft + || dockRect.mLeft >= dockParentRect.mRight) + { + res = false; + } + break; + } + } + } + + return res; +} + +void LLDockControl::moveDockable() +{ + // calculate new dockable position + LLRect dockRect = mDockWidget->calcScreenRect(); + LLRect rootRect; + mGetRectCallback(rootRect); + LLRect dockableRect = mDockableFloater->calcScreenRect(); S32 x = 0; S32 y = 0; @@ -92,8 +158,8 @@ void LLDockControl::calculateDockablePosition() { case TOP: x = dockRect.getCenterX() - dockableRect.getWidth() / 2; - y = dockRect.mTop + mDockTongue->getHeight() - + dockableRect.getHeight(); + y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight(); + // check is dockable inside root view rect if (x < rootRect.mLeft) { x = rootRect.mLeft; @@ -102,10 +168,29 @@ void LLDockControl::calculateDockablePosition() { x = rootRect.mRight - dockableRect.getWidth(); } + + + // calculate dock tongue position + LLRect dockParentRect = + mDockWidget->getParent()->calcScreenRect(); + if (dockRect.getCenterX() < dockParentRect.mLeft) + { + mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2; + } + else if (dockRect.getCenterX() > dockParentRect.mRight) + { + mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;; + } + else + { mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; + } mDockTongueY = dockRect.mTop; + break; } + + // move dockable dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), dockableRect.getHeight()); LLRect localDocableParentRect; @@ -115,17 +200,17 @@ void LLDockControl::calculateDockablePosition() mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY); - mPrevDockRect = dockRect; - mRootRect = rootRect; - mRecalculateDocablePosition = false; - } + } void LLDockControl::on() { + if (isDockVisible()) + { mDockableFloater->setCanDrag(false); mEnabled = true; mRecalculateDocablePosition = true; + } } void LLDockControl::off() @@ -141,3 +226,4 @@ void LLDockControl::drawToungue() mDockTongue->draw(mDockTongueX, mDockTongueY); } } + diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 7d8d5c7653..219ddfd092 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -51,10 +51,12 @@ public: }; public: + // callback for a function getting a rect valid for control's position + typedef boost::function<void (LLRect& )> get_rect_callback_t; + LOG_CLASS(LLDockControl); LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, - bool enabled); + const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback = NULL); virtual ~LLDockControl(); public: @@ -63,9 +65,15 @@ public: void setDock(LLView* dockWidget); void repositionDockable(); void drawToungue(); -protected: - virtual void calculateDockablePosition(); + bool isDockVisible(); + + // gets a rect that bounds possible positions for a dockable control + void getEnabledRect(LLRect& rect); + +private: + virtual void moveDockable(); private: + get_rect_callback_t mGetRectCallback; bool mEnabled; bool mRecalculateDocablePosition; DocAt mDockAt; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 75334acb39..9fcd386c19 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "llpanel.h" +#include "lltextbox.h" #include "llflatlistview.h" @@ -41,6 +42,8 @@ static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("fl const LLSD SELECTED_EVENT = LLSD().insert("selected", true); const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); +static const std::string COMMENT_TEXTBOX = "comment_text"; + LLFlatListView::Params::Params() : item_pad("item_pad"), allow_select("allow_select"), @@ -55,7 +58,12 @@ void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = rearrangeItems(); } -bool LLFlatListView::addItem(LLPanel* item, LLSD value /* = LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/) +const LLRect& LLFlatListView::getItemsRect() const +{ + return mItemsPanel->getRect(); +} + +bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/) { if (!item) return false; if (value.isUndefined()) return false; @@ -84,11 +92,12 @@ bool LLFlatListView::addItem(LLPanel* item, LLSD value /* = LLUUID::null*/, EAdd item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); rearrangeItems(); + notifyParentItemsRectChanged(); return true; } -bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, LLSD value /*= LLUUID::null*/) +bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value /*= LLUUID::null*/) { if (!after_item) return false; if (!item_to_add) return false; @@ -111,11 +120,11 @@ bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, else { pairs_iterator_t it = mItemPairs.begin(); - ++it; - while (it != mItemPairs.end()) + for (; it != mItemPairs.end(); ++it) { if (*it == after_pair) { + // insert new elements before the element at position of passed iterator. mItemPairs.insert(++it, new_pair); mItemsPanel->addChild(item_to_add); break; @@ -128,6 +137,7 @@ bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); rearrangeItems(); + notifyParentItemsRectChanged(); return true; } @@ -153,14 +163,14 @@ bool LLFlatListView::removeItemByValue(const LLSD& value) return removeItemPair(item_pair); } -bool LLFlatListView::removeItemByUUID(LLUUID& uuid) +bool LLFlatListView::removeItemByUUID(const LLUUID& uuid) { return removeItemByValue(LLSD(uuid)); } -LLPanel* LLFlatListView::getItemByValue(LLSD& value) const +LLPanel* LLFlatListView::getItemByValue(const LLSD& value) const { - if (value.isDefined()) return NULL; + if (value.isUndefined()) return NULL; item_pair_t* pair = getItemPair(value); if (pair) return pair->first; @@ -188,7 +198,7 @@ bool LLFlatListView::selectItemByValue(const LLSD& value, bool select /*= true*/ return selectItemPair(item_pair, select); } -bool LLFlatListView::selectItemByUUID(LLUUID& uuid, bool select /* = true*/) +bool LLFlatListView::selectItemByUUID(const LLUUID& uuid, bool select /* = true*/) { return selectItemByValue(LLSD(uuid), select); } @@ -252,7 +262,7 @@ void LLFlatListView::getSelectedItems(std::vector<LLPanel*>& selected_items) con } } -void LLFlatListView::resetSelection() +void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) { if (mSelectedItemPairs.empty()) return; @@ -264,6 +274,29 @@ void LLFlatListView::resetSelection() } mSelectedItemPairs.clear(); + + if (mCommitOnSelectionChange && !no_commit_on_deselection) + { + onCommit(); + } +} + +void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) +{ + if (NULL == mNoItemsCommentTextbox) + { + LLRect comment_rect = getRect(); + comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); + comment_rect.stretch(-getBorderWidth()); + LLTextBox::Params text_p; + text_p.name(COMMENT_TEXTBOX); + text_p.border_visible(false); + text_p.rect(comment_rect); + text_p.follows.flags(FOLLOWS_ALL); + mNoItemsCommentTextbox = LLUICtrlFactory::create<LLTextBox>(text_p, this); + } + + mNoItemsCommentTextbox->setValue(comment_text); } void LLFlatListView::clear() @@ -272,11 +305,32 @@ void LLFlatListView::clear() for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) { mItemsPanel->removeChild((*it)->first); - delete (*it)->first; + (*it)->first->die(); delete *it; } mItemPairs.clear(); mSelectedItemPairs.clear(); + + // also set items panel height to zero. Reshape it to allow reshaping of non-item children + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + + setNoItemsCommentVisible(true); + notifyParentItemsRectChanged(); +} + +void LLFlatListView::sort() +{ + if (!mItemComparator) + { + llwarns << "No comparator specified for sorting FlatListView items." << llendl; + return; + } + + mItemPairs.sort(ComparatorAdaptor(*mItemComparator)); + rearrangeItems(); } @@ -286,12 +340,16 @@ void LLFlatListView::clear() LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) -: LLScrollContainer(p), - mItemsPanel(NULL), - mItemPad(p.item_pad), - mAllowSelection(p.allow_select), - mMultipleSelection(p.multi_select), - mKeepOneItemSelected(p.keep_one_selected) +: LLScrollContainer(p) + , mItemComparator(NULL) + , mItemsPanel(NULL) + , mItemPad(p.item_pad) + , mAllowSelection(p.allow_select) + , mMultipleSelection(p.multi_select) + , mKeepOneItemSelected(p.keep_one_selected) + , mCommitOnSelectionChange(false) + , mPrevNotifyParentRect(LLRect()) + , mNoItemsCommentTextbox(NULL) { mBorderThickness = getBorderWidth(); @@ -315,19 +373,32 @@ void LLFlatListView::rearrangeItems() { static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + setNoItemsCommentVisible(mItemPairs.empty()); + if (mItemPairs.empty()) return; //calculating required height - assuming items can be of different height //list should accommodate all its items S32 height = 0; + S32 invisible_children_count = 0; pairs_iterator_t it = mItemPairs.begin(); for (; it != mItemPairs.end(); ++it) { LLPanel* item = (*it)->first; + + // skip invisible child + if (!item->getVisible()) + { + ++invisible_children_count; + continue; + } + height += item->getRect().getHeight(); } - height += mItemPad * (mItemPairs.size() - 1); + + // add paddings between items, excluding invisible ones + height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); LLRect rc = mItemsPanel->getRect(); S32 width = mItemsNoScrollWidth; @@ -346,14 +417,18 @@ void LLFlatListView::rearrangeItems() for (it2 = first_it; it2 != mItemPairs.end(); ++it2) { LLPanel* item = (*it2)->first; + + // skip invisible child + if (!item->getVisible()) + continue; + LLRect rc = item->getRect(); - if(it2 != first_it) - { - item_new_top -= (rc.getHeight() + mItemPad); - } rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); item->reshape(rc.getWidth(), rc.getHeight()); item->setRect(rc); + + // move top for next item in list + item_new_top -= (rc.getHeight() + mItemPad); } } @@ -443,6 +518,12 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) //a way of notifying panel of selection state changes LLPanel* item = item_pair->first; item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); + + if (mCommitOnSelectionChange) + { + onCommit(); + } + return true; } @@ -483,12 +564,82 @@ bool LLFlatListView::removeItemPair(item_pair_t* item_pair) } mItemsPanel->removeChild(item_pair->first); - delete item_pair->first; + item_pair->first->die(); delete item_pair; rearrangeItems(); + notifyParentItemsRectChanged(); return true; } +void LLFlatListView::notifyParentItemsRectChanged() +{ + S32 comment_height = 0; + + // take into account comment text height if exists + if (mNoItemsCommentTextbox && mNoItemsCommentTextbox->getVisible()) + { + comment_height = mNoItemsCommentTextbox->getTextPixelHeight(); + } + + LLRect req_rect = getItemsRect(); + + // get maximum of items total height and comment text height + req_rect.setOriginAndSize(req_rect.mLeft, req_rect.mBottom, req_rect.getWidth(), llmax(req_rect.getHeight(), comment_height)); + + // take into account border size. + req_rect.stretch(getBorderWidth()); + + if (req_rect == mPrevNotifyParentRect) + return; + + mPrevNotifyParentRect = req_rect; + + LLSD params; + params["action"] = "size_changes"; + params["width"] = req_rect.getWidth(); + params["height"] = req_rect.getHeight(); + + getParent()->notifyParent(params); +} + +void LLFlatListView::setNoItemsCommentVisible(bool visible) const +{ + if (mNoItemsCommentTextbox) + { + if (visible) + { + // We have to update child rect here because of issues with rect after reshaping while creating LLTextbox + // It is possible to have invalid LLRect if Flat List is in LLAccordionTab + LLRect comment_rect = getLocalRect(); + comment_rect.stretch(-getBorderWidth()); + mNoItemsCommentTextbox->setRect(comment_rect); + } + mNoItemsCommentTextbox->setVisible(visible); + } +} + +void LLFlatListView::getItems(std::vector<LLPanel*>& items) const +{ + if (mItemPairs.empty()) return; + + items.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + items.push_back((*it)->first); + } +} + +void LLFlatListView::getValues(std::vector<LLSD>& values) const +{ + if (mItemPairs.empty()) return; + + values.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + values.push_back((*it)->second); + } +} +//EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index bd0b419f4f..af5a9cfa9b 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -33,10 +33,10 @@ #ifndef LL_LLFLATLISTVIEW_H #define LL_LLFLATLISTVIEW_H +#include "llpanel.h" #include "llscrollcontainer.h" - -class LLPanel; +class LLTextBox; /** * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's. @@ -62,6 +62,38 @@ class LLFlatListView : public LLScrollContainer { public: + /** + * Abstract comparator for comparing flat list items in a form of LLPanel + */ + class ItemComparator + { + public: + ItemComparator() {}; + virtual ~ItemComparator() {}; + + /** Returns true if item1 < item2, false otherwise */ + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0; + }; + + /** + * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed + */ + class ItemReverseComparator : public ItemComparator + { + public: + ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {}; + virtual ~ItemReverseComparator() {}; + + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const + { + return mComparator.compare(item2, item1); + } + + private: + const ItemComparator& mComparator; + }; + + struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params> { /** turning on/off selection support */ @@ -85,18 +117,23 @@ public: /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /** Returns full rect of child panel */ + const LLRect& getItemsRect() const; + + /** Returns distance between items */ + const S32 getItemsPad() { return mItemPad; } /** * Adds and item and LLSD value associated with it to the list at specified position * @return true if the item was added, false otherwise */ - virtual bool addItem(LLPanel* item, LLSD value = LLUUID::null, EAddPosition pos = ADD_BOTTOM); + virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM); /** * Insert item_to_add along with associated value to the list right after the after_item. * @return true if the item was successfully added, false otherwise */ - virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, LLSD value = LLUUID::null); + virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null); /** * Remove specified item @@ -114,13 +151,19 @@ public: * Remove an item specified by uuid * @return true if the item was removed, false otherwise */ - virtual bool removeItemByUUID(LLUUID& uuid); + virtual bool removeItemByUUID(const LLUUID& uuid); /** * Get an item by value * @return the item as LLPanel if associated with value, NULL otherwise */ - virtual LLPanel* getItemByValue(LLSD& value) const; + virtual LLPanel* getItemByValue(const LLSD& value) const; + + template<class T> + T* getTypedItemByValue(const LLSD& value) const + { + return dynamic_cast<T*>(getItemByValue(value)); + } /** * Select or deselect specified item based on select @@ -138,9 +181,17 @@ public: * Select or deselect an item by associated uuid based on select * @return true if succeed, false otherwise */ - virtual bool selectItemByUUID(LLUUID& uuid, bool select = true); + virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true); + /** + * Get all panels stored in the list. + */ + virtual void getItems(std::vector<LLPanel*>& items) const; + /** + * Get all items values. + */ + virtual void getValues(std::vector<LLSD>& values) const; /** * Get LLSD associated with the first selected item @@ -176,9 +227,23 @@ public: virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const; - /** Resets selection of items */ - virtual void resetSelection(); + /** + * Resets selection of items. + * + * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true" + * argument for current Flat List. + * @param no_commit_on_deselection - if true onCommit callback will not be called + */ + virtual void resetSelection(bool no_commit_on_deselection = false); + /** + * Sets comment text which will be shown in the list is it is empty. + * + * Textbox to hold passed text is created while this method is called at the first time. + * + * @param comment_text - string to be shown as a comment. + */ + void setNoItemsCommentText( const std::string& comment_text); /** Turn on/off multiple selection support */ void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } @@ -186,6 +251,8 @@ public: /** Turn on/off selection support */ void setAllowSelection(bool can_select) { mAllowSelection = can_select; } + /** Sets flag whether onCommit should be fired if selection was changed */ + void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } /** Get number of selected items in the list */ U32 numSelected() const {return mSelectedItemPairs.size(); } @@ -197,6 +264,14 @@ public: /** Removes all items from the list */ virtual void clear(); + /** + * Set comparator to use for future sorts. + * + * This class does NOT manage lifetime of the comparator + * but assumes that the comparator is always alive. + */ + void setComparator(const ItemComparator* comp) { mItemComparator = comp; } + void sort(); protected: @@ -207,6 +282,19 @@ protected: typedef pairs_list_t::iterator pairs_iterator_t; typedef pairs_list_t::const_iterator pairs_const_iterator_t; + /** An adapter for a ItemComparator */ + struct ComparatorAdaptor + { + ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {}; + + bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) + { + return mComparator.compare(item_pair1->first, item_pair2->first); + } + + const ItemComparator& mComparator; + }; + friend class LLUICtrlFactory; LLFlatListView(const LLFlatListView::Params& p); @@ -214,7 +302,10 @@ protected: /** Manage selection on mouse events */ void onItemMouseClick(item_pair_t* item_pair, MASK mask); - /** Updates position of items */ + /** + * Updates position of items. + * It does not take into account invisible items. + */ virtual void rearrangeItems(); virtual item_pair_t* getItemPair(LLPanel* item) const; @@ -227,14 +318,27 @@ protected: virtual bool removeItemPair(item_pair_t* item_pair); + /** + * Notify parent about changed size of internal controls with "size_changes" action + * + * Size includes Items Rect width and either Items Rect height or comment text height. + * Comment text height is included if comment text is set and visible. + * List border size is also included into notified size. + */ + void notifyParentItemsRectChanged(); + private: void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} + void setNoItemsCommentVisible(bool visible) const; private: + /** Comparator to use when sorting the list. */ + const ItemComparator* mItemComparator; + LLPanel* mItemsPanel; S32 mItemsNoScrollWidth; @@ -242,7 +346,7 @@ private: S32 mBorderThickness; /** Items padding */ - U32 mItemPad; + S32 mItemPad; /** Selection support flag */ bool mAllowSelection; @@ -250,6 +354,14 @@ private: /** Multiselection support flag, ignored if selection is not supported */ bool mMultipleSelection; + /** + * Flag specified whether onCommit be called if selection is changed in the list. + * + * Can be ignored in the resetSelection() method. + * @see resetSelection() + */ + bool mCommitOnSelectionChange; + bool mKeepOneItemSelected; /** All pairs of the list */ @@ -257,6 +369,14 @@ private: /** Selected pairs for faster access */ pairs_list_t mSelectedItemPairs; + + /** + * Rectangle contained previous size of items parent notified last time. + * Is used to reduce amount of parentNotify() calls if size was not changed. + */ + LLRect mPrevNotifyParentRect; + + LLTextBox* mNoItemsCommentTextbox; }; #endif diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 60ddbc6cb3..ab9b59e252 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -216,6 +216,10 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL { mCachedKeyboardFocusList.pop_front(); old_focus_view->onFocusLost(); + + // part of fix of EXT-996 + // this need to handle event when user click inside in-world area + mFocusChangeSignal(); } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index d0adadd6d3..2c2dae216a 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -124,6 +124,11 @@ public: void unlockFocus(); BOOL focusLocked() const { return mLockedView != NULL; } + void addFocusChangeCallback(const boost::signals2::signal<void ()>::slot_type& cb) + { + mFocusChangeSignal.connect(cb); + } + private: LLUICtrl* mLockedView; @@ -150,6 +155,8 @@ private: typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t; focus_history_map_t mFocusHistory; + boost::signals2::signal<void()> mFocusChangeSignal; + #ifdef _DEBUG std::string mMouseCaptorName; std::string mKeyboardFocusName; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 9845b7e2ce..25e2475f59 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1443,8 +1443,8 @@ void LLNotifications::cancel(LLNotificationPtr pNotif) { llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; } - updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif); pNotif->cancel(); + updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif); } void LLNotifications::update(const LLNotificationPtr pNotif) diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index 172c4a9c65..ed150ac50c 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -66,7 +66,9 @@ LLScrollbar::Params::Params() up_button("up_button"), down_button("down_button"), left_button("left_button"), - right_button("right_button") + right_button("right_button"), + bg_visible("bg_visible", false), + bg_color("bg_color", LLColor4::black) { tab_stop = false; } @@ -92,7 +94,9 @@ LLScrollbar::LLScrollbar(const Params & p) mThumbImageH(p.thumb_image_horizontal), mTrackImageV(p.track_image_vertical), mTrackImageH(p.track_image_horizontal), - mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize")) + mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize")), + mBGVisible(p.bg_visible), + mBGColor(p.bg_color) { updateThumbRect(); @@ -482,6 +486,11 @@ void LLScrollbar::draw() { if (!getRect().isValid()) return; + if(mBGVisible) + { + gl_rect_2d(getLocalRect(), mBGColor.get(), TRUE); + } + S32 local_mouse_x; S32 local_mouse_y; LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 30d906e04c..7e72331a3f 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -66,8 +66,11 @@ public: track_image_horizontal, track_image_vertical; + Optional<bool> bg_visible; + Optional<LLUIColor> track_color, - thumb_color; + thumb_color, + bg_color; Optional<LLButton::Params> up_button; Optional<LLButton::Params> down_button; @@ -127,6 +130,12 @@ public: void onLineUpBtnPressed(const LLSD& data); void onLineDownBtnPressed(const LLSD& data); + void setBGColor(const LLUIColor& color) { mBGColor = color; } + const LLUIColor& getBGColor() const { return mBGColor; } + + void setBGVisible() { mBGVisible = true; } + bool getBGVisible() const { return mBGVisible; } + private: void updateThumbRect(); void changeLine(S32 delta, BOOL update_thumb ); @@ -151,6 +160,9 @@ private: LLUIColor mTrackColor; LLUIColor mThumbColor; + LLUIColor mBGColor; + + bool mBGVisible; LLUIImagePtr mThumbImageV; LLUIImagePtr mThumbImageH; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 30a042cff1..cd5926fb6b 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -67,12 +67,10 @@ static LLDefaultChildRegistry::Register<LLScrollContainer> r("scroll_container") #include "llscrollingpanellist.h" #include "llcontainerview.h" #include "llpanel.h" -#include "lllistctrl.h" static ScrollContainerRegistry::Register<LLScrollingPanelList> r1("scrolling_panel_list"); static ScrollContainerRegistry::Register<LLContainerView> r2("container_view"); static ScrollContainerRegistry::Register<LLPanel> r3("panel", &LLPanel::fromXML); -static ScrollContainerRegistry::Register<LLListCtrl> r4("list"); LLScrollContainer::Params::Params() : is_opaque("opaque"), diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 483106e857..54e42bf642 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -139,7 +139,9 @@ LLScrollListCtrl::Params::Params() bg_stripe_color("bg_stripe_color"), hovered_color("hovered_color"), highlighted_color("highlighted_color"), - contents("") + contents(""), + scroll_bar_bg_visible("scroll_bar_bg_visible"), + scroll_bar_bg_color("scroll_bar_bg_color") { name = "scroll_list"; mouse_opaque = true; @@ -220,6 +222,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); sbparams.visible(false); + sbparams.bg_visible(p.scroll_bar_bg_visible); + sbparams.bg_color(p.scroll_bar_bg_color); mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); addChild(mScrollbar); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 49a49499ef..83b2f71037 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -83,7 +83,8 @@ public: Optional<bool> has_border, draw_heading, draw_stripes, - background_visible; + background_visible, + scroll_bar_bg_visible; // layout Optional<S32> column_padding, @@ -104,7 +105,8 @@ public: bg_readonly_color, bg_stripe_color, hovered_color, - highlighted_color; + highlighted_color, + scroll_bar_bg_color; Optional<Contents> contents; diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index 291d1dc517..0517325e70 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -109,6 +109,7 @@ public: void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button const LLFontGL* getFont() const { return mDefaultFont; } + void setFont(const LLFontGL* font) { mDefaultFont = font; } void reshapeToFitText(); |