ParticleEffectUI.cpp

Christophe Delépine, 10/21/2010 11:21 am

Download (13.7 KB)

 
1
#include "ParticleEffectUI.h"
2
#include "BasicParticleEditor.h"
3
#include "CurveEdit.h"
4
#include "ParticleEmitterModelEdit.h"
5
#include "DirectionEdit.h"
6
#include "EmitterListEdit.h"
7
#include "Slider.h"
8
#include "FloatSliderEdit.h"
9
#include "ParticleEffectsWriter.h"
10
#include "ExplosionUpdateMsg.h"
11
#include "BaseSFXEditor.h"
12
13
#include "Communication/SFXComSlot.h"
14
15
// core
16
#include "../../SDK/PlatformIndependent/Core/ProductInformation.h"
17
#include "../../SDK/PlatformIndependent/Core/ServiceManager.h"
18
#include "../../SDK/PlatformIndependent/Core/Label.h"
19
#include "../../SDK/PlatformIndependent/Core/XMLParser.h"
20
#include "../../SDK/PlatformIndependent/Core/XMLElement.h"
21
#include "../../SDK/SDKRuntime.h"
22
#include "../../SDK/PlatformIndependent/Core/Thread.h"
23
#include "../../SDK/PlatformIndependent/Core/Timer.h"
24
#include "../../SDK/PlatformIndependent/SceneManagement/SceneManager.h"
25
26
// simulation facade
27
#include "../../SimulationFacade/ExplosionConfig.h"
28
#include "../../SimulationFacade/GenericObject.h"
29
30
#include <Wt/WPanel>
31
#include <Wt/WBreak>
32
#include <Wt/WContainerWidget>
33
#include <Wt/WLineEdit>
34
#include <Wt/WPushButton>
35
#include <Wt/WText>
36
#include <Wt/WSlider>
37
#include <Wt/WTable>
38
#include <Wt/WTree>
39
#include <Wt/WTreeNode>
40
#include <Wt/WIconPair>
41
#include <Wt/WGridLayout>
42
#include <Wt/WHBoxLayout>
43
#include <Wt/WVBoxLayout>
44
#include <Wt/WDoubleValidator>
45
#include <Wt/WRegExpValidator>
46
#include <Wt/WSignalMapper>
47
#include <Wt/WTimer>
48
#include <Wt/WLogger>
49
#include <Wt/WStandardItemModel>
50
#include <Wt/Chart/WCartesianChart>
51
#include <Wt/WPointF>
52
#include <Wt/WPainterPath>
53
#include <Wt/WPainter>
54
#include <Wt/WScrollArea>
55
#include <Wt/WGroupBox>
56
#include <Wt/WPopupMenu>
57
#include <Wt/WMessageBox>
58
#include <Wt/WDialog>
59
#include <Wt/WStackedWidget>
60
61
#include <Wt/Ext/Button>
62
#include <Wt/Ext/LineEdit>
63
#include <Wt/Ext/ComboBox>
64
#include <Wt/Ext/CheckBox>
65
#include <Wt/Ext/RadioButton>
66
#include <Wt/Ext/Calendar>
67
#include <Wt/Ext/DateField>
68
#include <Wt/Ext/Menu>
69
#include <Wt/Ext/ToolBar>
70
#include <Wt/Ext/NumberField>
71
72
73
using namespace Wt;
74
using namespace Wt::Chart;
75
using namespace TVNG;
76
77
//-------------------------------------------------------------------------
78
ParticleEffectUI::ParticleEffectUI(const char* panelName, SFXComData::PAGE_CODE pageCode, unsigned int emitterFuncCode,
79
                                                                   unsigned int parameterFuncCode)
