Skip to content
Snippets Groups Projects
Commit 2696e375 authored by Igor Borovkov's avatar Igor Borovkov
Browse files

partial implementation of EXT-6723 Create specialized view of inventory for...

partial implementation of EXT-6723 Create specialized view of inventory for "clothing" accordion tab of outfit editor

Initial implementation (no sorting, no grayed items from Base outfit)

Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/322

--HG--
branch : product-engine
parent c233b2cf
No related branches found
No related tags found
No related merge requests found
...@@ -104,6 +104,7 @@ set(viewer_SOURCE_FILES ...@@ -104,6 +104,7 @@ set(viewer_SOURCE_FILES
llclassifiedinfo.cpp llclassifiedinfo.cpp
llclassifiedstatsresponder.cpp llclassifiedstatsresponder.cpp
llcloud.cpp llcloud.cpp
llcofwearables.cpp
llcolorswatch.cpp llcolorswatch.cpp
llcommanddispatcherlistener.cpp llcommanddispatcherlistener.cpp
llcommandhandler.cpp llcommandhandler.cpp
...@@ -614,6 +615,7 @@ set(viewer_HEADER_FILES ...@@ -614,6 +615,7 @@ set(viewer_HEADER_FILES
llclassifiedinfo.h llclassifiedinfo.h
llclassifiedstatsresponder.h llclassifiedstatsresponder.h
llcloud.h llcloud.h
llcofwearables.h
llcolorswatch.h llcolorswatch.h
llcommanddispatcherlistener.h llcommanddispatcherlistener.h
llcommandhandler.h llcommandhandler.h
......
/**
* @file llcofwearables.cpp
* @brief LLCOFWearables displayes wearables from the current outfit split into three lists (attachments, clothing and body parts)
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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 "llviewerprecompiledheaders.h"
#include "llcofwearables.h"
#include "llappearancemgr.h"
#include "llinventory.h"
#include "llinventoryitemslist.h"
#include "llinventoryfunctions.h"
static LLRegisterPanelClassWrapper<LLCOFWearables> t_cof_wearables("cof_wearables");
const LLSD REARRANGE = LLSD().with("rearrange", LLSD());
LLCOFWearables::LLCOFWearables() : LLPanel(),
mAttachments(NULL),
mClothing(NULL),
mBodyParts(NULL),
mLastSelectedList(NULL)
{
};
// virtual
BOOL LLCOFWearables::postBuild()
{
mAttachments = getChild<LLFlatListView>("list_attachments");
mClothing = getChild<LLFlatListView>("list_clothing");
mBodyParts = getChild<LLFlatListView>("list_body_parts");
//selection across different list/tabs is not supported
mAttachments->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mAttachments));
mClothing->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mClothing));
mBodyParts->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mBodyParts));
mAttachments->setCommitOnSelectionChange(true);
mClothing->setCommitOnSelectionChange(true);
mBodyParts->setCommitOnSelectionChange(true);
return LLPanel::postBuild();
}
void LLCOFWearables::onSelectionChange(LLFlatListView* selected_list)
{
if (!selected_list) return;
if (selected_list != mLastSelectedList)
{
if (selected_list != mAttachments) mAttachments->resetSelection(true);
if (selected_list != mClothing) mClothing->resetSelection(true);
if (selected_list != mBodyParts) mBodyParts->resetSelection(true);
mLastSelectedList = selected_list;
}
onCommit();
}
void LLCOFWearables::refresh()
{
clear();
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
if (items.empty()) return;
for (U32 i = 0; i < items.size(); ++i)
{
LLViewerInventoryItem* item = items.get(i);
if (!item) continue;
LLPanelInventoryListItem* item_panel = LLPanelInventoryListItem::createItemPanel(item);
if (!item_panel) continue;
switch (item->getType())
{
case LLAssetType::AT_OBJECT:
mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
break;
case LLAssetType::AT_BODYPART:
mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
break;
case LLAssetType::AT_CLOTHING:
mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
break;
default: break;
}
}
mAttachments->sort(); //*TODO by Name
mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
mClothing->sort(); //*TODO by actual inventory item description
mClothing->notify(REARRANGE);
mBodyParts->sort(); //*TODO by name
mBodyParts->notify(REARRANGE);
}
LLUUID LLCOFWearables::getSelectedUUID()
{
if (!mLastSelectedList) return LLUUID::null;
return mLastSelectedList->getSelectedUUID();
}
void LLCOFWearables::clear()
{
mAttachments->clear();
mClothing->clear();
mBodyParts->clear();
}
//EOF
/**
* @file llcofwearables.h
* @brief LLCOFWearables displayes wearables from the current outfit split into three lists (attachments, clothing and body parts)
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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_LLCOFWEARABLES_H
#define LL_LLCOFWEARABLES_H
#include "llpanel.h"
class LLFlatListView;
class LLCOFWearables : public LLPanel
{
public:
LLCOFWearables();
virtual ~LLCOFWearables() {};
/*virtual*/ BOOL postBuild();
LLUUID getSelectedUUID();
void refresh();
void clear();
protected:
void onSelectionChange(LLFlatListView* selected_list);
LLFlatListView* mAttachments;
LLFlatListView* mClothing;
LLFlatListView* mBodyParts;
LLFlatListView* mLastSelectedList;
};
#endif
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "llagent.h" #include "llagent.h"
#include "llagentwearables.h" #include "llagentwearables.h"
#include "llappearancemgr.h" #include "llappearancemgr.h"
#include "llcofwearables.h"
#include "llfilteredwearablelist.h" #include "llfilteredwearablelist.h"
#include "llinventory.h" #include "llinventory.h"
#include "llinventoryitemslist.h" #include "llinventoryitemslist.h"
...@@ -121,9 +122,15 @@ class LLLookFetchObserver : public LLInventoryFetchDescendentsObserver ...@@ -121,9 +122,15 @@ class LLLookFetchObserver : public LLInventoryFetchDescendentsObserver
LLPanelOutfitEdit::LLPanelOutfitEdit() LLPanelOutfitEdit::LLPanelOutfitEdit()
: LLPanel(), mCurrentOutfitID(), mFetchLook(NULL), mSearchFilter(NULL), : LLPanel(),
mLookContents(NULL), mInventoryItemsPanel(NULL), mAddToOutfitBtn(NULL), mCurrentOutfitID(),
mRemoveFromOutfitBtn(NULL), mLookObserver(NULL) mFetchLook(NULL),
mSearchFilter(NULL),
mCOFWearables(NULL),
mInventoryItemsPanel(NULL),
mAddToOutfitBtn(NULL),
mRemoveFromOutfitBtn(NULL),
mLookObserver(NULL)
{ {
mSavedFolderState = new LLSaveFolderState(); mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE); mSavedFolderState->setApply(FALSE);
...@@ -171,9 +178,8 @@ BOOL LLPanelOutfitEdit::postBuild() ...@@ -171,9 +178,8 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL); childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL); childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL);
mLookContents = getChild<LLScrollListCtrl>("look_items_list"); mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list");
mLookContents->sortByColumn("look_item_sort", TRUE); mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
mLookContents->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
mInventoryItemsPanel = getChild<LLInventoryPanel>("inventory_items"); mInventoryItemsPanel = getChild<LLInventoryPanel>("inventory_items");
mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK); mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK);
...@@ -206,15 +212,6 @@ BOOL LLPanelOutfitEdit::postBuild() ...@@ -206,15 +212,6 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this)); childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this));
childSetEnabled("add_to_outfit_btn", false); childSetEnabled("add_to_outfit_btn", false);
mUpBtn = getChild<LLButton>("up_btn");
mUpBtn->setEnabled(TRUE);
mUpBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onUpClicked, this));
//*TODO rename mLookContents to mOutfitContents
mLookContents = getChild<LLScrollListCtrl>("look_items_list");
mLookContents->sortByColumn("look_item_sort", TRUE);
mLookContents->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
mRemoveFromOutfitBtn = getChild<LLButton>("remove_from_outfit_btn"); mRemoveFromOutfitBtn = getChild<LLButton>("remove_from_outfit_btn");
mRemoveFromOutfitBtn->setEnabled(FALSE); mRemoveFromOutfitBtn->setEnabled(FALSE);
mRemoveFromOutfitBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this)); mRemoveFromOutfitBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this));
...@@ -245,7 +242,10 @@ BOOL LLPanelOutfitEdit::postBuild() ...@@ -245,7 +242,10 @@ BOOL LLPanelOutfitEdit::postBuild()
void LLPanelOutfitEdit::moveWearable(bool closer_to_body) void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
{ {
LLViewerInventoryItem* wearable_to_move = gInventory.getItem(mLookContents->getSelectionInterface()->getCurrentID()); LLUUID item_id = mCOFWearables->getSelectedUUID();
if (item_id.isNull()) return;
LLViewerInventoryItem* wearable_to_move = gInventory.getItem(item_id);
LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body); LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
//*TODO why not to listen to inventory? //*TODO why not to listen to inventory?
...@@ -374,7 +374,7 @@ void LLPanelOutfitEdit::onAddToOutfitClicked(void) ...@@ -374,7 +374,7 @@ void LLPanelOutfitEdit::onAddToOutfitClicked(void)
void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void) void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
{ {
LLUUID id_to_remove = mLookContents->getSelectionInterface()->getCurrentID(); LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove); LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
...@@ -384,41 +384,9 @@ void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void) ...@@ -384,41 +384,9 @@ void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
} }
void LLPanelOutfitEdit::onUpClicked(void)
{
LLUUID inv_id = mLookContents->getSelectionInterface()->getCurrentID();
if (inv_id.isNull())
{
//nothing selected, do nothing
return;
}
LLViewerInventoryItem *link_item = gInventory.getItem(inv_id);
if (!link_item)
{
llwarns << "could not find inventory item based on currently worn link." << llendl;
return;
}
LLUUID asset_id = link_item->getAssetUUID();
if (asset_id.isNull())
{
llwarns << "inventory link has null Asset ID. could not get object reference" << llendl;
}
static const std::string empty = "";
LLWearableList::instance().getAsset(asset_id,
empty, // don't care about wearable name
link_item->getActualType(),
LLSidepanelAppearance::editWearable,
(void*)getParentUICtrl());
}
void LLPanelOutfitEdit::onEditWearableClicked(void) void LLPanelOutfitEdit::onEditWearableClicked(void)
{ {
LLUUID id_to_edit = mLookContents->getSelectionInterface()->getCurrentID(); LLUUID id_to_edit = mCOFWearables->getSelectedUUID();
LLViewerInventoryItem * item_to_edit = gInventory.getItem(id_to_edit); LLViewerInventoryItem * item_to_edit = gInventory.getItem(id_to_edit);
if (item_to_edit) if (item_to_edit)
...@@ -491,29 +459,11 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView ...@@ -491,29 +459,11 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView
void LLPanelOutfitEdit::onOutfitItemSelectionChange(void) void LLPanelOutfitEdit::onOutfitItemSelectionChange(void)
{ {
LLScrollListItem* item = mLookContents->getLastSelectedItem(); LLUUID item_id = mCOFWearables->getSelectedUUID();
if (!item)
return;
LLRect item_rect; //*TODO show Edit Wearable Button
mLookContents->localRectToOtherView(item->getRect(), &item_rect, this);
// TODO button(and item list) should be removed (when new widget is ready) LLViewerInventoryItem* item_to_remove = gInventory.getItem(item_id);
LLRect btn_rect = mEditWearableBtn->getRect();
btn_rect.set(item_rect.mRight - btn_rect.getWidth(), item_rect.mTop, item_rect.mRight, item_rect.mBottom);
mEditWearableBtn->setShape(btn_rect);
sendChildToFront(mEditWearableBtn);
mEditWearableBtn->setEnabled(TRUE);
if (!mEditWearableBtn->getVisible())
{
mEditWearableBtn->setVisible(TRUE);
}
const LLUUID& id_item_to_remove = item->getUUID();
LLViewerInventoryItem* item_to_remove = gInventory.getItem(id_item_to_remove);
if (!item_to_remove) return; if (!item_to_remove) return;
switch (item_to_remove->getType()) switch (item_to_remove->getType())
...@@ -534,34 +484,7 @@ void LLPanelOutfitEdit::changed(U32 mask) ...@@ -534,34 +484,7 @@ void LLPanelOutfitEdit::changed(U32 mask)
void LLPanelOutfitEdit::lookFetched(void) void LLPanelOutfitEdit::lookFetched(void)
{ {
LLInventoryModel::cat_array_t cat_array; mCOFWearables->refresh();
LLInventoryModel::item_array_t item_array;
// collectDescendentsIf takes non-const reference:
LLFindCOFValidItems is_cof_valid;
gInventory.collectDescendentsIf(mCurrentOutfitID,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
is_cof_valid);
for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
iter != item_array.end();
iter++)
{
const LLViewerInventoryItem *item = (*iter);
LLSD row;
row["id"] = item->getUUID();
LLSD& columns = row["columns"];
columns[0]["column"] = "look_item";
columns[0]["type"] = "text";
columns[0]["value"] = item->getName();
columns[1]["column"] = "look_item_sort";
columns[1]["type"] = "text"; // TODO: multi-wearable sort "type" should go here.
columns[1]["value"] = item->LLInventoryItem::getDescription();
mLookContents->addElement(row);
}
updateVerbs(); updateVerbs();
} }
...@@ -570,8 +493,6 @@ void LLPanelOutfitEdit::updateLookInfo() ...@@ -570,8 +493,6 @@ void LLPanelOutfitEdit::updateLookInfo()
{ {
if (getVisible()) if (getVisible())
{ {
mLookContents->clearRows();
mFetchLook->setFetchID(mCurrentOutfitID); mFetchLook->setFetchID(mCurrentOutfitID);
mFetchLook->startFetch(); mFetchLook->startFetch();
if (mFetchLook->isFinished()) if (mFetchLook->isFinished())
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "llinventorymodel.h" #include "llinventorymodel.h"
class LLButton; class LLButton;
class LLCOFWearables;
class LLTextBox; class LLTextBox;
class LLInventoryCategory; class LLInventoryCategory;
class LLInventoryLookObserver; class LLInventoryLookObserver;
...@@ -102,7 +103,6 @@ class LLPanelOutfitEdit : public LLPanel ...@@ -102,7 +103,6 @@ class LLPanelOutfitEdit : public LLPanel
void onOutfitItemSelectionChange(void); void onOutfitItemSelectionChange(void);
void onRemoveFromOutfitClicked(void); void onRemoveFromOutfitClicked(void);
void onEditWearableClicked(void); void onEditWearableClicked(void);
void onUpClicked(void);
void displayCurrentOutfit(); void displayCurrentOutfit();
...@@ -118,14 +118,12 @@ class LLPanelOutfitEdit : public LLPanel ...@@ -118,14 +118,12 @@ class LLPanelOutfitEdit : public LLPanel
LLUUID mCurrentOutfitID; LLUUID mCurrentOutfitID;
LLTextBox* mCurrentOutfitName; LLTextBox* mCurrentOutfitName;
LLScrollListCtrl* mLookContents;
LLInventoryPanel* mInventoryItemsPanel; LLInventoryPanel* mInventoryItemsPanel;
LLFilterEditor* mSearchFilter; LLFilterEditor* mSearchFilter;
LLSaveFolderState* mSavedFolderState; LLSaveFolderState* mSavedFolderState;
std::string mSearchString; std::string mSearchString;
LLButton* mAddToOutfitBtn; LLButton* mAddToOutfitBtn;
LLButton* mRemoveFromOutfitBtn; LLButton* mRemoveFromOutfitBtn;
LLButton* mUpBtn;
LLButton* mEditWearableBtn; LLButton* mEditWearableBtn;
LLToggleableMenu* mSaveMenu; LLToggleableMenu* mSaveMenu;
...@@ -134,6 +132,8 @@ class LLPanelOutfitEdit : public LLPanel ...@@ -134,6 +132,8 @@ class LLPanelOutfitEdit : public LLPanel
LLLookFetchObserver* mFetchLook; LLLookFetchObserver* mFetchLook;
LLInventoryLookObserver* mLookObserver; LLInventoryLookObserver* mLookObserver;
std::vector<LLLookItemType> mLookItemTypes; std::vector<LLLookItemType> mLookItemTypes;
LLCOFWearables* mCOFWearables;
}; };
#endif // LL_LLPANELOUTFITEDIT_H #endif // LL_LLPANELOUTFITEDIT_H
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
background_visible="true"
bg_alpha_color="DkGray"
border="false"
bottom="0"
follows="all"
height="200"
left="0"
name="cof_wearables"
width="313">
<accordion
follows="all"
height="373"
layout="topleft"
left="3"
top="0"
name="cof_wearables_accordion"
background_visible="true"
bg_alpha_color="DkGray2"
width="307">
<accordion_tab
layout="topleft"
name="tab_attachments"
title="Attachments">
<flat_list_view
allow_select="true"
follows="all"
height="150"
layout="topleft"
left="0"
name="list_attachments"
top="0"
width="307" />
</accordion_tab>
<accordion_tab
layout="topleft"
name="tab_clothing"
title="Clothing">
<flat_list_view
allow_select="true"
follows="all"
height="150"
layout="topleft"
left="0"
name="list_clothing"
top="0"
width="307" />
</accordion_tab>
<accordion_tab
layout="topleft"
name="tab_body_parts"
title="Body Parts">
<flat_list_view
allow_select="true"
follows="all"
height="150"
layout="topleft"
left="0"
name="list_body_parts"
top="0"
width="307" />
</accordion_tab>
</accordion>
</panel>
...@@ -149,29 +149,18 @@ ...@@ -149,29 +149,18 @@
auto_resize="true" auto_resize="true"
user_resize="true"> user_resize="true">
<scroll_list <!-- List containing items from the COF and Base outfit -->
width="300" <panel
column_padding="0" background_visible="false"
draw_heading="false" class="cof_wearables"
draw_stripes="false" filename="panel_cof_wearables.xml"
follows="left|top|right|bottom" follows="left|top|right|bottom"
height="193"
layout="topleft" layout="topleft"
name="look_items_list"
search_column="1"
sort_column="2"
left="0" left="0"
height="193" name="cof_wearables_list"
top="0"> top="0"
<scroll_list.columns width="300" />
label="Look Item"
name="look_item"
width="285" />
<scroll_list.columns
label="Outfit Item Sort"
width="0"
sort_column="look_item_sort"
name="look_item_sort" />
</scroll_list>
<panel <panel
background_visible="true" background_visible="true"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment