From cd0c40c71af767dd66694dc3329e08823aa6b6e7 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 27 Jun 2023 00:24:13 +0300
Subject: [PATCH] SL-19904 Outfit gallery keyboard support

---
 indra/newview/lloutfitgallery.cpp             | 353 ++++++++++++++++--
 indra/newview/lloutfitgallery.h               |  31 +-
 .../default/xui/en/panel_outfit_gallery.xml   |  42 +--
 3 files changed, 356 insertions(+), 70 deletions(-)

diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 415d0a96d71..de988555c5d 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -146,6 +146,264 @@ void LLOutfitGallery::draw()
     }
 }
 
+BOOL LLOutfitGallery::handleKeyHere(KEY key, MASK mask)
+{
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_RETURN:
+            // Open selected items if enter key hit on the inventory panel
+            if (mask == MASK_NONE && mSelectedOutfitUUID.notNull())
+            {
+                // Or should it wearSelectedOutfit?
+                getSelectedItem()->openOutfitsContent();
+            }
+            handled = TRUE;
+            break;
+        case KEY_DELETE:
+#if LL_DARWIN
+        case KEY_BACKSPACE:
+#endif
+            // Delete selected items if delete or backspace key hit on the inventory panel
+            // Note: on Mac laptop keyboards, backspace and delete are one and the same
+            if (mSelectedOutfitUUID.notNull())
+            {
+                onRemoveOutfit(mSelectedOutfitUUID);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_F2:
+            LLAppearanceMgr::instance().renameOutfit(mSelectedOutfitUUID);
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_UP:
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageUp(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_PAGE_DOWN:
+            if (mScrollPanel)
+            {
+                mScrollPanel->pageDown(30);
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_HOME:
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToTop();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_END:
+            if (mScrollPanel)
+            {
+                mScrollPanel->goToBottom();
+            }
+            handled = TRUE;
+            break;
+
+        case KEY_LEFT:
+            moveLeft();
+            handled = TRUE;
+            break;
+
+        case KEY_RIGHT:
+            moveRight();
+            handled = TRUE;
+            break;
+
+        case KEY_UP:
+            moveUp();
+            handled = TRUE;
+            break;
+
+        case KEY_DOWN:
+            moveDown();
+            handled = TRUE;
+            break;
+
+        default:
+            break;
+    }
+
+    if (handled)
+    {
+        mOutfitGalleryMenu->hide();
+    }
+
+    return handled;
+}
+
+void LLOutfitGallery::moveUp()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n -= mItemsInRow;
+            if (n >= 0)
+            {
+                item = mIndexToItemMap[n];
+                LLUUID item_id = item->getUUID();
+                ChangeOutfitSelection(nullptr, item_id);
+                item->setFocus(TRUE);
+
+                scrollToShowItem(mSelectedOutfitUUID);
+            }
+        }
+    }
+}
+
+void LLOutfitGallery::moveDown()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n += mItemsInRow;
+            if (n < mItemsAddedCount)
+            {
+                item = mIndexToItemMap[n];
+                LLUUID item_id = item->getUUID();
+                ChangeOutfitSelection(nullptr, item_id);
+                item->setFocus(TRUE);
+
+                scrollToShowItem(mSelectedOutfitUUID);
+            }
+        }
+    }
+}
+
+void LLOutfitGallery::moveLeft()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            // Might be better to get item from panel
+            S32 n = mItemIndexMap[item];
+            n--;
+            if (n < 0)
+            {
+                n = mItemsAddedCount - 1;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            ChangeOutfitSelection(nullptr, item_id);
+            item->setFocus(TRUE);
+
+            scrollToShowItem(mSelectedOutfitUUID);
+        }
+    }
+}
+
+void LLOutfitGallery::moveRight()
+{
+    if (mSelectedOutfitUUID.notNull() && mItemsAddedCount > 1)
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            S32 n = mItemIndexMap[item];
+            n++;
+            if (n == mItemsAddedCount)
+            {
+                n = 0;
+            }
+            item = mIndexToItemMap[n];
+            LLUUID item_id = item->getUUID();
+            ChangeOutfitSelection(nullptr, item_id);
+            item->setFocus(TRUE);
+
+            scrollToShowItem(mSelectedOutfitUUID);
+        }
+    }
+}
+
+void LLOutfitGallery::onFocusLost()
+{
+    LLOutfitListBase::onFocusLost();
+
+    if (mSelectedOutfitUUID.notNull())
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            item->setSelected(false);
+        }
+    }
+}
+
+void LLOutfitGallery::onFocusReceived()
+{
+    LLOutfitListBase::onFocusReceived();
+
+    if (mSelectedOutfitUUID.notNull())
+    {
+        LLOutfitGalleryItem* item = getSelectedItem();
+        if (item)
+        {
+            item->setSelected(true);
+        }
+    }
+}
+
+void LLOutfitGallery::onRemoveOutfit(const LLUUID& outfit_cat_id)
+{
+    LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(onOutfitsRemovalConfirmation, _1, _2, outfit_cat_id));
+}
+
+void LLOutfitGallery::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    if (option != 0) return; // canceled
+
+    if (outfit_cat_id.notNull())
+    {
+        gInventory.removeCategory(outfit_cat_id);
+    }
+}
+
+void LLOutfitGallery::scrollToShowItem(const LLUUID& item_id)
+{
+    LLOutfitGalleryItem* item = mOutfitMap[item_id];
+    if (item)
+    {
+        const LLRect visible_content_rect = mScrollPanel->getVisibleContentRect();
+
+        LLRect item_rect;
+        item->localRectToOtherView(item->getLocalRect(), &item_rect, mScrollPanel);
+        LLRect overlap_rect(item_rect);
+        overlap_rect.intersectWith(visible_content_rect);
+
+        //Scroll when the selected item is outside the visible area
+        if (overlap_rect.getHeight() + 5 < item->getRect().getHeight())
+        {
+            LLRect content_rect = mScrollPanel->getContentWindowRect();
+            LLRect constraint_rect;
+            constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight());
+
+            LLRect item_doc_rect;
+            item->localRectToOtherView(item->getLocalRect(), &item_doc_rect, mGalleryPanel);
+
+            mScrollPanel->scrollToShowRect(item_doc_rect, constraint_rect);
+        }
+    }
+}
+
 void LLOutfitGallery::updateRowsIfNeeded()
 {
     if(((getRect().getWidth() - mRowPanelWidth) > mItemWidth) && mRowCount > 1)
@@ -266,8 +524,9 @@ void LLOutfitGallery::addToGallery(LLOutfitGalleryItem* item)
         mHiddenItems.push_back(item);
         return;
     }
