diff options
Diffstat (limited to 'indra/newview/llpreviewgesture.cpp')
| -rw-r--r-- | indra/newview/llpreviewgesture.cpp | 3620 |
1 files changed, 1816 insertions, 1804 deletions
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 05faf17bdc..010dc48391 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -1,1804 +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_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); - 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); - 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); - 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"); - 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->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();
+}
|
