aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpreviewgesture.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llpreviewgesture.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llpreviewgesture.cpp')
-rw-r--r--linden/indra/newview/llpreviewgesture.cpp1717
1 files changed, 1717 insertions, 0 deletions
diff --git a/linden/indra/newview/llpreviewgesture.cpp b/linden/indra/newview/llpreviewgesture.cpp
new file mode 100644
index 0000000..1ff782a
--- /dev/null
+++ b/linden/indra/newview/llpreviewgesture.cpp
@@ -0,0 +1,1717 @@
1/**
2 * @file llpreviewgesture.cpp
3 * @brief Editing UI for inventory-based gestures.
4 *
5 * Copyright (c) 2004-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include <algorithm>
31
32#include "llpreviewgesture.h"
33
34// libraries
35#include "lldatapacker.h"
36#include "lldarray.h"
37#include "llstring.h"
38#include "lldir.h"
39#include "llmultigesture.h"
40#include "llvfile.h"
41
42// newview
43#include "llagent.h" // todo: remove
44#include "llbutton.h"
45#include "llcheckboxctrl.h"
46#include "llcombobox.h"
47#include "llfloatergesture.h" // for some label constants
48#include "llgesturemgr.h"
49#include "llinventorymodel.h"
50#include "llkeyboard.h"
51#include "lllineeditor.h"
52#include "llnotify.h"
53#include "llradiogroup.h"
54#include "llscrolllistctrl.h"
55#include "lltextbox.h"
56#include "llvieweruictrlfactory.h"
57#include "llviewerinventory.h"
58#include "llviewerobject.h"
59#include "llviewerobjectlist.h"
60#include "llviewerstats.h"
61#include "llviewerwindow.h" // busycount
62#include "viewer.h" // gVFS
63
64#include "llresmgr.h"
65
66const char NONE_LABEL[] = "---";
67const char SHIFT_LABEL[] = "Shift";
68const char CTRL_LABEL[] = "Ctrl";
69
70void dialog_refresh_all();
71
72// used for getting
73
74class LLInventoryGestureAvailable : public LLInventoryCompletionObserver
75{
76public:
77 LLInventoryGestureAvailable() {}
78
79protected:
80 virtual void done();
81};
82
83void LLInventoryGestureAvailable::done()
84{
85 LLPreview* preview = NULL;
86 item_ref_t::iterator it = mComplete.begin();
87 item_ref_t::iterator end = mComplete.end();
88 for(; it < end; ++it)
89 {
90 preview = LLPreview::find((*it));
91 if(preview)
92 {
93 preview->refresh();
94 }
95 }
96 gInventory.removeObserver(this);
97 delete this;
98}
99
100// Used for sorting
101struct SortItemPtrsByName
102{
103 bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2)
104 {
105 return (LLString::compareDict(i1->getName(), i2->getName()) < 0);
106 }
107};
108
109// static
110LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus)
111{
112 LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id);
113 if (previewp)
114 {
115 previewp->open();
116 if (take_focus)
117 {
118 previewp->setFocus(TRUE);
119 }
120 return previewp;
121 }
122
123 LLPreviewGesture* self = new LLPreviewGesture();
124
125 // Finish internal construction
126 self->init(item_id, object_id);
127
128 // Builds and adds to gFloaterView
129 gUICtrlFactory->buildFloater(self, "floater_preview_gesture.xml");
130 self->setTitle(title);
131
132 // Move window to top-left of screen
133 LLMultiFloater* hostp = self->getHost();
134 if (hostp == NULL)
135 {
136 LLRect r = self->getRect();
137 LLRect screen = gFloaterView->getRect();
138 r.setLeftTopAndSize(0, screen.getHeight(), r.getWidth(), r.getHeight());
139 self->setRect(r);
140 }
141 else
142 {
143 // re-add to host to update title
144 hostp->addFloater(self, TRUE);
145 }
146
147 // this will call refresh when we have everything.
148 LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
149 if(item && !item->isComplete())
150 {
151 LLInventoryGestureAvailable* observer;
152 observer = new LLInventoryGestureAvailable();
153 observer->watchItem(item_id);
154 gInventory.addObserver(observer);
155 item->fetchFromServer();
156 }
157 else
158 {
159 // not sure this is necessary.
160 self->refresh();
161 }
162
163 if (take_focus)
164 {
165 self->setFocus(TRUE);
166 }
167
168 return self;
169}
170
171
172// virtual
173BOOL LLPreviewGesture::handleKeyHere(KEY key, MASK mask,
174 BOOL called_from_parent)
175{
176 if(getVisible() && getEnabled())
177 {
178 if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
179 {
180 saveIfNeeded();
181 return TRUE;
182 }
183 }
184 return LLPreview::handleKeyHere(key, mask, called_from_parent);
185}
186
187
188// virtual
189BOOL LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
190 EDragAndDropType cargo_type,
191 void* cargo_data,
192 EAcceptance* accept,
193 LLString& tooltip_msg)
194{
195 BOOL handled = TRUE;
196 switch(cargo_type)
197 {
198 case DAD_ANIMATION:
199 case DAD_SOUND:
200 {
201 // TODO: Don't allow this if you can't transfer the sound/animation
202
203 // make a script step
204 LLInventoryItem* item = (LLInventoryItem*)cargo_data;
205 if (item
206 && gInventory.getItem(item->getUUID()))
207 {
208 LLPermissions perm = item->getPermissions();
209 if (!((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED))
210 {
211 *accept = ACCEPT_NO;
212 if (tooltip_msg.empty())
213 {
214 tooltip_msg.assign("Only animations and sounds\n"
215 "with unrestricted permissions\n"
216 "can be added to a gesture.");
217 }
218 break;
219 }
220 else if (drop)
221 {
222 LLScrollListItem* line = NULL;
223 if (cargo_type == DAD_ANIMATION)
224 {
225 line = addStep("Animation");
226 LLGestureStepAnimation* anim = (LLGestureStepAnimation*)line->getUserdata();
227 anim->mAnimAssetID = item->getAssetUUID();
228 anim->mAnimName = item->getName();
229 }
230 else if (cargo_type == DAD_SOUND)
231 {
232 line = addStep("Sound");
233 LLGestureStepSound* sound = (LLGestureStepSound*)line->getUserdata();
234 sound->mSoundAssetID = item->getAssetUUID();
235 sound->mSoundName = item->getName();
236 }
237 updateLabel(line);
238 mDirty = TRUE;
239 refresh();
240 }
241 *accept = ACCEPT_YES_COPY_MULTI;
242 }
243 else
244 {
245 // Not in user's inventory means it was in object inventory
246 *accept = ACCEPT_NO;
247 }
248 break;
249 }
250 default:
251 *accept = ACCEPT_NO;
252 if (tooltip_msg.empty())
253 {
254 tooltip_msg.assign("Only animations and sounds\n"
255 "can be added to a gesture.");
256 }
257 break;
258 }
259 return handled;
260}
261
262
263// virtual
264BOOL LLPreviewGesture::canClose()
265{
266 if(!mDirty)
267 {
268 return TRUE;
269 }
270 else
271 {
272 // Bring up view-modal dialog: Save changes? Yes, No, Cancel
273 gViewerWindow->alertXml("SaveChanges",
274 handleSaveChangesDialog,
275 this );
276 return FALSE;
277 }
278}
279
280// virtual
281void LLPreviewGesture::onClose(bool app_quitting)
282{
283 gGestureManager.stopGesture(mPreviewGesture);
284 LLPreview::onClose(app_quitting);
285}
286
287// virtual
288void LLPreviewGesture::setMinimized(BOOL minimize)
289{
290 if (minimize != isMinimized())
291 {
292 LLFloater::setMinimized(minimize);
293
294 // We're being restored
295 if (!minimize)
296 {
297 refresh();
298 }
299 }
300}
301
302
303// static
304void LLPreviewGesture::handleSaveChangesDialog(S32 option, void* data)
305{
306 LLPreviewGesture* self = (LLPreviewGesture*)data;
307 switch(option)
308 {
309 case 0: // "Yes"
310 gGestureManager.stopGesture(self->mPreviewGesture);
311 self->mCloseAfterSave = TRUE;
312 onClickSave(data);
313 break;
314
315 case 1: // "No"
316 gGestureManager.stopGesture(self->mPreviewGesture);
317 self->mDirty = FALSE; // Force the dirty flag because user has clicked NO on confirm save dialog...
318 self->close();
319 break;
320
321 case 2: // "Cancel"
322 default:
323 // If we were quitting, we didn't really mean it.
324 app_abort_quit();
325 break;
326 }
327}
328
329
330LLPreviewGesture::LLPreviewGesture()
331: LLPreview("Gesture Preview"),
332 mTriggerEditor(NULL),
333 mModifierCombo(NULL),
334 mKeyCombo(NULL),
335 mLibraryList(NULL),
336 mAddBtn(NULL),
337 mUpBtn(NULL),
338 mDownBtn(NULL),
339 mDeleteBtn(NULL),
340 mStepList(NULL),
341 mOptionsText(NULL),
342 mAnimationRadio(NULL),
343 mAnimationCombo(NULL),
344 mSoundCombo(NULL),
345 mChatEditor(NULL),
346 mSaveBtn(NULL),
347 mPreviewBtn(NULL),
348 mPreviewGesture(NULL),
349 mDirty(FALSE)
350{
351}
352
353
354LLPreviewGesture::~LLPreviewGesture()
355{
356 // Userdata for all steps is a LLGestureStep we need to clean up
357 std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
358 std::vector<LLScrollListItem*>::iterator data_itor;
359 for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
360 {
361 LLScrollListItem* item = *data_itor;
362 LLGestureStep* step = (LLGestureStep*)item->getUserdata();
363 delete step;
364 step = NULL;
365 }
366}
367
368
369BOOL LLPreviewGesture::postBuild()
370{
371 LLLineEditor* edit;
372 LLComboBox* combo;
373 LLButton* btn;
374 LLScrollListCtrl* list;
375 LLTextBox* text;
376 LLCheckBoxCtrl* check;
377
378 edit = LLViewerUICtrlFactory::getLineEditorByName(this, "trigger_editor");
379 edit->setKeystrokeCallback(onKeystrokeCommit);
380 edit->setCommitCallback(onCommitSetDirty);
381 edit->setCommitOnFocusLost(TRUE);
382 edit->setCallbackUserData(this);
383 edit->setIgnoreTab(TRUE);
384 mTriggerEditor = edit;
385
386 text = LLViewerUICtrlFactory::getTextBoxByName(this, "replace_text");
387 text->setEnabled(FALSE);
388 mReplaceText = text;
389
390 edit = LLViewerUICtrlFactory::getLineEditorByName(this, "replace_editor");
391 edit->setEnabled(FALSE);
392 edit->setKeystrokeCallback(onKeystrokeCommit);
393 edit->setCommitCallback(onCommitSetDirty);
394 edit->setCommitOnFocusLost(TRUE);
395 edit->setCallbackUserData(this);
396 edit->setIgnoreTab(TRUE);
397 mReplaceEditor = edit;
398
399 combo = LLViewerUICtrlFactory::getComboBoxByName(this, "modifier_combo");
400 combo->setCommitCallback(onCommitSetDirty);
401 combo->setCallbackUserData(this);
402 mModifierCombo = combo;
403
404 combo = LLViewerUICtrlFactory::getComboBoxByName(this, "key_combo");
405 combo->setCommitCallback(onCommitSetDirty);
406 combo->setCallbackUserData(this);
407 mKeyCombo = combo;
408
409 list = LLViewerUICtrlFactory::getScrollListByName(this, "library_list");
410 list->setCommitCallback(onCommitLibrary);
411 list->setDoubleClickCallback(onClickAdd);
412 list->setCallbackUserData(this);
413 mLibraryList = list;
414
415 btn = LLViewerUICtrlFactory::getButtonByName(this, "add_btn");
416 btn->setClickedCallback(onClickAdd);
417 btn->setCallbackUserData(this);
418 btn->setEnabled(FALSE);
419 mAddBtn = btn;
420
421 btn = LLViewerUICtrlFactory::getButtonByName(this, "up_btn");
422 btn->setClickedCallback(onClickUp);
423 btn->setCallbackUserData(this);
424 btn->setEnabled(FALSE);
425 mUpBtn = btn;
426
427 btn = LLViewerUICtrlFactory::getButtonByName(this, "down_btn");
428 btn->setClickedCallback(onClickDown);
429 btn->setCallbackUserData(this);
430 btn->setEnabled(FALSE);
431 mDownBtn = btn;
432
433 btn = LLViewerUICtrlFactory::getButtonByName(this, "delete_btn");
434 btn->setClickedCallback(onClickDelete);
435 btn->setCallbackUserData(this);
436 btn->setEnabled(FALSE);
437 mDeleteBtn = btn;
438
439 list = LLViewerUICtrlFactory::getScrollListByName(this, "step_list");
440 list->setCommitCallback(onCommitStep);
441 list->setCallbackUserData(this);
442 mStepList = list;
443
444 // Options
445 text = LLViewerUICtrlFactory::getTextBoxByName(this, "options_text");
446 text->setBorderVisible(TRUE);
447 mOptionsText = text;
448
449 combo = LLViewerUICtrlFactory::getComboBoxByName(this, "animation_list");
450 combo->setVisible(FALSE);
451 combo->setCommitCallback(onCommitAnimation);
452 combo->setCallbackUserData(this);
453 mAnimationCombo = combo;
454
455 LLRadioGroup* group;
456 group = LLViewerUICtrlFactory::getRadioGroupByName(this, "animation_trigger_type");
457 group->setVisible(FALSE);
458 group->setCommitCallback(onCommitAnimationTrigger);
459 group->setCallbackUserData(this);
460 mAnimationRadio = group;
461
462 combo = LLViewerUICtrlFactory::getComboBoxByName(this, "sound_list");
463 combo->setVisible(FALSE);
464 combo->setCommitCallback(onCommitSound);
465 combo->setCallbackUserData(this);
466 mSoundCombo = combo;
467
468 edit = LLViewerUICtrlFactory::getLineEditorByName(this, "chat_editor");
469 edit->setVisible(FALSE);
470 edit->setCommitCallback(onCommitChat);
471 //edit->setKeystrokeCallback(onKeystrokeCommit);
472 edit->setCommitOnFocusLost(TRUE);
473 edit->setCallbackUserData(this);
474 edit->setIgnoreTab(TRUE);
475 mChatEditor = edit;
476
477 check = LLViewerUICtrlFactory::getCheckBoxByName(this, "wait_anim_check");
478 check->setVisible(FALSE);
479 check->setCommitCallback(onCommitWait);
480 check->setCallbackUserData(this);
481 mWaitAnimCheck = check;
482
483 check = LLViewerUICtrlFactory::getCheckBoxByName(this, "wait_time_check");
484 check->setVisible(FALSE);
485 check->setCommitCallback(onCommitWait);
486 check->setCallbackUserData(this);
487 mWaitTimeCheck = check;
488
489 edit = LLViewerUICtrlFactory::getLineEditorByName(this, "wait_time_editor");
490 edit->setEnabled(FALSE);
491 edit->setVisible(FALSE);
492 edit->setPrevalidate(LLLineEditor::prevalidateFloat);
493// edit->setKeystrokeCallback(onKeystrokeCommit);
494 edit->setCommitOnFocusLost(TRUE);
495 edit->setCommitCallback(onCommitWaitTime);
496 edit->setCallbackUserData(this);
497 edit->setIgnoreTab(TRUE);
498 mWaitTimeEditor = edit;
499
500 // Buttons at the bottom
501 check = LLViewerUICtrlFactory::getCheckBoxByName(this, "active_check");
502 check->setCommitCallback(onCommitActive);
503 check->setCallbackUserData(this);
504 mActiveCheck = check;
505
506 btn = LLViewerUICtrlFactory::getButtonByName(this, "save_btn");
507 btn->setClickedCallback(onClickSave);
508 btn->setCallbackUserData(this);
509 mSaveBtn = btn;
510
511 btn = LLViewerUICtrlFactory::getButtonByName(this, "preview_btn");
512 btn->setClickedCallback(onClickPreview);
513 btn->setCallbackUserData(this);
514 mPreviewBtn = btn;
515
516
517 // Populate the comboboxes
518 addModifiers();
519 addKeys();
520 addAnimations();
521 addSounds();
522
523
524 LLInventoryItem* item = getItem();
525
526 if (item)
527 {
528 childSetCommitCallback("desc", LLPreview::onText, this);
529 childSetText("desc", item->getDescription());
530 childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe);
531 }
532
533 return TRUE;
534}
535
536
537void LLPreviewGesture::addModifiers()
538{
539 LLComboBox* combo = mModifierCombo;
540
541 combo->add( NONE_LABEL, ADD_BOTTOM );
542 combo->add( SHIFT_LABEL, ADD_BOTTOM );
543 combo->add( CTRL_LABEL, ADD_BOTTOM );
544 combo->setCurrentByIndex(0);
545}
546
547void LLPreviewGesture::addKeys()
548{
549 LLComboBox* combo = mKeyCombo;
550
551 combo->add( NONE_LABEL );
552 for (KEY key = KEY_F2; key <= KEY_F12; key++)
553 {
554 combo->add( LLKeyboard::stringFromKey(key), ADD_BOTTOM );
555 }
556 combo->setCurrentByIndex(0);
557}
558
559
560// TODO: Sort the legacy and non-legacy together?
561void LLPreviewGesture::addAnimations()
562{
563 LLComboBox* combo = mAnimationCombo;
564
565 combo->removeall();
566
567 combo->add("-- None --", LLUUID::null);
568
569 // Add all the default (legacy) animations
570 S32 i;
571 for (i = 0; i < gUserAnimStatesCount; ++i)
572 {
573 // Use the user-readable name
574 const char* label = gUserAnimStates[i].mLabel;
575 const LLUUID& id = gUserAnimStates[i].mID;
576 combo->add(label, id);
577 }
578
579 // Get all inventory items that are animations
580 LLViewerInventoryCategory::cat_array_t cats;
581 LLViewerInventoryItem::item_array_t items;
582 LLIsTypeWithPermissions is_copyable_animation(LLAssetType::AT_ANIMATION,
583 PERM_ITEM_UNRESTRICTED,
584 gAgent.getID(),
585 gAgent.getGroupID());
586 gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
587 cats,
588 items,
589 LLInventoryModel::EXCLUDE_TRASH,
590 is_copyable_animation);
591
592 // Copy into something we can sort
593 std::vector<LLInventoryItem*> animations;
594
595 S32 count = items.count();
596 for(i = 0; i < count; ++i)
597 {
598 animations.push_back( items.get(i) );
599 }
600
601 // Do the sort
602 std::sort(animations.begin(), animations.end(), SortItemPtrsByName());
603
604 // And load up the combobox
605 std::vector<LLInventoryItem*>::iterator it;
606 for (it = animations.begin(); it != animations.end(); ++it)
607 {
608 LLInventoryItem* item = *it;
609
610 combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
611 }
612}
613
614
615void LLPreviewGesture::addSounds()
616{
617 // Get all inventory items that are sounds
618 LLViewerInventoryCategory::cat_array_t cats;
619 LLViewerInventoryItem::item_array_t items;
620 LLIsTypeWithPermissions is_copyable_sound(LLAssetType::AT_SOUND,
621 PERM_ITEM_UNRESTRICTED,
622 gAgent.getID(),
623 gAgent.getGroupID());
624 gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
625 cats,
626 items,
627 LLInventoryModel::EXCLUDE_TRASH,
628 is_copyable_sound);
629
630 // Copy sounds into something we can sort
631 std::vector<LLInventoryItem*> sounds;
632
633 S32 i;
634 S32 count = items.count();
635 for(i = 0; i < count; ++i)
636 {
637 sounds.push_back( items.get(i) );
638 }
639
640 // Do the sort
641 std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName());
642
643 // And load up the combobox
644 LLComboBox* combo = mSoundCombo;
645 combo->removeall();
646 std::vector<LLInventoryItem*>::iterator it;
647 for (it = sounds.begin(); it != sounds.end(); ++it)
648 {
649 LLInventoryItem* item = *it;
650
651 combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM);
652 }
653}
654
655
656void LLPreviewGesture::init(const LLUUID& item_id, const LLUUID& object_id)
657{
658 // Sets ID and adds to instance list
659 setItemID(item_id);
660 setObjectID(object_id);
661}
662
663
664void LLPreviewGesture::refresh()
665{
666 // If previewing or item is incomplete, all controls are disabled
667 LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
668 bool is_complete = (item && item->isComplete()) ? true : false;
669 if (mPreviewGesture || !is_complete)
670 {
671
672 childSetEnabled("desc", FALSE);
673 //mDescEditor->setEnabled(FALSE);
674 mTriggerEditor->setEnabled(FALSE);
675 mReplaceText->setEnabled(FALSE);
676 mReplaceEditor->setEnabled(FALSE);
677 mModifierCombo->setEnabled(FALSE);
678 mKeyCombo->setEnabled(FALSE);
679 mLibraryList->setEnabled(FALSE);
680 mAddBtn->setEnabled(FALSE);
681 mUpBtn->setEnabled(FALSE);
682 mDownBtn->setEnabled(FALSE);
683 mDeleteBtn->setEnabled(FALSE);
684 mStepList->setEnabled(FALSE);
685 mOptionsText->setEnabled(FALSE);
686 mAnimationCombo->setEnabled(FALSE);
687 mAnimationRadio->setEnabled(FALSE);
688 mSoundCombo->setEnabled(FALSE);
689 mChatEditor->setEnabled(FALSE);
690 mWaitAnimCheck->setEnabled(FALSE);
691 mWaitTimeCheck->setEnabled(FALSE);
692 mWaitTimeEditor->setEnabled(FALSE);
693 mActiveCheck->setEnabled(FALSE);
694 mSaveBtn->setEnabled(FALSE);
695
696 // Make sure preview button is enabled, so we can stop it
697 mPreviewBtn->setEnabled(TRUE);
698 return;
699 }
700
701 BOOL modifiable = item->getPermissions().allowModifyBy(gAgent.getID());
702
703 childSetEnabled("desc", modifiable);
704 mTriggerEditor->setEnabled(TRUE);
705 mLibraryList->setEnabled(modifiable);
706 mStepList->setEnabled(modifiable);
707 mOptionsText->setEnabled(modifiable);
708 mAnimationCombo->setEnabled(modifiable);
709 mAnimationRadio->setEnabled(modifiable);
710 mSoundCombo->setEnabled(modifiable);
711 mChatEditor->setEnabled(modifiable);
712 mWaitAnimCheck->setEnabled(modifiable);
713 mWaitTimeCheck->setEnabled(modifiable);
714 mWaitTimeEditor->setEnabled(modifiable);
715 mActiveCheck->setEnabled(TRUE);
716
717 const std::string& trigger = mTriggerEditor->getText();
718 BOOL have_trigger = !trigger.empty();
719
720 const std::string& replace = mReplaceEditor->getText();
721 BOOL have_replace = !replace.empty();
722
723 LLScrollListItem* library_item = mLibraryList->getFirstSelected();
724 BOOL have_library = (library_item != NULL);
725
726 LLScrollListItem* step_item = mStepList->getFirstSelected();
727 S32 step_index = mStepList->getFirstSelectedIndex();
728 S32 step_count = mStepList->getItemCount();
729 BOOL have_step = (step_item != NULL);
730
731 mReplaceText->setEnabled(have_trigger || have_replace);
732 mReplaceEditor->setEnabled(have_trigger || have_replace);
733
734 mModifierCombo->setEnabled(TRUE);
735 mKeyCombo->setEnabled(TRUE);
736
737 mAddBtn->setEnabled(modifiable && have_library);
738 mUpBtn->setEnabled(modifiable && have_step && step_index > 0);
739 mDownBtn->setEnabled(modifiable && have_step && step_index < step_count-1);
740 mDeleteBtn->setEnabled(modifiable && have_step);
741
742 // Assume all not visible
743 mAnimationCombo->setVisible(FALSE);
744 mAnimationRadio->setVisible(FALSE);
745 mSoundCombo->setVisible(FALSE);
746 mChatEditor->setVisible(FALSE);
747 mWaitAnimCheck->setVisible(FALSE);
748 mWaitTimeCheck->setVisible(FALSE);
749 mWaitTimeEditor->setVisible(FALSE);
750
751 if (have_step)
752 {
753 // figure out the type, show proper options, update text
754 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
755 EStepType type = step->getType();
756 switch(type)
757 {
758 case STEP_ANIMATION:
759 {
760 LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
761 mOptionsText->setText("Animation to play:");
762 mAnimationCombo->setVisible(TRUE);
763 mAnimationRadio->setVisible(TRUE);
764 mAnimationRadio->setSelectedIndex((anim_step->mFlags & ANIM_FLAG_STOP) ? 1 : 0);
765 mAnimationCombo->setCurrentByID(anim_step->mAnimAssetID);
766 break;
767 }
768 case STEP_SOUND:
769 {
770 LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
771 mOptionsText->setText("Sound to play:");
772 mSoundCombo->setVisible(TRUE);
773 mSoundCombo->setCurrentByID(sound_step->mSoundAssetID);
774 break;
775 }
776 case STEP_CHAT:
777 {
778 LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
779 mOptionsText->setText("Chat to say:");
780 mChatEditor->setVisible(TRUE);
781 mChatEditor->setText(chat_step->mChatText);
782 break;
783 }
784 case STEP_WAIT:
785 {
786 LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
787 mOptionsText->setText("Wait:");
788 mWaitAnimCheck->setVisible(TRUE);
789 mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM);
790 mWaitTimeCheck->setVisible(TRUE);
791 mWaitTimeCheck->set(wait_step->mFlags & WAIT_FLAG_TIME);
792 mWaitTimeEditor->setVisible(TRUE);
793 char buffer[16];
794 sprintf(buffer, "%.1f", (double)wait_step->mWaitSeconds);
795 mWaitTimeEditor->setText(buffer);
796 break;
797 }
798 default:
799 break;
800 }
801 }
802 else
803 {
804 // no gesture
805 mOptionsText->setText("");
806 }
807
808 BOOL active = gGestureManager.isGestureActive(mItemUUID);
809 mActiveCheck->set(active);
810
811 // Can only preview if there are steps
812 mPreviewBtn->setEnabled(step_count > 0);
813
814 // And can only save if changes have been made
815 mSaveBtn->setEnabled(mDirty);
816 addAnimations();
817 addSounds();
818}
819
820
821void LLPreviewGesture::initDefaultGesture()
822{
823 LLScrollListItem* item;
824 item = addStep("Animation");
825 LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata();
826 anim->mAnimAssetID = ANIM_AGENT_HELLO;
827 anim->mAnimName = "Wave";
828 updateLabel(item);
829
830 item = addStep("Wait");
831 LLGestureStepWait* wait = (LLGestureStepWait*)item->getUserdata();
832 wait->mFlags = WAIT_FLAG_ALL_ANIM;
833 updateLabel(item);
834
835 item = addStep("Chat");
836 LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata();
837 chat_step->mChatText = "Hello, avatar!";
838 updateLabel(item);
839
840 // Start with item list selected
841 mStepList->selectFirstItem();
842
843 // this is *new* content, so we are dirty
844 mDirty = TRUE;
845}
846
847
848void LLPreviewGesture::loadAsset()
849{
850 LLInventoryItem* item = getItem();
851 if (!item) return;
852
853 LLUUID asset_id = item->getAssetUUID();
854 if (asset_id.isNull())
855 {
856 // Freshly created gesture, don't need to load asset.
857 // Blank gesture will be fine.
858 initDefaultGesture();
859 refresh();
860 return;
861 }
862
863 // TODO: Based on item->getPermissions().allow*
864 // could enable/disable UI.
865
866 // Copy the UUID, because the user might close the preview
867 // window if the download gets stalled.
868 LLUUID* item_idp = new LLUUID(mItemUUID);
869
870 const BOOL high_priority = TRUE;
871 gAssetStorage->getAssetData(asset_id,
872 LLAssetType::AT_GESTURE,
873 onLoadComplete,
874 (void**)item_idp,
875 high_priority);
876 mAssetStatus = PREVIEW_ASSET_LOADING;
877}
878
879
880// static
881void LLPreviewGesture::onLoadComplete(LLVFS *vfs,
882 const LLUUID& asset_uuid,
883 LLAssetType::EType type,
884 void* user_data, S32 status)
885{
886 LLUUID* item_idp = (LLUUID*)user_data;
887 LLPreview* preview = LLPreview::find(*item_idp);
888 if (preview)
889 {
890 LLPreviewGesture* self = (LLPreviewGesture*)preview;
891
892 if (0 == status)
893 {
894 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
895 S32 size = file.getSize();
896
897 char* buffer = new char[size+1];
898 file.read((U8*)buffer, size);
899 buffer[size] = '\0';
900
901 LLMultiGesture* gesture = new LLMultiGesture();
902
903 LLDataPackerAsciiBuffer dp(buffer, size+1);
904 BOOL ok = gesture->deserialize(dp);
905
906 if (ok)
907 {
908 // Everything has been successful. Load up the UI.
909 self->loadUIFromGesture(gesture);
910
911 self->mStepList->selectFirstItem();
912
913 self->mDirty = FALSE;
914 self->refresh();
915 }
916 else
917 {
918 llwarns << "Unable to load gesture" << llendl;
919 }
920
921 delete gesture;
922 gesture = NULL;
923
924 delete [] buffer;
925 buffer = NULL;
926
927 self->mAssetStatus = PREVIEW_ASSET_LOADED;
928 }
929 else
930 {
931 if( gViewerStats )
932 {
933 gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
934 }
935
936 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
937 LL_ERR_FILE_EMPTY == status)
938 {
939 LLNotifyBox::showXml("GestureMissing");
940 }
941 else
942 {
943 LLNotifyBox::showXml("UnableToLoadGesture");
944 }
945
946 llwarns << "Problem loading gesture: " << status << llendl;
947 self->mAssetStatus = PREVIEW_ASSET_ERROR;
948 }
949 }
950 delete item_idp;
951 item_idp = NULL;
952}
953
954
955void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
956{
957 /*LLInventoryItem* item = getItem();
958
959
960
961 if (item)
962 {
963 LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
964 descEditor->setText(item->getDescription());
965 }*/
966
967 mTriggerEditor->setText(gesture->mTrigger);
968
969 mReplaceEditor->setText(gesture->mReplaceText);
970
971 switch (gesture->mMask)
972 {
973 default:
974 case MASK_NONE:
975 mModifierCombo->setSimple( NONE_LABEL );
976 break;
977 case MASK_SHIFT:
978 mModifierCombo->setSimple( SHIFT_LABEL );
979 break;
980 case MASK_CONTROL:
981 mModifierCombo->setSimple( CTRL_LABEL );
982 break;
983 }
984
985 mKeyCombo->setCurrentByIndex(0);
986 if (gesture->mKey != KEY_NONE)
987 {
988 mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
989 }
990
991 // Make UI steps for each gesture step
992 S32 i;
993 S32 count = gesture->mSteps.size();
994 for (i = 0; i < count; ++i)
995 {
996 LLGestureStep* step = gesture->mSteps[i];
997
998 LLGestureStep* new_step = NULL;
999
1000 switch(step->getType())
1001 {
1002 case STEP_ANIMATION:
1003 {
1004 LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1005 LLGestureStepAnimation* new_anim_step =
1006 new LLGestureStepAnimation(*anim_step);
1007 new_step = new_anim_step;
1008 break;
1009 }
1010 case STEP_SOUND:
1011 {
1012 LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
1013 LLGestureStepSound* new_sound_step =
1014 new LLGestureStepSound(*sound_step);
1015 new_step = new_sound_step;
1016 break;
1017 }
1018 case STEP_CHAT:
1019 {
1020 LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
1021 LLGestureStepChat* new_chat_step =
1022 new LLGestureStepChat(*chat_step);
1023 new_step = new_chat_step;
1024 break;
1025 }
1026 case STEP_WAIT:
1027 {
1028 LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
1029 LLGestureStepWait* new_wait_step =
1030 new LLGestureStepWait(*wait_step);
1031 new_step = new_wait_step;
1032 break;
1033 }
1034 default:
1035 {
1036 break;
1037 }
1038 }
1039
1040 if (!new_step) continue;
1041
1042 // Create an enabled item with this step
1043 LLScrollListItem* item = new LLScrollListItem(TRUE, new_step);
1044 item->addColumn(new_step->getLabel(), LLFontGL::sSansSerifSmall);
1045
1046 // Add item to bottom of list
1047 mStepList->addItem(item, ADD_BOTTOM);
1048 }
1049}
1050
1051// Helpful structure so we can look up the inventory item
1052// after the save finishes.
1053struct LLSaveInfo
1054{
1055 LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const LLString& desc,
1056 const LLTransactionID tid)
1057 : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid)
1058 {
1059 }
1060
1061 LLUUID mItemUUID;
1062 LLUUID mObjectUUID;
1063 LLString mDesc;
1064 LLTransactionID mTransactionID;
1065};
1066
1067
1068void LLPreviewGesture::saveIfNeeded()
1069{
1070 if (!gAssetStorage)
1071 {
1072 llwarns << "Can't save gesture, no asset storage system." << llendl;
1073 return;
1074 }
1075
1076 if (!mDirty)
1077 {
1078 return;
1079 }
1080
1081 // Copy the UI into a gesture
1082 LLMultiGesture* gesture = createGesture();
1083
1084 // Serialize the gesture
1085 S32 max_size = gesture->getMaxSerialSize();
1086 char* buffer = new char[max_size];
1087
1088 LLDataPackerAsciiBuffer dp(buffer, max_size);
1089
1090 BOOL ok = gesture->serialize(dp);
1091
1092 if (dp.getCurrentSize() > 1000)
1093 {
1094 gViewerWindow->alertXml("GestureSaveFailedTooManySteps");
1095
1096 delete gesture;
1097 gesture = NULL;
1098 }
1099 else if (!ok)
1100 {
1101 gViewerWindow->alertXml("GestureSaveFailedTryAgain");
1102 delete gesture;
1103 gesture = NULL;
1104 }
1105 else
1106 {
1107 // Every save gets a new UUID. Yup.
1108 LLTransactionID tid;
1109 LLAssetID asset_id;
1110 tid.generate();
1111 asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
1112
1113 LLVFile file(gVFS, asset_id, LLAssetType::AT_GESTURE, LLVFile::APPEND);
1114
1115 S32 size = dp.getCurrentSize();
1116 file.setMaxSize(size);
1117 file.write((U8*)buffer, size);
1118
1119 // Upload that asset to the database
1120 LLInventoryItem* item = getItem();
1121 if (item)
1122 {
1123 LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
1124 LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
1125
1126 const BOOL temp_file = FALSE;
1127
1128 gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, temp_file);
1129
1130 }
1131
1132 // If this gesture is active, then we need to update the in-memory
1133 // active map with the new pointer.
1134 if (gGestureManager.isGestureActive(mItemUUID))
1135 {
1136 // gesture manager now owns the pointer
1137 gGestureManager.replaceGesture(mItemUUID, gesture, asset_id);
1138
1139 // replaceGesture may deactivate other gestures so let the
1140 // inventory know.
1141 gInventory.notifyObservers();
1142 }
1143 else
1144 {
1145 // we're done with this gesture
1146 delete gesture;
1147 gesture = NULL;
1148 }
1149
1150 mDirty = FALSE;
1151 refresh();
1152 }
1153
1154 delete [] buffer;
1155 buffer = NULL;
1156}
1157
1158
1159// TODO: This is very similar to LLPreviewNotecard::onSaveComplete.
1160// Could merge code.
1161// static
1162void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status) // StoreAssetData callback (fixed)
1163{
1164 LLSaveInfo* info = (LLSaveInfo*)user_data;
1165 if (info && (status == 0))
1166 {
1167 if(info->mObjectUUID.isNull())
1168 {
1169 // Saving into user inventory
1170 LLViewerInventoryItem* item;
1171 item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
1172 if(item)
1173 {
1174 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1175 new_item->setDescription(info->mDesc);
1176 new_item->setTransactionID(info->mTransactionID);
1177 new_item->setAssetUUID(asset_uuid);
1178 new_item->updateServer(FALSE);
1179 gInventory.updateItem(new_item);
1180 gInventory.notifyObservers();
1181 }
1182 else
1183 {
1184 llwarns << "Inventory item for gesture " << info->mItemUUID
1185 << " is no longer in agent inventory." << llendl
1186 }
1187 }
1188 else
1189 {
1190 // Saving into in-world object inventory
1191 LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
1192 LLViewerInventoryItem* item = NULL;
1193 if(object)
1194 {
1195 item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
1196 }
1197 if(object && item)
1198 {
1199 item->setDescription(info->mDesc);
1200 item->setAssetUUID(asset_uuid);
1201 item->setTransactionID(info->mTransactionID);
1202 object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
1203 dialog_refresh_all();
1204 }
1205 else
1206 {
1207 gViewerWindow->alertXml("GestureSaveFailedObjectNotFound");
1208 }
1209 }
1210
1211 // Find our window and close it if requested.
1212 LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(info->mItemUUID);
1213 if (previewp && previewp->mCloseAfterSave)
1214 {
1215 previewp->close();
1216 }
1217 }
1218 else
1219 {
1220 llwarns << "Problem saving gesture: " << status << llendl;
1221 LLStringBase<char>::format_map_t args;
1222 args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
1223 gViewerWindow->alertXml("GestureSaveFailedReason",args);
1224 }
1225 delete info;
1226 info = NULL;
1227}
1228
1229
1230LLMultiGesture* LLPreviewGesture::createGesture()
1231{
1232 LLMultiGesture* gesture = new LLMultiGesture();
1233
1234 gesture->mTrigger = mTriggerEditor->getText();
1235 gesture->mReplaceText = mReplaceEditor->getText();
1236
1237 const LLString& modifier = mModifierCombo->getSimple();
1238 if (modifier == CTRL_LABEL)
1239 {
1240 gesture->mMask = MASK_CONTROL;
1241 }
1242 else if (modifier == SHIFT_LABEL)
1243 {
1244 gesture->mMask = MASK_SHIFT;
1245 }
1246 else
1247 {
1248 gesture->mMask = MASK_NONE;
1249 }
1250
1251 if (mKeyCombo->getCurrentIndex() == 0)
1252 {
1253 gesture->mKey = KEY_NONE;
1254 }
1255 else
1256 {
1257 const LLString& key_string = mKeyCombo->getSimple();
1258 LLKeyboard::keyFromString(key_string.c_str(), &(gesture->mKey));
1259 }
1260
1261 std::vector<LLScrollListItem*> data_list = mStepList->getAllData();
1262 std::vector<LLScrollListItem*>::iterator data_itor;
1263 for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
1264 {
1265 LLScrollListItem* item = *data_itor;
1266 LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1267
1268 switch(step->getType())
1269 {
1270 case STEP_ANIMATION:
1271 {
1272 // Copy UI-generated step into actual gesture step
1273 LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1274 LLGestureStepAnimation* new_anim_step =
1275 new LLGestureStepAnimation(*anim_step);
1276 gesture->mSteps.push_back(new_anim_step);
1277 break;
1278 }
1279 case STEP_SOUND:
1280 {
1281 // Copy UI-generated step into actual gesture step
1282 LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
1283 LLGestureStepSound* new_sound_step =
1284 new LLGestureStepSound(*sound_step);
1285 gesture->mSteps.push_back(new_sound_step);
1286 break;
1287 }
1288 case STEP_CHAT:
1289 {
1290 // Copy UI-generated step into actual gesture step
1291 LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
1292 LLGestureStepChat* new_chat_step =
1293 new LLGestureStepChat(*chat_step);
1294 gesture->mSteps.push_back(new_chat_step);
1295 break;
1296 }
1297 case STEP_WAIT:
1298 {
1299 // Copy UI-generated step into actual gesture step
1300 LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
1301 LLGestureStepWait* new_wait_step =
1302 new LLGestureStepWait(*wait_step);
1303 gesture->mSteps.push_back(new_wait_step);
1304 break;
1305 }
1306 default:
1307 {
1308 break;
1309 }
1310 }
1311 }
1312
1313 return gesture;
1314}
1315
1316
1317// static
1318void LLPreviewGesture::updateLabel(LLScrollListItem* item)
1319{
1320 LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1321
1322 LLScrollListCell* cell = item->getColumn(0);
1323 LLScrollListText* text_cell = (LLScrollListText*)cell;
1324 std::string label = step->getLabel();
1325 text_cell->setText(label);
1326}
1327
1328// static
1329void LLPreviewGesture::onCommitSetDirty(LLUICtrl* ctrl, void* data)
1330{
1331 LLPreviewGesture* self = (LLPreviewGesture*)data;
1332 self->mDirty = TRUE;
1333 self->refresh();
1334}
1335
1336// static
1337void LLPreviewGesture::onCommitLibrary(LLUICtrl* ctrl, void* data)
1338{
1339 LLPreviewGesture* self = (LLPreviewGesture*)data;
1340
1341 LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
1342 if (library_item)
1343 {
1344 self->mStepList->deselectAllItems();
1345 self->refresh();
1346 }
1347}
1348
1349
1350// static
1351void LLPreviewGesture::onCommitStep(LLUICtrl* ctrl, void* data)
1352{
1353 LLPreviewGesture* self = (LLPreviewGesture*)data;
1354
1355 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1356 if (!step_item) return;
1357
1358 self->mLibraryList->deselectAllItems();
1359 self->refresh();
1360}
1361
1362
1363// static
1364void LLPreviewGesture::onCommitAnimation(LLUICtrl* ctrl, void* data)
1365{
1366 LLPreviewGesture* self = (LLPreviewGesture*)data;
1367
1368 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1369 if (step_item)
1370 {
1371 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1372 if (step->getType() == STEP_ANIMATION)
1373 {
1374 // Assign the animation name
1375 LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1376 if (self->mAnimationCombo->getCurrentIndex() == 0)
1377 {
1378 anim_step->mAnimName.clear();
1379 anim_step->mAnimAssetID.setNull();
1380 }
1381 else
1382 {
1383 anim_step->mAnimName = self->mAnimationCombo->getSimple();
1384 anim_step->mAnimAssetID = self->mAnimationCombo->getCurrentID();
1385 }
1386 //anim_step->mFlags = 0x0;
1387
1388 // Update the UI label in the list
1389 updateLabel(step_item);
1390
1391 self->mDirty = TRUE;
1392 self->refresh();
1393 }
1394 }
1395}
1396
1397// static
1398void LLPreviewGesture::onCommitAnimationTrigger(LLUICtrl* ctrl, void *data)
1399{
1400 LLPreviewGesture* self = (LLPreviewGesture*)data;
1401
1402 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1403 if (step_item)
1404 {
1405 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1406 if (step->getType() == STEP_ANIMATION)
1407 {
1408 LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
1409 if (self->mAnimationRadio->getSelectedIndex() == 0)
1410 {
1411 // start
1412 anim_step->mFlags &= ~ANIM_FLAG_STOP;
1413 }
1414 else
1415 {
1416 // stop
1417 anim_step->mFlags |= ANIM_FLAG_STOP;
1418 }
1419 // Update the UI label in the list
1420 updateLabel(step_item);
1421
1422 self->mDirty = TRUE;
1423 self->refresh();
1424 }
1425 }
1426}
1427
1428// static
1429void LLPreviewGesture::onCommitSound(LLUICtrl* ctrl, void* data)
1430{
1431 LLPreviewGesture* self = (LLPreviewGesture*)data;
1432
1433 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1434 if (step_item)
1435 {
1436 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1437 if (step->getType() == STEP_SOUND)
1438 {
1439 // Assign the sound name
1440 LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
1441 sound_step->mSoundName = self->mSoundCombo->getSimple();
1442 sound_step->mSoundAssetID = self->mSoundCombo->getCurrentID();
1443 sound_step->mFlags = 0x0;
1444
1445 // Update the UI label in the list
1446 updateLabel(step_item);
1447
1448 self->mDirty = TRUE;
1449 self->refresh();
1450 }
1451 }
1452}
1453
1454// static
1455void LLPreviewGesture::onCommitChat(LLUICtrl* ctrl, void* data)
1456{
1457 LLPreviewGesture* self = (LLPreviewGesture*)data;
1458
1459 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1460 if (!step_item) return;
1461
1462 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1463 if (step->getType() != STEP_CHAT) return;
1464
1465 LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
1466 chat_step->mChatText = self->mChatEditor->getText();
1467 chat_step->mFlags = 0x0;
1468
1469 // Update the UI label in the list
1470 updateLabel(step_item);
1471
1472 self->mDirty = TRUE;
1473 self->refresh();
1474}
1475
1476// static
1477void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data)
1478{
1479 LLPreviewGesture* self = (LLPreviewGesture*)data;
1480
1481 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1482 if (!step_item) return;
1483
1484 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1485 if (step->getType() != STEP_WAIT) return;
1486
1487 LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
1488 U32 flags = 0x0;
1489 if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM;
1490 if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME;
1491 wait_step->mFlags = flags;
1492
1493 {
1494 LLLocale locale(LLLocale::USER_LOCALE);
1495
1496 F32 wait_seconds = (F32)atof(self->mWaitTimeEditor->getText().c_str());
1497 if (wait_seconds < 0.f) wait_seconds = 0.f;
1498 if (wait_seconds > 3600.f) wait_seconds = 3600.f;
1499 wait_step->mWaitSeconds = wait_seconds;
1500 }
1501
1502 // Enable the input area if necessary
1503 self->mWaitTimeEditor->setEnabled(self->mWaitTimeCheck->get());
1504
1505 // Update the UI label in the list
1506 updateLabel(step_item);
1507
1508 self->mDirty = TRUE;
1509 self->refresh();
1510}
1511
1512// static
1513void LLPreviewGesture::onCommitWaitTime(LLUICtrl* ctrl, void* data)
1514{
1515 LLPreviewGesture* self = (LLPreviewGesture*)data;
1516
1517 LLScrollListItem* step_item = self->mStepList->getFirstSelected();
1518 if (!step_item) return;
1519
1520 LLGestureStep* step = (LLGestureStep*)step_item->getUserdata();
1521 if (step->getType() != STEP_WAIT) return;
1522
1523 self->mWaitTimeCheck->set(TRUE);
1524 onCommitWait(ctrl, data);
1525}
1526
1527
1528// static
1529void LLPreviewGesture::onKeystrokeCommit(LLLineEditor* caller,
1530 void* data)
1531{
1532 // Just commit every keystroke
1533 onCommitSetDirty(caller, data);
1534}
1535
1536// static
1537void LLPreviewGesture::onClickAdd(void* data)
1538{
1539 LLPreviewGesture* self = (LLPreviewGesture*)data;
1540
1541 LLScrollListItem* library_item = self->mLibraryList->getFirstSelected();
1542 if (!library_item) return;
1543
1544 const LLScrollListCell* library_cell = library_item->getColumn(0);
1545 const std::string& library_text = library_cell->getText();
1546
1547 self->addStep(library_text);
1548
1549 self->mDirty = TRUE;
1550 self->refresh();
1551}
1552
1553LLScrollListItem* LLPreviewGesture::addStep(const std::string& library_text)
1554{
1555 LLGestureStep* step = NULL;
1556 if (!LLString::compareInsensitive(library_text.c_str(), "Animation"))
1557 {
1558 step = new LLGestureStepAnimation();
1559 }
1560 else if (!LLString::compareInsensitive(library_text.c_str(), "Sound"))
1561 {
1562 step = new LLGestureStepSound();
1563 }
1564 else if (!LLString::compareInsensitive(library_text.c_str(), "Chat"))
1565 {
1566 step = new LLGestureStepChat();
1567 }
1568 else if (!LLString::compareInsensitive(library_text.c_str(), "Wait"))
1569 {
1570 step = new LLGestureStepWait();
1571 }
1572
1573 // Create an enabled item with this step
1574 LLScrollListItem* step_item = new LLScrollListItem(TRUE, step);
1575 std::string label = step->getLabel();
1576 step_item->addColumn(label, LLFontGL::sSansSerifSmall);
1577
1578 // Add item to bottom of list
1579 mStepList->addItem(step_item, ADD_BOTTOM);
1580
1581 // And move selection to the list on the right
1582 mLibraryList->deselectAllItems();
1583 mStepList->deselectAllItems();
1584
1585 step_item->setSelected(TRUE);
1586
1587 return step_item;
1588}
1589
1590// static
1591void LLPreviewGesture::onClickUp(void* data)
1592{
1593 LLPreviewGesture* self = (LLPreviewGesture*)data;
1594
1595 S32 selected_index = self->mStepList->getFirstSelectedIndex();
1596 if (selected_index > 0)
1597 {
1598 self->mStepList->swapWithPrevious(selected_index);
1599 self->mDirty = TRUE;
1600 self->refresh();
1601 }
1602}
1603
1604// static
1605void LLPreviewGesture::onClickDown(void* data)
1606{
1607 LLPreviewGesture* self = (LLPreviewGesture*)data;
1608
1609 S32 selected_index = self->mStepList->getFirstSelectedIndex();
1610 if (selected_index < 0) return;
1611
1612 S32 count = self->mStepList->getItemCount();
1613 if (selected_index < count-1)
1614 {
1615 self->mStepList->swapWithNext(selected_index);
1616 self->mDirty = TRUE;
1617 self->refresh();
1618 }
1619}
1620
1621// static
1622void LLPreviewGesture::onClickDelete(void* data)
1623{
1624 LLPreviewGesture* self = (LLPreviewGesture*)data;
1625
1626 LLScrollListItem* item = self->mStepList->getFirstSelected();
1627 S32 selected_index = self->mStepList->getFirstSelectedIndex();
1628 if (selected_index >= 0)
1629 {
1630 LLGestureStep* step = (LLGestureStep*)item->getUserdata();
1631 delete step;
1632 step = NULL;
1633
1634 self->mStepList->deleteSingleItem(selected_index);
1635
1636 self->mDirty = TRUE;
1637 self->refresh();
1638 }
1639}
1640
1641// static
1642void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data)
1643{
1644 LLPreviewGesture* self = (LLPreviewGesture*)data;
1645 if (!gGestureManager.isGestureActive(self->mItemUUID))
1646 {
1647 gGestureManager.activateGesture(self->mItemUUID);
1648 }
1649 else
1650 {
1651 gGestureManager.deactivateGesture(self->mItemUUID);
1652 }
1653
1654 // Make sure the (active) label in the inventory gets updated.
1655 LLViewerInventoryItem* item = gInventory.getItem(self->mItemUUID);
1656 if (item)
1657 {
1658 gInventory.updateItem(item);
1659 gInventory.notifyObservers();
1660 }
1661
1662 self->refresh();
1663}
1664
1665// static
1666void LLPreviewGesture::onClickSave(void* data)
1667{
1668 LLPreviewGesture* self = (LLPreviewGesture*)data;
1669 self->saveIfNeeded();
1670}
1671
1672// static
1673void LLPreviewGesture::onClickPreview(void* data)
1674{
1675 LLPreviewGesture* self = (LLPreviewGesture*)data;
1676
1677 if (!self->mPreviewGesture)
1678 {
1679 // make temporary gesture
1680 self->mPreviewGesture = self->createGesture();
1681
1682 // add a callback
1683 self->mPreviewGesture->mDoneCallback = onDonePreview;
1684 self->mPreviewGesture->mCallbackData = self;
1685
1686 // set the button title
1687 self->mPreviewBtn->setLabelSelected("Stop");
1688 self->mPreviewBtn->setLabelUnselected("Stop");
1689
1690 // play it, and delete when done
1691 gGestureManager.playGesture(self->mPreviewGesture);
1692
1693 self->refresh();
1694 }
1695 else
1696 {
1697 // Will call onDonePreview() below
1698 gGestureManager.stopGesture(self->mPreviewGesture);
1699
1700 self->refresh();
1701 }
1702}
1703
1704
1705// static
1706void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data)
1707{
1708 LLPreviewGesture* self = (LLPreviewGesture*)data;
1709
1710 self->mPreviewBtn->setLabelSelected("Preview");
1711 self->mPreviewBtn->setLabelUnselected("Preview");
1712
1713 delete self->mPreviewGesture;
1714 self->mPreviewGesture = NULL;
1715
1716 self->refresh();
1717}