1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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
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"
59 //**************************************************************************************************************************
60 CParticleDlg::CParticleDlg(class CObjectViewer
* main
, CWnd
*pParent
, CMainFrame
* mainFrame
, CAnimationDlg
*animDLG
)
61 : CDialog(CParticleDlg::IDD
, pParent
),
63 CurrentRightPane(NULL
),
67 _AutoUpdateBBox(false),
71 //{{AFX_DATA_INIT(CParticleDlg)
72 // NOTE: the ClassWizard will add member initialization here
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
;
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
;
112 if (_PW
) _PW
->setModificationCallback(NULL
);
116 //**************************************************************************************************************************
117 void CParticleDlg::DoDataExchange(CDataExchange
* pDX
)
119 CDialog::DoDataExchange(pDX
);
120 //{{AFX_DATA_MAP(CParticleDlg)
125 BEGIN_MESSAGE_MAP(CParticleDlg
, CDialog
)
126 //{{AFX_MSG_MAP(CParticleDlg)
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
)
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();
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
167 menu
.LoadMenu(MAKEINTRESOURCE(IDR_PARTICLE_DLG_MENU
));
168 this->SetMenu(&menu
);
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);
221 CRect
res(ox
, oy
, cx
- 10, cy
- 20);
226 //**************************************************************************************************************************
227 void CParticleDlg::setRightPane(CWnd
*pane
)
229 AFX_MANAGE_STATE(AfxGetStaticModuleState());
230 if (CurrentRightPane
)
232 CurrentRightPane
->DestroyWindow();
234 delete CurrentRightPane
;
235 CurrentRightPane
= pane
;
240 pane
->ShowWindow(SW_SHOW
);
243 CurrentRightPane
->GetClientRect(&r
);
245 CurrRightPaneWidth
= r
.right
;
246 CurrRightPaneHeight
= r
.bottom
;
251 this->SendMessage(WM_SIZE
, SIZE_RESTORED
, r
.right
+ (r
.bottom
<< 16));
253 this->MoveWindow(&r
);
254 if (CurrentRightPane
)
256 CurrentRightPane
->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
)
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
;
301 if (StartStopDlg
->isBBoxDisplayEnabled() && currPS
)
303 NL3D::CNELU::Driver
->setupModelMatrix(currPS
->getSysMat());
306 NLMISC::CAABBox currBBox
;
307 currPS
->forceComputeBBox(currBBox
);
311 _CurrBBox
= currBBox
;
315 NL3D::CPSUtil::displayBBox(NL3D::CNELU::Driver
, _CurrBBox
, CRGBA::Blue
);
316 _CurrBBox
= NLMISC::CAABBox::computeAABBoxUnion(currBBox
, _CurrBBox
);
318 currPS
->setPrecomputedBBox(_CurrBBox
);
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
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
,
380 const std::string
&parentSkelName
,
381 const std::string
&parentBoneName
)
384 node
->stickPSToSkeleton(skel
, bone
, parentSkelName
, parentBoneName
);
387 if (_ObjView
->getMainFrame()->MouseMoveType
== CMainFrame::MoveFX
)
389 _ObjView
->getMainFrame()->OnEditMovecamera();
391 _ObjView
->getMainFrame()->ToolBar
.Invalidate();
395 //**************************************************************************************************************************
396 void CParticleDlg::unstickPSFromSkeleton(CParticleWorkspace::CNode
*node
)
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
);
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
;
434 ::MessageBox(parent
, nlUtf8ToTStr(e
.what()), getStrRsc(IDS_ERROR
), MB_ICONEXCLAMATION
);
441 //**************************************************************************************************************************
442 bool CParticleDlg::loadPS(HWND parent
, CParticleWorkspace::CNode
&psNode
, TLoadPSBehav behav
)
444 bool loadingOK
= true;
447 if (!psNode
.loadPS())
452 case Silent
: return false; // no op
454 ::MessageBox(parent
, (LPCTSTR
) (CString(psNode
.getFilename().c_str()) + " : " + getStrRsc(IDS_COULDNT_INSTANCIATE_PS
)), getStrRsc(IDS_ERROR
), MB_OK
|MB_ICONEXCLAMATION
);
457 case ReportErrorSkippable
:
459 CSkippableMessageBox
mb(getStrRsc(IDS_ERROR
), CString(psNode
.getFilename().c_str()) + " : " + getStrRsc(IDS_COULDNT_INSTANCIATE_PS
), CWnd::FromHandle(parent
));
461 return !mb
.getBypassFlag();
471 setStatusBarText(CString(psNode
.getFullPath().c_str()) + " " + getStrRsc(IDS_LOADED
));
474 catch (const NLMISC::Exception
&e
)
478 case Silent
: return false; // no op
480 ::MessageBox(parent
, nlUtf8ToTStr(e
.what()), getStrRsc(IDS_ERROR
), MB_OK
| MB_ICONEXCLAMATION
);
483 case ReportErrorSkippable
:
485 CSkippableMessageBox
mb(getStrRsc(IDS_ERROR
), CString(e
.what()), CWnd::FromHandle(parent
));
487 return !mb
.getBypassFlag();
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()
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
);
514 saveWorkspaceStructure();
517 if (_PW
->isContentModified())
519 saveWorkspaceContent(true);
524 //**************************************************************************************************************************
525 void CParticleDlg::closeWorkspace()
528 ParticleTreeCtrl
->setActiveNode(NULL
);
529 ParticleTreeCtrl
->reset();
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();
545 CParticleWorkspace
*newPW
= new CParticleWorkspace
;
546 newPW
->setModificationCallback(ParticleTreeCtrl
);
547 newPW
->init(_ObjView
, cf
.getFullPath(), _ObjView
->getFontManager(), _ObjView
->getFontGenerator());
548 // save empty workspace
553 catch(const NLMISC::EStream
&e
)
555 MessageBox(nlUtf8ToTStr(e
.what()), getStrRsc(IDS_ERROR
), MB_ICONEXCLAMATION
);
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
)
580 CUniquePtr
<CParticleWorkspace
> newPW(new CParticleWorkspace
);
581 newPW
->init(_ObjView
, fullPath
, _ObjView
->getFontManager(), _ObjView
->getFontGenerator());
582 newPW
->setModificationCallback(ParticleTreeCtrl
);
583 // save empty workspace
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()));
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
);
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()
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())
659 bool keepSaving
= savePS(*this, *_PW
->getNode(k
), k
!= _PW
->getNumNode());
660 if (!keepSaving
) break;
664 // ask if the user wants to save the ps, or save all ps
666 mess
= CString(_PW
->getNode(k
)->getFilename().c_str()) + getStrRsc(IDS_SAVE_MODIFIED_PS
);
667 CSaveOptionsDlg
sop(getStrRsc(IDS_SAVE_FILE
), mess
, this);
669 bool saveThisFile
= 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);
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;
696 StartStopDlg
->setActiveNode(node
);
697 if(MainFrame
->isMoveFX())
701 _ObjView
->getMouseListener().setModelMatrix(node
->getPSModel()->getMatrix());
705 _ObjView
->getMouseListener().setModelMatrix(NLMISC::CMatrix::Identity
);
709 if(MainFrame
->isMoveFXUserMatrix())
713 _ObjView
->getMouseListener().setModelMatrix(node
->getPSModel()->getUserMatrix());
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
);
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());
749 //**************************************************************************************************************************
750 void CParticleDlg::updateMenu()
752 if (!ParticleTreeCtrl
) return;
753 CMenu
*menu
= GetMenu();
755 // update the view menu
756 menu
->CheckMenuItem(IDM_VIEW_PS_FILENAME
, MF_BYCOMMAND
|(ParticleTreeCtrl
->getViewFilenameFlag() ? MF_CHECKED
: 0));