Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / tools / 3d / object_viewer / particle_dlg.cpp
blobf3d323d20764aad6a5478eb93873aa6864262d94
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // particle_dlg.cpp : implementation file
24 #include "std_afx.h"
25 #include "object_viewer.h"
26 #include "particle_dlg.h"
27 #include "editable_range.h"
28 #include "located_properties.h"
29 #include "particle_system_edit.h"
30 #include "skippable_message_box.h"
31 #include "main_frame.h"
33 // TODO : remove these include when the test system will be removed
34 #include "nel/3d/particle_system.h"
35 #include "nel/3d/ps_force.h"
36 #include "nel/3d/ps_emitter.h"
37 #include "nel/3d/ps_particle.h"
38 #include "nel/3d/ps_util.h"
39 #include "nel/3d/ps_zone.h"
40 #include "nel/3d/ps_color.h"
41 #include "nel/3d/ps_float.h"
42 #include "nel/3d/ps_int.h"
43 #include "nel/3d/ps_plane_basis_maker.h"
44 #include "nel/3d/particle_system_model.h"
45 #include "nel/3d/particle_system_shape.h"
46 #include "nel/3d/texture_file.h"
47 #include "nel/3d/texture_grouped.h"
48 #include "nel/3d/nelu.h"
49 #include "nel/3d/font_manager.h"
51 #include "nel/misc/file.h"
52 #include "start_stop_particle_system.h"
54 #include "save_options_dlg.h"
55 #include "create_file_dlg.h"
57 using namespace NL3D;
59 //**************************************************************************************************************************
60 CParticleDlg::CParticleDlg(class CObjectViewer* main, CWnd *pParent, CMainFrame* mainFrame, CAnimationDlg *animDLG)
61 : CDialog(CParticleDlg::IDD, pParent),
62 MainFrame(mainFrame),
63 CurrentRightPane(NULL),
64 _ActiveNode(NULL),
65 _ObjView(main),
66 _EmptyBBox(true),
67 _AutoUpdateBBox(false),
68 _PW(NULL)
71 //{{AFX_DATA_INIT(CParticleDlg)
72 // NOTE: the ClassWizard will add member initialization here
73 //}}AFX_DATA_INIT
74 nlverify (FontManager = main->getFontManager());
75 nlverify (FontGenerator = main->getFontGenerator());
76 NL3D::CParticleSystem::setSerializeIdentifierFlag(true); // serialize identifiers for edition
77 ParticleTreeCtrl = new CParticleTreeCtrl(this);
78 StartStopDlg = new CStartStopParticleSystem(this, animDLG);
79 /** register us, so that our 'go' method will be called
80 * this gives us a chance to display a bbox when needed
82 _ObjView->registerMainLoopCallBack(this);
86 //**************************************************************************************************************************
87 BOOL CParticleDlg::Create( UINT nIDTemplate, CWnd* pParentWnd /*= NULL*/ )
89 if (!CDialog::Create(nIDTemplate, pParentWnd)) return FALSE;
90 return TRUE;
93 //**************************************************************************************************************************
94 void CParticleDlg::moveElement(const NLMISC::CMatrix &mat)
96 ParticleTreeCtrl->moveElement(mat);
99 //**************************************************************************************************************************
100 NLMISC::CMatrix CParticleDlg::getElementMatrix(void) const
102 return ParticleTreeCtrl->getElementMatrix();
105 //**************************************************************************************************************************
106 CParticleDlg::~CParticleDlg()
108 _ObjView->removeMainLoopCallBack(this);
109 delete ParticleTreeCtrl;
110 delete CurrentRightPane;
111 delete StartStopDlg;
112 if (_PW) _PW->setModificationCallback(NULL);
113 delete _PW;
116 //**************************************************************************************************************************
117 void CParticleDlg::DoDataExchange(CDataExchange* pDX)
119 CDialog::DoDataExchange(pDX);
120 //{{AFX_DATA_MAP(CParticleDlg)
121 //}}AFX_DATA_MAP
125 BEGIN_MESSAGE_MAP(CParticleDlg, CDialog)
126 //{{AFX_MSG_MAP(CParticleDlg)
127 ON_WM_DESTROY()
128 ON_WM_SIZE()
129 ON_WM_SHOWWINDOW()
130 ON_WM_CHAR()
131 ON_COMMAND(IDM_CREATE_NEW_PS_WORKSPACE, OnCreateNewPsWorkspace)
132 ON_COMMAND(IDM_LOAD_PS_WORKSPACE, OnLoadPSWorkspace)
133 ON_COMMAND(IDM_SAVE_ALL_PS_WORKSPACE, OnSaveAllPsWorkspace)
134 ON_COMMAND(IDM_SAVE_PS_WORKSPACE, OnSavePsWorkspace)
135 ON_COMMAND(IDM_VIEW_PS_FILENAME, OnViewPsFilename)
136 //}}AFX_MSG_MAP
137 END_MESSAGE_MAP()
139 //**************************************************************************************************************************
140 void CParticleDlg::OnDestroy()
142 checkModifiedWorkSpace();
143 if (CurrentRightPane)
145 CurrentRightPane->DestroyWindow();
146 delete CurrentRightPane;
147 CurrentRightPane = NULL;
149 setRegisterWindowState (this, REGKEY_OBJ_PARTICLE_DLG);
150 CDialog::OnDestroy();
153 //**************************************************************************************************************************
154 BOOL CParticleDlg::OnInitDialog()
156 CDialog::OnInitDialog();
157 CRect r;
158 GetWindowRect(&r);
159 ParticleTreeCtrl->Create(WS_VISIBLE | WS_TABSTOP | WS_CHILD | WS_BORDER
160 | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_EDITLABELS
161 | TVS_DISABLEDRAGDROP , r, this, 0x1005);
162 ParticleTreeCtrl->init();
163 ParticleTreeCtrl->ShowWindow(SW_SHOW);
164 StartStopDlg->Create(IDD_PARTICLE_SYSTEM_START_STOP, this);
165 // create menu bar that allow to create / load a particle workspace
166 CMenu menu;
167 menu.LoadMenu(MAKEINTRESOURCE(IDR_PARTICLE_DLG_MENU));
168 this->SetMenu(&menu);
169 menu.Detach();
170 updateMenu();
172 _StatusBar.Create(this);
173 UINT indicators = ID_PS_EDITOR_STATUS;
174 _StatusBar.SetIndicators(&indicators, 1);
175 _StatusBar.SetPaneInfo(0, ID_PS_EDITOR_STATUS, SBPS_NORMAL, computeStatusBarWidth());
176 RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, ID_PS_EDITOR_STATUS);
177 return TRUE; // return TRUE unless you set the focus to a control
178 // EXCEPTION: OCX Property Pages should return FALSE
181 //**************************************************************************************************************************
182 void CParticleDlg::setStatusBarText(CString &str)
184 _StatusBar.SetPaneText(0, str, TRUE);
187 //**************************************************************************************************************************
188 void CParticleDlg::OnSize(UINT nType, int cx, int cy)
190 AFX_MANAGE_STATE(AfxGetStaticModuleState());
191 bool blocked = false;
192 if (ParticleTreeCtrl->m_hWnd && this->m_hWnd)
194 CRect r = getTreeRect(cx, cy);
195 ParticleTreeCtrl->MoveWindow(&r);
196 if (CurrentRightPane)
198 CurrentRightPane->MoveWindow(r.right + 10, r.top, r.right + CurrRightPaneWidth + 10, r.top + CurrRightPaneHeight);
200 CDialog::OnSize(nType, cx, cy);
201 if (IsWindow(_StatusBar))
203 _StatusBar.SetPaneInfo(0, ID_PS_EDITOR_STATUS, SBPS_NORMAL, computeStatusBarWidth());
204 RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, ID_PS_EDITOR_STATUS);
209 //**************************************************************************************************************************
210 CRect CParticleDlg::getTreeRect(int cx, int cy) const
212 const uint ox = 0, oy = 10;
214 if (CurrentRightPane)
216 CRect res(ox, oy, cx - CurrRightPaneWidth - 10, cy - 20);
217 return res;
219 else
221 CRect res(ox, oy, cx - 10, cy - 20);
222 return res;
226 //**************************************************************************************************************************
227 void CParticleDlg::setRightPane(CWnd *pane)
229 AFX_MANAGE_STATE(AfxGetStaticModuleState());
230 if (CurrentRightPane)
232 CurrentRightPane->DestroyWindow();
234 delete CurrentRightPane;
235 CurrentRightPane = pane;
236 RECT r;
237 if (pane)
240 pane->ShowWindow(SW_SHOW);
243 CurrentRightPane->GetClientRect(&r);
245 CurrRightPaneWidth = r.right;
246 CurrRightPaneHeight = r.bottom;
250 GetClientRect(&r);
251 this->SendMessage(WM_SIZE, SIZE_RESTORED, r.right + (r.bottom << 16));
252 GetWindowRect(&r);
253 this->MoveWindow(&r);
254 if (CurrentRightPane)
256 CurrentRightPane->Invalidate();
258 this->Invalidate();
259 ParticleTreeCtrl->Invalidate();
262 //**************************************************************************************************************************
263 LRESULT CParticleDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
266 if (message == WM_GETMINMAXINFO)
268 sint cx = 150, cy = 150;
269 if (CurrentRightPane)
271 RECT r;
272 CurrentRightPane->GetClientRect(&r);
273 cx += CurrRightPaneWidth;
274 if (cy < (CurrRightPaneHeight + 20) ) cy = CurrRightPaneHeight + 20;
278 MINMAXINFO *inf = (MINMAXINFO *) lParam;
279 inf->ptMinTrackSize.x = cx;
280 inf->ptMinTrackSize.y = cy;
284 return CDialog::WindowProc(message, wParam, lParam);
288 //**************************************************************************************************************************
289 void CParticleDlg::OnShowWindow(BOOL bShow, UINT nStatus)
291 CDialog::OnShowWindow(bShow, nStatus);
292 StartStopDlg->ShowWindow(bShow);
296 //**************************************************************************************************************************
297 void CParticleDlg::goPostRender()
299 NL3D::CParticleSystem *currPS = _ActiveNode ? _ActiveNode->getPSPointer() : NULL;
300 if (!currPS) return;
301 if (StartStopDlg->isBBoxDisplayEnabled() && currPS)
303 NL3D::CNELU::Driver->setupModelMatrix(currPS->getSysMat());
304 if (_AutoUpdateBBox)
306 NLMISC::CAABBox currBBox;
307 currPS->forceComputeBBox(currBBox);
308 if (_EmptyBBox)
310 _EmptyBBox = false;
311 _CurrBBox = currBBox;
313 else
315 NL3D::CPSUtil::displayBBox(NL3D::CNELU::Driver, _CurrBBox, CRGBA::Blue);
316 _CurrBBox = NLMISC::CAABBox::computeAABBoxUnion(currBBox, _CurrBBox);
318 currPS->setPrecomputedBBox(_CurrBBox);
320 else
322 currPS->getLastComputedBBox(_CurrBBox);
324 NL3D::CPSUtil::displayBBox(NL3D::CNELU::Driver, _CurrBBox, currPS->getAutoComputeBBox() ? CRGBA::White : CRGBA::Red);
326 // copy user matrix into current fx
327 nlassert(_ObjView);
328 _ActiveNode->getPSModel()->setUserMatrix(_ObjView->getFXUserMatrix());
331 //**************************************************************************************************************************
332 void CParticleDlg::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
334 if (nChar == (UINT) 'p' || nChar == (UINT) 'P' || nChar == (UINT) ' ')
336 // simulate a start / stop on the system
337 StartStopDlg->toggle();
340 CDialog::OnChar(nChar, nRepCnt, nFlags);
343 //**************************************************************************************************************************
344 const NLMISC::CMatrix &CParticleDlg::getPSMatrix() const
346 if (!getActivePSM()) return NLMISC::CMatrix::Identity;
347 return getActivePSM()->getMatrix();
350 //**************************************************************************************************************************
351 const NLMISC::CMatrix &CParticleDlg::getPSWorldMatrix() const
353 if (!getActivePSM()) return NLMISC::CMatrix::Identity;
354 return getActivePSM()->getWorldMatrix();
357 //**************************************************************************************************************************
358 void CParticleDlg::setPSMatrix(const NLMISC::CMatrix &mat)
360 if (!getActivePSM()) return;
361 getActivePSM()->setMatrix(mat);
364 //**************************************************************************************************************************
365 void CParticleDlg::setPSWorldMatrix(const NLMISC::CMatrix &mat)
367 if (!getActivePSM()) return;
368 CMatrix invParentMat = getActivePSM()->getMatrix() * getActivePSM()->getWorldMatrix().inverted();
369 invParentMat.normalize(CMatrix::XYZ);
370 CMatrix newMat = invParentMat * mat;
371 newMat.normalize(CMatrix::XYZ);
372 getActivePSM()->setMatrix(newMat);
376 //**************************************************************************************************************************
377 void CParticleDlg::stickPSToSkeleton(CParticleWorkspace::CNode *node,
378 NL3D::CSkeletonModel *skel,
379 uint bone,
380 const std::string &parentSkelName,
381 const std::string &parentBoneName)
383 if (!node) return;
384 node->stickPSToSkeleton(skel, bone, parentSkelName, parentBoneName);
385 if (skel)
387 if (_ObjView->getMainFrame()->MouseMoveType == CMainFrame::MoveFX)
389 _ObjView->getMainFrame()->OnEditMovecamera();
391 _ObjView->getMainFrame()->ToolBar.Invalidate();
395 //**************************************************************************************************************************
396 void CParticleDlg::unstickPSFromSkeleton(CParticleWorkspace::CNode *node)
398 if (!node) return;
399 node->unstickPSFromSkeleton();
400 _ObjView->getMainFrame()->ToolBar.Invalidate();
403 //**************************************************************************************************************************
404 bool CParticleDlg::savePS(HWND parent, CParticleWorkspace::CNode &psNode, bool askToContinueWhenError)
406 return savePSAs(parent, psNode, psNode.getFullPath(), askToContinueWhenError);
409 //**************************************************************************************************************************
410 bool CParticleDlg::savePSAs(HWND parent, CParticleWorkspace::CNode &psNode ,const std::string &fullPath, bool askToContinueWhenError)
412 nlassert(psNode.getPSPointer());
413 if (psNode.getResetAutoCountFlag() && psNode.getPSPointer()->getAutoCountFlag())
415 MessageBox(psNode.getFilename().c_str() + getStrRsc(IDS_AUTO_COUNT_ERROR), getStrRsc(IDS_WARNING), MB_ICONEXCLAMATION);
416 return false;
418 StartStopDlg->stop();
421 psNode.savePSAs(fullPath);
422 psNode.setModified(false);
423 setStatusBarText(CString(fullPath.c_str()) + " " + getStrRsc(IDS_SAVED));
425 catch (const NLMISC::Exception &e)
427 if (askToContinueWhenError)
429 int result = ::MessageBox(parent, CString(e.what()) + getStrRsc(IDS_CONTINUE_SAVING) , getStrRsc(IDS_ERROR), MB_ICONEXCLAMATION);
430 return result == MB_OK;
432 else
434 ::MessageBox(parent, nlUtf8ToTStr(e.what()), getStrRsc(IDS_ERROR), MB_ICONEXCLAMATION);
435 return false;
438 return true;
441 //**************************************************************************************************************************
442 bool CParticleDlg::loadPS(HWND parent, CParticleWorkspace::CNode &psNode, TLoadPSBehav behav)
444 bool loadingOK = true;
447 if (!psNode.loadPS())
449 loadingOK = false;
450 switch(behav)
452 case Silent: return false; // no op
453 case ReportError:
454 ::MessageBox(parent, (LPCTSTR) (CString(psNode.getFilename().c_str()) + " : " + getStrRsc(IDS_COULDNT_INSTANCIATE_PS)), getStrRsc(IDS_ERROR), MB_OK|MB_ICONEXCLAMATION);
455 return true;
456 break;
457 case ReportErrorSkippable:
459 CSkippableMessageBox mb(getStrRsc(IDS_ERROR), CString(psNode.getFilename().c_str()) + " : " + getStrRsc(IDS_COULDNT_INSTANCIATE_PS), CWnd::FromHandle(parent));
460 mb.DoModal();
461 return !mb.getBypassFlag();
463 break;
464 default:
465 nlassert(0);
466 break;
469 else
471 setStatusBarText(CString(psNode.getFullPath().c_str()) + " " + getStrRsc(IDS_LOADED));
474 catch (const NLMISC::Exception &e)
476 switch(behav)
478 case Silent: return false; // no op
479 case ReportError:
480 ::MessageBox(parent, nlUtf8ToTStr(e.what()), getStrRsc(IDS_ERROR), MB_OK | MB_ICONEXCLAMATION);
481 return true;
482 break;
483 case ReportErrorSkippable:
485 CSkippableMessageBox mb(getStrRsc(IDS_ERROR), CString(e.what()), CWnd::FromHandle(parent));
486 mb.DoModal();
487 return !mb.getBypassFlag();
489 break;
490 default:
491 nlassert(0);
492 break;
495 if (psNode.getPSPointer()->hasLoop())
497 localizedMessageBox(parent, IDS_FX_HAS_LOOP, IDS_WARNING, MB_OK|MB_ICONEXCLAMATION);
499 return behav != Silent;
503 //**************************************************************************************************************************
504 void CParticleDlg::checkModifiedWorkSpace()
506 if (_PW)
508 // see if current tree has been changed
509 if (_PW->isModified())
511 int result = localizedMessageBox(*this, IDS_PS_WORKSPACE_MODIFIED, IDS_PARTICLE_EDITOR, MB_YESNO|MB_ICONQUESTION);
512 if (result == IDYES)
514 saveWorkspaceStructure();
517 if (_PW->isContentModified())
519 saveWorkspaceContent(true);
524 //**************************************************************************************************************************
525 void CParticleDlg::closeWorkspace()
527 setActiveNode(NULL);
528 ParticleTreeCtrl->setActiveNode(NULL);
529 ParticleTreeCtrl->reset();
530 delete _PW;
531 _PW = NULL;
534 //**************************************************************************************************************************
535 void CParticleDlg::OnCreateNewPsWorkspace()
537 checkModifiedWorkSpace();
538 // ask name of the new workspace to create
539 CCreateFileDlg cf(getStrRsc(IDS_CHOOSE_WORKSPACE_NAME), "", "pws");
540 INT_PTR result = cf.DoModal();
541 if (result = IDOK)
543 if (cf.touchFile())
545 CParticleWorkspace *newPW = new CParticleWorkspace;
546 newPW->setModificationCallback(ParticleTreeCtrl);
547 newPW->init(_ObjView, cf.getFullPath(), _ObjView->getFontManager(), _ObjView->getFontGenerator());
548 // save empty workspace
551 newPW->save();
553 catch(const NLMISC::EStream &e)
555 MessageBox(nlUtf8ToTStr(e.what()), getStrRsc(IDS_ERROR), MB_ICONEXCLAMATION);
557 closeWorkspace();
558 _PW = newPW;
559 ParticleTreeCtrl->buildTreeFromWorkSpace(*_PW);
565 //**************************************************************************************************************************
566 void CParticleDlg::OnLoadPSWorkspace()
568 checkModifiedWorkSpace();
569 static const TCHAR BASED_CODE szFilter[] = _T("particle workspaces(*.pws)|*.pws||");
570 CFileDialog fd( TRUE, _T(".pws"), _T("*.pws"), 0, szFilter);
571 INT_PTR result = fd.DoModal();
572 if (result != IDOK) return;
573 loadWorkspace(NLMISC::tStrToUtf8(fd.GetPathName()));
576 //**************************************************************************************************************************
577 void CParticleDlg::loadWorkspace(const std::string &fullPath)
579 // Add to the path
580 CUniquePtr<CParticleWorkspace> newPW(new CParticleWorkspace);
581 newPW->init(_ObjView, fullPath, _ObjView->getFontManager(), _ObjView->getFontGenerator());
582 newPW->setModificationCallback(ParticleTreeCtrl);
583 // save empty workspace
586 newPW->load();
587 setStatusBarText(CString(newPW->getFilename().c_str()) + " " + getStrRsc(IDS_LOADED));
589 catch(const NLMISC::EStream &e)
591 MessageBox(nlUtf8ToTStr(e.what()), getStrRsc(IDS_ERROR), MB_ICONEXCLAMATION);
592 setStatusBarText(CString(e.what()));
593 return;
595 // try to load each ps
596 CParticleWorkspace::CNode *firstLoadedNode = NULL;
597 bool displayErrorMsg = true;
598 for(uint k = 0; k < newPW->getNumNode(); ++k)
601 displayErrorMsg = loadPS(*this, *newPW->getNode(k), displayErrorMsg ? ReportErrorSkippable : Silent);
602 if (newPW->getNode(k)->isLoaded() && !firstLoadedNode)
604 firstLoadedNode = newPW->getNode(k);
607 closeWorkspace();
608 _PW = newPW.release();
609 ParticleTreeCtrl->buildTreeFromWorkSpace(*_PW);
610 setActiveNode(firstLoadedNode);
611 ParticleTreeCtrl->setActiveNode(firstLoadedNode);
612 ParticleTreeCtrl->expandRoot();
613 setStatusBarText(getStrRsc(IDS_READY));
616 //**************************************************************************************************************************
617 void CParticleDlg::OnSaveAllPsWorkspace()
619 saveWorkspaceStructure();
620 saveWorkspaceContent(false);
623 //**************************************************************************************************************************
624 void CParticleDlg::OnSavePsWorkspace()
626 saveWorkspaceStructure();
627 saveWorkspaceContent(true);
630 //**************************************************************************************************************************
631 void CParticleDlg::saveWorkspaceStructure()
633 nlassert(_PW);
636 _PW->save();
637 setStatusBarText(CString(_PW->getFilename().c_str()) + " " + getStrRsc(IDS_SAVED));
639 catch(const NLMISC::EStream &e)
641 localizedMessageBox(*this, nlUtf8ToTStr(e.what()), IDS_ERROR, MB_ICONEXCLAMATION);
642 setStatusBarText(CString(e.what()));
647 //**************************************************************************************************************************
648 void CParticleDlg::saveWorkspaceContent(bool askToSaveModifiedPS)
650 StartStopDlg->stop();
651 bool saveAll = !askToSaveModifiedPS;
652 // check each component of the tree
653 for(uint k = 0; k < _PW->getNumNode(); ++k)
655 if (_PW->getNode(k)->isModified())
657 if (saveAll)
659 bool keepSaving = savePS(*this, *_PW->getNode(k), k != _PW->getNumNode());
660 if (!keepSaving) break;
662 else
664 // ask if the user wants to save the ps, or save all ps
665 CString mess;
666 mess = CString(_PW->getNode(k)->getFilename().c_str()) + getStrRsc(IDS_SAVE_MODIFIED_PS);
667 CSaveOptionsDlg sop(getStrRsc(IDS_SAVE_FILE), mess, this);
668 sop.DoModal();
669 bool saveThisFile = false;
670 bool stop = false;
671 switch(sop.getChoice())
673 case CSaveOptionsDlg::Yes: saveThisFile = true; break;
674 case CSaveOptionsDlg::No: saveThisFile = false; break;
675 case CSaveOptionsDlg::SaveAll: saveAll = true; break;
676 case CSaveOptionsDlg::Stop: stop = true; break;
677 default: nlassert(0);
679 if (stop) break;
680 if (saveAll || saveThisFile)
682 bool keepSaving = savePS(*this, *_PW->getNode(k), k != _PW->getNumNode());
683 if (!keepSaving) break;
688 setStatusBarText(getStrRsc(IDS_READY));
691 //**************************************************************************************************************************
692 void CParticleDlg::setActiveNode(CParticleWorkspace::CNode *node)
694 if (node == _ActiveNode) return;
695 _ActiveNode = node;
696 StartStopDlg->setActiveNode(node);
697 if(MainFrame->isMoveFX())
699 if (node)
701 _ObjView->getMouseListener().setModelMatrix(node->getPSModel()->getMatrix());
703 else
705 _ObjView->getMouseListener().setModelMatrix(NLMISC::CMatrix::Identity);
708 else
709 if(MainFrame->isMoveFXUserMatrix())
711 if (node)
713 _ObjView->getMouseListener().setModelMatrix(node->getPSModel()->getUserMatrix());
715 else
717 _ObjView->getMouseListener().setModelMatrix(NLMISC::CMatrix::Identity);
722 //**************************************************************************************************************************
723 NL3D::CParticleSystemModel *CParticleDlg::getModelFromPS(NL3D::CParticleSystem *ps) const
725 if (!ps) return NULL;
726 if (!_PW) return NULL;
727 CParticleWorkspace::CNode *node = _PW->getNodeFromPS(ps);
728 if (!node) return NULL;
729 return node->getPSModel();
732 //**************************************************************************************************************************
733 uint CParticleDlg::computeStatusBarWidth() const
735 nlassert(ParticleTreeCtrl);
736 CRect tcRect;
737 ParticleTreeCtrl->GetClientRect(&tcRect);
738 if (!CurrentRightPane) return (uint) std::max((sint) tcRect.Width() - 16, (sint) 0);
739 return (uint) std::max((sint) tcRect.Width() - 4, (sint) 0);
742 //**************************************************************************************************************************
743 void CParticleDlg::OnViewPsFilename()
745 ParticleTreeCtrl->setViewFilenameFlag(!ParticleTreeCtrl->getViewFilenameFlag());
746 updateMenu();
749 //**************************************************************************************************************************
750 void CParticleDlg::updateMenu()
752 if (!ParticleTreeCtrl) return;
753 CMenu *menu = GetMenu();
754 if (!menu) return;
755 // update the view menu
756 menu->CheckMenuItem(IDM_VIEW_PS_FILENAME, MF_BYCOMMAND|(ParticleTreeCtrl->getViewFilenameFlag() ? MF_CHECKED : 0));