+    mItemIndexMap[item] = mItemsAddedCount;
+    mIndexToItemMap[mItemsAddedCount] = item;
     mItemsAddedCount++;
-    mItemIndexMap[item] = mItemsAddedCount - 1;
     int n = mItemsAddedCount;
     int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
     int n_prev = n - 1;
@@ -303,6 +562,7 @@ void LLOutfitGallery::removeFromGalleryLast(LLOutfitGalleryItem* item)
     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--;
+    mIndexToItemMap.erase(mItemsAddedCount);
 
     bool remove_row = row_count != row_count_prev;
     removeFromLastRow(mItems[mItemsAddedCount]);
@@ -328,6 +588,7 @@ void LLOutfitGallery::removeFromGalleryMiddle(LLOutfitGalleryItem* item)
     }
     int n = mItemIndexMap[item];
     mItemIndexMap.erase(item);
+    mIndexToItemMap.erase(n);
     std::vector<LLOutfitGalleryItem*> saved;
     for (int i = mItemsAddedCount - 1; i > n; i--)
     {
@@ -361,9 +622,15 @@ LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID
     gitem->setFollowsTop();
     gitem->setOutfitName(name);
     gitem->setUUID(outfit_id);
+    gitem->setGallery(this);
     return gitem;
 }
 
