diff options
author | Steven Bennetts <steve@lindenlab.com> | 2009-09-11 23:50:59 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2009-09-11 23:50:59 +0000 |
commit | 7df79382a075646a51f21bed0d7f8de883fc3608 (patch) | |
tree | e7a71ed0dc7e05e4091066e3a0455343dfcfce4f /indra/llui | |
parent | 56449313529145a3d3c0e231967d9502b549056c (diff) |
merge https://svn.aws.productengine.com/secondlife/export-from-ll/viewer-2-0@1634 https://svn.aws.productengine.com/secondlife/pe/stable-2@1648 -> viewer-2.0.0-3
* Bugs: EXT-888 EXT-866 EXT-861 EXT-858 EXT-864 EXT-875 EXT-884 EXT-718 EXT-786 EXT-885 EXT-910 EXT-845 EXT-312 EXT-823 EXT-868
* New Development: EXT-748 EXT-863 EXT-835
QA: Please test Recent List to verify it has no troubles.
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llui/lldockcontrol.cpp | 13 | ||||
-rw-r--r-- | indra/llui/lldockcontrol.h | 3 | ||||
-rw-r--r-- | indra/llui/llfiltereditor.cpp | 74 | ||||
-rw-r--r-- | indra/llui/llfiltereditor.h | 30 | ||||
-rw-r--r-- | indra/llui/llflatlistview.cpp | 494 | ||||
-rw-r--r-- | indra/llui/llflatlistview.h | 262 | ||||
-rw-r--r-- | indra/llui/llsearcheditor.cpp | 82 | ||||
-rw-r--r-- | indra/llui/llsearcheditor.h | 24 | ||||
-rw-r--r-- | indra/llui/lltabcontainer.cpp | 9 | ||||
-rw-r--r-- | indra/llui/llview.h | 2 |
11 files changed, 871 insertions, 124 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index cc9362a252..fce6b759a4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -40,6 +40,7 @@ set(llui_SOURCE_FILES lleditmenuhandler.cpp llf32uictrl.cpp llfiltereditor.cpp + llflatlistview.cpp llfloater.cpp llfloaterreg.cpp llflyoutbutton.cpp @@ -122,6 +123,7 @@ set(llui_HEADER_FILES lleditmenuhandler.h llf32uictrl.h llfiltereditor.h + llflatlistview.h llfloater.h llfloaterreg.h llflyoutbutton.h diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index e119d387ce..d666f2be56 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -48,12 +48,25 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, { off(); } + + if (dockWidget != NULL) { + repositionDockable(); + } } LLDockControl::~LLDockControl() { } +void LLDockControl::setDock(LLView* dockWidget) +{ + mDockWidget = dockWidget; + if (mDockWidget != NULL) + { + repositionDockable(); + } +} + void LLDockControl::repositionDockable() { if (mEnabled) diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index ae4e53ddc9..7d8d5c7653 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -60,8 +60,7 @@ public: public: void on(); void off(); - void setDock(LLView* dockWidget) - { mDockWidget = dockWidget;}; + void setDock(LLView* dockWidget); void repositionDockable(); void drawToungue(); protected: diff --git a/indra/llui/llfiltereditor.cpp b/indra/llui/llfiltereditor.cpp index 26b5f2e182..390504234d 100644 --- a/indra/llui/llfiltereditor.cpp +++ b/indra/llui/llfiltereditor.cpp @@ -37,81 +37,15 @@ #include "llfiltereditor.h" LLFilterEditor::LLFilterEditor(const LLFilterEditor::Params& p) -: LLUICtrl(p) +: LLSearchEditor(p) { - LLLineEditor::Params line_editor_p(p); - line_editor_p.name("filter edit box"); - line_editor_p.rect(getLocalRect()); - line_editor_p.follows.flags(FOLLOWS_ALL); - line_editor_p.text_pad_right(getRect().getHeight()); - line_editor_p.revert_on_esc(false); - line_editor_p.keystroke_callback(boost::bind(&LLUICtrl::onCommit, this)); - - mFilterEditor = LLUICtrlFactory::create<LLLineEditor>(line_editor_p); - addChild(mFilterEditor); - - S32 btn_width = getRect().getHeight(); // button is square, and as tall as search editor - LLRect clear_btn_rect(getRect().getWidth() - btn_width, getRect().getHeight(), getRect().getWidth(), 0); - LLButton::Params button_params(p.clear_filter_button); - button_params.name(std::string("clear filter")); - button_params.rect(clear_btn_rect) ; - button_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); - button_params.tab_stop(false); - button_params.click_callback.function(boost::bind(&LLFilterEditor::onClearFilter, this, _2)); - - mClearFilterButton = LLUICtrlFactory::create<LLButton>(button_params); - mFilterEditor->addChild(mClearFilterButton); -} - -//virtual -void LLFilterEditor::setValue(const LLSD& value ) -{ - mFilterEditor->setValue(value); -} - -//virtual -LLSD LLFilterEditor::getValue() const -{ - return mFilterEditor->getValue(); -} - -//virtual -BOOL LLFilterEditor::setTextArg( const std::string& key, const LLStringExplicit& text ) -{ - return mFilterEditor->setTextArg(key, text); } -//virtual -BOOL LLFilterEditor::setLabelArg( const std::string& key, const LLStringExplicit& text ) -{ - return mFilterEditor->setLabelArg(key, text); -} - -//virtual -void LLFilterEditor::setLabel( const LLStringExplicit &new_label ) -{ - mFilterEditor->setLabel(new_label); -} - -//virtual -void LLFilterEditor::clear() -{ - if (mFilterEditor) - { - mFilterEditor->clear(); - } -} -void LLFilterEditor::draw() +void LLFilterEditor::handleKeystroke() { - mClearFilterButton->setVisible(!mFilterEditor->getWText().empty()); - - LLUICtrl::draw(); -} + this->LLSearchEditor::handleKeystroke(); -void LLFilterEditor::onClearFilter(const LLSD& data) -{ - setText(LLStringUtil::null); + // Commit on every keystroke. onCommit(); } - diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index fceb82af8d..c43a76b130 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -42,18 +42,14 @@ #ifndef LL_FILTEREDITOR_H #define LL_FILTEREDITOR_H -#include "lllineeditor.h" -#include "llbutton.h" +#include "llsearcheditor.h" -class LLFilterEditor : public LLUICtrl +class LLFilterEditor : public LLSearchEditor { public: - struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> + struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params> { - Optional<LLButton::Params> clear_filter_button; - Params() - : clear_filter_button("clear_filter_button") { name = "filter_editor"; } @@ -62,26 +58,8 @@ public: protected: LLFilterEditor(const Params&); friend class LLUICtrlFactory; -public: - virtual ~LLFilterEditor() {} - - /*virtual*/ void draw(); - - void setText(const LLStringExplicit &new_text) { mFilterEditor->setText(new_text); } - - // LLUICtrl interface - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - virtual void setLabel( const LLStringExplicit &new_label ); - virtual void clear(); - -private: - void onClearFilter(const LLSD& data); - LLLineEditor* mFilterEditor; - LLButton* mClearFilterButton; + /*virtual*/ void handleKeystroke(); }; #endif // LL_FILTEREDITOR_H diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp new file mode 100644 index 0000000000..75334acb39 --- /dev/null +++ b/indra/llui/llflatlistview.cpp @@ -0,0 +1,494 @@ +/** + * @file llflatlistview.cpp + * @brief LLFlatListView base class + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpanel.h" + +#include "llflatlistview.h" + +static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("flat_list_view"); + +const LLSD SELECTED_EVENT = LLSD().insert("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); + +LLFlatListView::Params::Params() +: item_pad("item_pad"), + allow_select("allow_select"), + multi_select("multi_select"), + keep_one_selected("keep_one_selected") +{}; + +void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + LLScrollContainer::reshape(width, height, called_from_parent); + setItemsNoScrollWidth(width); + rearrangeItems(); +} + +bool LLFlatListView::addItem(LLPanel* item, LLSD value /* = LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/) +{ + if (!item) return false; + if (value.isUndefined()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item->getParent() == mItemsPanel) return false; + + item_pair_t* new_pair = new item_pair_t(item, value); + switch (pos) + { + case ADD_TOP: + mItemPairs.push_front(new_pair); + //in LLView::draw() children are iterated in backorder + mItemsPanel->addChildInBack(item); + break; + case ADD_BOTTOM: + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item); + break; + default: + break; + } + + //_4 is for MASK + item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + + rearrangeItems(); + return true; +} + + +bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, LLSD value /*= LLUUID::null*/) +{ + if (!after_item) return false; + if (!item_to_add) return false; + if (value.isUndefined()) return false; + + if (mItemPairs.empty()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item_to_add->getParent() == mItemsPanel) return false; + + item_pair_t* after_pair = getItemPair(after_item); + if (!after_pair) return false; + + item_pair_t* new_pair = new item_pair_t(item_to_add, value); + if (after_pair == mItemPairs.back()) + { + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item_to_add); + } + else + { + pairs_iterator_t it = mItemPairs.begin(); + ++it; + while (it != mItemPairs.end()) + { + if (*it == after_pair) + { + mItemPairs.insert(++it, new_pair); + mItemsPanel->addChild(item_to_add); + break; + } + } + } + + //_4 is for MASK + item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + + rearrangeItems(); + return true; +} + + +bool LLFlatListView::removeItem(LLPanel* item) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return removeItemPair(item_pair); +} + +bool LLFlatListView::removeItemByValue(const LLSD& value) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return removeItemPair(item_pair); +} + +bool LLFlatListView::removeItemByUUID(LLUUID& uuid) +{ + return removeItemByValue(LLSD(uuid)); +} + +LLPanel* LLFlatListView::getItemByValue(LLSD& value) const +{ + if (value.isDefined()) return NULL; + + item_pair_t* pair = getItemPair(value); + if (pair) return pair->first; + return NULL; +} + +bool LLFlatListView::selectItem(LLPanel* item, bool select /*= true*/) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByValue(const LLSD& value, bool select /*= true*/) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByUUID(LLUUID& uuid, bool select /* = true*/) +{ + return selectItemByValue(LLSD(uuid), select); +} + + +LLSD LLFlatListView::getSelectedValue() const +{ + if (mSelectedItemPairs.empty()) return LLSD(); + + item_pair_t* first_selected_pair = mSelectedItemPairs.front(); + return first_selected_pair->second; +} + +void LLFlatListView::getSelectedValues(std::vector<LLSD>& selected_values) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_values.push_back((*it)->second); + } +} + +LLUUID LLFlatListView::getSelectedUUID() const +{ + const LLSD& value = getSelectedValue(); + if (value.isDefined() && value.isUUID()) + { + return value.asUUID(); + } + else + { + return LLUUID::null; + } +} + +void LLFlatListView::getSelectedUUIDs(std::vector<LLUUID>& selected_uuids) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_uuids.push_back((*it)->second.asUUID()); + } +} + +LLPanel* LLFlatListView::getSelectedItem() const +{ + if (mSelectedItemPairs.empty()) return NULL; + + return mSelectedItemPairs.front()->first; +} + +void LLFlatListView::getSelectedItems(std::vector<LLPanel*>& selected_items) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_items.push_back((*it)->first); + } +} + +void LLFlatListView::resetSelection() +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* pair_to_deselect = *it; + LLPanel* item = pair_to_deselect->first; + item->setValue(UNSELECTED_EVENT); + } + + mSelectedItemPairs.clear(); +} + +void LLFlatListView::clear() +{ + // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + mItemsPanel->removeChild((*it)->first); + delete (*it)->first; + delete *it; + } + mItemPairs.clear(); + mSelectedItemPairs.clear(); +} + + +////////////////////////////////////////////////////////////////////////// +// PROTECTED STUFF +////////////////////////////////////////////////////////////////////////// + + +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) +{ + mBorderThickness = getBorderWidth(); + + LLRect scroll_rect = getRect(); + LLRect items_rect; + + setItemsNoScrollWidth(scroll_rect.getWidth()); + items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); + + LLPanel::Params pp; + pp.rect(items_rect); + mItemsPanel = LLUICtrlFactory::create<LLPanel> (pp); + addChild(mItemsPanel); + + //we don't need to stretch in vertical direction on reshaping by a parent + //no bottom following! + mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); +}; + +void LLFlatListView::rearrangeItems() +{ + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + if (mItemPairs.empty()) return; + + //calculating required height - assuming items can be of different height + //list should accommodate all its items + S32 height = 0; + + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + LLPanel* item = (*it)->first; + height += item->getRect().getHeight(); + } + height += mItemPad * (mItemPairs.size() - 1); + + LLRect rc = mItemsPanel->getRect(); + S32 width = mItemsNoScrollWidth; + + // update width to avoid horizontal scrollbar + if (height > getRect().getHeight() - 2 * mBorderThickness) + width -= scrollbar_size; + + //changes the bottom, end of the list goes down in the scroll container + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); + mItemsPanel->setRect(rc); + + //reshaping items + S32 item_new_top = height; + pairs_iterator_t it2, first_it = mItemPairs.begin(); + for (it2 = first_it; it2 != mItemPairs.end(); ++it2) + { + LLPanel* item = (*it2)->first; + 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); + } +} + +void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) +{ + if (!item_pair) return; + + bool select_item = !isSelected(item_pair); + + //*TODO find a better place for that enforcing stuff + if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; + + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(); + selectItemPair(item_pair, select_item); +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const +{ + llassert(item); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (item_pair->first == item) return item_pair; + } + return NULL; +} + +//compares two LLSD's +bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2) +{ + llassert(llsd_1.isDefined()); + llassert(llsd_2.isDefined()); + + if (llsd_1.type() != llsd_2.type()) return false; + + if (!llsd_1.isMap()) + { + if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); + + //assumptions that string representaion is enough for other types + return llsd_1.asString() == llsd_2.asString(); + } + + if (llsd_1.size() != llsd_2.size()) return false; + + LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); + LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); + for (S32 i = 0; i < llsd_1.size(); ++i) + { + if ((*llsd_1_it).first != (*llsd_2_it).first) return false; + if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; + ++llsd_1_it; + ++llsd_2_it; + } + return true; +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(const LLSD& value) const +{ + llassert(value.isDefined()); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (llsds_are_equal(item_pair->second, value)) return item_pair; + } + return NULL; +} + +bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) +{ + llassert(item_pair); + + if (!mAllowSelection && select) return false; + + if (isSelected(item_pair) == select) return true; //already in specified selection state + if (select) + { + mSelectedItemPairs.push_back(item_pair); + } + else + { + mSelectedItemPairs.remove(item_pair); + } + + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); + return true; +} + +bool LLFlatListView::isSelected(item_pair_t* item_pair) const +{ + llassert(item_pair); + + pairs_const_iterator_t it_end = mSelectedItemPairs.end(); + return std::find(mSelectedItemPairs.begin(), it_end, item_pair) != it_end; +} + +bool LLFlatListView::removeItemPair(item_pair_t* item_pair) +{ + llassert(item_pair); + + bool deleted = false; + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* _item_pair = *it; + if (_item_pair == item_pair) + { + mItemPairs.erase(it); + deleted = true; + break; + } + } + + if (!deleted) return false; + + for (pairs_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* selected_item_pair = *it; + if (selected_item_pair == item_pair) + { + it = mSelectedItemPairs.erase(it); + break; + } + } + + mItemsPanel->removeChild(item_pair->first); + delete item_pair->first; + delete item_pair; + + rearrangeItems(); + + return true; +} + + diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h new file mode 100644 index 0000000000..bd0b419f4f --- /dev/null +++ b/indra/llui/llflatlistview.h @@ -0,0 +1,262 @@ +/** + * @file llflatlistview.h + * @brief LLFlatListView base class + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLATLISTVIEW_H +#define LL_LLFLATLISTVIEW_H + +#include "llscrollcontainer.h" + + +class LLPanel; + +/** + * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's. + * LLSD can be associated with each added item, it can keep data from an item in digested form. + * Associated LLSD's can be of any type (singular, a map etc.). + * Items (LLPanel's subclasses) can be of different height. + * The list is LLPanel created in itself and grows in height while new items are added. + * + * The control can manage selection of its items when the flag "allow_select" is set. Also ability to select + * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag + * is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items) + * since any item of the list was selected. + * + * Examples of using this control are presented in Picks panel (Me Profile and Profile View), where this control is used to + * manage the list of pick items. + * + * ASSUMPTIONS AND STUFF + * - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise + * - Order of returned selected items are not guaranteed + * - The control assumes that all items being added are unique. + */ +class LLFlatListView : public LLScrollContainer +{ +public: + + struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params> + { + /** turning on/off selection support */ + Optional<bool> allow_select; + + /** turning on/off multiple selection (works while clicking and holding CTRL)*/ + Optional<bool> multi_select; + + /** don't allow to deselect all selected items (for mouse events on items only) */ + Optional<bool> keep_one_selected; + + /** padding between items */ + Optional<U32> item_pad; + + Params(); + }; + + virtual ~LLFlatListView() { clear(); }; + + + /** 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); + + + /** + * 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); + + /** + * 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); + + /** + * Remove specified item + * @return true if the item was removed, false otherwise + */ + virtual bool removeItem(LLPanel* item); + + /** + * Remove an item specified by value + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByValue(const LLSD& value); + + /** + * Remove an item specified by uuid + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByUUID(LLUUID& uuid); + + /** + * Get an item by value + * @return the item as LLPanel if associated with value, NULL otherwise + */ + virtual LLPanel* getItemByValue(LLSD& value) const; + + /** + * Select or deselect specified item based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItem(LLPanel* item, bool select = true); + + /** + * Select or deselect an item by associated value based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByValue(const LLSD& value, bool select = true); + + /** + * 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); + + + + /** + * Get LLSD associated with the first selected item + */ + virtual LLSD getSelectedValue() const; + + /** + * Get LLSD's associated with selected items. + * @param selected_values std::vector being populated with LLSD associated with selected items + */ + virtual void getSelectedValues(std::vector<LLSD>& selected_values) const; + + + /** + * Get LLUUID associated with selected item + * @return LLUUID if such was associated with selected item + */ + virtual LLUUID getSelectedUUID() const; + + /** + * Get LLUUIDs associated with selected items + * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items + */ + virtual void getSelectedUUIDs(std::vector<LLUUID>& selected_uuids) const; + + /** Get the top selected item */ + virtual LLPanel* getSelectedItem() const; + + /** + * Get selected items + * @param selected_items An std::vector being populated with pointers to selected items + */ + virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const; + + + /** Resets selection of items */ + virtual void resetSelection(); + + + /** Turn on/off multiple selection support */ + void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } + + /** Turn on/off selection support */ + void setAllowSelection(bool can_select) { mAllowSelection = can_select; } + + + /** Get number of selected items in the list */ + U32 numSelected() const {return mSelectedItemPairs.size(); } + + /** Get number of items in the list */ + U32 size() const { return mItemPairs.size(); } + + + /** Removes all items from the list */ + virtual void clear(); + + +protected: + + /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ + typedef std::pair<LLPanel*, LLSD> item_pair_t; + + typedef std::list<item_pair_t*> pairs_list_t; + typedef pairs_list_t::iterator pairs_iterator_t; + typedef pairs_list_t::const_iterator pairs_const_iterator_t; + + + friend class LLUICtrlFactory; + LLFlatListView(const LLFlatListView::Params& p); + + /** Manage selection on mouse events */ + void onItemMouseClick(item_pair_t* item_pair, MASK mask); + + /** Updates position of items */ + virtual void rearrangeItems(); + + virtual item_pair_t* getItemPair(LLPanel* item) const; + + virtual item_pair_t* getItemPair(const LLSD& value) const; + + virtual bool selectItemPair(item_pair_t* item_pair, bool select); + + virtual bool isSelected(item_pair_t* item_pair) const; + + virtual bool removeItemPair(item_pair_t* item_pair); + + +private: + + void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} + + +private: + + LLPanel* mItemsPanel; + + S32 mItemsNoScrollWidth; + + S32 mBorderThickness; + + /** Items padding */ + U32 mItemPad; + + /** Selection support flag */ + bool mAllowSelection; + + /** Multiselection support flag, ignored if selection is not supported */ + bool mMultipleSelection; + + bool mKeepOneItemSelected; + + /** All pairs of the list */ + pairs_list_t mItemPairs; + + /** Selected pairs for faster access */ + pairs_list_t mSelectedItemPairs; +}; + +#endif diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index fbcbb55b85..b87f645f3f 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -38,30 +38,68 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) : LLUICtrl(p) + , mSearchButton(NULL) + , mClearButton(NULL) { - S32 btn_top = p.search_button.top_pad + p.search_button.rect.height; - S32 btn_right = p.search_button.rect.width + p.search_button.left_pad; - LLRect search_btn_rect(p.search_button.left_pad, btn_top, btn_right, p.search_button.top_pad); + S32 srch_btn_top = p.search_button.top_pad + p.search_button.rect.height; + S32 srch_btn_right = p.search_button.rect.width + p.search_button.left_pad; + LLRect srch_btn_rect(p.search_button.left_pad, srch_btn_top, srch_btn_right, p.search_button.top_pad); + S32 text_pad_left = p.text_pad_left; + if (p.search_button_visible) + text_pad_left += srch_btn_rect.getWidth(); + + // Set up line editor. LLLineEditor::Params line_editor_params(p); line_editor_params.name("filter edit box"); line_editor_params.rect(getLocalRect()); line_editor_params.follows.flags(FOLLOWS_ALL); - line_editor_params.text_pad_left(p.text_pad_left + search_btn_rect.getWidth()); + line_editor_params.text_pad_left(text_pad_left); + line_editor_params.revert_on_esc(false); line_editor_params.commit_callback.function(boost::bind(&LLUICtrl::onCommit, this)); + line_editor_params.keystroke_callback(boost::bind(&LLSearchEditor::handleKeystroke, this)); mSearchEditor = LLUICtrlFactory::create<LLLineEditor>(line_editor_params); addChild(mSearchEditor); - LLButton::Params button_params(p.search_button); - button_params.name(std::string("clear filter")); - button_params.rect(search_btn_rect) ; - button_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); - button_params.tab_stop(false); - button_params.click_callback.function(boost::bind(&LLUICtrl::onCommit, this)); + if (p.search_button_visible) + { + // Set up search button. + LLButton::Params srch_btn_params(p.search_button); + srch_btn_params.name(std::string("search button")); + srch_btn_params.rect(srch_btn_rect) ; + srch_btn_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); + srch_btn_params.tab_stop(false); + srch_btn_params.click_callback.function(boost::bind(&LLUICtrl::onCommit, this)); + + mSearchButton = LLUICtrlFactory::create<LLButton>(srch_btn_params); + mSearchEditor->addChild(mSearchButton); + } + + if (p.clear_button_visible) + { + // Set up clear button. + S32 clr_btn_width = getRect().getHeight(); // button is square, and as tall as search editor + LLRect clear_btn_rect(getRect().getWidth() - clr_btn_width, getRect().getHeight(), getRect().getWidth(), 0); + LLButton::Params clr_btn_params(p.clear_button); + clr_btn_params.name(std::string("clear button")); + clr_btn_params.rect(clear_btn_rect) ; + clr_btn_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); + clr_btn_params.tab_stop(false); + clr_btn_params.click_callback.function(boost::bind(&LLSearchEditor::onClearButtonClick, this, _2)); + + mClearButton = LLUICtrlFactory::create<LLButton>(clr_btn_params); + mSearchEditor->addChild(mClearButton); + } +} + +//virtual +void LLSearchEditor::draw() +{ + if (mClearButton) + mClearButton->setVisible(!mSearchEditor->getWText().empty()); - mSearchButton = LLUICtrlFactory::create<LLButton>(button_params); - mSearchEditor->addChild(mSearchButton); + LLUICtrl::draw(); } //virtual @@ -89,6 +127,12 @@ BOOL LLSearchEditor::setLabelArg( const std::string& key, const LLStringExplicit } //virtual +void LLSearchEditor::setLabel( const LLStringExplicit &new_label ) +{ + mSearchEditor->setLabel(new_label); +} + +//virtual void LLSearchEditor::clear() { if (mSearchEditor) @@ -96,3 +140,17 @@ void LLSearchEditor::clear() mSearchEditor->clear(); } } + +void LLSearchEditor::onClearButtonClick(const LLSD& data) +{ + setText(LLStringUtil::null); + mSearchEditor->doDelete(); // force keystroke callback +} + +void LLSearchEditor::handleKeystroke() +{ + if (mKeystrokeCallback) + { + mKeystrokeCallback(this, getValue()); + } +} diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index cd2867b493..f395e7e816 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -50,10 +50,15 @@ class LLSearchEditor : public LLUICtrl public: struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> { - Optional<LLButton::Params> search_button; + Optional<LLButton::Params> search_button, clear_button; + Optional<bool> search_button_visible, clear_button_visible; + Optional<commit_callback_t> keystroke_callback; Params() : search_button("search_button") + , search_button_visible("search_button_visible") + , clear_button("clear_button") + , clear_button_visible("clear_button_visible") { name = "search_editor"; } @@ -66,26 +71,29 @@ protected: public: virtual ~LLSearchEditor() {} + /*virtual*/ void draw(); + void setText(const LLStringExplicit &new_text) { mSearchEditor->setText(new_text); } const std::string& getText() const { return mSearchEditor->getText(); } - // LLUICtrl interface virtual void setValue(const LLSD& value ); virtual LLSD getValue() const; virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual void setLabel( const LLStringExplicit &new_label ); virtual void clear(); - void setKeystrokeCallback(LLLineEditor::callback_t callback, void* user_data) - { - if(mSearchEditor) - mSearchEditor->setKeystrokeCallback(callback,user_data); - } + void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } + +protected: + void onClearButtonClick(const LLSD& data); + virtual void handleKeystroke(); -private: + commit_callback_t mKeystrokeCallback; LLLineEditor* mSearchEditor; LLButton* mSearchButton; + LLButton* mClearButton; }; #endif // LL_SEARCHEDITOR_H diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index cabd0be522..3a13c91fac 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -429,7 +429,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) { static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -498,7 +498,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -540,7 +540,7 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -1840,12 +1840,11 @@ void LLTabContainer::updateMaxScrollPos() void LLTabContainer::commitHoveredButton(S32 x, S32 y) { - if (hasMouseCapture()) + if (!getTabsHidden() && hasMouseCapture()) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); S32 local_x = x - tuple->mButton->getRect().mLeft; S32 local_y = y - tuple->mButton->getRect().mBottom; if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) diff --git a/indra/llui/llview.h b/indra/llui/llview.h index d80c2af568..1f7e5afaae 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -633,7 +633,7 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co // did we find *something* with that name? if (child) { - llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T*).name() << llendl; + llwarns << "Found child named " << name << " but of wrong type " << typeid(*child).name() << ", expecting " << typeid(T*).name() << llendl; } result = getDefaultWidget<T>(name); if (!result) |