]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/af/DialogAFConstraint.cpp
hello world
[icculus/iodoom3.git] / neo / tools / af / DialogAFConstraint.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../../sys/win32/rc/AFEditor_resource.h"
33
34 #include "DialogAF.h"
35 #include "DialogAFName.h"
36 #include "DialogAFConstraint.h"
37 #include "DialogAFConstraintFixed.h"
38 #include "DialogAFConstraintBallAndSocket.h"
39 #include "DialogAFConstraintUniversal.h"
40 #include "DialogAFConstraintHinge.h"
41 #include "DialogAFConstraintSlider.h"
42 #include "DialogAFConstraintSpring.h"
43
44 #ifdef ID_DEBUG_MEMORY
45 #undef new
46 #undef DEBUG_NEW
47 #define DEBUG_NEW new
48 #endif
49
50
51 typedef struct {
52         declAFConstraintType_t type;
53         const char *name;
54 } c_type_t;
55
56 c_type_t constraintTypes[] = {
57         { DECLAF_CONSTRAINT_FIXED, "fixed" },
58         { DECLAF_CONSTRAINT_BALLANDSOCKETJOINT, "ball and socket" },
59         { DECLAF_CONSTRAINT_UNIVERSALJOINT, "universal" },
60         { DECLAF_CONSTRAINT_HINGE, "hinge" },
61         { DECLAF_CONSTRAINT_SLIDER, "slider" },
62         { DECLAF_CONSTRAINT_SPRING, "spring" },
63         { DECLAF_CONSTRAINT_INVALID, NULL }
64 };
65
66
67 const char *ConstraintTypeToString( declAFConstraintType_t type ) {
68         for ( int i = 0; constraintTypes[i].name; i++ ) {
69                 if ( constraintTypes[i].type == type ) {
70                         return constraintTypes[i].name;
71                 }
72         }
73         return "";
74 }
75
76 declAFConstraintType_t StringToConstraintType( const char *str ) {
77         for ( int i = 0; constraintTypes[i].name; i++ ) {
78                 if ( idStr::Icmp( constraintTypes[i].name, str ) == 0 ) {
79                         return constraintTypes[i].type;
80                 }
81         }
82         return DECLAF_CONSTRAINT_INVALID;
83 }
84
85
86 // DialogAFConstraint dialog
87
88 toolTip_t DialogAFConstraint::toolTips[] = {
89         { IDC_COMBO_CONSTRAINTS, "select contraint for editing" },
90         { IDC_BUTTON_NEWCONSTRAINT, "create a new constraint" },
91         { IDC_BUTTON_RENAMECONSTRAINT, "rename the selected constraint" },
92         { IDC_BUTTON_DELETECONSTRAINT, "delete the selected constraint" },
93         { IDC_COMBO_CONSTRAINT_TYPE, "constraint type" },
94         { IDC_COMBO_CONSTRAINT_BODY1, "first constrained body" },
95         { IDC_COMBO_CONSTRAINT_BODY2, "second constrained body" },
96         { IDC_EDIT_CONSTRAINT_FRICTION, "constraint friction" },
97         { 0, NULL }
98 };
99
100 IMPLEMENT_DYNAMIC(DialogAFConstraint, CDialog)
101
102 /*
103 ================
104 DialogAFConstraint::DialogAFConstraint
105 ================
106 */
107 DialogAFConstraint::DialogAFConstraint( CWnd* pParent /*=NULL*/ )
108         : CDialog(DialogAFConstraint::IDD, pParent)
109         , m_friction(0)
110         , constraint(NULL)
111         , file(NULL)
112         , constraintDlg(NULL)
113 {
114         Create( IDD_DIALOG_AF_CONSTRAINT, pParent );
115         EnableToolTips( TRUE );
116 }
117
118 /*
119 ================
120 DialogAFConstraint::~DialogAFConstraint
121 ================
122 */
123 DialogAFConstraint::~DialogAFConstraint() {
124 }
125
126 /*
127 ================
128 DialogAFConstraint::DoDataExchange
129 ================
130 */
131 void DialogAFConstraint::DoDataExchange( CDataExchange* pDX ) {
132         CDialog::DoDataExchange(pDX);
133         //{{AFX_DATA_MAP(DialogAFConstraint)
134         DDX_Control(pDX, IDC_COMBO_CONSTRAINTS, m_comboConstraintList);
135         DDX_Control(pDX, IDC_COMBO_CONSTRAINT_TYPE, m_comboConstraintType);
136         DDX_Control(pDX, IDC_COMBO_CONSTRAINT_BODY1, m_comboBody1List);
137         DDX_Control(pDX, IDC_COMBO_CONSTRAINT_BODY2, m_comboBody2List);
138         DDX_Text(pDX, IDC_EDIT_CONSTRAINT_FRICTION, m_friction);
139         //}}AFX_DATA_MAP
140 }
141
142 /*
143 ================
144 DialogAFConstraint::InitConstraintList
145 ================
146 */
147 void DialogAFConstraint::InitConstraintList( void ) {
148         CString str;
149
150         m_comboConstraintList.ResetContent();
151         if ( !file ) {
152                 return;
153         }
154         for ( int i = 0; i < file->constraints.Num(); i++ ) {
155                 m_comboConstraintList.AddString( file->constraints[i]->name.c_str() );
156         }
157         if ( m_comboConstraintList.GetCount() != 0 ) {
158                 m_comboConstraintList.SetCurSel( 0 );
159                 m_comboConstraintList.GetLBText( 0, str );
160                 LoadConstraint( str );
161         }
162 }
163
164 /*
165 ================
166 DialogAFConstraint::InitConstraintTypeDlg
167 ================
168 */
169 void DialogAFConstraint::InitConstraintTypeDlg( void ) {
170         CString str;
171         RECT rect;
172
173         if ( !file || !constraint ) {
174                 return;
175         }
176
177         UpdateData( TRUE );
178
179         if ( constraintDlg ) {
180                 constraintDlg->ShowWindow( SW_HIDE );
181         }
182
183         GetSafeComboBoxSelection( &m_comboConstraintType, str, -1 );
184         switch( StringToConstraintType( str ) ) {
185                 case DECLAF_CONSTRAINT_FIXED:
186                         fixedDlg->LoadConstraint( constraint );
187                         constraintDlg = fixedDlg;
188                         break;
189                 case DECLAF_CONSTRAINT_BALLANDSOCKETJOINT:
190                         ballAndSocketDlg->LoadConstraint( constraint );
191                         constraintDlg = ballAndSocketDlg;
192                         break;
193                 case DECLAF_CONSTRAINT_UNIVERSALJOINT:
194                         universalDlg->LoadConstraint( constraint );
195                         constraintDlg = universalDlg;
196                         break;
197                 case DECLAF_CONSTRAINT_HINGE:
198                         hingeDlg->LoadConstraint( constraint );
199                         constraintDlg = hingeDlg;
200                         break;
201                 case DECLAF_CONSTRAINT_SLIDER:
202                         sliderDlg->LoadConstraint( constraint );
203                         constraintDlg = sliderDlg;
204                         break;
205                 case DECLAF_CONSTRAINT_SPRING:
206                         springDlg->LoadConstraint( constraint );
207                         constraintDlg = springDlg;
208                         break;
209         }
210
211         if ( constraintDlg ) {
212                 constraintDlg->ShowWindow( SW_SHOW );
213                 constraintDlg->GetWindowRect( &rect );
214                 constraintDlg->MoveWindow( 0, 117, rect.right - rect.left, rect.bottom - rect.top );
215         }
216 }
217
218 /*
219 ================
220 DialogAFConstraint::InitBodyLists
221 ================
222 */
223 void DialogAFConstraint::InitBodyLists( void ) {
224         m_comboBody1List.ResetContent();
225         m_comboBody2List.ResetContent();
226         if ( !file ) {
227                 return;
228         }
229         for ( int i = 0; i < file->bodies.Num(); i++ ) {
230                 m_comboBody1List.AddString( file->bodies[i]->name );
231                 m_comboBody2List.AddString( file->bodies[i]->name );
232         }
233         // the second body may also be the world
234         m_comboBody2List.AddString( "world" );  // FIXME: we currently assume this is the last body in the list
235 }
236
237 /*
238 ================
239 DialogAFConstraint::InitNewRenameDeleteButtons
240 ================
241 */
242 void DialogAFConstraint::InitNewRenameDeleteButtons( void ) {
243         if ( file && file->bodies.Num() >= 1 ) {
244                 GetDlgItem( IDC_BUTTON_NEWCONSTRAINT )->EnableWindow( true );
245         }
246         else {
247                 GetDlgItem( IDC_BUTTON_NEWCONSTRAINT )->EnableWindow( false );
248         }
249
250         if ( file && m_comboConstraintList.GetCount() >= 1 ) {
251                 GetDlgItem( IDC_BUTTON_RENAMECONSTRAINT )->EnableWindow( true );
252                 GetDlgItem( IDC_BUTTON_DELETECONSTRAINT )->EnableWindow( true );
253         }
254         else {
255                 GetDlgItem( IDC_BUTTON_RENAMECONSTRAINT )->EnableWindow( false );
256                 GetDlgItem( IDC_BUTTON_DELETECONSTRAINT )->EnableWindow( false );
257         }
258 }
259
260 /*
261 ================
262 DialogAFConstraint::LoadFile
263 ================
264 */
265 void DialogAFConstraint::LoadFile( idDeclAF *af ) {
266         file = af;
267         constraint = NULL;
268         ballAndSocketDlg->LoadFile( af );
269         universalDlg->LoadFile( af );
270         hingeDlg->LoadFile( af );
271         sliderDlg->LoadFile( af );
272         springDlg->LoadFile( af );
273         InitBodyLists();
274         InitConstraintList();
275         InitNewRenameDeleteButtons();
276 }
277
278 /*
279 ================
280 DialogAFConstraint::SaveFile
281 ================
282 */
283 void DialogAFConstraint::SaveFile( void ) {
284         SaveConstraint();
285 }
286
287 /*
288 ================
289 DialogAFConstraint::LoadConstraint
290 ================
291 */
292 void DialogAFConstraint::LoadConstraint( const char *name ) {
293         int i, s1, s2;
294
295         if ( !file ) {
296                 return;
297         }
298         for ( i = 0; i < file->constraints.Num(); i++ ) {
299                 if ( file->constraints[i]->name.Icmp( name ) == 0 ) {
300                         break;
301                 }
302         }
303         if ( i >= file->constraints.Num() ) {
304                 return;
305         }
306         constraint = file->constraints[i];
307
308         // load the constraint type from the current idDeclAF_Constraint
309         SetSafeComboBoxSelection( &m_comboConstraintType, ConstraintTypeToString( constraint->type ), -1 );
310
311         // load constrained bodies from the current idDeclAF_Constraint
312         s1 = SetSafeComboBoxSelection( &m_comboBody1List, constraint->body1.c_str(), -1 );
313         s2 = SetSafeComboBoxSelection( &m_comboBody2List, constraint->body2.c_str(), s1 );
314
315         // load friction from the current idDeclAF_Constraint
316         m_friction = constraint->friction;
317
318         // update displayed values
319         UpdateData( FALSE );
320
321         InitConstraintTypeDlg();
322
323         if ( GetStyle() & WS_VISIBLE ) {
324                 // highlight the current constraint ingame
325                 cvarSystem->SetCVarString( "af_highlightConstraint", name );
326         }
327 }
328
329 /*
330 ================
331 DialogAFConstraint::SaveConstraint
332 ================
333 */
334 void DialogAFConstraint::SaveConstraint( void ) {
335         int s1, s2;
336         CString str;
337
338         if ( !file || !constraint ) {
339                 return;
340         }
341         UpdateData( TRUE );
342
343         // save constraint type to the current idDeclAF_Constraint
344         GetSafeComboBoxSelection( &m_comboConstraintType, str, -1 );
345         constraint->type = StringToConstraintType( str );
346
347         // save constrained bodies to the current idDeclAF_Constraint
348         s1 = GetSafeComboBoxSelection( &m_comboBody1List, str, -1 );
349         constraint->body1 = str;
350         s2 = GetSafeComboBoxSelection( &m_comboBody2List, str, s1 );
351         constraint->body2 = str;
352
353         // save friction to the current idDeclAF_Constraint
354         constraint->friction = m_friction;
355
356         AFDialogSetFileModified();
357 }
358
359 /*
360 ================
361 DialogAFConstraint::UpdateFile
362 ================
363 */
364 void DialogAFConstraint::UpdateFile( void ) {
365         SaveConstraint();
366         if ( file ) {
367                 gameEdit->AF_UpdateEntities( file->GetName() );
368         }
369 }
370
371 /*
372 ================
373 DialogAFConstraint::OnInitDialog
374 ================
375 */
376 BOOL DialogAFConstraint::OnInitDialog()  {
377
378         CDialog::OnInitDialog();
379
380         // initialize the constraint types
381         m_comboConstraintType.ResetContent();
382         for ( int i = 0; constraintTypes[i].name; i++ ) {
383                 m_comboConstraintType.AddString( constraintTypes[i].name );
384         }
385
386         fixedDlg = new DialogAFConstraintFixed( this );
387         fixedDlg->ShowWindow( SW_HIDE );
388
389         ballAndSocketDlg = new DialogAFConstraintBallAndSocket( this );
390         ballAndSocketDlg->ShowWindow( SW_HIDE );
391
392         universalDlg = new DialogAFConstraintUniversal( this );
393         universalDlg->ShowWindow( SW_HIDE );
394
395         hingeDlg = new DialogAFConstraintHinge( this );
396         hingeDlg->ShowWindow( SW_HIDE );
397
398         sliderDlg = new DialogAFConstraintSlider( this );
399         sliderDlg->ShowWindow( SW_HIDE );
400
401         springDlg = new DialogAFConstraintSpring( this );
402         springDlg->ShowWindow( SW_HIDE );
403
404         constraintDlg = NULL;
405
406         InitNewRenameDeleteButtons();
407
408         return TRUE;  // return TRUE unless you set the focus to a control
409                       // EXCEPTION: OCX Property Pages should return FALSE
410 }
411
412 /*
413 ================
414 DialogAFConstraint::OnToolHitTest
415 ================
416 */
417 int DialogAFConstraint::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const {
418         CDialog::OnToolHitTest( point, pTI );
419         return DefaultOnToolHitTest( toolTips, this, point, pTI );
420 }
421
422 BEGIN_MESSAGE_MAP(DialogAFConstraint, CDialog)
423         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
424         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
425         ON_WM_SHOWWINDOW()
426         ON_CBN_SELCHANGE(IDC_COMBO_CONSTRAINTS, OnCbnSelchangeComboConstraints)
427         ON_CBN_SELCHANGE(IDC_COMBO_CONSTRAINT_TYPE, OnCbnSelchangeComboConstraintType)
428         ON_CBN_SELCHANGE(IDC_COMBO_CONSTRAINT_BODY1, OnCbnSelchangeComboConstraintBody1)
429         ON_CBN_SELCHANGE(IDC_COMBO_CONSTRAINT_BODY2, OnCbnSelchangeComboConstraintBody2)
430         ON_EN_CHANGE(IDC_EDIT_CONSTRAINT_FRICTION, OnEnChangeEditConstraintFriction)
431         ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_CONSTRAINT_FRICTION, OnDeltaposSpinConstraintFriction)
432         ON_BN_CLICKED(IDC_BUTTON_NEWCONSTRAINT, OnBnClickedButtonNewconstraint)
433         ON_BN_CLICKED(IDC_BUTTON_RENAMECONSTRAINT, OnBnClickedButtonRenameconstraint)
434         ON_BN_CLICKED(IDC_BUTTON_DELETECONSTRAINT, OnBnClickedButtonDeleteconstraint)
435 END_MESSAGE_MAP()
436
437
438 // DialogAFConstraint message handlers
439
440 BOOL DialogAFConstraint::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
441         return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult );
442 }
443
444 void DialogAFConstraint::OnShowWindow( BOOL bShow, UINT nStatus ) {
445         if ( bShow && constraint ) {
446                 cvarSystem->SetCVarString( "af_highlightConstraint", constraint->name.c_str() );
447         } else {
448                 cvarSystem->SetCVarString( "af_highlightConstraint", "" );
449         }
450         CDialog::OnShowWindow( bShow, nStatus );
451 }
452
453 void DialogAFConstraint::OnCbnSelchangeComboConstraints() {
454         CString str;
455
456         GetSafeComboBoxSelection( &m_comboConstraintList, str, -1 );
457         LoadConstraint( str );
458 }
459
460 void DialogAFConstraint::OnBnClickedButtonNewconstraint() {
461         DialogAFName nameDlg;
462         CString str;
463
464         nameDlg.SetComboBox( &m_comboConstraintList );
465         if ( nameDlg.DoModal() == IDOK ) {
466                 nameDlg.GetName( str );
467                 // create new constraint
468                 file->NewConstraint( str );
469                 m_comboConstraintList.SetCurSel( m_comboConstraintList.AddString( str ) );
470                 LoadConstraint( str );
471                 gameEdit->AF_UpdateEntities( file->GetName() );
472                 AFDialogSetFileModified();
473         }
474         InitNewRenameDeleteButtons();
475 }
476
477 void DialogAFConstraint::OnBnClickedButtonRenameconstraint() {
478         int i;
479         CString name, newName;
480         DialogAFName nameDlg;
481
482         if ( !file || !constraint ) {
483                 return;
484         }
485
486         i = m_comboConstraintList.GetCurSel();
487         if ( i != CB_ERR ) {
488                 m_comboConstraintList.GetLBText( i, name );
489                 nameDlg.SetName( name );
490                 nameDlg.SetComboBox( &m_comboConstraintList );
491                 if ( nameDlg.DoModal() == IDOK ) {
492                         nameDlg.GetName( newName );
493                         // rename constraint;
494                         file->RenameConstraint( name, newName );
495                         m_comboConstraintList.DeleteString( i );
496                         m_comboConstraintList.SetCurSel( m_comboConstraintList.AddString( newName ) );
497                         LoadConstraint( newName );
498                         gameEdit->AF_UpdateEntities( file->GetName() );
499                         AFDialogSetFileModified();
500                 }
501         }
502 }
503
504 void DialogAFConstraint::OnBnClickedButtonDeleteconstraint() {
505         int i;
506         CString str;
507
508         if ( !file || !constraint ) {
509                 return;
510         }
511
512         i = m_comboConstraintList.GetCurSel();
513         if ( i != CB_ERR ) {
514                 if ( MessageBox( "Are you sure you want to delete this constraint ?", "Delete Constraint", MB_YESNO | MB_ICONQUESTION ) == IDYES ) {
515                         m_comboConstraintList.GetLBText( i, str );
516                         // delete current constraint
517                         file->DeleteConstraint( str );
518                         constraint = NULL;
519                         m_comboConstraintList.DeleteString( i );
520                         OnCbnSelchangeComboConstraints();
521                         gameEdit->AF_UpdateEntities( file->GetName() );
522                         AFDialogSetFileModified();
523                 }
524         }
525         InitNewRenameDeleteButtons();
526 }
527
528 void DialogAFConstraint::OnCbnSelchangeComboConstraintType() {
529         InitConstraintTypeDlg();
530         UpdateFile();
531 }
532
533 void DialogAFConstraint::OnCbnSelchangeComboConstraintBody1() {
534         CString str;
535         GetSafeComboBoxSelection( &m_comboBody1List, str, -1 );
536         UnsetSafeComboBoxSelection( &m_comboBody2List, str );
537         UpdateFile();
538 }
539
540 void DialogAFConstraint::OnCbnSelchangeComboConstraintBody2() {
541         CString str;
542         GetSafeComboBoxSelection( &m_comboBody2List, str, -1 );
543         UnsetSafeComboBoxSelection( &m_comboBody1List, str );
544         UpdateFile();
545 }
546
547 void DialogAFConstraint::OnEnChangeEditConstraintFriction() {
548         if ( EditControlEnterHit( (CEdit *) GetDlgItem( IDC_EDIT_CONSTRAINT_FRICTION ) ) ) {
549                 UpdateFile();
550         }
551         else {
552                 EditVerifyFloat( (CEdit *) GetDlgItem( IDC_EDIT_CONSTRAINT_FRICTION ), false );
553         }
554 }
555
556 void DialogAFConstraint::OnDeltaposSpinConstraintFriction(NMHDR *pNMHDR, LRESULT *pResult) {
557         LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
558         m_friction = EditSpinFloat( (CEdit *)GetDlgItem( IDC_EDIT_CONSTRAINT_FRICTION ), pNMUpDown->iDelta < 0 );
559         UpdateFile();
560         *pResult = 0;
561 }