+LLOutfitGalleryItem* LLOutfitGallery::getSelectedItem()
+{
+    return mOutfitMap[mSelectedOutfitUUID];
+}
+
 void LLOutfitGallery::buildGalleryPanel(int row_count)
 {
     LLPanel::Params params;
@@ -608,6 +875,7 @@ void LLOutfitGallery::onChangeOutfitSelection(LLWearableItemsList* list, const L
     {
         mOutfitMap[category_id]->setSelected(TRUE);
     }
+    // mSelectedOutfitUUID will be set in LLOutfitListBase::ChangeOutfitSelection
 }
 
 void LLOutfitGallery::wearSelectedOutfit()
@@ -659,7 +927,8 @@ static LLDefaultChildRegistry::Register<LLOutfitGalleryItem> r("outfit_gallery_i
 
 LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
     : LLPanel(p),
-    mTexturep(NULL),
+    mGallery(nullptr),
+    mTexturep(nullptr),
     mSelected(false),
     mWorn(false),
     mDefaultImage(true),
@@ -763,9 +1032,64 @@ BOOL LLOutfitGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
 }
 
 BOOL LLOutfitGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+    return openOutfitsContent() || LLPanel::handleDoubleClick(x, y, mask);
+}
+
+BOOL LLOutfitGalleryItem::handleKeyHere(KEY key, MASK mask)
+{
+    if (!mGallery)
+    {
+        return FALSE;
+    }
+
+    BOOL handled = FALSE;
+    switch (key)
+    {
+        case KEY_LEFT:
+            mGallery->moveLeft();
+            handled = true;
+            break;
+
+        case KEY_RIGHT:
+            mGallery->moveRight();
+            handled = true;
+            break;
+
+        case KEY_UP:
+            mGallery->moveUp();
+            handled = true;
+            break;
+
+        case KEY_DOWN:
+            mGallery->moveDown();
+            handled = true;
+            break;
+
+        default:
+            break;
+    }
+    return handled;
+}
+
+void LLOutfitGalleryItem::onFocusLost()
+{
+    setSelected(false);
+
+    LLPanel::onFocusLost();
+}
+
+void LLOutfitGalleryItem::onFocusReceived()
+{
+    setSelected(true);
+
+    LLPanel::onFocusReceived();
+}
+
+bool LLOutfitGalleryItem::openOutfitsContent()
 {
     LLTabContainer* appearence_tabs = LLPanelOutfitsInventory::findInstance()->getChild<LLTabContainer>("appearance_tabs");
-    if (appearence_tabs && (mUUID != LLUUID()))
+    if (appearence_tabs && mUUID.notNull())
     {
         appearence_tabs->selectTabByName("outfitslist_tab");
         LLPanel* panel = appearence_tabs->getCurrentPanel();
@@ -778,12 +1102,11 @@ BOOL LLOutfitGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
                 outfit_list->setSelectedOutfitByUUID(mUUID);
                 LLAccordionCtrlTab* tab = accordion->getSelectedTab();
                 tab->showAndFocusHeader();
-                return TRUE;
+                return true;
             }
         }
     }
-
-    return LLPanel::handleDoubleClick(x, y, mask);
+    return false;
 }
 
 bool LLOutfitGalleryItem::setImageAssetId(LLUUID image_asset_id)
@@ -829,7 +1152,7 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
                   boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
     registrar.add("Outfit.Edit", boost::bind(editOutfit));
     registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
-    registrar.add("Outfit.Delete", boost::bind(&LLOutfitGalleryContextMenu::onRemoveOutfit, this, selected_id));
+    registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));
     registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));
     registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id));
     enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));
@@ -848,22 +1171,6 @@ void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id)
     }
 }
 
-void LLOutfitGalleryContextMenu::onRemoveOutfit(const LLUUID& outfit_cat_id)
-{
-    LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation, this, _1, _2, outfit_cat_id));
-}
-
-void LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id)
-{
-    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-    if (option != 0) return; // canceled
-    
-    if (outfit_cat_id.notNull())
-    {
-        gInventory.removeCategory(outfit_cat_id);
-    }
-}
-
 void LLOutfitGalleryContextMenu::onCreate(const LLSD& data)
 {
     LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString());
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index 16116d4b719..9915752962e 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -74,6 +74,18 @@ class LLOutfitGallery : public LLOutfitListBase
     /*virtual*/ BOOL postBuild();
     /*virtual*/ void onOpen(const LLSD& info);
     /*virtual*/ void draw();
+    /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+    void moveUp();
+    void moveDown();
+    void moveLeft();
+    void moveRight();
+
+    /*virtual*/ void onFocusLost();
+    /*virtual*/ void onFocusReceived();
+
+    static void onRemoveOutfit(const LLUUID& outfit_cat_id);
+    static void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
+    void scrollToShowItem(const LLUUID& item_id);
 
     void wearSelectedOutfit();
 
