summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llfloatergesture.cpp313
-rw-r--r--indra/newview/llfloatergesture.h42
-rw-r--r--indra/newview/skins/default/xui/en/floater_gesture.xml12
-rw-r--r--indra/newview/skins/default/xui/en/menu_gesture_gear.xml75
4 files changed, 350 insertions, 92 deletions
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index af86274472..0f8e4c10d7 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -34,32 +34,24 @@
#include "llfloatergesture.h"
-#include "lldir.h"
#include "llinventory.h"
-#include "llmultigesture.h"
+#include "llinventorybridge.h"
+#include "llinventorymodel.h"
+#include "llinventoryclipboard.h"
#include "llagent.h"
-#include "llviewerwindow.h"
-#include "llbutton.h"
-#include "llcombobox.h"
+#include "llappearancemgr.h"
+#include "llclipboard.h"
#include "llgesturemgr.h"
-#include "llinventorymodel.h"
-#include "llinventorypanel.h"
-#include "llfloaterinventory.h"
#include "llkeyboard.h"
-#include "lllineeditor.h"
+#include "llmenugl.h"
+#include "llmultigesture.h"
#include "llpreviewgesture.h"
-#include "llresizehandle.h"
-#include "llscrollbar.h"
-#include "llscrollcontainer.h"
#include "llscrolllistctrl.h"
-#include "lltextbox.h"
#include "lltrans.h"
-#include "lluictrlfactory.h"
#include "llviewergesture.h"
-#include "llviewertexturelist.h"
+#include "llviewermenu.h"
#include "llviewerinventory.h"
-#include "llvoavatar.h"
#include "llviewercontrol.h"
BOOL item_name_precedes( LLInventoryItem* a, LLInventoryItem* b )
@@ -77,6 +69,35 @@ public:
private:
LLFloaterGesture* mFloater;
};
+//-----------------------------
+// GestureCallback
+//-----------------------------
+
+class GestureShowCallback : public LLInventoryCallback
+{
+public:
+ void fire(const LLUUID &inv_item)
+ {
+ LLPreviewGesture::show(inv_item, LLUUID::null);
+ }
+};
+
+class GestureCopiedCallback : public LLInventoryCallback
+{
+private:
+ LLFloaterGesture* mFloater;
+
+public:
+ GestureCopiedCallback(LLFloaterGesture* floater): mFloater(floater)
+ {}
+ void fire(const LLUUID &inv_item)
+ {
+ if(mFloater)
+ {
+ mFloater->addGesture(inv_item,NULL,mFloater->getChild<LLScrollListCtrl>("gesture_list"));
+ }
+ }
+};
//---------------------------------------------------------------------------
// LLFloaterGesture
@@ -86,7 +107,13 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key)
{
mObserver = new LLFloaterGestureObserver(this);
LLGestureManager::instance().addObserver(mObserver);
- //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_gesture.xml");
+
+ mCommitCallbackRegistrar.add("Gesture.Action.ToogleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.CopyPast", boost::bind(&LLFloaterGesture::onCopyPastAction, this, _2));
+ mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this));
+
+ mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2));
}
void LLFloaterGesture::done()
@@ -151,19 +178,18 @@ BOOL LLFloaterGesture::postBuild()
label = getTitle();
setTitle(label);
-
- getChild<LLUICtrl>("gesture_list")->setCommitCallback(boost::bind(&LLFloaterGesture::onCommitList, this));
- getChild<LLScrollListCtrl>("gesture_list")->setDoubleClickCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
-
- getChild<LLUICtrl>("inventory_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickInventory, this));
+ mGestureList = getChild<LLScrollListCtrl>("gesture_list");
+ mGestureList->setCommitCallback(boost::bind(&LLFloaterGesture::onCommitList, this));
+ mGestureList->setDoubleClickCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
getChild<LLUICtrl>("edit_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickEdit, this));
getChild<LLUICtrl>("play_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
getChild<LLUICtrl>("stop_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
getChild<LLButton>("activate_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
-
+
getChild<LLUICtrl>("new_gesture_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickNew, this));
+ getChild<LLButton>("del_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onDeleteSelected, this));
childSetVisible("play_btn", true);
childSetVisible("stop_btn", false);
@@ -178,14 +204,13 @@ BOOL LLFloaterGesture::postBuild()
buildGestureList();
- childSetFocus("gesture_list");
+ mGestureList->setFocus(TRUE);
- LLCtrlListInterface *list = getGestureList();
- if (list)
+ if (mGestureList)
{
const BOOL ascending = TRUE;
- list->sortByColumn(std::string("name"), ascending);
- list->selectFirstItem();
+ mGestureList->sortByColumn(std::string("name"), ascending);
+ mGestureList->selectFirstItem();
}
// Update button labels
@@ -199,18 +224,17 @@ void LLFloaterGesture::refreshAll()
{
buildGestureList();
- LLCtrlListInterface *list = getGestureList();
- if (!list) return;
+ if (!mGestureList) return;
if (mSelectedID.isNull())
{
- list->selectFirstItem();
+ mGestureList->selectFirstItem();
}
else
{
- if (! list->setCurrentByID(mSelectedID))
+ if (! mGestureList->setCurrentByID(mSelectedID))
{
- list->selectFirstItem();
+ mGestureList->selectFirstItem();
}
}
@@ -220,20 +244,16 @@ void LLFloaterGesture::refreshAll()
void LLFloaterGesture::buildGestureList()
{
- LLCtrlListInterface *list = getGestureList();
- LLCtrlScrollInterface *scroll = childGetScrollInterface("gesture_list");
-
- if (! (list && scroll)) return;
-
- LLUUID selected_item = list->getCurrentID();
+ std::vector<LLUUID> selected_items;
+ getSelectedIds(selected_items);
LL_DEBUGS("Gesture")<< "Rebuilding gesture list "<< LL_ENDL;
- list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+ mGestureList->deleteAllItems();
LLGestureManager::item_map_t::const_iterator it;
const LLGestureManager::item_map_t& active_gestures = LLGestureManager::instance().getActiveGestures();
for (it = active_gestures.begin(); it != active_gestures.end(); ++it)
{
- addGesture(it->first,it->second, list);
+ addGesture(it->first,it->second, mGestureList);
}
if (gInventory.isCategoryComplete(mGestureFolderID))
{
@@ -249,16 +269,17 @@ void LLFloaterGesture::buildGestureList()
if (active_gestures.find(item->getUUID()) == active_gestures.end())
{
// if gesture wasn't loaded yet, we can display only name
- addGesture(item->getUUID(), NULL, list);
+ addGesture(item->getUUID(), NULL, mGestureList);
}
}
}
// attempt to preserve scroll position through re-builds
// since we do re-build any time anything dirties
- if(list->selectByValue(LLSD(selected_item)))
+ for(std::vector<LLUUID>::iterator it = selected_items.begin(); it != selected_items.end(); it++)
{
- scroll->scrollToShowSelected();
+ mGestureList->selectByID(*it);
}
+ mGestureList->scrollToShowSelected();
}
void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gesture,LLCtrlListInterface * list )
@@ -346,33 +367,59 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur
list->addElement(element, ADD_BOTTOM);
}
-void LLFloaterGesture::onClickInventory()
+void LLFloaterGesture::getSelectedIds(std::vector<LLUUID>& ids)
+{
+ std::vector<LLScrollListItem*> items = mGestureList->getAllSelected();
+ for(std::vector<LLScrollListItem*>::const_iterator it = items.begin(); it != items.end(); it++)
+ {
+ ids.push_back((*it)->getUUID());
+ }
+}
+
+bool LLFloaterGesture::isActionEnabled(const LLSD& command)
{
- LLCtrlListInterface *list = getGestureList();
- if (!list) return;
- const LLUUID& item_id = list->getCurrentID();
+ // paste copy_uuid edit_gesture
+ std::string command_name = command.asString();
+ if("paste" == command_name)
+ {
+ if(!LLInventoryClipboard::instance().hasContents())
+ return false;
- LLFloaterInventory* inv = LLFloaterInventory::showAgentInventory();
- if (!inv) return;
- inv->getPanel()->setSelection(item_id, TRUE);
+ LLDynamicArray<LLUUID> ids;
+ LLInventoryClipboard::instance().retrieve(ids);
+ for(LLDynamicArray<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+
+ if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if("copy_uuid" == command_name || "edit_gesture" == command_name
+ || "inspect" == command_name)
+ {
+ return mGestureList->getAllSelected().size() == 1;
+ }
+ return true;
}
void LLFloaterGesture::onClickPlay()
{
- LLCtrlListInterface *list = getGestureList();
- if (!list) return;
- const LLUUID& item_id = list->getCurrentID();
+ const LLUUID& item_id = mGestureList->getCurrentID();
if(item_id.isNull()) return;
LL_DEBUGS("Gesture")<<" Trying to play gesture id: "<< item_id <<LL_ENDL;
if(!LLGestureManager::instance().isGestureActive(item_id))
{
- // we need to inform server about gesture activating to be consistent with LLPreviewGesture.
+ // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboBox.
BOOL inform_server = TRUE;
BOOL deactivate_similar = FALSE;
+ LLGestureManager::instance().setGestureLoadedCallback(item_id, boost::bind(&LLFloaterGesture::playGesture, this, item_id));
LLGestureManager::instance().activateGestureWithAsset(item_id, gInventory.getItem(item_id)->getAssetUUID(), inform_server, deactivate_similar);
LL_DEBUGS("Gesture")<< "Activating gesture with inventory ID: " << item_id <<LL_ENDL;
- LLGestureManager::instance().setGestureLoadedCallback(item_id, boost::bind(&LLFloaterGesture::playGesture, this, item_id));
}
else
{
@@ -380,15 +427,6 @@ void LLFloaterGesture::onClickPlay()
}
}
-class GestureShowCallback : public LLInventoryCallback
-{
-public:
- void fire(const LLUUID &inv_item)
- {
- LLPreviewGesture::show(inv_item, LLUUID::null);
- }
-};
-
void LLFloaterGesture::onClickNew()
{
LLPointer<LLInventoryCallback> cb = new GestureShowCallback();
@@ -399,27 +437,96 @@ void LLFloaterGesture::onClickNew()
void LLFloaterGesture::onActivateBtnClick()
{
- LLCtrlListInterface* list = getGestureList();
-
- LLUUID gesture_inv_id = list->getSelectedValue();
+ std::vector<LLUUID> ids;
+ getSelectedIds(ids);
+ if(ids.empty())
+ return;
+
LLGestureManager* gm = LLGestureManager::getInstance();
-
- if(gm->isGestureActive(gesture_inv_id))
+ std::vector<LLUUID>::const_iterator it = ids.begin();
+ BOOL first_gesture_state = gm->isGestureActive(*it);
+ BOOL is_mixed = FALSE;
+ while( ++it != ids.end() )
{
- gm->deactivateGesture(gesture_inv_id);
+ if(first_gesture_state != gm->isGestureActive(*it))
+ {
+ is_mixed = TRUE;
+ break;
+ }
}
- else
+ for(std::vector<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); it++)
{
- gm->activateGesture(gesture_inv_id);
+ if(is_mixed)
+ {
+ gm->activateGesture(*it);
+ }
+ else
+ {
+ if(first_gesture_state)
+ {
+ gm->deactivateGesture(*it);
+ }
+ else
+ {
+ gm->activateGesture(*it);
+ }
+ }
}
}
+void LLFloaterGesture::onCopyPastAction(const LLSD& command)
+{
+ std::string command_name = command.asString();
+ // since we select this comman inventory item had already arrived .
+ if("copy_gesture" == command_name)
+ {
+ std::vector<LLUUID> ids;
+ getSelectedIds(ids);
+ // make sure that clopboard is empty
+ LLInventoryClipboard::instance().reset();
+ for(std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+ if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ LLInventoryClipboard::instance().add(item->getUUID());
+ }
+ }
+ }
+ else if ("paste" == command_name)
+ {
+ LLInventoryClipboard& clipbord = LLInventoryClipboard::instance();
+ LLDynamicArray<LLUUID> ids;
+ clipbord.retrieve(ids);
+ if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID))
+ return;
+ LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID);
+ LLPointer<GestureCopiedCallback> cb = new GestureCopiedCallback(this);
+
+ for(LLDynamicArray<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+ LLStringUtil::format_map_t string_args;
+ string_args["[COPY_NAME]"] = item->getName();
+ if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ LL_DEBUGS("Gesture")<< "Copying gesture " << item->getName() << " "<< item->getUUID() << " into "
+ << gesture_dir->getName() << " "<< gesture_dir->getUUID() << LL_ENDL;
+ copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(),
+ gesture_dir->getUUID(), getString("copy_name", string_args), cb);
+ }
+ }
+ clipbord.reset();
+ }
+ else if ("copy_uuid" == command_name)
+ {
+ gClipboard.copyFromString(utf8str_to_wstring(mGestureList->getCurrentID().asString()), mGestureList->getCurrentID());
+ }
+}
void LLFloaterGesture::onClickEdit()
{
- LLCtrlListInterface *list = getGestureList();
- if (!list) return;
- const LLUUID& item_id = list->getCurrentID();
+ const LLUUID& item_id = mGestureList->getCurrentID();
LLInventoryItem* item = gInventory.getItem(item_id);
if (!item) return;
@@ -433,7 +540,7 @@ void LLFloaterGesture::onClickEdit()
void LLFloaterGesture::onCommitList()
{
- const LLUUID& item_id = childGetValue("gesture_list").asUUID();
+ const LLUUID& item_id = mGestureList->getCurrentID();
mSelectedID = item_id;
if (LLGestureManager::instance().isGesturePlaying(item_id))
@@ -447,8 +554,60 @@ void LLFloaterGesture::onCommitList()
childSetVisible("stop_btn", false);
}
}
+
+void LLFloaterGesture::onDeleteSelected()
+{
+ std::vector<LLUUID> ids;
+ getSelectedIds(ids);
+ if(ids.empty())
+ return;
+
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLGestureManager* gm = LLGestureManager::getInstance();
+ for(std::vector<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ const LLUUID& selected_item = *it;
+ LLInventoryItem* inv_item = gInventory.getItem(selected_item);
+ if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ if(gm->isGestureActive(selected_item))
+ {
+ gm->deactivateGesture(selected_item);
+ }
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
+ new_item->setParent(trash_id);
+ // no need to restamp it though it's a move into trash because
+ // it's a brand new item already.
+ new_item->updateParentOnServer(FALSE);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
+ buildGestureList();
+}
+
+void LLFloaterGesture::addToCurrentOutFit()
+{
+ std::vector<LLUUID> ids;
+ getSelectedIds(ids);
+ LLAppearanceManager* am = LLAppearanceManager::getInstance();
+ for(std::vector<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ am->addCOFItemLink(*it);
+ }
+}
+
void LLFloaterGesture::playGesture(LLUUID item_id)
{
+ LL_DEBUGS("Gesture")<<"Playing gesture "<< item_id<<LL_ENDL;
+
if (LLGestureManager::instance().isGesturePlaying(item_id))
{
LLGestureManager::instance().stopGesture(item_id);
diff --git a/indra/newview/llfloatergesture.h b/indra/newview/llfloatergesture.h
index 50bef818da..14e132900d 100644
--- a/indra/newview/llfloatergesture.h
+++ b/indra/newview/llfloatergesture.h
@@ -36,11 +36,10 @@
#ifndef LL_LLFLOATERGESTURE_H
#define LL_LLFLOATERGESTURE_H
+#include <vector>
#include "llfloater.h"
-#include "llinventorymodel.h"
#include "llinventoryobserver.h"
-#include "lldarray.h"
class LLScrollContainer;
class LLView;
@@ -53,6 +52,7 @@ class LLScrollListCtrl;
class LLFloaterGestureObserver;
class LLFloaterGestureInventoryObserver;
class LLMultiGesture;
+class LLMenuGL;
class LLFloaterGesture
: public LLFloater, LLInventoryFetchDescendentsObserver
@@ -65,26 +65,46 @@ public:
virtual BOOL postBuild();
virtual void done ();
void refreshAll();
+ /**
+ * @brief Add new scrolllistitem into gesture_list.
+ * @param item_id inventory id of gesture
+ * @param gesture can be NULL , if item was not loaded yet
+ */
+ void addGesture(const LLUUID& item_id, LLMultiGesture* gesture, LLCtrlListInterface * list);
protected:
// Reads from the gesture manager's list of active gestures
// and puts them in this list.
void buildGestureList();
- void addGesture(const LLUUID& item_id, LLMultiGesture* gesture, LLCtrlListInterface * list);
- void onClickInventory();
+ void playGesture(LLUUID item_id);
+private:
+ void addToCurrentOutFit();
+ /**
+ * @brief This method is using to collect selected items.
+ * In some places gesture_list can be rebuilt by gestureObservers during iterating data from LLScrollListCtrl::getAllSelected().
+ * Therefore we have to copy these items to avoid viewer crash.
+ * @see LLFloaterGesture::onActivateBtnClick
+ */
+ void getSelectedIds(std::vector<LLUUID>& ids);
+ bool isActionEnabled(const LLSD& command);
+ /**
+ * @brief Activation rules:
+ * According to Gesture Spec:
+ * 1. If all selected gestures are active: set to inactive
+ * 2. If all selected gestures are inactive: set to active
+ * 3. If selected gestures are in a mixed state: set all to active
+ */
+ void onActivateBtnClick();
void onClickEdit();
void onClickPlay();
void onClickNew();
void onCommitList();
- void playGesture(LLUUID item_id);
- LLCtrlListInterface* getGestureList() const
- {
- return childGetListInterface("gesture_list");
- }
- void onActivateBtnClick();
-protected:
+ void onCopyPastAction(const LLSD& command);
+ void onDeleteSelected();
+
LLUUID mSelectedID;
LLUUID mGestureFolderID;
+ LLScrollListCtrl* mGestureList;
LLFloaterGestureObserver* mObserver;
};
diff --git a/indra/newview/skins/default/xui/en/floater_gesture.xml b/indra/newview/skins/default/xui/en/floater_gesture.xml
index 21d292847a..9f5e6828d2 100644
--- a/indra/newview/skins/default/xui/en/floater_gesture.xml
+++ b/indra/newview/skins/default/xui/en/floater_gesture.xml
@@ -21,12 +21,16 @@
name="playing">
(Playing)
</floater.string>
+ <!-- It's used to build new name for gesture created by "Copy" menu item -->
+ <floater.string
+ name="copy_name">Copy of [COPY_NAME]</floater.string>
<scroll_list
bottom_delta="400"
draw_heading="true"
follows="all"
layout="topleft"
left="0"
+ multi_select="true"
top="20"
name="gesture_list">
<scroll_list.columns
@@ -57,18 +61,18 @@
left="0"
name="bottom_panel"
width="313">
- <button
+ <menu_button
follows="bottom|left"
- font="SansSerifBigBold"
- tool_tip="Change sort and view of recent residents list"
height="18"
image_disabled="OptionsMenu_Disabled"
image_selected="OptionsMenu_Press"
image_unselected="OptionsMenu_Off"
layout="topleft"
left="10"
- name="recent_viewsort_btn"
+ menu_filename="menu_gesture_gear.xml"
+ name="gear_btn"
top="5"
+ tool_tip="More options"
width="18" />
<button
follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
new file mode 100644
index 0000000000..4642e82c0b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ mouse_opaque="false"
+ name="menu_gesture_gear"
+ visible="false">
+ <menu_item_call
+ font="SansSerifBold"
+ label="Add/Remove from Favorites"
+ layout="topleft"
+ name="activate">
+ <on_click
+ function="Gesture.Action.ToogleActiveState" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy"
+ layout="topleft"
+ name="copy_gesture">
+ <on_click
+ function="Gesture.Action.CopyPast"
+ parameter="copy_gesture" />
+ <on_enable
+ function="Gesture.EnableAction"
+ parameter="copy_gesture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste"
+ layout="topleft"
+ name="paste">
+ <on_click
+ function="Gesture.Action.CopyPast"
+ parameter="paste" />
+ <on_enable
+ function="Gesture.EnableAction"
+ parameter="paste" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy UUID"
+ layout="topleft"
+ name="copy_uuid">
+ <on_click
+ function="Gesture.Action.CopyPast"
+ parameter="copy_uuid" />
+ <on_enable
+ function="Gesture.EnableAction"
+ parameter="copy_uuid" />
+ </menu_item_call>
+ <menu_item_call
+ label="Save to current outfit"
+ layout="topleft"
+ name="save_to_outfit">
+ <on_click
+ function="Gesture.Action.SaveToCOF" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit_gesture">
+ <on_click
+ function="Gesture.Action.ShowPreview" />
+ <on_enable
+ function="Gesture.EnableAction"
+ parameter="edit_gesture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Inspect"
+ layout="topleft"
+ name="inspect">
+ <on_click
+ function="Gesture.Action.ShowPreview" />
+ <on_enable
+ function="Gesture.EnableAction"
+ parameter="inspect" />
+ </menu_item_call>
+</menu>