summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/lldockablefloater.cpp48
-rw-r--r--indra/llui/lldockablefloater.h23
-rw-r--r--indra/llui/lldockcontrol.cpp124
-rw-r--r--indra/llui/lldockcontrol.h16
-rw-r--r--indra/llui/llflatlistview.cpp195
-rw-r--r--indra/llui/llflatlistview.h142
-rw-r--r--indra/llui/llfocusmgr.cpp4
-rw-r--r--indra/llui/llfocusmgr.h7
-rw-r--r--indra/llui/llnotifications.cpp2
-rw-r--r--indra/llui/llscrollbar.cpp13
-rw-r--r--indra/llui/llscrollbar.h14
-rw-r--r--indra/llui/llscrollcontainer.cpp2
-rw-r--r--indra/llui/llscrolllistctrl.cpp6
-rw-r--r--indra/llui/llscrolllistctrl.h6
-rw-r--r--indra/llui/lltextbox.h1
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();