80
:
81
pageCode_ (pageCode),
82
emitterFuncCode_ (emitterFuncCode),
83
parameterFuncCode_ (parameterFuncCode),
84
editor_ (NULL),
85
messageBox_(NULL),
86
currentSelectedNode_(NULL),
87
com_ (BaseSFXEditor::sfxEditorInstance_->GetComSlot ())
88
{
89
        WVBoxLayout* layout = new WVBoxLayout();
90
        layout->setContentsMargins(0, 0, 0, 0);
91
        setLayout(layout);
92
93
        // toolbar
94
        Ext::ToolBar *toolBar = new Ext::ToolBar();
95
        Ext::Button *button = toolBar->addButton("Save");
96
        button->clicked().connect(this, &ParticleEffectUI::SaveClicked);
97
        layout->addWidget(toolBar);
98
        
99
        WContainerWidget* container = new WContainerWidget();
100
    WHBoxLayout *boxLayout = new WHBoxLayout(container);
101
        boxLayout->setContentsMargins(0, 0, 0, 0);
102
        
103
        layout->addWidget(container, 1);
104
        dynamicView_ = new WStackedWidget();
105
106
        // panel
107
        WPanel* panel = new WPanel();
108
        panel->setTitle(panelName);
109
        modelTree_ = new WTree();
110
        modelTree_->setSelectionMode(SingleSelection);
111
112
        WTreeNode* rootnode = new WTreeNode("");
113
        modelsRoot_ = rootnode;
114
        rootnode->setNodeVisible(false);
115
        rootnode->setSelectable(false);
116
        modelTree_->setTreeRoot(rootnode);
117
118
        boxLayout->addWidget(panel);
119
        boxLayout->setResizable(0, true);
120
        boxLayout->addWidget(dynamicView_, 1);
121
122
        WScrollArea* scrollArea = new WScrollArea();
123
        scrollArea->setScrollBarPolicy(WScrollArea::ScrollBarAsNeeded);
124
        scrollArea->setWidget(modelTree_);
125
        panel->setCentralWidget(scrollArea);
126
127
        boxLayout->setResizable(0, true);
128
129
        pemEdit_ = new ParticleEmitterModelEdit();
130
        pemEdit_->MinMaxParamChanged().connect(this, &ParticleEffectUI::MinMaxParamChanged);
131
        pemEdit_->FloatParamChanged().connect(this, &ParticleEffectUI::FloatParamChanged);
132
        pemEdit_->Vector3ParamChanged().connect(this, &ParticleEffectUI::Vector3ParamChanged);
133
        pemEdit_->IntParamChanged().connect(this, &ParticleEffectUI::IntParamChanged);
134
135
        dynamicView_->addWidget(new WContainerWidget());
136
        dynamicView_->addWidget(pemEdit_);
137
138
        mouseUpMapper_ = new WSignalMapper< WTreeNode*, WMouseEvent >(this);
139
        mouseUpMapper_->mapped().connect(this, &ParticleEffectUI::MouseUpBasicEmitter);
140
141
        popupActionMapper_ = new Wt::WSignalMapper< int >(this);
142
        popupActionMapper_->mapped().connect(this, &ParticleEffectUI::PopupAction);
143
144
        popup_ = new WPopupMenu();
145
        WPopupMenuItem* item = popup_->addItem("Copy");
146
        popupActionMapper_->mapConnect(item->triggered(), POPUP_COPY);
147
        item = popup_->addItem("Paste");
148
        popupActionMapper_->mapConnect(item->triggered(), POPUP_PASTE);
149
        item = popup_->addItem("Clone");
150
        popupActionMapper_->mapConnect(item->triggered(), POPUP_CLONE);
151
        popup_->addSeparator();
152
        item = popup_->addItem("Rename");
153
        popupActionMapper_->mapConnect(item->triggered(), POPUP_RENAME);
154
        item = popup_->addItem("Delete");
155
        item->setChecked(true);
156
        popupActionMapper_->mapConnect(item->triggered(), POPUP_DELETE);
157
158
        renameDialog_ = new WDialog();
159
        renameDialog_->setWindowTitle("Change Name");
160
        WContainerWidget* content = renameDialog_->contents();
161
        WVBoxLayout* dialogLayout = new WVBoxLayout(content);
162
        {
163
                WHBoxLayout* layout = new WHBoxLayout();
164
                dialogLayout->addLayout(layout);
165
166
                WText* text = new WText("Name :");
167
                text->setWordWrap(false);
168
                layout->addWidget(text, 0, AlignMiddle);
169
                renameEdit_ = new WLineEdit();
170
                renameEdit_->setTextSize(30);
171
                layout->addWidget(renameEdit_, 1, AlignMiddle);
172
        }
173
        {
174
                WHBoxLayout* layout = new WHBoxLayout();
175
                dialogLayout->addLayout(layout);
176
177
                WPushButton* ok = new WPushButton("OK");
178
                WPushButton* cancel = new WPushButton("Cancel");
179
                ok->clicked().connect(this, &ParticleEffectUI::RenameOK);
180
                cancel->clicked().connect(this, &ParticleEffectUI::RenameCancel);
181
                layout->addStretch(1);
182
                layout->addWidget(ok, 0, AlignMiddle);
183
                layout->addWidget(cancel, 0, AlignMiddle);
184
        }        
185
}
186
187
//-------------------------------------------------------------------------
188
ParticleEffectUI::~ParticleEffectUI()
189
{
190
        delete popup_;
191
        delete renameDialog_;
192
193
        if (editor_ != NULL)
194
                delete editor_;
195
}
196
197
//-------------------------------------------------------------------------
198
void ParticleEffectUI::NodeSelectionChanged(bool selected)
199
{
200
        if (!selected) 
201
                currentSelectedNode_ = NULL;
202
        else
203
        {
204
                const WTree::WTreeNodeSet& selectedNodes = modelTree_->selectedNodes();
205
                currentSelectedNode_ = *selectedNodes.begin();
206
                WTreeNode* modelNode = GetModelNode(currentSelectedNode_);
207
                UpdateSelectModel (emitterFuncCode_, modelNode->label()->text().toUTF8().c_str(), currentSelectedNode_->label()->text().toUTF8().c_str());
208
                dynamicView_->setCurrentWidget(pemEdit_);
209
                pemEdit_->UpdateUI(editor_->GetCurrentParticleEmitterModel ());
210
        }
211
}
212
213
//-------------------------------------------------------------------------
214
void ParticleEffectUI::RenameOK()
215
{
216
        WTreeNode* node = currentSelectedNode_;
217
218
        renameDialog_->setHidden(true);
219
220
        std::string name( renameEdit_->text().toUTF8() );
221
        if (name.empty()) return;
222
        if (node->label()->text().toUTF8() == name) return;
223
224
        if (RenameEmitterModel(name.c_str()) == false) return;
225
226
        node->label()->setText(name.c_str());
227
228
        // keep nodes sorted by name
229
        WTreeNode* parent = node->parentNode();
230
        parent->removeChildNode(node);
231
        const std::vector< WTreeNode * > &childNodes = parent->childNodes();
232
        for (int index(0); index<childNodes.size(); index++)
233
        {
234
                WTreeNode* child = childNodes.at(index);
235
                if (child->label()->text().toUTF8() > name)
236
                        break;
237
        }
238
        parent->insertChildNode(index, node);
239
        modelTree_->select(node);
240
}
241
242
//-------------------------------------------------------------------------
243
void ParticleEffectUI::RenameCancel()
244
{
245
        renameDialog_->setHidden(true);
246
}
247
248
//-------------------------------------------------------------------------
249
void ParticleEffectUI::MouseUpBasicEmitter(WTreeNode* node, const WMouseEvent& evt)
250
{
251
        if (evt.button() == WMouseEvent::RightButton)
252
        {
253
                if (currentSelectedNode_ != node)
254
                {
255
                        modelTree_->select(node);
256
                }
257
                if (popup_->isHidden())
258
                        popup_->popup(evt);
259
                else
260
                        popup_->hide();
261
        }        
262
        else
263
                popup_->hide();
264
}
265
266
//-------------------------------------------------------------------------
267
WTreeNode* ParticleEffectUI::GetModelNode(WTreeNode* emitterModelNode) const
268
{
269
        WTreeNode* node = emitterModelNode;
270
        do
271
        {
272
                node = node->parentNode();
273
        } 
274
        while (node->parentNode() != modelsRoot_);
275
276
        return node;
277
}
278
279
//-------------------------------------------------------------------------
280
void ParticleEffectUI::UpdateSelectModel(unsigned int funcCode, const char* modelName, const char* emitterModelName)
281
{
282
        ModelNamesData data (pageCode_, funcCode, modelName, emitterModelName);
283
        com_->Write (data);
284
285
        if (editor_ != NULL)
286
        {
287
                editor_->SetCurrentModel (modelName, emitterModelName);
288
        }
289
}
290
291
//-------------------------------------------------------------------------
292
void ParticleEffectUI::MinMaxParamChanged(unsigned int paramId, float minValue, float maxValue, const TVNG::FloatAnimationCurve* curve)
293
{
294
        ParameterData data (pageCode_, parameterFuncCode_, paramId, minValue, maxValue, curve);
295
        com_->Write (data);
296
        editor_->SetParam(paramId, minValue, maxValue, curve);
297
}
298
299
//-------------------------------------------------------------------------
300
void ParticleEffectUI::Vector3ParamChanged(unsigned int paramId, const Vector3f& value)
301
{
302
        Vector3fParameterData data (pageCode_, parameterFuncCode_, paramId, value);
303
        com_->Write (data);
304
        editor_->SetParam(paramId, value);
305
}
306
307
//-------------------------------------------------------------------------
308
void ParticleEffectUI::FloatParamChanged(unsigned int paramId, float value)
309
{
310
        FloatParameterData data (pageCode_, parameterFuncCode_, paramId, value);
311
        com_->Write (data);
312
        editor_->SetParam(paramId, value);
313
}
314
315
//-------------------------------------------------------------------------
316
void ParticleEffectUI::IntParamChanged(unsigned int paramId, int value)
317
{
318
        IntParameterData data (pageCode_, parameterFuncCode_, paramId, value);
319
        com_->Write (data);
320
        editor_->SetParam(paramId, value);
321
}
322
323
//-------------------------------------------------------------------------
324
void ParticleEffectUI::SaveClicked()
325
{
326
        messageBox_ = new WMessageBox("Save", "Do you want to overwrite the configuration file ?", Wt::NoIcon, Wt::Ok | Wt::Cancel);
327
        messageBox_->textWidget()->setWordWrap(false);
328
        messageBox_->buttonClicked().connect(this, &ParticleEffectUI::SaveConfirmationDone);
329
        messageBox_->show();
330
}
331
332
//-------------------------------------------------------------------------
333
void ParticleEffectUI::SaveConfirmationDone(StandardButton result)
334
{
335
        if (result == Ok)
336
                editor_->Save();
337
338
        delete messageBox_;
339
        messageBox_ = 0;
340
}
341
342
//-------------------------------------------------------------------------
343
WTreeNode* ParticleEffectUI::AddTreeNode (const char* nodeName)
344
{
345
        WIconPair *modelIcon = new WIconPair("resources/icons/b-2-icon.png", "resources/icons/b-2-icon.png", false);
346
        WTreeNode* modelNode = new WTreeNode(nodeName, modelIcon);
347
        modelNode->setSelectable(false);
348
        modelTree_->treeRoot()->addChildNode(modelNode);
349
350
        return modelNode;
351
}
352
353
//-------------------------------------------------------------------------
354
WTreeNode* ParticleEffectUI::AddTreeNode (WTreeNode* father, const char* nodeName, bool isSelectable /*=false*/)
355
{
356
        WTreeNode* node = new WTreeNode(nodeName);
357
        node->setSelectable(isSelectable);
358
        father->addChildNode(node);
359
        return node;
360
}
361
362
//-------------------------------------------------------------------------
363
WTreeNode* ParticleEffectUI::CreateTreeNode(WTreeNode* father, const ParticleEmitterModelPtr& emitterModel )
364
{
365
        WTreeNode* node = new WTreeNode( emitterModel->GetName() );
366
367
        node->selected().connect(this, &ParticleEffectUI::NodeSelectionChanged);
368
369
        mouseUpMapper_->mapConnect1(node->label()->mouseWentUp(), node);
370
371
        node->label()->setAttributeValue("oncontextmenu", "event.cancelBubble = true; event.returnValue = false; return false;");
372
        unsigned int count = emitterModel->GetChildrenCount();
373
        for (unsigned int i(0); i<count; i++)
374
        {
375
                CreateTreeNode( node, emitterModel->GetChild(i) );
376
        }
377
        father->addChildNode( node );
378
        return node;
379
}
380
381
//-------------------------------------------------------------------------
382
void ParticleEffectUI::ExpandTree ()
383
{
384
        modelTree_->treeRoot()->expand();
385
}
386
387
//-------------------------------------------------------------------------
388
void ParticleEffectUI::PopupAction(int item) 
389
{
390
        popup_->hide();
391
        if (popup_->result() == NULL) return;
392
        
393
        switch (item)
394
        {
395
        case POPUP_RENAME:
396
                {
397
                        renameEdit_->setText(currentSelectedNode_->label()->text().toUTF8());
398
                        renameDialog_->show();
399
                }
400
                break;
401
        case POPUP_DELETE:
402
                {
403
                        std::string message = "Delete " + currentSelectedNode_->label()->text().toUTF8() + " ?";
404
                        messageBox_ = new WMessageBox("Delete Confirmation", message.c_str(), Wt::NoIcon, Wt::Ok | Wt::Cancel);
405
                        messageBox_->textWidget()->setWordWrap(false);
406
                        messageBox_->buttonClicked().connect(this, &ParticleEffectUI::DeleteConfirmationDone);
407
                        messageBox_->show();
408
                }
409
                break;
410
        }
411
}
412
413
//-------------------------------------------------------------------------
414
void ParticleEffectUI::DeleteConfirmationDone(StandardButton result) 
415
{
416
        if (result == Ok)
417
        {
418
                bool deleted = DeleteEmitterModel(currentSelectedNode_->label()->text().toUTF8().c_str());
419
                if (deleted)
420
                {
421
                        WTreeNode* parentNode = currentSelectedNode_->parentNode();
422
                        parentNode->removeChildNode(currentSelectedNode_);
423
                        dynamicView_->setCurrentIndex(0);
424
                }
425
        }
426
427
        delete messageBox_;
428
        messageBox_ = 0;
429
}
430
431