@@ -108,8 +120,6 @@ class LLOutfitGallery : public LLOutfitListBase
     void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring);
 
 private:
-    void uploadPhoto(LLUUID outfit_id);
-    void uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id);
     LLUUID getPhotoAssetId(const LLUUID& outfit_id);
     LLUUID getDefaultPhoto();
     void addToGallery(LLOutfitGalleryItem* item);
@@ -127,6 +137,7 @@ class LLOutfitGallery : public LLOutfitListBase
     void updateGalleryWidth();
 
     LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id);
+    LLOutfitGalleryItem* getSelectedItem();
 
     void onTextureSelectionChanged(LLInventoryItem* itemp);
 
@@ -170,9 +181,10 @@ class LLOutfitGallery : public LLOutfitListBase
     typedef std::map<LLUUID, LLOutfitGalleryItem*>      outfit_map_t;
     typedef outfit_map_t::value_type                    outfit_map_value_t;
     outfit_map_t                                        mOutfitMap;
-    typedef std::map<LLOutfitGalleryItem*, int>         item_num_map_t;
+    typedef std::map<LLOutfitGalleryItem*, S32>         item_num_map_t;
     typedef item_num_map_t::value_type                  item_numb_map_value_t;
     item_num_map_t                                      mItemIndexMap;
+    std::map<S32, LLOutfitGalleryItem*>                 mIndexToItemMap;
 
 
     LLInventoryCategoriesObserver* 	mOutfitsObserver;
@@ -185,14 +197,13 @@ class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
     LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list)
     : LLOutfitContextMenu(outfit_list),
     mOutfitList(outfit_list){}
+
 protected:
     /* virtual */ LLContextMenu* createMenu();
     bool onEnable(LLSD::String param);
     bool onVisible(LLSD::String param);
     void onThumbnail(const LLUUID& outfit_cat_id);
     void onCreate(const LLSD& data);
-    void onRemoveOutfit(const LLUUID& outfit_cat_id);
-    void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
 private:
     LLOutfitListBase*	mOutfitList;
 };
@@ -226,14 +237,21 @@ class LLOutfitGalleryItem : public LLPanel
     /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
     /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
     /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+    /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+    /*virtual*/ void onFocusLost();
+    /*virtual*/ void onFocusReceived();
+
+    bool openOutfitsContent();
 
+    void setGallery(LLOutfitGallery* gallery) { mGallery = gallery; }
     void setDefaultImage();
     bool setImageAssetId(LLUUID asset_id);
     LLUUID getImageAssetId();
     void setOutfitName(std::string name);
     void setOutfitWorn(bool value);
     void setSelected(bool value);
-    void setUUID(LLUUID outfit_id) {mUUID = outfit_id;}
+    void setUUID(const LLUUID &outfit_id) {mUUID = outfit_id;}
+    LLUUID getUUID() const { return mUUID; }
     
     std::string getItemName() {return mOutfitName;}
     bool isDefaultImage() {return mDefaultImage;}
@@ -242,6 +260,7 @@ class LLOutfitGalleryItem : public LLPanel
     void setHidden(bool hidden) {mHidden = hidden;}
     
 private:
+    LLOutfitGallery* mGallery;
     LLPointer<LLViewerFetchedTexture> mTexturep;
     LLUUID mUUID;
     LLUUID mImageAssetId;
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
index e3790ae09b2..e951d253913 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
@@ -40,50 +40,10 @@
    layout="topleft"
    left="4"
    top="0"
+   tab_stop="true"
    name="gallery_scroll_panel"
    opaque="false"
    top_pad="0">
-   <!--outfit_gallery_item
-    layout="topleft"
-    left="10"
-    name="preview_outfit1"
-    height="175"
-    width="150"
-    follows="left|top"/-->
-     <!--layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="0" name="top_gallery_stack" orientation="horizontal">
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-    </layout_stack>
-    <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="190" name="top_gallery_stack" orientation="horizontal">
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-      </layout_panel>
-    </layout_stack>
-     <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="380" name="top_gallery_stack" orientation="horizontal">
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
-         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
-       </layout_panel>
-     </layout_stack-->
-    <!--</panel>-->  
   </scroll_container> 
   <panel
      background_visible="true"
-- 
GitLab