diff options
Diffstat (limited to 'indra/newview/llpreviewgesture.cpp')
-rw-r--r-- | indra/newview/llpreviewgesture.cpp | 3632 |
1 files changed, 1816 insertions, 1816 deletions
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 010dc48391..56f23a0458 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -1,1816 +1,1816 @@ -/**
- * @file llpreviewgesture.cpp
- * @brief Editing UI for inventory-based gestures.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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 "llpreviewgesture.h"
-
-#include "llagent.h"
-#include "llanimstatelabels.h"
-#include "llanimationstates.h"
-#include "llappviewer.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
-#include "lldatapacker.h"
-#include "lldelayedgestureerror.h"
-#include "llfloaterreg.h"
-#include "llgesturemgr.h"
-#include "llinventorydefines.h"
-#include "llinventoryfunctions.h"
-#include "llinventorymodel.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llkeyboard.h"
-#include "llmultigesture.h"
-#include "llnotificationsutil.h"
-#include "llradiogroup.h"
-#include "llresmgr.h"
-#include "lltrans.h"
-#include "llfilesystem.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerassetupload.h"
-
-std::string NONE_LABEL;
-std::string SHIFT_LABEL;
-std::string CTRL_LABEL;
-
-void dialog_refresh_all();
-
-// used for getting
-
-class LLInventoryGestureAvailable : public LLInventoryCompletionObserver
-{
-public:
- LLInventoryGestureAvailable() {}
-
-protected:
- virtual void done();
-};
-
-void LLInventoryGestureAvailable::done()
-{
- for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it)
- {
- LLPreviewGesture* preview = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *it);
- if(preview)
- {
- preview->refresh();
- }
- }
- gInventory.removeObserver(this);
- delete this;
-}
-
-// Used for sorting
-struct SortItemPtrsByName
-{
- bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
- {
- return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0);
- }
-};
-
-// static
-LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id)
-{
- LLPreviewGesture* preview = LLFloaterReg::showTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES);
- if (!preview)
- {
- return NULL;
- }
-
- preview->setObjectID(object_id);
-
- // Start speculative download of sounds and animations
- const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
- LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);
-
- const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
- LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);
-
- // this will call refresh when we have everything.
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem();
- if (item && !item->isFinished())
- {
- LLInventoryGestureAvailable* observer;
- observer = new LLInventoryGestureAvailable();
- observer->watchItem(item_id);
- gInventory.addObserver(observer);
- item->fetchFromServer();
- }
- else
- {
- // not sure this is necessary.
- preview->refresh();
- }
-
- return preview;
-}
-
-void LLPreviewGesture::draw()
-{
- // Skip LLPreview::draw() to avoid description update
- LLFloater::draw();
-}
-
-// virtual
-bool LLPreviewGesture::handleKeyHere(KEY key, MASK mask)
-{
- if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
- {
- saveIfNeeded();
- return true;
- }
-
- return LLPreview::handleKeyHere(key, mask);
-}
-
-
-// virtual
-bool LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- bool handled = true;
- switch(cargo_type)
- {
- case DAD_ANIMATION:
- case DAD_SOUND:
- {
- // TODO: Don't allow this if you can't transfer the sound/animation
-
- // make a script step
- LLInventoryItem* item = (LLInventoryItem*)cargo_data;
- if (item
- && gInventory.getItem(item->getUUID()))
- {
- LLPermissions perm = item->getPermissions();
- if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED))
- {
- *accept = ACCEPT_NO;
- if (tooltip_msg.empty())
- {
- tooltip_msg.assign("Only animations and sounds\n"
- "with unrestricted permissions\n"
- "can be added to a gesture.");
- }
- break;
- }
- else if (drop)
- {
- LLScrollListItem* line = NULL;
- if (cargo_type == DAD_ANIMATION)
- {
- line = addStep( STEP_ANIMATION );
- LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata();
- anim->mAnimAssetID = item->getAssetUUID();
- anim->mAnimName = item->getName();
- }
- else if (cargo_type == DAD_SOUND)
- {
- line = addStep( STEP_SOUND );
- LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata();
- sound->mSoundAssetID = item->getAssetUUID();
- sound->mSoundName = item->getName();
- }
- updateLabel(line);
- mDirty = true;
- refresh();
- }
- *accept = ACCEPT_YES_COPY_MULTI;
- }
- else
- {
- // Not in user's inventory means it was in object inventory
- *accept = ACCEPT_NO;
- }
- break;
- }
- default:
- *accept = ACCEPT_NO;
- if (tooltip_msg.empty())
- {
- tooltip_msg.assign("Only animations and sounds\n"
- "can be added to a gesture.");
- }
- break;
- }
- return handled;
-}
-
-
-// virtual
-bool LLPreviewGesture::canClose()
-{
-
- if(!mDirty || mForceClose)
- {
- return true;
- }
- else
- {
- if(!mSaveDialogShown)
- {
- mSaveDialogShown = true;
- // Bring up view-modal dialog: Save changes? Yes, No, Cancel
- LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(),
- boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) );
- }
- return false;
- }
-}
-
-// virtual
-void LLPreviewGesture::onClose(bool app_quitting)
-{
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
-}
-
-// virtual
-void LLPreviewGesture::onUpdateSucceeded()
-{
- refresh();
-}
-
-void LLPreviewGesture::onVisibilityChanged ( const LLSD& new_visibility )
-{
- if (new_visibility.asBoolean())
- {
- refresh();
- }
-}
-
-
-bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
-{
- mSaveDialogShown = false;
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- switch(option)
- {
- case 0: // "Yes"
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
- mCloseAfterSave = true;
- onClickSave(this);
- break;
-
- case 1: // "No"
- LLGestureMgr::instance().stopGesture(mPreviewGesture);
- mDirty = false; // Force the dirty flag because user has clicked NO on confirm save dialog...
- closeFloater();
- break;
-
- case 2: // "Cancel"
- default:
- // If we were quitting, we didn't really mean it.
- LLAppViewer::instance()->abortQuit();
- break;
- }
- return false;
-}
-
-
-LLPreviewGesture::LLPreviewGesture(const LLSD& key)
-: LLPreview(key),
- mTriggerEditor(NULL),
- mModifierCombo(NULL),
- mKeyCombo(NULL),
- mLibraryList(NULL),
- mAddBtn(NULL),
- mUpBtn(NULL),
- mDownBtn(NULL),
- mDeleteBtn(NULL),
- mStepList(NULL),
- mOptionsText(NULL),
- mAnimationRadio(NULL),
- mAnimationCombo(NULL),
- mSoundCombo(NULL),
- mChatEditor(NULL),
- mSaveBtn(NULL),
- mPreviewBtn(NULL),
- mPreviewGesture(NULL),
- mDirty(false)
-{
- NONE_LABEL = LLTrans::getString("---");
- SHIFT_LABEL = LLTrans::getString("KBShift");
- CTRL_LABEL = LLTrans::getString("KBCtrl");
-}
-
-
-LLPreviewGesture::~LLPreviewGesture()
-{
- // Userdata for all steps is a LLGestureStep we need to clean up
- std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
- std::vector<LLScrollListItem*>::iterator data_itor;
- for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
- {
- LLScrollListItem* item = *data_itor;
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
- delete step;
- step = NULL;
- }
-}
-
-
-bool LLPreviewGesture::postBuild()
-{
- setVisibleCallback(boost::bind(&LLPreviewGesture::onVisibilityChanged, this, _2));
-
- LLLineEditor* edit;
- LLComboBox* combo;
- LLButton* btn;
- LLScrollListCtrl* list;
- LLTextBox* text;
- LLCheckBoxCtrl* check;
-
- edit = getChild<LLLineEditor>("desc");
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
-
- edit = getChild<LLLineEditor>("trigger_editor");
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitCallback(onCommitSetDirty, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mTriggerEditor = edit;
-
- text = getChild<LLTextBox>("replace_text");
- text->setEnabled(false);
- mReplaceText = text;
-
- edit = getChild<LLLineEditor>("replace_editor");
- edit->setEnabled(false);
- edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitCallback(onCommitSetDirty, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mReplaceEditor = edit;
-
- combo = getChild<LLComboBox>( "modifier_combo");
- combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
- mModifierCombo = combo;
-
- combo = getChild<LLComboBox>( "key_combo");
- combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
- mKeyCombo = combo;
-
- list = getChild<LLScrollListCtrl>("library_list");
- list->setCommitCallback(onCommitLibrary, this);
- list->setDoubleClickCallback(onClickAdd, this);
- mLibraryList = list;
-
- btn = getChild<LLButton>( "add_btn");
- btn->setClickedCallback(onClickAdd, this);
- btn->setEnabled(false);
- mAddBtn = btn;
-
- btn = getChild<LLButton>( "up_btn");
- btn->setClickedCallback(onClickUp, this);
- btn->setEnabled(false);
- mUpBtn = btn;
-
- btn = getChild<LLButton>( "down_btn");
- btn->setClickedCallback(onClickDown, this);
- btn->setEnabled(false);
- mDownBtn = btn;
-
- btn = getChild<LLButton>( "delete_btn");
- btn->setClickedCallback(onClickDelete, this);
- btn->setEnabled(false);
- mDeleteBtn = btn;
-
- list = getChild<LLScrollListCtrl>("step_list");
- list->setCommitCallback(onCommitStep, this);
- mStepList = list;
-
- // Options
- mOptionsText = getChild<LLTextBox>("options_text");
-
- combo = getChild<LLComboBox>( "animation_list");
- combo->setVisible(false);
- combo->setCommitCallback(onCommitAnimation, this);
- mAnimationCombo = combo;
-
- LLRadioGroup* group;
- group = getChild<LLRadioGroup>("animation_trigger_type");
- group->setVisible(false);
- group->setCommitCallback(onCommitAnimationTrigger, this);
- mAnimationRadio = group;
-
- combo = getChild<LLComboBox>( "sound_list");
- combo->setVisible(false);
- combo->setCommitCallback(onCommitSound, this);
- mSoundCombo = combo;
-
- edit = getChild<LLLineEditor>("chat_editor");
- edit->setVisible(false);
- edit->setCommitCallback(onCommitChat, this);
- //edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitOnFocusLost(true);
- edit->setIgnoreTab(true);
- mChatEditor = edit;
-
- check = getChild<LLCheckBoxCtrl>( "wait_key_release_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitKeyReleaseCheck = check;
-
- check = getChild<LLCheckBoxCtrl>( "wait_anim_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitAnimCheck = check;
-
- check = getChild<LLCheckBoxCtrl>( "wait_time_check");
- check->setVisible(false);
- check->setCommitCallback(onCommitWait, this);
- mWaitTimeCheck = check;
-
- edit = getChild<LLLineEditor>("wait_time_editor");
- edit->setEnabled(false);
- edit->setVisible(false);
- edit->setPrevalidate(LLTextValidate::validateFloat);
-// edit->setKeystrokeCallback(onKeystrokeCommit, this);
- edit->setCommitOnFocusLost(true);
- edit->setCommitCallback(onCommitWaitTime, this);
- edit->setIgnoreTab(true);
- mWaitTimeEditor = edit;
-
- // Buttons at the bottom
- check = getChild<LLCheckBoxCtrl>( "active_check");
- check->setCommitCallback(onCommitActive, this);
- mActiveCheck = check;
-
- btn = getChild<LLButton>( "save_btn");
- btn->setClickedCallback(onClickSave, this);
- mSaveBtn = btn;
-
- btn = getChild<LLButton>( "preview_btn");
- btn->setClickedCallback(onClickPreview, this);
- mPreviewBtn = btn;
-
-
- // Populate the comboboxes
- addModifiers();
- addKeys();
- addAnimations();
- addSounds();
-
- const LLInventoryItem* item = getItem();
-
- if (item)
- {
- getChild<LLUICtrl>("desc")->setValue(item->getDescription());
- getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- }
-
- return LLPreview::postBuild();
-}
-
-
-void LLPreviewGesture::addModifiers()
-{
- LLComboBox* combo = mModifierCombo;
-
- combo->add( NONE_LABEL, ADD_BOTTOM );
- combo->add( SHIFT_LABEL, ADD_BOTTOM );
- combo->add( CTRL_LABEL, ADD_BOTTOM );
- combo->setCurrentByIndex(0);
-}
-
-void LLPreviewGesture::addKeys()
-{
- LLComboBox* combo = mKeyCombo;
-
- combo->add( NONE_LABEL );
- for (KEY key = KEY_F2; key <= KEY_F12; key++)
- {
- combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM );
- }
- combo->setCurrentByIndex(0);
-}
-
-
-// TODO: Sort the legacy and non-legacy together?
-void LLPreviewGesture::addAnimations()
-{
- LLComboBox* combo = mAnimationCombo;
-
- combo->removeall();
-
- std::string none_text = getString("none_text");
-
- combo->add(none_text, LLUUID::null);
-
- // Add all the default (legacy) animations
- S32 i;
- for (i = 0; i < gUserAnimStatesCount; ++i)
- {
- // Use the user-readable name
- std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName );
- const LLUUID& id = gUserAnimStates[i].mID;
- combo->add(label, id);
- }
-
- // Get all inventory items that are animations
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
- PERM_ITEM_UNRESTRICTED,
- gAgent.getID(),
- gAgent.getGroupID());
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_copyable_animation);
-
- // Copy into something we can sort
- std::vector<LLInventoryItem*> animations;
-
- S32 count = items.size();
- for(i = 0; i < count; ++i)
- {
- animations.push_back( items.at(i) );
- }
-
- // Do the sort
- std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
-
- // And load up the combobox
- std::vector<LLInventoryItem*>::iterator it;
- for (it = animations.begin(); it != animations.end(); ++it)
- {
- LLInventoryItem* item = *it;
-
- combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
- }
-}
-
-
-void LLPreviewGesture::addSounds()
-{
- LLComboBox* combo = mSoundCombo;
- combo->removeall();
-
- std::string none_text = getString("none_text");
-
- combo->add(none_text, LLUUID::null);
-
- // Get all inventory items that are sounds
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
- PERM_ITEM_UNRESTRICTED,
- gAgent.getID(),
- gAgent.getGroupID());
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_copyable_sound);
-
- // Copy sounds into something we can sort
- std::vector<LLInventoryItem*> sounds;
-
- S32 i;
- S32 count = items.size();
- for(i = 0; i < count; ++i)
- {
- sounds.push_back( items.at(i) );
- }
-
- // Do the sort
- std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
-
- // And load up the combobox
- std::vector<LLInventoryItem*>::iterator it;
- for (it = sounds.begin(); it != sounds.end(); ++it)
- {
- LLInventoryItem* item = *it;
-
- combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
- }
-}
-
-
-void LLPreviewGesture::refresh()
-{
- LLPreview::refresh();
- // If previewing or item is incomplete, all controls are disabled
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
- bool is_complete = item && item->isFinished();
- if (mPreviewGesture || !is_complete)
- {
-
- getChildView("desc")->setEnabled(false);
- //mDescEditor->setEnabled(false);
- mTriggerEditor->setEnabled(false);
- mReplaceText->setEnabled(false);
- mReplaceEditor->setEnabled(false);
- mModifierCombo->setEnabled(false);
- mKeyCombo->setEnabled(false);
- mLibraryList->setEnabled(false);
- mAddBtn->setEnabled(false);
- mUpBtn->setEnabled(false);
- mDownBtn->setEnabled(false);
- mDeleteBtn->setEnabled(false);
- mStepList->setEnabled(false);
- mOptionsText->setEnabled(false);
- mAnimationCombo->setEnabled(false);
- mAnimationRadio->setEnabled(false);
- mSoundCombo->setEnabled(false);
- mChatEditor->setEnabled(false);
- mWaitKeyReleaseCheck->setEnabled(false);
- mWaitAnimCheck->setEnabled(false);
- mWaitTimeCheck->setEnabled(false);
- mWaitTimeEditor->setEnabled(false);
- mActiveCheck->setEnabled(false);
- mSaveBtn->setEnabled(false);
-
- // Make sure preview button is enabled, so we can stop it
- mPreviewBtn->setEnabled(true);
- return;
- }
-
- bool modifiable = item->getPermissions().allowModifyBy(gAgent.getID());
-
- getChildView("desc")->setEnabled(modifiable);
- mTriggerEditor->setEnabled(true);
- mLibraryList->setEnabled(modifiable);
- mStepList->setEnabled(modifiable);
- mOptionsText->setEnabled(modifiable);
- mAnimationCombo->setEnabled(modifiable);
- mAnimationRadio->setEnabled(modifiable);
- mSoundCombo->setEnabled(modifiable);
- mChatEditor->setEnabled(modifiable);
- mWaitKeyReleaseCheck->setEnabled(modifiable);
- mWaitAnimCheck->setEnabled(modifiable);
- mWaitTimeCheck->setEnabled(modifiable);
- mWaitTimeEditor->setEnabled(modifiable);
- mActiveCheck->setEnabled(true);
-
- const std::string& trigger = mTriggerEditor->getText();
- bool have_trigger = !trigger.empty();
-
- const std::string& replace = mReplaceEditor->getText();
- bool have_replace = !replace.empty();
-
- LLScrollListItem* library_item = mLibraryList->getFirstSelected();
- bool have_library = (library_item != NULL);
-
- LLScrollListItem* step_item = mStepList->getFirstSelected();
- S32 step_index = mStepList->getFirstSelectedIndex();
- S32 step_count = mStepList->getItemCount();
- bool have_step = (step_item != NULL);
-
- mReplaceText->setEnabled(have_trigger || have_replace);
- mReplaceEditor->setEnabled(have_trigger || have_replace);
-
- mModifierCombo->setEnabled(true);
- mKeyCombo->setEnabled(true);
-
- mAddBtn->setEnabled(modifiable && have_library);
- mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
- mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1);
- mDeleteBtn->setEnabled(modifiable && have_step);
-
- // Assume all not visible
- mAnimationCombo->setVisible(false);
- mAnimationRadio->setVisible(false);
- mSoundCombo->setVisible(false);
- mChatEditor->setVisible(false);
- mWaitKeyReleaseCheck->setVisible(false);
- mWaitAnimCheck->setVisible(false);
- mWaitTimeCheck->setVisible(false);
- mWaitTimeEditor->setVisible(false);
-
- std::string optionstext;
-
- if (have_step)
- {
- // figure out the type, show proper options, update text
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- EStepType type = step->getType();
-
- switch(type)
- {
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- optionstext = getString("step_anim");
- mAnimationCombo->setVisible(true);
- mAnimationRadio->setVisible(true);
- mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
- mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- optionstext = getString("step_sound");
- mSoundCombo->setVisible(true);
- mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- optionstext = getString("step_chat");
- mChatEditor->setVisible(true);
- mChatEditor->setText(chat_step->mChatText);
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- optionstext = getString("step_wait");
- mWaitKeyReleaseCheck->setVisible(true);
- mWaitKeyReleaseCheck->set(wait_step->mFlags & WAIT_FLAG_KEY_RELEASE);
- mWaitAnimCheck->setVisible(true);
- mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
- mWaitTimeCheck->setVisible(true);
- mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
- mWaitTimeEditor->setVisible(true);
- std::string buffer = llformat("%.1f", (double)wait_step->mWaitSeconds);
- mWaitTimeEditor->setText(buffer);
- break;
- }
- default:
- break;
- }
- }
-
- mOptionsText->setText(optionstext);
-
- bool active = LLGestureMgr::instance().isGestureActive(mItemUUID);
- mActiveCheck->set(active);
-
- // Can only preview if there are steps
- mPreviewBtn->setEnabled(step_count > 0);
-
- // And can only save if changes have been made
- mSaveBtn->setEnabled(mDirty);
- addAnimations();
- addSounds();
-}
-
-
-void LLPreviewGesture::initDefaultGesture()
-{
- LLScrollListItem* item;
- item = addStep( STEP_ANIMATION );
- LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata();
- anim->mAnimAssetID = ANIM_AGENT_HELLO;
- anim->mAnimName = LLTrans::getString("Wave");
- updateLabel(item);
-
- item = addStep( STEP_WAIT );
- LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
- wait->mFlags = WAIT_FLAG_ALL_ANIM;
- updateLabel(item);
-
- item = addStep( STEP_CHAT );
- LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
- chat_step->mChatText = LLTrans::getString("HelloAvatar");
- updateLabel(item);
-
- // Start with item list selected
- mStepList->selectFirstItem();
-
- // this is *new* content, so we are dirty
- mDirty = true;
-}
-
-
-void LLPreviewGesture::loadAsset()
-{
- const LLInventoryItem* item = getItem();
- if (!item)
- {
- // Don't set asset status here; we may not have set the item id yet
- // (e.g. when this gets called initially)
- //mAssetStatus = PREVIEW_ASSET_ERROR;
- return;
- }
-
- LLUUID asset_id = item->getAssetUUID();
- if (asset_id.isNull())
- {
- // Freshly created gesture, don't need to load asset.
- // Blank gesture will be fine.
- initDefaultGesture();
- refresh();
- mAssetStatus = PREVIEW_ASSET_LOADED;
- return;
- }
-
- // TODO: Based on item->getPermissions().allow*
- // could enable/disable UI.
-
- // Copy the UUID, because the user might close the preview
- // window if the download gets stalled.
- LLUUID* item_idp = new LLUUID(mItemUUID);
-
- const bool high_priority = true;
- gAssetStorage->getAssetData(asset_id,
- LLAssetType::AT_GESTURE,
- onLoadComplete,
- (void**)item_idp,
- high_priority);
- mAssetStatus = PREVIEW_ASSET_LOADING;
-}
-
-
-// static
-void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status)
-{
- LLUUID* item_idp = (LLUUID*)user_data;
-
- LLPreviewGesture* self = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *item_idp);
- if (self)
- {
- if (0 == status)
- {
- LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
- S32 size = file.getSize();
-
- std::vector<char> buffer(size+1);
- file.read((U8*)&buffer[0], size);
- buffer[size] = '\0';
-
- LLMultiGesture* gesture = new LLMultiGesture();
-
- LLDataPackerAsciiBuffer dp(&buffer[0], size+1);
- bool ok = gesture->deserialize(dp);
-
- if (ok)
- {
- // Everything has been successful. Load up the UI.
- self->loadUIFromGesture(gesture);
-
- self->mStepList->selectFirstItem();
-
- self->mDirty = false;
- self->refresh();
- self->refreshFromItem(); // to update description and title
- }
- else
- {
- LL_WARNS() << "Unable to load gesture" << LL_ENDL;
- }
-
- delete gesture;
- gesture = NULL;
-
- self->mAssetStatus = PREVIEW_ASSET_LOADED;
- }
- else
- {
- if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
- LL_ERR_FILE_EMPTY == status)
- {
- LLDelayedGestureError::gestureMissing( *item_idp );
- }
- else
- {
- LLDelayedGestureError::gestureFailedToLoad( *item_idp );
- }
-
- LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL;
- self->mAssetStatus = PREVIEW_ASSET_ERROR;
- }
- }
- delete item_idp;
- item_idp = NULL;
-}
-
-
-void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
-{
- /*LLInventoryItem* item = getItem();
-
-
-
- if (item)
- {
- LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
- descEditor->setText(item->getDescription());
- }*/
-
- mTriggerEditor->setText(gesture->mTrigger);
-
- mReplaceEditor->setText(gesture->mReplaceText);
-
- switch (gesture->mMask)
- {
- default:
- case MASK_NONE:
- mModifierCombo->setSimple( NONE_LABEL );
- break;
- case MASK_SHIFT:
- mModifierCombo->setSimple( SHIFT_LABEL );
- break;
- case MASK_CONTROL:
- mModifierCombo->setSimple( CTRL_LABEL );
- break;
- }
-
- mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10);
-
- mKeyCombo->setCurrentByIndex(0);
- if (gesture->mKey != KEY_NONE)
- {
- mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
- }
-
- mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL);
-
- // Make UI steps for each gesture step
- S32 i;
- S32 count = gesture->mSteps.size();
- for (i = 0; i < count; ++i)
- {
- LLGestureStep* step = gesture->mSteps[i];
-
- LLGestureStep* new_step = NULL;
-
- switch(step->getType())
- {
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- LLGestureStepAnimation* new_anim_step =
- new LLGestureStepAnimation(*anim_step);
- new_step = new_anim_step;
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- LLGestureStepSound* new_sound_step =
- new LLGestureStepSound(*sound_step);
- new_step = new_sound_step;
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- LLGestureStepChat* new_chat_step =
- new LLGestureStepChat(*chat_step);
- new_step = new_chat_step;
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- LLGestureStepWait* new_wait_step =
- new LLGestureStepWait(*wait_step);
- new_step = new_wait_step;
- break;
- }
- default:
- {
- break;
- }
- }
-
- if (!new_step) continue;
-
- // Create an enabled item with this step
- LLSD row;
- row["columns"][0]["value"] = getLabel( new_step->getLabel());
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- LLScrollListItem* item = mStepList->addElement(row);
- item->setUserdata(new_step);
- }
-}
-
-// Helpful structure so we can look up the inventory item
-// after the save finishes.
-struct LLSaveInfo
-{
- LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc,
- const LLTransactionID tid)
- : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid)
- {
- }
-
- LLUUID mItemUUID;
- LLUUID mObjectUUID;
- std::string mDesc;
- LLTransactionID mTransactionID;
-};
-
-
-void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId)
-{
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (LLGestureMgr::instance().isGestureActive(itemId))
- {
- // Active gesture edited from menu.
- LLGestureMgr::instance().replaceGesture(itemId, newAssetId);
- gInventory.notifyObservers();
- }
-
- //gesture will have a new asset_id
- LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId));
- if (previewp)
- {
- previewp->onUpdateSucceeded();
- }
-}
-
-
-void LLPreviewGesture::saveIfNeeded()
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Can't save gesture, no asset storage system." << LL_ENDL;
- return;
- }
-
- if (!mDirty)
- {
- return;
- }
-
- // Copy the UI into a gesture
- LLMultiGesture* gesture = createGesture();
-
- // Serialize the gesture
- S32 maxSize = gesture->getMaxSerialSize();
- char* buffer = new char[maxSize];
-
- LLDataPackerAsciiBuffer dp(buffer, maxSize);
-
- bool ok = gesture->serialize(dp);
-
- if (dp.getCurrentSize() > 1000)
- {
- LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
-
- delete gesture;
- gesture = NULL;
- return;
- }
- else if (!ok)
- {
- LLNotificationsUtil::add("GestureSaveFailedTryAgain");
- delete gesture;
- gesture = NULL;
- return;
- }
-
- LLAssetID assetId;
- LLPreview::onCommit();
- bool delayedUpload(false);
-
- LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
- if (item)
- {
- const LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- LL_WARNS() << "Not connected to a region, cannot save gesture." << LL_ENDL;
- return;
- }
- std::string agent_url = region->getCapability("UpdateGestureAgentInventory");
- std::string task_url = region->getCapability("UpdateGestureTaskInventory");
-
- if (!agent_url.empty() && !task_url.empty())
- {
- std::string url;
- LLResourceUploadInfo::ptr_t uploadInfo;
-
- if (mObjectUUID.isNull() && !agent_url.empty())
- {
- //need to disable the preview floater so item
- //isn't re-saved before new asset arrives
- //fake out refresh.
- item->setComplete(false);
- refresh();
- item->setComplete(true);
-
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_GESTURE, buffer,
- [](LLUUID itemId, LLUUID newAssetId, LLUUID, LLSD)
- {
- LLPreviewGesture::finishInventoryUpload(itemId, newAssetId);
- },
- nullptr);
- url = agent_url;
- }
- else if (!mObjectUUID.isNull() && !task_url.empty())
- {
- uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, nullptr, nullptr);
- url = task_url;
- }
-
- if (!url.empty() && uploadInfo)
- {
- delayedUpload = true;
-
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
-
- }
- else if (gAssetStorage)
- {
- // Every save gets a new UUID. Yup.
- LLTransactionID tid;
- tid.generate();
- assetId = tid.makeAssetID(gAgent.getSecureSessionID());
-
- LLFileSystem file(assetId, LLAssetType::AT_GESTURE, LLFileSystem::APPEND);
-
- S32 size = dp.getCurrentSize();
- file.write((U8*)buffer, size);
-
- LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
- LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
- gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, false);
- }
-
- }
-
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
- {
- // gesture manager now owns the pointer
- LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId);
-
- // replaceGesture may deactivate other gestures so let the
- // inventory know.
- gInventory.notifyObservers();
- }
- else
- {
- // we're done with this gesture
- delete gesture;
- gesture = NULL;
- }
-
- mDirty = false;
- // refresh will be called when callback
- // if triggered when delayedUpload
- if(!delayedUpload)
- {
- refresh();
- }
-
-}
-
-
-// TODO: This is very similar to LLPreviewNotecard::onSaveComplete.
-// Could merge code.
-// static
-void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
-{
- LLSaveInfo* info = (LLSaveInfo*)user_data;
- if (info && (status == 0))
- {
- if(info->mObjectUUID.isNull())
- {
- // Saving into user inventory
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
- if(item)
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setDescription(info->mDesc);
- new_item->setTransactionID(info->mTransactionID);
- new_item->setAssetUUID(asset_uuid);
- new_item->updateServer(false);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LL_WARNS() << "Inventory item for gesture " << info->mItemUUID
- << " is no longer in agent inventory." << LL_ENDL;
- }
- }
- else
- {
- // Saving into in-world object inventory
- LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
- LLViewerInventoryItem* item = NULL;
- if(object)
- {
- item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
- }
- if(object && item)
- {
- item->setDescription(info->mDesc);
- item->setAssetUUID(asset_uuid);
- item->setTransactionID(info->mTransactionID);
- object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
- dialog_refresh_all();
- }
- else
- {
- LLNotificationsUtil::add("GestureSaveFailedObjectNotFound");
- }
- }
-
- // Find our window and close it if requested.
- LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", info->mItemUUID);
- if (previewp && previewp->mCloseAfterSave)
- {
- previewp->closeFloater();
- }
- }
- else
- {
- LL_WARNS() << "Problem saving gesture: " << status << LL_ENDL;
- LLSD args;
- args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
- LLNotificationsUtil::add("GestureSaveFailedReason", args);
- }
- delete info;
- info = NULL;
-}
-
-
-LLMultiGesture* LLPreviewGesture::createGesture()
-{
- LLMultiGesture* gesture = new LLMultiGesture();
-
- gesture->mTrigger = mTriggerEditor->getText();
- gesture->mReplaceText = mReplaceEditor->getText();
-
- const std::string& modifier = mModifierCombo->getSimple();
- if (modifier == CTRL_LABEL)
- {
- gesture->mMask = MASK_CONTROL;
- }
- else if (modifier == SHIFT_LABEL)
- {
- gesture->mMask = MASK_SHIFT;
- }
- else
- {
- gesture->mMask = MASK_NONE;
- }
-
- if (mKeyCombo->getCurrentIndex() == 0)
- {
- gesture->mKey = KEY_NONE;
- }
- else
- {
- const std::string& key_string = mKeyCombo->getSimple();
- LLKeyboard::keyFromString(key_string, &(gesture->mKey));
- }
-
- std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
- std::vector<LLScrollListItem*>::iterator data_itor;
- for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
- {
- LLScrollListItem* item = *data_itor;
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
-
- switch(step->getType())
- {
- case STEP_ANIMATION:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- LLGestureStepAnimation* new_anim_step =
- new LLGestureStepAnimation(*anim_step);
- gesture->mSteps.push_back(new_anim_step);
- break;
- }
- case STEP_SOUND:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- LLGestureStepSound* new_sound_step =
- new LLGestureStepSound(*sound_step);
- gesture->mSteps.push_back(new_sound_step);
- break;
- }
- case STEP_CHAT:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- LLGestureStepChat* new_chat_step =
- new LLGestureStepChat(*chat_step);
- gesture->mSteps.push_back(new_chat_step);
- break;
- }
- case STEP_WAIT:
- {
- // Copy UI-generated step into actual gesture step
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- LLGestureStepWait* new_wait_step =
- new LLGestureStepWait(*wait_step);
- gesture->mSteps.push_back(new_wait_step);
- break;
- }
- default:
- {
- break;
- }
- }
- }
-
- return gesture;
-}
-
-
-void LLPreviewGesture::onCommitKeyorModifier()
-{
- // SL-14139: ctrl-F10 is currently used to access top menu,
- // so don't allow to bound gestures to this combination.
-
- mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL);
- mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10));
- mDirty = true;
- refresh();
-}
-
-// static
-void LLPreviewGesture::updateLabel(LLScrollListItem* item)
-{
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
-
- LLScrollListCell* cell = item->getColumn(0);
- LLScrollListText* text_cell = (LLScrollListText*)cell;
- std::string label = getLabel( step->getLabel());
- text_cell->setText(label);
-}
-
-// static
-void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
- if (library_item)
- {
- self->mStepList->deselectAllItems();
- self->refresh();
- }
-}
-
-
-// static
-void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- self->mLibraryList->deselectAllItems();
- self->refresh();
-}
-
-
-// static
-void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_ANIMATION)
- {
- // Assign the animation name
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- if (self->mAnimationCombo->getCurrentIndex() == 0)
- {
- anim_step->mAnimName.clear();
- anim_step->mAnimAssetID.setNull();
- }
- else
- {
- anim_step->mAnimName = self->mAnimationCombo->getSimple();
- anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID();
- }
- //anim_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_ANIMATION)
- {
- LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
- if (self->mAnimationRadio->getSelectedIndex() == 0)
- {
- // start
- anim_step->mFlags &= ~ANIM_FLAG_STOP;
- }
- else
- {
- // stop
- anim_step->mFlags |= ANIM_FLAG_STOP;
- }
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (step_item)
- {
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() == STEP_SOUND)
- {
- // Assign the sound name
- LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
- sound_step->mSoundName = self->mSoundCombo->getSimple();
- sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
- sound_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
- }
- }
-}
-
-// static
-void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_CHAT) return;
-
- LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
- chat_step->mChatText = self->mChatEditor->getText();
- chat_step->mFlags = 0x0;
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_WAIT) return;
-
- LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- U32 flags = 0x0;
- if (self->mWaitKeyReleaseCheck->get()) flags |= WAIT_FLAG_KEY_RELEASE;
- if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
- if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
- wait_step->mFlags = flags;
-
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str());
- if (wait_seconds < 0.f) wait_seconds = 0.f;
- if (wait_seconds > 3600.f) wait_seconds = 3600.f;
- wait_step->mWaitSeconds = wait_seconds;
- }
-
- // Enable the input area if necessary
- self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
-
- // Update the UI label in the list
- updateLabel(step_item);
-
- self->mDirty = true;
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* step_item = self->mStepList->getFirstSelected();
- if (!step_item) return;
-
- LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
- if (step->getType() != STEP_WAIT) return;
-
- self->mWaitTimeCheck->set(true);
- onCommitWait(ctrl, data);
-}
-
-
-// static
-void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
- void* data)
-{
- // Just commit every keystroke
- onCommitSetDirty(caller, data);
-}
-
-// static
-void LLPreviewGesture::onClickAdd(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
- if (!library_item) return;
-
- S32 library_item_index = self->mLibraryList->getFirstSelectedIndex();
-
- const LLScrollListCell* library_cell = library_item->getColumn(0);
- const std::string& library_text = library_cell->getValue().asString();
-
- if( library_item_index >= STEP_EOF )
- {
- LL_ERRS() << "Unknown step type: " << library_text << LL_ENDL;
- return;
- }
-
- self->addStep( (EStepType)library_item_index );
- self->mDirty = true;
- self->refresh();
-}
-
-LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type )
-{
- // Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml
-
- LLGestureStep* step = NULL;
- switch( step_type)
- {
- case STEP_ANIMATION:
- step = new LLGestureStepAnimation();
-
- break;
- case STEP_SOUND:
- step = new LLGestureStepSound();
- break;
- case STEP_CHAT:
- step = new LLGestureStepChat();
- break;
- case STEP_WAIT:
- step = new LLGestureStepWait();
- break;
- default:
- LL_ERRS() << "Unknown step type: " << (S32)step_type << LL_ENDL;
- return NULL;
- }
-
-
- // Create an enabled item with this step
- LLSD row;
- row["columns"][0]["value"] = getLabel(step->getLabel());
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- LLScrollListItem* step_item = mStepList->addElement(row);
- step_item->setUserdata(step);
-
- // And move selection to the list on the right
- mLibraryList->deselectAllItems();
- mStepList->deselectAllItems();
-
- step_item->setSelected(true);
-
- return step_item;
-}
-
-// static
-std::string LLPreviewGesture::getLabel(std::vector<std::string> labels)
-{
- std::vector<std::string> v_labels = labels ;
- std::string result("");
-
- if( v_labels.size() != 2)
- {
- return result;
- }
-
- if(v_labels[0]=="Chat")
- {
- result=LLTrans::getString("Chat Message");
- }
- else if(v_labels[0]=="Sound")
- {
- result=LLTrans::getString("Sound");
- }
- else if(v_labels[0]=="Wait")
- {
- result=LLTrans::getString("Wait");
- }
- else if(v_labels[0]=="AnimFlagStop")
- {
- result=LLTrans::getString("AnimFlagStop");
- }
- else if(v_labels[0]=="AnimFlagStart")
- {
- result=LLTrans::getString("AnimFlagStart");
- }
-
- // lets localize action value
- std::string action = v_labels[1];
- if ("None" == action)
- {
- action = LLTrans::getString("GestureActionNone");
- }
- else if ("until animations are done" == action)
- {
- action = LLFloaterReg::getInstance("preview_gesture")->getChild<LLCheckBoxCtrl>("wait_anim_check")->getLabel();
- }
- result.append(action);
- return result;
-
-}
-// static
-void LLPreviewGesture::onClickUp(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (selected_index > 0)
- {
- self->mStepList->swapWithPrevious(selected_index);
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onClickDown(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (selected_index < 0) return;
-
- S32 count = self->mStepList->getItemCount();
- if (selected_index < count-1)
- {
- self->mStepList->swapWithNext(selected_index);
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onClickDelete(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- LLScrollListItem* item = self->mStepList->getFirstSelected();
- S32 selected_index = self->mStepList->getFirstSelectedIndex();
- if (item && selected_index >= 0)
- {
- LLGestureStep* step = (LLGestureStep*)item->getUserdata();
- delete step;
- step = NULL;
-
- self->mStepList->deleteSingleItem(selected_index);
-
- self->mDirty = true;
- self->refresh();
- }
-}
-
-// static
-void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- if (!LLGestureMgr::instance().isGestureActive(self->mItemUUID))
- {
- LLGestureMgr::instance().activateGesture(self->mItemUUID);
- }
- else
- {
- LLGestureMgr::instance().deactivateGesture(self->mItemUUID);
- }
-
- // Make sure the (active) label in the inventory gets updated.
- LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
- if (item)
- {
- gInventory.updateItem(item);
- gInventory.notifyObservers();
- }
-
- self->refresh();
-}
-
-// static
-void LLPreviewGesture::onClickSave(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
- self->saveIfNeeded();
-}
-
-// static
-void LLPreviewGesture::onClickPreview(void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- if (!self->mPreviewGesture)
- {
- // make temporary gesture
- self->mPreviewGesture = self->createGesture();
-
- // add a callback
- self->mPreviewGesture->mDoneCallback = onDonePreview;
- self->mPreviewGesture->mCallbackData = self;
-
- // set the button title
- self->mPreviewBtn->setLabel(self->getString("stop_txt"));
-
- // play it, and delete when done
- LLGestureMgr::instance().playGesture(self->mPreviewGesture);
-
- self->refresh();
- }
- else
- {
- // Will call onDonePreview() below
- LLGestureMgr::instance().stopGesture(self->mPreviewGesture);
-
- self->refresh();
- }
-}
-
-
-// static
-void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
-{
- LLPreviewGesture* self = (LLPreviewGesture*)data;
-
- self->mPreviewBtn->setLabel(self->getString("preview_txt"));
-
- delete self->mPreviewGesture;
- self->mPreviewGesture = NULL;
-
- self->refresh();
-}
+/** + * @file llpreviewgesture.cpp + * @brief Editing UI for inventory-based gestures. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "llpreviewgesture.h" + +#include "llagent.h" +#include "llanimstatelabels.h" +#include "llanimationstates.h" +#include "llappviewer.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldelayedgestureerror.h" +#include "llfloaterreg.h" +#include "llgesturemgr.h" +#include "llinventorydefines.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llkeyboard.h" +#include "llmultigesture.h" +#include "llnotificationsutil.h" +#include "llradiogroup.h" +#include "llresmgr.h" +#include "lltrans.h" +#include "llfilesystem.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewerassetupload.h" + +std::string NONE_LABEL; +std::string SHIFT_LABEL; +std::string CTRL_LABEL; + +void dialog_refresh_all(); + +// used for getting + +class LLInventoryGestureAvailable : public LLInventoryCompletionObserver +{ +public: + LLInventoryGestureAvailable() {} + +protected: + virtual void done(); +}; + +void LLInventoryGestureAvailable::done() +{ + for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it) + { + LLPreviewGesture* preview = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *it); + if(preview) + { + preview->refresh(); + } + } + gInventory.removeObserver(this); + delete this; +} + +// Used for sorting +struct SortItemPtrsByName +{ + bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2) + { + return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0); + } +}; + +// static +LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id) +{ + LLPreviewGesture* preview = LLFloaterReg::showTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES); + if (!preview) + { + return NULL; + } + + preview->setObjectID(object_id); + + // Start speculative download of sounds and animations + const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION); + LLInventoryModelBackgroundFetch::instance().start(animation_folder_id); + + const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND); + LLInventoryModelBackgroundFetch::instance().start(sound_folder_id); + + // this will call refresh when we have everything. + LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem(); + if (item && !item->isFinished()) + { + LLInventoryGestureAvailable* observer; + observer = new LLInventoryGestureAvailable(); + observer->watchItem(item_id); + gInventory.addObserver(observer); + item->fetchFromServer(); + } + else + { + // not sure this is necessary. + preview->refresh(); + } + + return preview; +} + +void LLPreviewGesture::draw() +{ + // Skip LLPreview::draw() to avoid description update + LLFloater::draw(); +} + +// virtual +bool LLPreviewGesture::handleKeyHere(KEY key, MASK mask) +{ + if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL))) + { + saveIfNeeded(); + return true; + } + + return LLPreview::handleKeyHere(key, mask); +} + + +// virtual +bool LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + bool handled = true; + switch(cargo_type) + { + case DAD_ANIMATION: + case DAD_SOUND: + { + // TODO: Don't allow this if you can't transfer the sound/animation + + // make a script step + LLInventoryItem* item = (LLInventoryItem*)cargo_data; + if (item + && gInventory.getItem(item->getUUID())) + { + LLPermissions perm = item->getPermissions(); + if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)) + { + *accept = ACCEPT_NO; + if (tooltip_msg.empty()) + { + tooltip_msg.assign("Only animations and sounds\n" + "with unrestricted permissions\n" + "can be added to a gesture."); + } + break; + } + else if (drop) + { + LLScrollListItem* line = NULL; + if (cargo_type == DAD_ANIMATION) + { + line = addStep( STEP_ANIMATION ); + LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata(); + anim->mAnimAssetID = item->getAssetUUID(); + anim->mAnimName = item->getName(); + } + else if (cargo_type == DAD_SOUND) + { + line = addStep( STEP_SOUND ); + LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata(); + sound->mSoundAssetID = item->getAssetUUID(); + sound->mSoundName = item->getName(); + } + updateLabel(line); + mDirty = true; + refresh(); + } + *accept = ACCEPT_YES_COPY_MULTI; + } + else + { + // Not in user's inventory means it was in object inventory + *accept = ACCEPT_NO; + } + break; + } + default: + *accept = ACCEPT_NO; + if (tooltip_msg.empty()) + { + tooltip_msg.assign("Only animations and sounds\n" + "can be added to a gesture."); + } + break; + } + return handled; +} + + +// virtual +bool LLPreviewGesture::canClose() +{ + + if(!mDirty || mForceClose) + { + return true; + } + else + { + if(!mSaveDialogShown) + { + mSaveDialogShown = true; + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), + boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) ); + } + return false; + } +} + +// virtual +void LLPreviewGesture::onClose(bool app_quitting) +{ + LLGestureMgr::instance().stopGesture(mPreviewGesture); +} + +// virtual +void LLPreviewGesture::onUpdateSucceeded() +{ + refresh(); +} + +void LLPreviewGesture::onVisibilityChanged ( const LLSD& new_visibility ) +{ + if (new_visibility.asBoolean()) + { + refresh(); + } +} + + +bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response) +{ + mSaveDialogShown = false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: // "Yes" + LLGestureMgr::instance().stopGesture(mPreviewGesture); + mCloseAfterSave = true; + onClickSave(this); + break; + + case 1: // "No" + LLGestureMgr::instance().stopGesture(mPreviewGesture); + mDirty = false; // Force the dirty flag because user has clicked NO on confirm save dialog... + closeFloater(); + break; + + case 2: // "Cancel" + default: + // If we were quitting, we didn't really mean it. + LLAppViewer::instance()->abortQuit(); + break; + } + return false; +} + + +LLPreviewGesture::LLPreviewGesture(const LLSD& key) +: LLPreview(key), + mTriggerEditor(NULL), + mModifierCombo(NULL), + mKeyCombo(NULL), + mLibraryList(NULL), + mAddBtn(NULL), + mUpBtn(NULL), + mDownBtn(NULL), + mDeleteBtn(NULL), + mStepList(NULL), + mOptionsText(NULL), + mAnimationRadio(NULL), + mAnimationCombo(NULL), + mSoundCombo(NULL), + mChatEditor(NULL), + mSaveBtn(NULL), + mPreviewBtn(NULL), + mPreviewGesture(NULL), + mDirty(false) +{ + NONE_LABEL = LLTrans::getString("---"); + SHIFT_LABEL = LLTrans::getString("KBShift"); + CTRL_LABEL = LLTrans::getString("KBCtrl"); +} + + +LLPreviewGesture::~LLPreviewGesture() +{ + // Userdata for all steps is a LLGestureStep we need to clean up + std::vector<LLScrollListItem*> data_list = mStepList->getAllData(); + std::vector<LLScrollListItem*>::iterator data_itor; + for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) + { + LLScrollListItem* item = *data_itor; + LLGestureStep* step = (LLGestureStep*)item->getUserdata(); + delete step; + step = NULL; + } +} + + +bool LLPreviewGesture::postBuild() +{ + setVisibleCallback(boost::bind(&LLPreviewGesture::onVisibilityChanged, this, _2)); + + LLLineEditor* edit; + LLComboBox* combo; + LLButton* btn; + LLScrollListCtrl* list; + LLTextBox* text; + LLCheckBoxCtrl* check; + + edit = getChild<LLLineEditor>("desc"); + edit->setKeystrokeCallback(onKeystrokeCommit, this); + + edit = getChild<LLLineEditor>("trigger_editor"); + edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitCallback(onCommitSetDirty, this); + edit->setCommitOnFocusLost(true); + edit->setIgnoreTab(true); + mTriggerEditor = edit; + + text = getChild<LLTextBox>("replace_text"); + text->setEnabled(false); + mReplaceText = text; + + edit = getChild<LLLineEditor>("replace_editor"); + edit->setEnabled(false); + edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitCallback(onCommitSetDirty, this); + edit->setCommitOnFocusLost(true); + edit->setIgnoreTab(true); + mReplaceEditor = edit; + + combo = getChild<LLComboBox>( "modifier_combo"); + combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this)); + mModifierCombo = combo; + + combo = getChild<LLComboBox>( "key_combo"); + combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this)); + mKeyCombo = combo; + + list = getChild<LLScrollListCtrl>("library_list"); + list->setCommitCallback(onCommitLibrary, this); + list->setDoubleClickCallback(onClickAdd, this); + mLibraryList = list; + + btn = getChild<LLButton>( "add_btn"); + btn->setClickedCallback(onClickAdd, this); + btn->setEnabled(false); + mAddBtn = btn; + + btn = getChild<LLButton>( "up_btn"); + btn->setClickedCallback(onClickUp, this); + btn->setEnabled(false); + mUpBtn = btn; + + btn = getChild<LLButton>( "down_btn"); + btn->setClickedCallback(onClickDown, this); + btn->setEnabled(false); + mDownBtn = btn; + + btn = getChild<LLButton>( "delete_btn"); + btn->setClickedCallback(onClickDelete, this); + btn->setEnabled(false); + mDeleteBtn = btn; + + list = getChild<LLScrollListCtrl>("step_list"); + list->setCommitCallback(onCommitStep, this); + mStepList = list; + + // Options + mOptionsText = getChild<LLTextBox>("options_text"); + + combo = getChild<LLComboBox>( "animation_list"); + combo->setVisible(false); + combo->setCommitCallback(onCommitAnimation, this); + mAnimationCombo = combo; + + LLRadioGroup* group; + group = getChild<LLRadioGroup>("animation_trigger_type"); + group->setVisible(false); + group->setCommitCallback(onCommitAnimationTrigger, this); + mAnimationRadio = group; + + combo = getChild<LLComboBox>( "sound_list"); + combo->setVisible(false); + combo->setCommitCallback(onCommitSound, this); + mSoundCombo = combo; + + edit = getChild<LLLineEditor>("chat_editor"); + edit->setVisible(false); + edit->setCommitCallback(onCommitChat, this); + //edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitOnFocusLost(true); + edit->setIgnoreTab(true); + mChatEditor = edit; + + check = getChild<LLCheckBoxCtrl>( "wait_key_release_check"); + check->setVisible(false); + check->setCommitCallback(onCommitWait, this); + mWaitKeyReleaseCheck = check; + + check = getChild<LLCheckBoxCtrl>( "wait_anim_check"); + check->setVisible(false); + check->setCommitCallback(onCommitWait, this); + mWaitAnimCheck = check; + + check = getChild<LLCheckBoxCtrl>( "wait_time_check"); + check->setVisible(false); + check->setCommitCallback(onCommitWait, this); + mWaitTimeCheck = check; + + edit = getChild<LLLineEditor>("wait_time_editor"); + edit->setEnabled(false); + edit->setVisible(false); + edit->setPrevalidate(LLTextValidate::validateFloat); +// edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitOnFocusLost(true); + edit->setCommitCallback(onCommitWaitTime, this); + edit->setIgnoreTab(true); + mWaitTimeEditor = edit; + + // Buttons at the bottom + check = getChild<LLCheckBoxCtrl>( "active_check"); + check->setCommitCallback(onCommitActive, this); + mActiveCheck = check; + + btn = getChild<LLButton>( "save_btn"); + btn->setClickedCallback(onClickSave, this); + mSaveBtn = btn; + + btn = getChild<LLButton>( "preview_btn"); + btn->setClickedCallback(onClickPreview, this); + mPreviewBtn = btn; + + + // Populate the comboboxes + addModifiers(); + addKeys(); + addAnimations(); + addSounds(); + + const LLInventoryItem* item = getItem(); + + if (item) + { + getChild<LLUICtrl>("desc")->setValue(item->getDescription()); + getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); + } + + return LLPreview::postBuild(); +} + + +void LLPreviewGesture::addModifiers() +{ + LLComboBox* combo = mModifierCombo; + + combo->add( NONE_LABEL, ADD_BOTTOM ); + combo->add( SHIFT_LABEL, ADD_BOTTOM ); + combo->add( CTRL_LABEL, ADD_BOTTOM ); + combo->setCurrentByIndex(0); +} + +void LLPreviewGesture::addKeys() +{ + LLComboBox* combo = mKeyCombo; + + combo->add( NONE_LABEL ); + for (KEY key = KEY_F2; key <= KEY_F12; key++) + { + combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM ); + } + combo->setCurrentByIndex(0); +} + + +// TODO: Sort the legacy and non-legacy together? +void LLPreviewGesture::addAnimations() +{ + LLComboBox* combo = mAnimationCombo; + + combo->removeall(); + + std::string none_text = getString("none_text"); + + combo->add(none_text, LLUUID::null); + + // Add all the default (legacy) animations + S32 i; + for (i = 0; i < gUserAnimStatesCount; ++i) + { + // Use the user-readable name + std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ); + const LLUUID& id = gUserAnimStates[i].mID; + combo->add(label, id); + } + + // Get all inventory items that are animations + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION, + PERM_ITEM_UNRESTRICTED, + gAgent.getID(), + gAgent.getGroupID()); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_copyable_animation); + + // Copy into something we can sort + std::vector<LLInventoryItem*> animations; + + S32 count = items.size(); + for(i = 0; i < count; ++i) + { + animations.push_back( items.at(i) ); + } + + // Do the sort + std::sort(animations.begin(), animations.end(), SortItemPtrsByName()); + + // And load up the combobox + std::vector<LLInventoryItem*>::iterator it; + for (it = animations.begin(); it != animations.end(); ++it) + { + LLInventoryItem* item = *it; + + combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM); + } +} + + +void LLPreviewGesture::addSounds() +{ + LLComboBox* combo = mSoundCombo; + combo->removeall(); + + std::string none_text = getString("none_text"); + + combo->add(none_text, LLUUID::null); + + // Get all inventory items that are sounds + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND, + PERM_ITEM_UNRESTRICTED, + gAgent.getID(), + gAgent.getGroupID()); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_copyable_sound); + + // Copy sounds into something we can sort + std::vector<LLInventoryItem*> sounds; + + S32 i; + S32 count = items.size(); + for(i = 0; i < count; ++i) + { + sounds.push_back( items.at(i) ); + } + + // Do the sort + std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName()); + + // And load up the combobox + std::vector<LLInventoryItem*>::iterator it; + for (it = sounds.begin(); it != sounds.end(); ++it) + { + LLInventoryItem* item = *it; + + combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM); + } +} + + +void LLPreviewGesture::refresh() +{ + LLPreview::refresh(); + // If previewing or item is incomplete, all controls are disabled + LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); + bool is_complete = item && item->isFinished(); + if (mPreviewGesture || !is_complete) + { + + getChildView("desc")->setEnabled(false); + //mDescEditor->setEnabled(false); + mTriggerEditor->setEnabled(false); + mReplaceText->setEnabled(false); + mReplaceEditor->setEnabled(false); + mModifierCombo->setEnabled(false); + mKeyCombo->setEnabled(false); + mLibraryList->setEnabled(false); + mAddBtn->setEnabled(false); + mUpBtn->setEnabled(false); + mDownBtn->setEnabled(false); + mDeleteBtn->setEnabled(false); + mStepList->setEnabled(false); + mOptionsText->setEnabled(false); + mAnimationCombo->setEnabled(false); + mAnimationRadio->setEnabled(false); + mSoundCombo->setEnabled(false); + mChatEditor->setEnabled(false); + mWaitKeyReleaseCheck->setEnabled(false); + mWaitAnimCheck->setEnabled(false); + mWaitTimeCheck->setEnabled(false); + mWaitTimeEditor->setEnabled(false); + mActiveCheck->setEnabled(false); + mSaveBtn->setEnabled(false); + + // Make sure preview button is enabled, so we can stop it + mPreviewBtn->setEnabled(true); + return; + } + + bool modifiable = item->getPermissions().allowModifyBy(gAgent.getID()); + + getChildView("desc")->setEnabled(modifiable); + mTriggerEditor->setEnabled(true); + mLibraryList->setEnabled(modifiable); + mStepList->setEnabled(modifiable); + mOptionsText->setEnabled(modifiable); + mAnimationCombo->setEnabled(modifiable); + mAnimationRadio->setEnabled(modifiable); + mSoundCombo->setEnabled(modifiable); + mChatEditor->setEnabled(modifiable); + mWaitKeyReleaseCheck->setEnabled(modifiable); + mWaitAnimCheck->setEnabled(modifiable); + mWaitTimeCheck->setEnabled(modifiable); + mWaitTimeEditor->setEnabled(modifiable); + mActiveCheck->setEnabled(true); + + const std::string& trigger = mTriggerEditor->getText(); + bool have_trigger = !trigger.empty(); + + const std::string& replace = mReplaceEditor->getText(); + bool have_replace = !replace.empty(); + + LLScrollListItem* library_item = mLibraryList->getFirstSelected(); + bool have_library = (library_item != NULL); + + LLScrollListItem* step_item = mStepList->getFirstSelected(); + S32 step_index = mStepList->getFirstSelectedIndex(); + S32 step_count = mStepList->getItemCount(); + bool have_step = (step_item != NULL); + + mReplaceText->setEnabled(have_trigger || have_replace); + mReplaceEditor->setEnabled(have_trigger || have_replace); + + mModifierCombo->setEnabled(true); + mKeyCombo->setEnabled(true); + + mAddBtn->setEnabled(modifiable && have_library); + mUpBtn->setEnabled(modifiable && have_step && step_index > 0); + mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1); + mDeleteBtn->setEnabled(modifiable && have_step); + + // Assume all not visible + mAnimationCombo->setVisible(false); + mAnimationRadio->setVisible(false); + mSoundCombo->setVisible(false); + mChatEditor->setVisible(false); + mWaitKeyReleaseCheck->setVisible(false); + mWaitAnimCheck->setVisible(false); + mWaitTimeCheck->setVisible(false); + mWaitTimeEditor->setVisible(false); + + std::string optionstext; + + if (have_step) + { + // figure out the type, show proper options, update text + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + EStepType type = step->getType(); + + switch(type) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + optionstext = getString("step_anim"); + mAnimationCombo->setVisible(true); + mAnimationRadio->setVisible(true); + mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0); + mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID); + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + optionstext = getString("step_sound"); + mSoundCombo->setVisible(true); + mSoundCombo->setCurrentByID(sound_step->mSoundAssetID); + break; + } + case STEP_CHAT: + { + LLGestureStepChat* chat_step = (LLGestureStepChat*)step; + optionstext = getString("step_chat"); + mChatEditor->setVisible(true); + mChatEditor->setText(chat_step->mChatText); + break; + } + case STEP_WAIT: + { + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + optionstext = getString("step_wait"); + mWaitKeyReleaseCheck->setVisible(true); + mWaitKeyReleaseCheck->set(wait_step->mFlags & WAIT_FLAG_KEY_RELEASE); + mWaitAnimCheck->setVisible(true); + mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM); + mWaitTimeCheck->setVisible(true); + mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME); + mWaitTimeEditor->setVisible(true); + std::string buffer = llformat("%.1f", (double)wait_step->mWaitSeconds); + mWaitTimeEditor->setText(buffer); + break; + } + default: + break; + } + } + + mOptionsText->setText(optionstext); + + bool active = LLGestureMgr::instance().isGestureActive(mItemUUID); + mActiveCheck->set(active); + + // Can only preview if there are steps + mPreviewBtn->setEnabled(step_count > 0); + + // And can only save if changes have been made + mSaveBtn->setEnabled(mDirty); + addAnimations(); + addSounds(); +} + + +void LLPreviewGesture::initDefaultGesture() +{ + LLScrollListItem* item; + item = addStep( STEP_ANIMATION ); + LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata(); + anim->mAnimAssetID = ANIM_AGENT_HELLO; + anim->mAnimName = LLTrans::getString("Wave"); + updateLabel(item); + + item = addStep( STEP_WAIT ); + LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata(); + wait->mFlags = WAIT_FLAG_ALL_ANIM; + updateLabel(item); + + item = addStep( STEP_CHAT ); + LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata(); + chat_step->mChatText = LLTrans::getString("HelloAvatar"); + updateLabel(item); + + // Start with item list selected + mStepList->selectFirstItem(); + + // this is *new* content, so we are dirty + mDirty = true; +} + + +void LLPreviewGesture::loadAsset() +{ + const LLInventoryItem* item = getItem(); + if (!item) + { + // Don't set asset status here; we may not have set the item id yet + // (e.g. when this gets called initially) + //mAssetStatus = PREVIEW_ASSET_ERROR; + return; + } + + LLUUID asset_id = item->getAssetUUID(); + if (asset_id.isNull()) + { + // Freshly created gesture, don't need to load asset. + // Blank gesture will be fine. + initDefaultGesture(); + refresh(); + mAssetStatus = PREVIEW_ASSET_LOADED; + return; + } + + // TODO: Based on item->getPermissions().allow* + // could enable/disable UI. + + // Copy the UUID, because the user might close the preview + // window if the download gets stalled. + LLUUID* item_idp = new LLUUID(mItemUUID); + + const bool high_priority = true; + gAssetStorage->getAssetData(asset_id, + LLAssetType::AT_GESTURE, + onLoadComplete, + (void**)item_idp, + high_priority); + mAssetStatus = PREVIEW_ASSET_LOADING; +} + + +// static +void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLUUID* item_idp = (LLUUID*)user_data; + + LLPreviewGesture* self = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", *item_idp); + if (self) + { + if (0 == status) + { + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + S32 size = file.getSize(); + + std::vector<char> buffer(size+1); + file.read((U8*)&buffer[0], size); + buffer[size] = '\0'; + + LLMultiGesture* gesture = new LLMultiGesture(); + + LLDataPackerAsciiBuffer dp(&buffer[0], size+1); + bool ok = gesture->deserialize(dp); + + if (ok) + { + // Everything has been successful. Load up the UI. + self->loadUIFromGesture(gesture); + + self->mStepList->selectFirstItem(); + + self->mDirty = false; + self->refresh(); + self->refreshFromItem(); // to update description and title + } + else + { + LL_WARNS() << "Unable to load gesture" << LL_ENDL; + } + + delete gesture; + gesture = NULL; + + self->mAssetStatus = PREVIEW_ASSET_LOADED; + } + else + { + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + LLDelayedGestureError::gestureMissing( *item_idp ); + } + else + { + LLDelayedGestureError::gestureFailedToLoad( *item_idp ); + } + + LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL; + self->mAssetStatus = PREVIEW_ASSET_ERROR; + } + } + delete item_idp; + item_idp = NULL; +} + + +void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture) +{ + /*LLInventoryItem* item = getItem(); + + + + if (item) + { + LLLineEditor* descEditor = getChild<LLLineEditor>("desc"); + descEditor->setText(item->getDescription()); + }*/ + + mTriggerEditor->setText(gesture->mTrigger); + + mReplaceEditor->setText(gesture->mReplaceText); + + switch (gesture->mMask) + { + default: + case MASK_NONE: + mModifierCombo->setSimple( NONE_LABEL ); + break; + case MASK_SHIFT: + mModifierCombo->setSimple( SHIFT_LABEL ); + break; + case MASK_CONTROL: + mModifierCombo->setSimple( CTRL_LABEL ); + break; + } + + mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10); + + mKeyCombo->setCurrentByIndex(0); + if (gesture->mKey != KEY_NONE) + { + mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey)); + } + + mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL); + + // Make UI steps for each gesture step + S32 i; + S32 count = gesture->mSteps.size(); + for (i = 0; i < count; ++i) + { + LLGestureStep* step = gesture->mSteps[i]; + + LLGestureStep* new_step = NULL; + + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + LLGestureStepAnimation* new_anim_step = + new LLGestureStepAnimation(*anim_step); + new_step = new_anim_step; + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + LLGestureStepSound* new_sound_step = + new LLGestureStepSound(*sound_step); + new_step = new_sound_step; + break; + } + case STEP_CHAT: + { + LLGestureStepChat* chat_step = (LLGestureStepChat*)step; + LLGestureStepChat* new_chat_step = + new LLGestureStepChat(*chat_step); + new_step = new_chat_step; + break; + } + case STEP_WAIT: + { + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + LLGestureStepWait* new_wait_step = + new LLGestureStepWait(*wait_step); + new_step = new_wait_step; + break; + } + default: + { + break; + } + } + + if (!new_step) continue; + + // Create an enabled item with this step + LLSD row; + row["columns"][0]["value"] = getLabel( new_step->getLabel()); + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + LLScrollListItem* item = mStepList->addElement(row); + item->setUserdata(new_step); + } +} + +// Helpful structure so we can look up the inventory item +// after the save finishes. +struct LLSaveInfo +{ + LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc, + const LLTransactionID tid) + : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid) + { + } + + LLUUID mItemUUID; + LLUUID mObjectUUID; + std::string mDesc; + LLTransactionID mTransactionID; +}; + + +void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId) +{ + // If this gesture is active, then we need to update the in-memory + // active map with the new pointer. + if (LLGestureMgr::instance().isGestureActive(itemId)) + { + // Active gesture edited from menu. + LLGestureMgr::instance().replaceGesture(itemId, newAssetId); + gInventory.notifyObservers(); + } + + //gesture will have a new asset_id + LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId)); + if (previewp) + { + previewp->onUpdateSucceeded(); + } +} + + +void LLPreviewGesture::saveIfNeeded() +{ + if (!gAssetStorage) + { + LL_WARNS() << "Can't save gesture, no asset storage system." << LL_ENDL; + return; + } + + if (!mDirty) + { + return; + } + + // Copy the UI into a gesture + LLMultiGesture* gesture = createGesture(); + + // Serialize the gesture + S32 maxSize = gesture->getMaxSerialSize(); + char* buffer = new char[maxSize]; + + LLDataPackerAsciiBuffer dp(buffer, maxSize); + + bool ok = gesture->serialize(dp); + + if (dp.getCurrentSize() > 1000) + { + LLNotificationsUtil::add("GestureSaveFailedTooManySteps"); + + delete gesture; + gesture = NULL; + return; + } + else if (!ok) + { + LLNotificationsUtil::add("GestureSaveFailedTryAgain"); + delete gesture; + gesture = NULL; + return; + } + + LLAssetID assetId; + LLPreview::onCommit(); + bool delayedUpload(false); + + LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem(); + if (item) + { + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS() << "Not connected to a region, cannot save gesture." << LL_ENDL; + return; + } + std::string agent_url = region->getCapability("UpdateGestureAgentInventory"); + std::string task_url = region->getCapability("UpdateGestureTaskInventory"); + + if (!agent_url.empty() && !task_url.empty()) + { + std::string url; + LLResourceUploadInfo::ptr_t uploadInfo; + + if (mObjectUUID.isNull() && !agent_url.empty()) + { + //need to disable the preview floater so item + //isn't re-saved before new asset arrives + //fake out refresh. + item->setComplete(false); + refresh(); + item->setComplete(true); + + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_GESTURE, buffer, + [](LLUUID itemId, LLUUID newAssetId, LLUUID, LLSD) + { + LLPreviewGesture::finishInventoryUpload(itemId, newAssetId); + }, + nullptr); + url = agent_url; + } + else if (!mObjectUUID.isNull() && !task_url.empty()) + { + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, nullptr, nullptr); + url = task_url; + } + + if (!url.empty() && uploadInfo) + { + delayedUpload = true; + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + + } + else if (gAssetStorage) + { + // Every save gets a new UUID. Yup. + LLTransactionID tid; + tid.generate(); + assetId = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLFileSystem file(assetId, LLAssetType::AT_GESTURE, LLFileSystem::APPEND); + + S32 size = dp.getCurrentSize(); + file.write((U8*)buffer, size); + + LLLineEditor* descEditor = getChild<LLLineEditor>("desc"); + LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid); + gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, false); + } + + } + + // If this gesture is active, then we need to update the in-memory + // active map with the new pointer. + if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID)) + { + // gesture manager now owns the pointer + LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId); + + // replaceGesture may deactivate other gestures so let the + // inventory know. + gInventory.notifyObservers(); + } + else + { + // we're done with this gesture + delete gesture; + gesture = NULL; + } + + mDirty = false; + // refresh will be called when callback + // if triggered when delayedUpload + if(!delayedUpload) + { + refresh(); + } + +} + + +// TODO: This is very similar to LLPreviewNotecard::onSaveComplete. +// Could merge code. +// static +void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) +{ + LLSaveInfo* info = (LLSaveInfo*)user_data; + if (info && (status == 0)) + { + if(info->mObjectUUID.isNull()) + { + // Saving into user inventory + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); + if(item) + { + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + new_item->setDescription(info->mDesc); + new_item->setTransactionID(info->mTransactionID); + new_item->setAssetUUID(asset_uuid); + new_item->updateServer(false); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + LL_WARNS() << "Inventory item for gesture " << info->mItemUUID + << " is no longer in agent inventory." << LL_ENDL; + } + } + else + { + // Saving into in-world object inventory + LLViewerObject* object = gObjectList.findObject(info->mObjectUUID); + LLViewerInventoryItem* item = NULL; + if(object) + { + item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID); + } + if(object && item) + { + item->setDescription(info->mDesc); + item->setAssetUUID(asset_uuid); + item->setTransactionID(info->mTransactionID); + object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false); + dialog_refresh_all(); + } + else + { + LLNotificationsUtil::add("GestureSaveFailedObjectNotFound"); + } + } + + // Find our window and close it if requested. + LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", info->mItemUUID); + if (previewp && previewp->mCloseAfterSave) + { + previewp->closeFloater(); + } + } + else + { + LL_WARNS() << "Problem saving gesture: " << status << LL_ENDL; + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotificationsUtil::add("GestureSaveFailedReason", args); + } + delete info; + info = NULL; +} + + +LLMultiGesture* LLPreviewGesture::createGesture() +{ + LLMultiGesture* gesture = new LLMultiGesture(); + + gesture->mTrigger = mTriggerEditor->getText(); + gesture->mReplaceText = mReplaceEditor->getText(); + + const std::string& modifier = mModifierCombo->getSimple(); + if (modifier == CTRL_LABEL) + { + gesture->mMask = MASK_CONTROL; + } + else if (modifier == SHIFT_LABEL) + { + gesture->mMask = MASK_SHIFT; + } + else + { + gesture->mMask = MASK_NONE; + } + + if (mKeyCombo->getCurrentIndex() == 0) + { + gesture->mKey = KEY_NONE; + } + else + { + const std::string& key_string = mKeyCombo->getSimple(); + LLKeyboard::keyFromString(key_string, &(gesture->mKey)); + } + + std::vector<LLScrollListItem*> data_list = mStepList->getAllData(); + std::vector<LLScrollListItem*>::iterator data_itor; + for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) + { + LLScrollListItem* item = *data_itor; + LLGestureStep* step = (LLGestureStep*)item->getUserdata(); + + switch(step->getType()) + { + case STEP_ANIMATION: + { + // Copy UI-generated step into actual gesture step + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + LLGestureStepAnimation* new_anim_step = + new LLGestureStepAnimation(*anim_step); + gesture->mSteps.push_back(new_anim_step); + break; + } + case STEP_SOUND: + { + // Copy UI-generated step into actual gesture step + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + LLGestureStepSound* new_sound_step = + new LLGestureStepSound(*sound_step); + gesture->mSteps.push_back(new_sound_step); + break; + } + case STEP_CHAT: + { + // Copy UI-generated step into actual gesture step + LLGestureStepChat* chat_step = (LLGestureStepChat*)step; + LLGestureStepChat* new_chat_step = + new LLGestureStepChat(*chat_step); + gesture->mSteps.push_back(new_chat_step); + break; + } + case STEP_WAIT: + { + // Copy UI-generated step into actual gesture step + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + LLGestureStepWait* new_wait_step = + new LLGestureStepWait(*wait_step); + gesture->mSteps.push_back(new_wait_step); + break; + } + default: + { + break; + } + } + } + + return gesture; +} + + +void LLPreviewGesture::onCommitKeyorModifier() +{ + // SL-14139: ctrl-F10 is currently used to access top menu, + // so don't allow to bound gestures to this combination. + + mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL); + mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10)); + mDirty = true; + refresh(); +} + +// static +void LLPreviewGesture::updateLabel(LLScrollListItem* item) +{ + LLGestureStep* step = (LLGestureStep*)item->getUserdata(); + + LLScrollListCell* cell = item->getColumn(0); + LLScrollListText* text_cell = (LLScrollListText*)cell; + std::string label = getLabel( step->getLabel()); + text_cell->setText(label); +} + +// static +void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + self->mDirty = true; + self->refresh(); +} + +// static +void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* library_item = self->mLibraryList->getFirstSelected(); + if (library_item) + { + self->mStepList->deselectAllItems(); + self->refresh(); + } +} + + +// static +void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (!step_item) return; + + self->mLibraryList->deselectAllItems(); + self->refresh(); +} + + +// static +void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (step_item) + { + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() == STEP_ANIMATION) + { + // Assign the animation name + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + if (self->mAnimationCombo->getCurrentIndex() == 0) + { + anim_step->mAnimName.clear(); + anim_step->mAnimAssetID.setNull(); + } + else + { + anim_step->mAnimName = self->mAnimationCombo->getSimple(); + anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID(); + } + //anim_step->mFlags = 0x0; + + // Update the UI label in the list + updateLabel(step_item); + + self->mDirty = true; + self->refresh(); + } + } +} + +// static +void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (step_item) + { + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() == STEP_ANIMATION) + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + if (self->mAnimationRadio->getSelectedIndex() == 0) + { + // start + anim_step->mFlags &= ~ANIM_FLAG_STOP; + } + else + { + // stop + anim_step->mFlags |= ANIM_FLAG_STOP; + } + // Update the UI label in the list + updateLabel(step_item); + + self->mDirty = true; + self->refresh(); + } + } +} + +// static +void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (step_item) + { + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() == STEP_SOUND) + { + // Assign the sound name + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + sound_step->mSoundName = self->mSoundCombo->getSimple(); + sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID(); + sound_step->mFlags = 0x0; + + // Update the UI label in the list + updateLabel(step_item); + + self->mDirty = true; + self->refresh(); + } + } +} + +// static +void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (!step_item) return; + + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() != STEP_CHAT) return; + + LLGestureStepChat* chat_step = (LLGestureStepChat*)step; + chat_step->mChatText = self->mChatEditor->getText(); + chat_step->mFlags = 0x0; + + // Update the UI label in the list + updateLabel(step_item); + + self->mDirty = true; + self->refresh(); +} + +// static +void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (!step_item) return; + + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() != STEP_WAIT) return; + + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + U32 flags = 0x0; + if (self->mWaitKeyReleaseCheck->get()) flags |= WAIT_FLAG_KEY_RELEASE; + if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM; + if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME; + wait_step->mFlags = flags; + + { + LLLocale locale(LLLocale::USER_LOCALE); + + F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str()); + if (wait_seconds < 0.f) wait_seconds = 0.f; + if (wait_seconds > 3600.f) wait_seconds = 3600.f; + wait_step->mWaitSeconds = wait_seconds; + } + + // Enable the input area if necessary + self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get()); + + // Update the UI label in the list + updateLabel(step_item); + + self->mDirty = true; + self->refresh(); +} + +// static +void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* step_item = self->mStepList->getFirstSelected(); + if (!step_item) return; + + LLGestureStep* step = (LLGestureStep*)step_item->getUserdata(); + if (step->getType() != STEP_WAIT) return; + + self->mWaitTimeCheck->set(true); + onCommitWait(ctrl, data); +} + + +// static +void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller, + void* data) +{ + // Just commit every keystroke + onCommitSetDirty(caller, data); +} + +// static +void LLPreviewGesture::onClickAdd(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* library_item = self->mLibraryList->getFirstSelected(); + if (!library_item) return; + + S32 library_item_index = self->mLibraryList->getFirstSelectedIndex(); + + const LLScrollListCell* library_cell = library_item->getColumn(0); + const std::string& library_text = library_cell->getValue().asString(); + + if( library_item_index >= STEP_EOF ) + { + LL_ERRS() << "Unknown step type: " << library_text << LL_ENDL; + return; + } + + self->addStep( (EStepType)library_item_index ); + self->mDirty = true; + self->refresh(); +} + +LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) +{ + // Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml + + LLGestureStep* step = NULL; + switch( step_type) + { + case STEP_ANIMATION: + step = new LLGestureStepAnimation(); + + break; + case STEP_SOUND: + step = new LLGestureStepSound(); + break; + case STEP_CHAT: + step = new LLGestureStepChat(); + break; + case STEP_WAIT: + step = new LLGestureStepWait(); + break; + default: + LL_ERRS() << "Unknown step type: " << (S32)step_type << LL_ENDL; + return NULL; + } + + + // Create an enabled item with this step + LLSD row; + row["columns"][0]["value"] = getLabel(step->getLabel()); + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + LLScrollListItem* step_item = mStepList->addElement(row); + step_item->setUserdata(step); + + // And move selection to the list on the right + mLibraryList->deselectAllItems(); + mStepList->deselectAllItems(); + + step_item->setSelected(true); + + return step_item; +} + +// static +std::string LLPreviewGesture::getLabel(std::vector<std::string> labels) +{ + std::vector<std::string> v_labels = labels ; + std::string result(""); + + if( v_labels.size() != 2) + { + return result; + } + + if(v_labels[0]=="Chat") + { + result=LLTrans::getString("Chat Message"); + } + else if(v_labels[0]=="Sound") + { + result=LLTrans::getString("Sound"); + } + else if(v_labels[0]=="Wait") + { + result=LLTrans::getString("Wait"); + } + else if(v_labels[0]=="AnimFlagStop") + { + result=LLTrans::getString("AnimFlagStop"); + } + else if(v_labels[0]=="AnimFlagStart") + { + result=LLTrans::getString("AnimFlagStart"); + } + + // lets localize action value + std::string action = v_labels[1]; + if ("None" == action) + { + action = LLTrans::getString("GestureActionNone"); + } + else if ("until animations are done" == action) + { + action = LLFloaterReg::getInstance("preview_gesture")->getChild<LLCheckBoxCtrl>("wait_anim_check")->getLabel(); + } + result.append(action); + return result; + +} +// static +void LLPreviewGesture::onClickUp(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + S32 selected_index = self->mStepList->getFirstSelectedIndex(); + if (selected_index > 0) + { + self->mStepList->swapWithPrevious(selected_index); + self->mDirty = true; + self->refresh(); + } +} + +// static +void LLPreviewGesture::onClickDown(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + S32 selected_index = self->mStepList->getFirstSelectedIndex(); + if (selected_index < 0) return; + + S32 count = self->mStepList->getItemCount(); + if (selected_index < count-1) + { + self->mStepList->swapWithNext(selected_index); + self->mDirty = true; + self->refresh(); + } +} + +// static +void LLPreviewGesture::onClickDelete(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + LLScrollListItem* item = self->mStepList->getFirstSelected(); + S32 selected_index = self->mStepList->getFirstSelectedIndex(); + if (item && selected_index >= 0) + { + LLGestureStep* step = (LLGestureStep*)item->getUserdata(); + delete step; + step = NULL; + + self->mStepList->deleteSingleItem(selected_index); + + self->mDirty = true; + self->refresh(); + } +} + +// static +void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + if (!LLGestureMgr::instance().isGestureActive(self->mItemUUID)) + { + LLGestureMgr::instance().activateGesture(self->mItemUUID); + } + else + { + LLGestureMgr::instance().deactivateGesture(self->mItemUUID); + } + + // Make sure the (active) label in the inventory gets updated. + LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID); + if (item) + { + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + + self->refresh(); +} + +// static +void LLPreviewGesture::onClickSave(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + self->saveIfNeeded(); +} + +// static +void LLPreviewGesture::onClickPreview(void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + if (!self->mPreviewGesture) + { + // make temporary gesture + self->mPreviewGesture = self->createGesture(); + + // add a callback + self->mPreviewGesture->mDoneCallback = onDonePreview; + self->mPreviewGesture->mCallbackData = self; + + // set the button title + self->mPreviewBtn->setLabel(self->getString("stop_txt")); + + // play it, and delete when done + LLGestureMgr::instance().playGesture(self->mPreviewGesture); + + self->refresh(); + } + else + { + // Will call onDonePreview() below + LLGestureMgr::instance().stopGesture(self->mPreviewGesture); + + self->refresh(); + } +} + + +// static +void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data) +{ + LLPreviewGesture* self = (LLPreviewGesture*)data; + + self->mPreviewBtn->setLabel(self->getString("preview_txt")); + + delete self->mPreviewGesture; + self->mPreviewGesture = NULL; + + self->refresh(); +} |