summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llinspecttexture.cpp14
-rw-r--r--indra/newview/llinventoryfunctions.cpp5
-rw-r--r--indra/newview/llinventoryfunctions.h9
-rw-r--r--indra/newview/llinventorygallery.cpp924
-rw-r--r--indra/newview/llinventorygallery.h233
-rw-r--r--indra/newview/llinventorypanel.cpp11
-rw-r--r--indra/newview/llinventorypanel.h5
-rw-r--r--indra/newview/llpanelmaininventory.cpp157
-rw-r--r--indra/newview/llpanelmaininventory.h18
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_view_default.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery.xml37
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml63
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml23
14 files changed, 1459 insertions, 43 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7c30d8eba8..d587f8bfc4 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -380,6 +380,7 @@ set(viewer_SOURCE_FILES
llinventorybridge.cpp
llinventoryfilter.cpp
llinventoryfunctions.cpp
+ llinventorygallery.cpp
llinventoryicon.cpp
llinventoryitemslist.cpp
llinventorylistitem.cpp
@@ -1023,6 +1024,7 @@ set(viewer_HEADER_FILES
llinventorybridge.h
llinventoryfilter.h
llinventoryfunctions.h
+ llinventorygallery.h
llinventoryicon.h
llinventoryitemslist.h
llinventorylistitem.h
diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp
index 843b4da757..82676bced8 100644
--- a/indra/newview/llinspecttexture.cpp
+++ b/indra/newview/llinspecttexture.cpp
@@ -38,20 +38,6 @@
// Helper functions
//
-class LLIsTextureType : public LLInventoryCollectFunctor
-{
-public:
- LLIsTextureType() {}
- virtual ~LLIsTextureType() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item);
-};
-
-bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
-{
- return item && (item->getType() == LLAssetType::AT_TEXTURE);
-}
-
LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)
{
const LLSD& sdTooltip = p.create_params;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index dd116ce2d2..68722e91b3 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -2352,6 +2352,11 @@ void LLFindWearablesOfType::setType(LLWearableType::EType type)
mWearableType = type;
}
+bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if (item)
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 1cc778f8a5..918e919e61 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -472,6 +472,15 @@ private:
LLWearableType::EType mWearableType;
};
+class LLIsTextureType : public LLInventoryCollectFunctor
+{
+public:
+ LLIsTextureType() {}
+ virtual ~LLIsTextureType() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
/** Filter out wearables-links */
class LLFindActualWearablesOfType : public LLFindWearablesOfType
{
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
new file mode 100644
index 0000000000..b5fd3aaece
--- /dev/null
+++ b/indra/newview/llinventorygallery.cpp
@@ -0,0 +1,924 @@
+/**
+ * @file llinventorygallery.cpp
+ * @brief LLInventoryGallery class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorygallery.h"
+
+#include "llaccordionctrltab.h"
+#include "llcommonutils.h"
+#include "lliconctrl.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llthumbnailctrl.h"
+#include "lltextbox.h"
+#include "llviewerfoldertype.h"
+
+#include "llinventoryicon.h"
+
+static LLPanelInjector<LLInventoryGallery> t_inventory_gallery("inventory_gallery");
+
+const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
+
+LLInventoryGallery::LLInventoryGallery(const LLInventoryGallery::Params& p)
+ : LLPanel(),
+ mScrollPanel(NULL),
+ mGalleryPanel(NULL),
+ mLastRowPanel(NULL),
+ mGalleryCreated(false),
+ mRowCount(0),
+ mItemsAddedCount(0),
+ mRowPanelHeight(p.row_panel_height),
+ mVerticalGap(p.vertical_gap),
+ mHorizontalGap(p.horizontal_gap),
+ mItemWidth(p.item_width),
+ mItemHeight(p.item_height),
+ mItemHorizontalGap(p.item_horizontal_gap),
+ mItemsInRow(p.items_in_row),
+ mRowPanWidthFactor(p.row_panel_width_factor),
+ mGalleryWidthFactor(p.gallery_width_factor),
+ mIsInitialized(false)
+{
+ updateGalleryWidth();
+}
+
+LLInventoryGallery::Params::Params()
+ : row_panel_height("row_panel_height", 180),
+ vertical_gap("vertical_gap", 10),
+ horizontal_gap("horizontal_gap", 10),
+ item_width("item_width", 150),
+ item_height("item_height", 175),
+ item_horizontal_gap("item_horizontal_gap", 16),
+ items_in_row("items_in_row", GALLERY_ITEMS_PER_ROW_MIN),
+ row_panel_width_factor("row_panel_width_factor", 166),
+ gallery_width_factor("gallery_width_factor", 163)
+{
+ addSynonym(row_panel_height, "row_height");
+}
+
+const LLInventoryGallery::Params& LLInventoryGallery::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLInventoryGallery>();
+}
+
+BOOL LLInventoryGallery::postBuild()
+{
+ mScrollPanel = getChild<LLScrollContainer>("gallery_scroll_panel");
+ LLPanel::Params params = LLPanel::getDefaultParams();
+ mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
+ mMessageTextBox = getChild<LLTextBox>("empty_txt");
+
+ return TRUE;
+}
+
+LLInventoryGallery::~LLInventoryGallery()
+{
+ while (!mUnusedRowPanels.empty())
+ {
+ LLPanel* panelp = mUnusedRowPanels.back();
+ mUnusedRowPanels.pop_back();
+ panelp->die();
+ }
+ while (!mUnusedItemPanels.empty())
+ {
+ LLPanel* panelp = mUnusedItemPanels.back();
+ mUnusedItemPanels.pop_back();
+ panelp->die();
+ }
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+}
+
+void LLInventoryGallery::setRootFolder(const LLUUID cat_id)
+{
+ LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
+ if(!category || (mFolderID == cat_id))
+ {
+ return;
+ }
+ if(mFolderID.notNull())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ }
+ mFolderID = cat_id;
+ updateRootFolder();
+}
+
+void LLInventoryGallery::updateRootFolder()
+{
+ if (mIsInitialized)
+ {
+ S32 count = mItemsAddedCount;
+ for (S32 i = count - 1; i >= 0; i--)
+ {
+ updateRemovedItem(mItems[i]->getUUID());
+ }
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+ }
+ {
+ mRootChangedSignal();
+
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ gInventory.addObserver(mCategoriesObserver);
+
+ // Start observing changes in selected category.
+ mCategoriesObserver->addCategory(mFolderID,
+ boost::bind(&LLInventoryGallery::refreshList, this, mFolderID));
+
+ LLViewerInventoryCategory* category = gInventory.getCategory(mFolderID);
+ //If not all items are fetched now
+ // the observer will refresh the list as soon as the new items
+ // arrive.
+ category->fetch();
+
+ //refreshList(cat_id);
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+
+ gInventory.getDirectDescendentsOf(mFolderID, cat_array, item_array);
+
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array->begin();
+ iter != cat_array->end();
+ iter++)
+ {
+ updateAddedItem((*iter)->getUUID());
+ }
+
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin();
+ iter != item_array->end();
+ iter++)
+ {
+ updateAddedItem((*iter)->getUUID());
+ }
+ reArrangeRows();
+ mIsInitialized = true;
+
+ if (mScrollPanel)
+ {
+ mScrollPanel->goToTop();
+ }
+ }
+
+ if (!mGalleryCreated)
+ {
+ initGallery();
+ }
+}
+
+void LLInventoryGallery::initGallery()
+{
+ if (!mGalleryCreated)
+ {
+ uuid_vec_t cats;
+ getCurrentCategories(cats);
+ int n = cats.size();
+ buildGalleryPanel(n);
+ mScrollPanel->addChild(mGalleryPanel);
+ for (int i = 0; i < n; i++)
+ {
+ addToGallery(mItemMap[cats[i]]);
+ }
+ reArrangeRows();
+ mGalleryCreated = true;
+ }
+}
+
+void LLInventoryGallery::draw()
+{
+ LLPanel::draw();
+ if (mGalleryCreated)
+ {
+ updateRowsIfNeeded();
+ }
+}
+
+void LLInventoryGallery::updateRowsIfNeeded()
+{
+ if(((getRect().getWidth() - mRowPanelWidth) > mItemWidth) && mRowCount > 1)
+ {
+ reArrangeRows(1);
+ }
+ else if((mRowPanelWidth > (getRect().getWidth() + mItemHorizontalGap)) && mItemsInRow > GALLERY_ITEMS_PER_ROW_MIN)
+ {
+ reArrangeRows(-1);
+ }
+}
+
+bool compareGalleryItem(LLInventoryGalleryItem* item1, LLInventoryGalleryItem* item2)
+{
+ if (item1->getSortGroup() != item2->getSortGroup())
+ {
+ return (item1->getSortGroup() < item2->getSortGroup());
+ }
+ if(((item1->isDefaultImage() && item2->isDefaultImage()) || (!item1->isDefaultImage() && !item2->isDefaultImage())))
+ {
+ std::string name1 = item1->getItemName();
+ std::string name2 = item2->getItemName();
+
+ return (LLStringUtil::compareDict(name1, name2) < 0);
+ }
+ else
+ {
+ return item2->isDefaultImage();
+ }
+}
+
+void LLInventoryGallery::reArrangeRows(S32 row_diff)
+{
+ std::vector<LLInventoryGalleryItem*> buf_items = mItems;
+ for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = buf_items.rbegin(); it != buf_items.rend(); ++it)
+ {
+ removeFromGalleryLast(*it);
+ }
+ for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = mHiddenItems.rbegin(); it != mHiddenItems.rend(); ++it)
+ {
+ buf_items.push_back(*it);
+ }
+ mHiddenItems.clear();
+
+ mItemsInRow+= row_diff;
+ updateGalleryWidth();
+ std::sort(buf_items.begin(), buf_items.end(), compareGalleryItem);
+
+ for (std::vector<LLInventoryGalleryItem*>::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it)
+ {
+ (*it)->setHidden(false);
+ applyFilter(*it, mFilterSubString);
+ addToGallery(*it);
+ }
+ updateMessageVisibility();
+}
+
+void LLInventoryGallery::updateGalleryWidth()
+{
+ mRowPanelWidth = mRowPanWidthFactor * mItemsInRow - mItemHorizontalGap;
+ mGalleryWidth = mGalleryWidthFactor * mItemsInRow - mItemHorizontalGap;
+}
+
+LLPanel* LLInventoryGallery::addLastRow()
+{
+ mRowCount++;
+ int row = 0;
+ int vgap = mVerticalGap * row;
+ LLPanel* result = buildRowPanel(0, row * mRowPanelHeight + vgap);
+ mGalleryPanel->addChild(result);
+ return result;
+}
+
+void LLInventoryGallery::moveRowUp(int row)
+{
+ moveRow(row, mRowCount - 1 - row + 1);
+}
+
+void LLInventoryGallery::moveRowDown(int row)
+{
+ moveRow(row, mRowCount - 1 - row - 1);
+}
+
+void LLInventoryGallery::moveRow(int row, int pos)
+{
+ int vgap = mVerticalGap * pos;
+ moveRowPanel(mRowPanels[row], 0, pos * mRowPanelHeight + vgap);
+}
+
+void LLInventoryGallery::removeLastRow()
+{
+ mRowCount--;
+ mGalleryPanel->removeChild(mLastRowPanel);
+ mUnusedRowPanels.push_back(mLastRowPanel);
+ mRowPanels.pop_back();
+ if (mRowPanels.size() > 0)
+ {
+ // Just removed last row
+ mLastRowPanel = mRowPanels.back();
+ }
+ else
+ {
+ mLastRowPanel = NULL;
+ }
+}
+
+LLPanel* LLInventoryGallery::addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap)
+{
+ LLPanel* lpanel = buildItemPanel(pos * mItemWidth + hgap);
+ lpanel->addChild(item);
+ row_stack->addChild(lpanel);
+ mItemPanels.push_back(lpanel);
+ return lpanel;
+}
+
+void LLInventoryGallery::addToGallery(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.push_back(item);
+ return;
+ }
+ mItemsAddedCount++;
+ mItemIndexMap[item] = mItemsAddedCount - 1;
+ int n = mItemsAddedCount;
+ int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+ int n_prev = n - 1;
+ int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+
+ bool add_row = row_count != row_count_prev;
+ int pos = 0;
+ if (add_row)
+ {
+ for (int i = 0; i < row_count_prev; i++)
+ {
+ moveRowUp(i);
+ }
+ mLastRowPanel = addLastRow();
+ mRowPanels.push_back(mLastRowPanel);
+ }
+ pos = (n - 1) % mItemsInRow;
+ mItems.push_back(item);
+ addToRow(mLastRowPanel, item, pos, mHorizontalGap * pos);
+ reshapeGalleryPanel(row_count);
+}
+
+
+void LLInventoryGallery::removeFromGalleryLast(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.pop_back();
+ return;
+ }
+ int n_prev = mItemsAddedCount;
+ int n = mItemsAddedCount - 1;
+ int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+ int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+ mItemsAddedCount--;
+
+ bool remove_row = row_count != row_count_prev;
+ removeFromLastRow(mItems[mItemsAddedCount]);
+ mItems.pop_back();
+ if (remove_row)
+ {
+ for (int i = 0; i < row_count_prev - 1; i++)
+ {
+ moveRowDown(i);
+ }
+ removeLastRow();
+ }
+ reshapeGalleryPanel(row_count);
+}
+
+
+void LLInventoryGallery::removeFromGalleryMiddle(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.erase(std::remove(mHiddenItems.begin(), mHiddenItems.end(), item), mHiddenItems.end());
+ return;
+ }
+ int n = mItemIndexMap[item];
+ mItemIndexMap.erase(item);
+ std::vector<LLInventoryGalleryItem*> saved;
+ for (int i = mItemsAddedCount - 1; i > n; i--)
+ {
+ saved.push_back(mItems[i]);
+ removeFromGalleryLast(mItems[i]);
+ }
+ removeFromGalleryLast(mItems[n]);
+ int saved_count = saved.size();
+ for (int i = 0; i < saved_count; i++)
+ {
+ addToGallery(saved.back());
+ saved.pop_back();
+ }
+}
+
+void LLInventoryGallery::removeFromLastRow(LLInventoryGalleryItem* item)
+{
+ mItemPanels.back()->removeChild(item);
+ mLastRowPanel->removeChild(mItemPanels.back());
+ mUnusedItemPanels.push_back(mItemPanels.back());
+ mItemPanels.pop_back();
+}
+
+LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id)
+{
+ LLInventoryGalleryItem::Params giparams;
+ LLInventoryGalleryItem* gitem = LLUICtrlFactory::create<LLInventoryGalleryItem>(giparams);
+ gitem->reshape(mItemWidth, mItemHeight);
+ gitem->setVisible(true);
+ gitem->setFollowsLeft();
+ gitem->setFollowsTop();
+ gitem->setName(name);
+ gitem->setUUID(item_id);
+ gitem->setGallery(this);
+ gitem->setType(type);
+ gitem->setThumbnail(thumbnail_id);
+ return gitem;
+}
+
+void LLInventoryGallery::buildGalleryPanel(int row_count)
+{
+ LLPanel::Params params;
+ mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
+ reshapeGalleryPanel(row_count);
+}
+
+void LLInventoryGallery::reshapeGalleryPanel(int row_count)
+{
+ int bottom = 0;
+ int left = 0;
+ int height = row_count * (mRowPanelHeight + mVerticalGap);
+ LLRect rect = LLRect(left, bottom + height, left + mGalleryWidth, bottom);
+ mGalleryPanel->setRect(rect);
+ mGalleryPanel->reshape(mGalleryWidth, height);
+ mGalleryPanel->setVisible(true);
+ mGalleryPanel->setFollowsLeft();
+ mGalleryPanel->setFollowsTop();
+}
+
+LLPanel* LLInventoryGallery::buildItemPanel(int left)
+{
+ LLPanel::Params lpparams;
+ int top = 0;
+ LLPanel* lpanel = NULL;
+ if(mUnusedItemPanels.empty())
+ {
+ lpanel = LLUICtrlFactory::create<LLPanel>(lpparams);
+ }
+ else
+ {
+ lpanel = mUnusedItemPanels.back();
+ mUnusedItemPanels.pop_back();
+ }
+ LLRect rect = LLRect(left, top + mItemHeight, left + mItemWidth + mItemHorizontalGap, top);
+ lpanel->setRect(rect);
+ lpanel->reshape(mItemWidth + mItemHorizontalGap, mItemHeight);
+ lpanel->setVisible(true);
+ lpanel->setFollowsLeft();
+ lpanel->setFollowsTop();
+ return lpanel;
+}
+
+LLPanel* LLInventoryGallery::buildRowPanel(int left, int bottom)
+{
+ LLPanel::Params sparams;
+ LLPanel* stack = NULL;
+ if(mUnusedRowPanels.empty())
+ {
+ stack = LLUICtrlFactory::create<LLPanel>(sparams);
+ }
+ else
+ {
+ stack = mUnusedRowPanels.back();
+ mUnusedRowPanels.pop_back();
+ }
+ moveRowPanel(stack, left, bottom);
+ return stack;
+}
+
+void LLInventoryGallery::moveRowPanel(LLPanel* stack, int left, int bottom)
+{
+ LLRect rect = LLRect(left, bottom + mRowPanelHeight, left + mRowPanelWidth, bottom);
+ stack->setRect(rect);
+ stack->reshape(mRowPanelWidth, mRowPanelHeight);
+ stack->setVisible(true);
+ stack->setFollowsLeft();
+ stack->setFollowsTop();
+}
+
+void LLInventoryGallery::setFilterSubString(const std::string& string)
+{
+ mFilterSubString = string;
+ reArrangeRows();
+}
+
+void LLInventoryGallery::applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring)
+{
+ if (!item) return;
+
+ std::string item_name = item->getItemName();
+ LLStringUtil::toUpper(item_name);
+
+ std::string cur_filter = filter_substring;
+ LLStringUtil::toUpper(cur_filter);
+
+ bool hidden = (std::string::npos == item_name.find(cur_filter));
+ item->setHidden(hidden);
+}
+
+void LLInventoryGallery::getCurrentCategories(uuid_vec_t& vcur)
+{
+ for (gallery_item_map_t::const_iterator iter = mItemMap.begin();
+ iter != mItemMap.end();
+ iter++)
+ {
+ if ((*iter).second != NULL)
+ {
+ vcur.push_back((*iter).first);
+ }
+ }
+}
+
+void LLInventoryGallery::updateAddedItem(LLUUID item_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(item_id);
+ if (!obj)
+ {
+ LL_WARNS("InventoryGallery") << "Failed to find item: " << item_id << LL_ENDL;
+ return;
+ }
+
+ LLUUID thumbnail_id = obj->getThumbnailUUID();;
+
+ if ((LLAssetType::AT_CATEGORY == obj->getType()) && thumbnail_id.isNull())
+ {
+ thumbnail_id = getOutfitImageID(item_id);
+ }
+
+ LLInventoryGalleryItem* item = buildGalleryItem(obj->getName(), item_id, obj->getType(), thumbnail_id);
+ mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
+
+ item->setFocusReceivedCallback(boost::bind(&LLInventoryGallery::onChangeItemSelection, this, item_id));
+ if (mGalleryCreated)
+ {
+ addToGallery(item);
+ }
+}
+
+void LLInventoryGallery::updateRemovedItem(LLUUID item_id)
+{
+ gallery_item_map_t::iterator item_iter = mItemMap.find(item_id);
+ if (item_iter != mItemMap.end())
+ {
+ LLInventoryGalleryItem* item = item_iter->second;
+
+ deselectItem(item_id);
+ mItemMap.erase(item_iter);
+ removeFromGalleryMiddle(item);
+
+ // kill removed item
+ if (item != NULL)
+ {
+ item->die();
+ }
+ }
+
+}
+
+void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
+{
+ gallery_item_map_t::iterator iter = mItemMap.find(item_id);
+ if (iter != mItemMap.end())
+ {
+ LLInventoryGalleryItem* item = iter->second;
+ if (item)
+ {
+ item->setName(name);
+ }
+ }
+}
+
+void LLInventoryGallery::onChangeItemSelection(const LLUUID& category_id)
+{
+ if (mSelectedItemID == category_id)
+ return;
+
+ if (mItemMap[mSelectedItemID])
+ {
+ mItemMap[mSelectedItemID]->setSelected(FALSE);
+ }
+ if (mItemMap[category_id])
+ {
+ mItemMap[category_id]->setSelected(TRUE);
+ }
+ mSelectedItemID = category_id;
+ signalSelectionItemID(category_id);
+}
+
+void LLInventoryGallery::updateMessageVisibility()
+{
+ mMessageTextBox->setVisible(mItems.empty());
+ mScrollPanel->setVisible(!mItems.empty());
+}
+
+void LLInventoryGallery::refreshList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+
+ gInventory.getDirectDescendentsOf(category_id, cat_array, item_array);
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ // Create added and removed items vectors.
+ computeDifference(*cat_array, *item_array, vadded, vremoved);
+
+ // Handle added tabs.
+ for (uuid_vec_t::const_iterator iter = vadded.begin();
+ iter != vadded.end();
+ ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateAddedItem(cat_id);
+ }
+
+ // Handle removed tabs.
+ for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateRemovedItem(cat_id);
+ }
+
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ LLInventoryObject* obj = gInventory.getObject(*items_iter);
+ if(!obj)
+ {
+ return;
+ }
+
+ updateChangedItemName(*items_iter, obj->getName());
+ }
+
+}
+
+void LLInventoryGallery::computeDifference(
+ const LLInventoryModel::cat_array_t vcats,
+ const LLInventoryModel::item_array_t vitems,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew;
+ // Creating a vector of newly collected UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin();
+ iter != vcats.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+ for (LLInventoryModel::item_array_t::const_iterator iter = vitems.begin();
+ iter != vitems.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+ getCurrentCategories(vcur);
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLInventoryGallery::deselectItem(const LLUUID& category_id)
+{
+ // Reset selection if the item is selected.
+ if (category_id == mSelectedItemID)
+ {
+ mSelectedItemID = LLUUID::null;
+ signalSelectionItemID(mSelectedItemID);
+ }
+}
+
+void LLInventoryGallery::signalSelectionItemID(const LLUUID& category_id)
+{
+ mSelectionChangeSignal(category_id);
+}
+
+boost::signals2::connection LLInventoryGallery::setSelectionChangeCallback(selection_change_callback_t cb)
+{
+ return mSelectionChangeSignal.connect(cb);
+}
+
+LLUUID LLInventoryGallery::getOutfitImageID(LLUUID outfit_id)
+{
+ LLUUID thumbnail_id;
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+ if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+ {
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ // Not LLIsOfAssetType, because we allow links
+ LLIsTextureType f;
+ gInventory.getDirectDescendentsOf(outfit_id, cats, items, f);
+
+ // Exactly one texture found => show the texture as thumbnail
+ if (1 == items.size())
+ {
+ LLViewerInventoryItem* item = items.front();
+ if (item && item->getIsLinkType())
+ {
+ item = item->getLinkedItem();
+ }
+ if (item)
+ {
+ thumbnail_id = item->getAssetUUID();
+ }
+ }
+ }
+ return thumbnail_id;
+}
+
+boost::signals2::connection LLInventoryGallery::setRootChangedCallback(root_changed_callback_t cb)
+{
+ return mRootChangedSignal.connect(cb);
+}
+
+void LLInventoryGallery::onForwardFolder()
+{
+ if(isForwardAvailable())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ mFolderID = mForwardFolders.back();
+ mForwardFolders.pop_back();
+ updateRootFolder();
+ }
+}
+
+void LLInventoryGallery::onBackwardFolder()
+{
+ if(isBackwardAvailable())
+ {
+ mForwardFolders.push_back(mFolderID);
+ mFolderID = mBackwardFolders.back();
+ mBackwardFolders.pop_back();
+ updateRootFolder();
+ }
+}
+
+void LLInventoryGallery::clearNavigationHistory()
+{
+ mForwardFolders.clear();
+ mBackwardFolders.clear();
+}
+
+bool LLInventoryGallery::isBackwardAvailable()
+{
+ return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventoryGallery::isForwardAvailable()
+{
+ return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+//-----------------------------
+// LLInventoryGalleryItem
+//-----------------------------
+
+static LLDefaultChildRegistry::Register<LLInventoryGalleryItem> r("inventory_gallery_item");
+
+LLInventoryGalleryItem::LLInventoryGalleryItem(const Params& p)
+ : LLPanel(p),
+ mSelected(false),
+ mDefaultImage(true),
+ mName(""),
+ mUUID(LLUUID()),
+ mIsFolder(true),
+ mGallery(NULL),
+ mType(LLAssetType::AT_NONE),
+ mSortGroup(SG_ITEM)
+{
+ buildFromFile("panel_inventory_gallery_item.xml");
+}
+
+LLInventoryGalleryItem::~LLInventoryGalleryItem()
+{
+}
+
+BOOL LLInventoryGalleryItem::postBuild()
+{
+ mNameText = getChild<LLTextBox>("item_name");
+
+ mTextBgPanel = getChild<LLPanel>("text_bg_panel");
+ mHidden = false;
+ return TRUE;
+}
+
+void LLInventoryGalleryItem::setType(LLAssetType::EType type)
+{
+ mType = type;
+ mIsFolder = (mType == LLAssetType::AT_CATEGORY);
+
+ std::string icon_name = LLInventoryIcon::getIconName(mType);
+ if(mIsFolder)
+ {
+ mSortGroup = SG_NORMAL_FOLDER;
+ LLViewerInventoryCategory * cat = gInventory.getCategory(mUUID);
+ if (cat)
+ {
+ LLFolderType::EType preferred_type = cat->getPreferredType();
+ icon_name = LLViewerFolderType::lookupIconName(preferred_type);
+
+ if (preferred_type == LLFolderType::FT_TRASH)
+ {
+ mSortGroup = SG_TRASH_FOLDER;
+ }
+ else if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ mSortGroup = SG_SYSTEM_FOLDER;
+ }
+ }
+ }
+
+ getChild<LLIconCtrl>("item_type")->setValue(icon_name);
+}
+
+void LLInventoryGalleryItem::setThumbnail(LLUUID id)
+{
+ mDefaultImage = id.isNull();
+ if(mDefaultImage)
+ {
+ getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue("Thumbnail_Fallback");
+ }
+ else
+ {
+ getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue(id);
+ }
+}
+
+void LLInventoryGalleryItem::draw()
+{
+ LLPanel::draw();
+
+ // Draw border
+ LLUIColor border_color = LLUIColorTable::instance().getColor(mSelected ? "MenuItemHighlightBgColor" : "TextFgTentativeColor", LLColor4::white);
+ LLRect border = getChildView("preview_thumbnail")->getRect();
+ border.mRight = border.mRight + 1;
+ gl_rect_2d(border, border_color.get(), FALSE);
+}
+
+void LLInventoryGalleryItem::setName(std::string name)
+{
+ mNameText->setText(name);
+ mNameText->setToolTip(name);
+ mName = name;
+}
+
+void LLInventoryGalleryItem::setSelected(bool value)
+{
+ mSelected = value;
+ mTextBgPanel->setBackgroundVisible(value);
+}
+
+BOOL LLInventoryGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ setFocus(TRUE);
+ return LLUICtrl::handleMouseDown(x, y, mask);
+}
+
+BOOL LLInventoryGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ setFocus(TRUE);
+ return LLUICtrl::handleRightMouseDown(x, y, mask);
+}
+
+BOOL LLInventoryGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ if (mIsFolder && mGallery)
+ {
+ mGallery->setRootFolder(mUUID);
+ }
+ else
+ {
+ LLInvFVBridgeAction::doAction(mUUID,&gInventory);
+ //todo: some item types require different handling
+ }
+
+ return TRUE;
+}
+
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
new file mode 100644
index 0000000000..ab9d27e260
--- /dev/null
+++ b/indra/newview/llinventorygallery.h
@@ -0,0 +1,233 @@
+/**
+ * @file llinventorygallery.h
+ * @brief LLInventoryGallery class definition
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYGALLERY_H
+#define LL_LLINVENTORYGALLERY_H
+
+#include "llpanel.h"
+#include "llinventorymodel.h"
+
+class LLInventoryCategoriesObserver;
+class LLInventoryGalleryItem;
+class LLScrollContainer;
+class LLTextBox;
+
+class LLInventoryGallery : public LLPanel
+{
+public:
+
+ typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
+ typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
+
+ struct Params
+ : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ Optional<S32> row_panel_height;
+ Optional<S32> row_panel_width_factor;
+ Optional<S32> gallery_width_factor;
+ Optional<S32> vertical_gap;
+ Optional<S32> horizontal_gap;
+ Optional<S32> item_width;
+ Optional<S32> item_height;
+ Optional<S32> item_horizontal_gap;
+ Optional<S32> items_in_row;
+
+ Params();
+ };
+
+ static const LLInventoryGallery::Params& getDefaultParams();
+
+ LLInventoryGallery(const LLInventoryGallery::Params& params = getDefaultParams());
+ ~LLInventoryGallery();
+
+ BOOL postBuild();
+ void initGallery();
+ void draw();
+
+ void setFilterSubString(const std::string& string);
+ std::string getFilterSubString() { return mFilterSubString; }
+
+ void getCurrentCategories(uuid_vec_t& vcur);
+ void updateAddedItem(LLUUID item_id);
+ void updateRemovedItem(LLUUID item_id);
+ void updateChangedItemName(LLUUID item_id, std::string name);
+
+ void updateMessageVisibility();
+
+ void setRootFolder(const LLUUID cat_id);
+ void updateRootFolder();
+ LLUUID getRootFolder() { return mFolderID; }
+ typedef boost::function<void()> root_changed_callback_t;
+ boost::signals2::connection setRootChangedCallback(root_changed_callback_t cb);
+ void onForwardFolder();
+ void onBackwardFolder();
+ void clearNavigationHistory();
+ bool isBackwardAvailable();
+ bool isForwardAvailable();
+
+ void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
+ void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
+ std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
+ std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
+
+ LLUUID getOutfitImageID(LLUUID outfit_id);
+
+ void refreshList(const LLUUID& category_id);
+ void computeDifference(const LLInventoryModel::cat_array_t vcats, const LLInventoryModel::item_array_t vitems, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+ void deselectItem(const LLUUID& category_id);
+ void signalSelectionItemID(const LLUUID& category_id);
+ boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
+
+protected:
+
+ void onChangeItemSelection(const LLUUID& category_id);
+
+ void applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
+
+ LLInventoryCategoriesObserver* mCategoriesObserver;
+ LLUUID mSelectedItemID;
+ bool mIsInitialized;
+
+ selection_change_signal_t mSelectionChangeSignal;
+ boost::signals2::signal<void()> mRootChangedSignal;
+ LLUUID mFolderID;
+ std::list<LLUUID> mBackwardFolders;
+ std::list<LLUUID> mForwardFolders;
+
+private:
+ void addToGallery(LLInventoryGalleryItem* item);
+ void removeFromGalleryLast(LLInventoryGalleryItem* item);
+ void removeFromGalleryMiddle(LLInventoryGalleryItem* item);
+ LLPanel* addLastRow();
+ void removeLastRow();
+ void moveRowUp(int row);
+ void moveRowDown(int row);
+ void moveRow(int row, int pos);
+ LLPanel* addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap);
+ void removeFromLastRow(LLInventoryGalleryItem* item);
+ void reArrangeRows(S32 row_diff = 0);
+ void updateRowsIfNeeded();
+ void updateGalleryWidth();
+
+ LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id);
+
+ void buildGalleryPanel(int row_count);
+ void reshapeGalleryPanel(int row_count);
+ LLPanel* buildItemPanel(int left);
+ LLPanel* buildRowPanel(int left, int bottom);
+ void moveRowPanel(LLPanel* stack, int left, int bottom);
+
+ std::vector<LLPanel*> mRowPanels;
+ std::vector<LLPanel*> mItemPanels;
+ std::vector<LLPanel*> mUnusedRowPanels;
+ std::vector<LLPanel*> mUnusedItemPanels;
+ std::vector<LLInventoryGalleryItem*> mItems;
+ std::vector<LLInventoryGalleryItem*> mHiddenItems;
+ LLScrollContainer* mScrollPanel;
+ LLPanel* mGalleryPanel;
+ LLPanel* mLastRowPanel;
+ LLTextBox* mMessageTextBox;
+ int mRowCount;
+ int mItemsAddedCount;
+ bool mGalleryCreated;
+
+ /* Params */
+ int mRowPanelHeight;
+ int mVerticalGap;
+ int mHorizontalGap;
+ int mItemWidth;
+ int mItemHeight;
+ int mItemHorizontalGap;
+ int mItemsInRow;
+ int mRowPanelWidth;
+ int mGalleryWidth;
+ int mRowPanWidthFactor;
+ int mGalleryWidthFactor;
+
+ std::string mFilterSubString;
+
+ typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
+ gallery_item_map_t mItemMap;
+ std::map<LLInventoryGalleryItem*, S32> mItemIndexMap;
+};
+
+class LLInventoryGalleryItem : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {};
+
+ enum EInventorySortGroup
+ {
+ SG_SYSTEM_FOLDER,
+ SG_TRASH_FOLDER,
+ SG_NORMAL_FOLDER,
+ SG_ITEM
+ };
+
+ LLInventoryGalleryItem(const Params& p);
+ virtual ~LLInventoryGalleryItem();
+
+ BOOL postBuild();
+ void draw();
+ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+
+ void setName(std::string name);
+ void setSelected(bool value);
+ void setUUID(LLUUID id) {mUUID = id;}
+ LLUUID getUUID() { return mUUID;}
+
+ std::string getItemName() {return mName;}
+ bool isDefaultImage() {return mDefaultImage;}
+
+ bool isHidden() {return mHidden;}
+ void setHidden(bool hidden) {mHidden = hidden;}
+
+ void setType(LLAssetType::EType type);
+ void setThumbnail(LLUUID id);
+ void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
+ bool isFolder() { return mIsFolder; }
+ EInventorySortGroup getSortGroup() { return mSortGroup; }
+
+private:
+ LLUUID mUUID;
+ LLTextBox* mNameText;
+ LLPanel* mTextBgPanel;
+ bool mSelected;
+ bool mDefaultImage;
+ bool mHidden;
+ bool mIsFolder;
+
+ EInventorySortGroup mSortGroup;
+ LLAssetType::EType mType;
+ std::string mName;
+ LLInventoryGallery* mGallery;
+};
+
+#endif
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 7d4abab98f..caaff79c06 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -2097,12 +2097,15 @@ void LLInventorySingleFolderPanel::openInCurrentWindow(const LLSD& userdata)
void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
{
- if(mFolderID.notNull())
+ if (mFolderID != new_id)
{
- mBackwardFolders.push_back(mFolderID);
+ if(mFolderID.notNull())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ }
+ mFolderID = new_id;
+ updateSingleFolderRoot();
}
- mFolderID = new_id;
- updateSingleFolderRoot();
}
void LLInventorySingleFolderPanel::onForwardFolder()
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 31dd7aec23..b2c27daeec 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -406,6 +406,11 @@ public:
bool isBackwardAvailable();
bool isForwardAvailable();
+ void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
+ void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
+ std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
+ std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
+
void setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb);
typedef boost::function<void()> root_changed_callback_t;
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 9fab6e4d2e..a867077ab0 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -37,6 +37,7 @@
#include "llfilepicker.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
+#include "llinventorygallery.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llfiltereditor.h"
#include "llfloatersidepanelcontainer.h"
@@ -115,7 +116,9 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p)
mNeedUploadCost(true),
mMenuViewDefault(NULL),
mSingleFolderMode(false),
- mFolderRootChangedConnection()
+ mViewMode(VIEW_LIST),
+ mListViewRootUpdatedConnection(),
+ mGalleryRootUpdatedConnection()
{
// Menu Callbacks (non contex menus)
mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2));
@@ -242,9 +245,12 @@ BOOL LLPanelMainInventory::postBuild()
mViewMenuButton = getChild<LLMenuButton>("view_btn");
mSingleFolderPanelInventory = getChild<LLInventorySingleFolderPanel>("single_folder_inv");
- mFolderRootChangedConnection = mSingleFolderPanelInventory->setRootChangedCallback(boost::bind(&LLPanelMainInventory::updateTitle, this));
+ mListViewRootUpdatedConnection = mSingleFolderPanelInventory->setRootChangedCallback(boost::bind(&LLPanelMainInventory::updateTitle, this));
mSingleFolderPanelInventory->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mSingleFolderPanelInventory, _1, _2));
+ mInventoryGalleryPanel = getChild<LLInventoryGallery>("gallery_view_inv");
+ mGalleryRootUpdatedConnection = mInventoryGalleryPanel->setRootChangedCallback(boost::bind(&LLPanelMainInventory::updateTitle, this));
+
initListCommandsHandlers();
const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost());
@@ -322,9 +328,13 @@ LLPanelMainInventory::~LLPanelMainInventory( void )
mMenuAddHandle.markDead();
}
- if (mFolderRootChangedConnection.connected())
+ if (mListViewRootUpdatedConnection.connected())
+ {
+ mListViewRootUpdatedConnection.disconnect();
+ }
+ if (mGalleryRootUpdatedConnection.connected())
{
- mFolderRootChangedConnection.disconnect();
+ mGalleryRootUpdatedConnection.disconnect();
}
}
@@ -635,10 +645,18 @@ void LLPanelMainInventory::onClearSearch()
void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
{
+ if(mSingleFolderMode && isGalleryViewMode())
+ {
+ mFilterSubString = search_string;
+ mInventoryGalleryPanel->setFilterSubString(mFilterSubString);
+ return;
+ }
+
if (search_string == "")
{
onClearSearch();
}
+
if (!mActivePanel)
{
return;
@@ -863,8 +881,9 @@ void LLPanelMainInventory::updateItemcountText()
{
LLInventoryModel::cat_array_t *cats;
LLInventoryModel::item_array_t *items;
- gInventory.getDirectDescendentsOf(mSingleFolderPanelInventory->getSingleFolderRoot(), cats, items);
-
+
+ gInventory.getDirectDescendentsOf(getCurrentSFVRoot(), cats, items);
+
string_args["[ITEM_COUNT]"] = llformat("%d", items->size());
string_args["[CATEGORY_COUNT]"] = llformat("%d", cats->size());
text = getString("ItemcountCompleted", string_args);
@@ -1334,7 +1353,8 @@ void LLPanelMainInventory::toggleViewMode()
mSingleFolderMode = !mSingleFolderMode;
getChild<LLPanel>("default_inventory_panel")->setVisible(!mSingleFolderMode);
- getChild<LLPanel>("single_folder_inventory")->setVisible(mSingleFolderMode);
+ getChild<LLPanel>("single_folder_inventory")->setVisible(mSingleFolderMode && isListViewMode());
+ getChild<LLPanel>("gallery_view_inventory")->setVisible(mSingleFolderMode && isGalleryViewMode());
getChild<LLLayoutPanel>("nav_buttons")->setVisible(mSingleFolderMode);
getChild<LLButton>("view_mode_btn")->setImageOverlay(mSingleFolderMode ? getString("default_mode_btn") : getString("single_folder_mode_btn"));
@@ -1362,7 +1382,10 @@ void LLPanelMainInventory::onViewModeClick()
LLUUID new_root_folder;
if(mSingleFolderMode)
{
- selected_folder = mSingleFolderPanelInventory->getSingleFolderRoot();
+ if(isListViewMode())
+ {
+ selected_folder = mSingleFolderPanelInventory->getSingleFolderRoot();
+ }
}
else
{
@@ -1413,33 +1436,57 @@ void LLPanelMainInventory::onViewModeClick()
void LLPanelMainInventory::onUpFolderClicked()
{
- const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot());
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
if (cat)
{
if (cat->getParentUUID().notNull())
{
- mSingleFolderPanelInventory->changeFolderRoot(cat->getParentUUID());
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->changeFolderRoot(cat->getParentUUID());
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setRootFolder(cat->getParentUUID());
+ }
}
}
}
void LLPanelMainInventory::onBackFolderClicked()
{
- mSingleFolderPanelInventory->onBackwardFolder();
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->onBackwardFolder();
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->onBackwardFolder();
+ }
}
void LLPanelMainInventory::onForwardFolderClicked()
{
- mSingleFolderPanelInventory->onForwardFolder();
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->onForwardFolder();
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->onForwardFolder();
+ }
}
void LLPanelMainInventory::setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history)
{
- mSingleFolderPanelInventory->changeFolderRoot(folder_id);
- if(clear_nav_history)
+ if(isListViewMode())
{
- mSingleFolderPanelInventory->clearNavigationHistory();
- updateNavButtons();
+ mSingleFolderPanelInventory->changeFolderRoot(folder_id);
+ if(clear_nav_history)
+ {
+ mSingleFolderPanelInventory->clearNavigationHistory();
+ updateNavButtons();
+ }
}
}
@@ -1638,7 +1685,16 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
if (command_name == "include_links")
{
mActivePanel->getFilter().toggleSearchVisibilityLinks();
- }
+ }
+
+ if (command_name == "list_view")
+ {
+ setViewMode(VIEW_LIST);
+ }
+ if (command_name == "gallery_view")
+ {
+ setViewMode(VIEW_GALLERY);
+ }
}
void LLPanelMainInventory::onVisibilityChange( BOOL new_visibility )
@@ -1821,11 +1877,11 @@ BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
if (command_name == "list_view")
{
- return true;
+ return isListViewMode();
}
if (command_name == "gallery_view")
{
- return false;
+ return isGalleryViewMode();
}
if (command_name == "combination_view")
{
@@ -1862,7 +1918,7 @@ void LLPanelMainInventory::updateTitle()
{
if(mSingleFolderMode)
{
- const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot());
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
if (cat)
{
inventory_floater->setTitle(cat->getName());
@@ -1883,10 +1939,18 @@ void LLPanelMainInventory::updateTitle()
void LLPanelMainInventory::updateNavButtons()
{
- getChild<LLButton>("back_btn")->setEnabled(mSingleFolderPanelInventory->isBackwardAvailable());
- getChild<LLButton>("forward_btn")->setEnabled(mSingleFolderPanelInventory->isForwardAvailable());
-
- const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot());
+ if(isListViewMode())
+ {
+ getChild<LLButton>("back_btn")->setEnabled(mSingleFolderPanelInventory->isBackwardAvailable());
+ getChild<LLButton>("forward_btn")->setEnabled(mSingleFolderPanelInventory->isForwardAvailable());
+ }
+ if(isGalleryViewMode())
+ {
+ getChild<LLButton>("back_btn")->setEnabled(mInventoryGalleryPanel->isBackwardAvailable());
+ getChild<LLButton>("forward_btn")->setEnabled(mInventoryGalleryPanel->isForwardAvailable());
+ }
+
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
bool up_enabled = (cat && cat->getParentUUID().notNull());
getChild<LLButton>("up_btn")->setEnabled(up_enabled);
}
@@ -1900,5 +1964,50 @@ LLSidepanelInventory* LLPanelMainInventory::getParentSidepanelInventory()
}
return NULL;
}
+
+void LLPanelMainInventory::setViewMode(EViewModeType mode)
+{
+ if(mode != mViewMode)
+ {
+ LLUUID cur_root = getCurrentSFVRoot();
+ mViewMode = mode;
+
+ getChild<LLPanel>("single_folder_inventory")->setVisible(mSingleFolderMode && isListViewMode());
+ getChild<LLPanel>("gallery_view_inventory")->setVisible(mSingleFolderMode && isGalleryViewMode());
+
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->changeFolderRoot(cur_root);
+ mSingleFolderPanelInventory->setNavForwardList(mInventoryGalleryPanel->getNavForwardList());
+ mSingleFolderPanelInventory->setNavBackwardList(mInventoryGalleryPanel->getNavBackwardList());
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setRootFolder(cur_root);
+ mInventoryGalleryPanel->setNavForwardList(mSingleFolderPanelInventory->getNavForwardList());
+ mInventoryGalleryPanel->setNavBackwardList(mSingleFolderPanelInventory->getNavBackwardList());
+ }
+ updateNavButtons();
+
+ if((isListViewMode() && (mActivePanel->getFilterSubString() != mFilterSubString)) ||
+ (isGalleryViewMode() && (mInventoryGalleryPanel->getFilterSubString() != mFilterSubString)))
+ {
+ onFilterEdit(mFilterSubString);
+ }
+ }
+}
+
+LLUUID LLPanelMainInventory::getCurrentSFVRoot()
+{
+ if(isListViewMode())
+ {
+ return mSingleFolderPanelInventory->getSingleFolderRoot();
+ }
+ if(isGalleryViewMode())
+ {
+ return mInventoryGalleryPanel->getRootFolder();
+ }
+ return LLUUID::null;
+}
// List Commands //
////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index 5f488539dd..51c4ace874 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -38,6 +38,7 @@
class LLComboBox;
class LLFolderViewItem;
class LLInventoryPanel;
+class LLInventoryGallery;
class LLSaveFolderState;
class LLFilterEditor;
class LLTabContainer;
@@ -65,6 +66,13 @@ public:
BOOL postBuild();
+ enum EViewModeType
+ {
+ VIEW_LIST,
+ VIEW_GALLERY,
+ VIEW_COMBINATION
+ };
+
virtual BOOL handleKeyHere(KEY key, MASK mask);
// Inherited functionality
@@ -108,6 +116,11 @@ public:
LLUUID getSingleFolderViewRoot();
bool isSingleFolderMode() { return mSingleFolderMode; }
+ void setViewMode(EViewModeType mode);
+ bool isListViewMode() { return (mViewMode == VIEW_LIST); }
+ bool isGalleryViewMode() { return (mViewMode == VIEW_GALLERY); }
+ LLUUID getCurrentSFVRoot();
+
protected:
//
// Misc functions
@@ -163,9 +176,12 @@ private:
LLComboBox* mSearchTypeCombo;
bool mSingleFolderMode;
+ EViewModeType mViewMode;
LLInventorySingleFolderPanel* mSingleFolderPanelInventory;
+ LLInventoryGallery* mInventoryGalleryPanel;
- boost::signals2::connection mFolderRootChangedConnection;
+ boost::signals2::connection mListViewRootUpdatedConnection;
+ boost::signals2::connection mGalleryRootUpdatedConnection;
//////////////////////////////////////////////////////////////////////////////////
// List Commands //
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
index c7f9822e41..28ec8f2bf1 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
@@ -89,6 +89,7 @@
<menu_item_check
label="Combination view"
layout="topleft"
+ enabled="false"
name="combination_view">
<on_click
function="Inventory.GearDefault.Custom.Action"
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
new file mode 100644
index 0000000000..68f78a77c8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="390"
+ name="Inventory Gallery"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="404">
+ <text
+ type="string"
+ clip_partial="false"
+ follows="left|top"
+ layout="topleft"
+ left="13"
+ name="empty_txt"
+ top="0"
+ height="32"
+ valign="center"
+ parse_urls="true"
+ wrap="true">
+ Folder is empty.
+ </text>
+ <scroll_container
+ follows="all"
+ height="400"
+ layout="topleft"
+ left="4"
+ top="0"
+ name="gallery_scroll_panel"
+ opaque="false"
+ top_pad="0">
+ </scroll_container>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
new file mode 100644
index 0000000000..80beb2ec8a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="false"
+ background_opaque="false"
+ bg_alpha_color="FrogGreen"
+ bg_opaque_color="FrogGreen"
+ border="false"
+ bevel_style="none"
+ follows="left|top"
+ height="149"
+ width="130"
+ name="gallery_item_panel"
+ layout="topleft"
+ left="0"
+ top="0">
+ <thumbnail
+ name="preview_thumbnail"
+ image_name="Thumbnail_Fallback"
+ layout="topleft"
+ follows="left|top"
+ interactable="false"
+ height="128"
+ width="128"
+ top="0"
+ left="1"/>
+ <icon
+ left="5"
+ top_pad="-25"
+ layout="topleft"
+ name="item_type"
+ height="20"
+ width="20"
+ follows="left|top"
+ visible="true"
+ image_name="Inv_Eye"/>
+ <panel
+ background_visible="false"
+ background_opaque="true"
+ bg_opaque_color="MenuItemHighlightBgColor"
+ border="false"
+ bevel_style="none"
+ follows="left|top"
+ left="0"
+ top="129"
+ height="25"
+ width="148"
+ name="text_bg_panel">
+ <text
+ read_only="true"
+ length="1"
+ follows="left|top"
+ left="1"
+ height="10"
+ layout="topleft"
+ name="item_name"
+ parse_urls="false"
+ top="2"
+ width="150"
+ use_ellipses="true">
+ Item name, folder name.
+ </text>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index af4511a92d..3cdb3c5003 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -306,4 +306,27 @@
folder_indentation="-8"/>
</single_folder_inventory_panel>
</panel>
+ <panel
+ follows="all"
+ halign="center"
+ height="372"
+ layout="topleft"
+ left="7"
+ name="gallery_view_inventory"
+ top_delta="0"
+ visible="false"
+ width="312">
+ <panel
+ class="inventory_gallery"
+ filename="panel_inventory_gallery.xml"
+ left="0"
+ top="0"
+ height="372"
+ width="312"
+ name="gallery_view_inv"
+ background_visible="true"
+ follows="all"
+ layout="topleft" />
+ </panel>
+ </panel>
</panel>