]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/decl/DialogEntityDefEditor.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / decl / DialogEntityDefEditor.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/Common_resource.h"
33 #include "../../sys/win32/rc/DeclEditor_resource.h"
34
35 #include "../comafx/CPathTreeCtrl.h"
36 #include "DialogDeclBrowser.h"
37 #include "DialogDeclEditor.h"
38 #include "DialogEntityDefEditor.h"
39
40 #ifdef ID_DEBUG_MEMORY
41 #undef new
42 #undef DEBUG_NEW
43 #define DEBUG_NEW new
44 #endif
45
46
47 // DialogEntityDefEditor dialog
48
49 toolTip_t DialogEntityDefEditor::toolTips[] = {
50         { IDC_DECLEDITOR_BUTTON_TEST, "Test Decl" },
51         { IDOK, "Save Decl" },
52         { IDCANCEL, "Cancel" },
53         { 0, NULL }
54 };
55
56
57 IMPLEMENT_DYNAMIC(DialogEntityDefEditor, CDialog)
58
59 /*
60 ================
61 DialogEntityDefEditor::DialogEntityDefEditor
62 ================
63 */
64 DialogEntityDefEditor::DialogEntityDefEditor( CWnd* pParent /*=NULL*/ )
65         : CDialog(DialogEntityDefEditor::IDD, pParent)
66         , decl(NULL)
67         , firstLine(0)
68 {
69 }
70
71 /*
72 ================
73 DialogEntityDefEditor::~DialogEntityDefEditor
74 ================
75 */
76 DialogEntityDefEditor::~DialogEntityDefEditor() {
77 }
78
79 /*
80 ================
81 DialogEntityDefEditor::DoDataExchange
82 ================
83 */
84 void DialogEntityDefEditor::DoDataExchange(CDataExchange* pDX) {
85         CDialog::DoDataExchange(pDX);
86         //{{AFX_DATA_MAP(DialogEntityDefEditor)
87         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_EDIT_DECLNAME, declNameEdit);
88         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_COMBO_INHERIT, inheritCombo);
89         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_COMBO_SPAWNCLASS, spawnclassCombo);
90
91         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_LIST_KEYVALS, keyValsList);
92
93         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_STATIC_KEY, keyLabel);
94         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_EDIT_KEY, keyEdit);
95         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_BUTTON_ADD, addButton);
96         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_BUTTON_DELETE, delButton);
97         DDX_Control(pDX, IDC_ENTITYDEFEDITOR_LINE, line);
98
99         DDX_Control(pDX, IDC_DECLEDITOR_BUTTON_TEST, testButton);
100         DDX_Control(pDX, IDOK, okButton);
101         DDX_Control(pDX, IDCANCEL, cancelButton);
102         //}}AFX_DATA_MAP
103 }
104
105 /*
106 ================
107 DialogEntityDefEditor::PreTranslateMessage
108 ================
109 */
110 BOOL DialogEntityDefEditor::PreTranslateMessage( MSG* pMsg ) {
111         if ( WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST ) {
112                 if ( m_hAccel && ::TranslateAccelerator( m_hWnd, m_hAccel, pMsg ) ) {
113                         return TRUE;
114                 }
115         }
116         return CWnd::PreTranslateMessage(pMsg);
117 }
118
119 /*
120 ================
121 DialogEntityDefEditor::TestDecl
122 ================
123 */
124 bool DialogEntityDefEditor::TestDecl( const idStr &declText ) {
125         idLexer src( LEXFL_NOSTRINGCONCAT );
126         idToken token;
127         int indent;
128
129         src.LoadMemory( declText, declText.Length(), "decl text" );
130
131         indent = 0;
132         while( src.ReadToken( &token ) ) {
133                 if ( token == "{" ) {
134                         indent++;
135                 } else if ( token == "}" ) {
136                         indent--;
137                 }
138         }
139
140         if ( indent < 0 ) {
141                 MessageBox( "Missing opening brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
142                 return false;
143         }
144         if ( indent > 0 ) {
145                 MessageBox( "Missing closing brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
146                 return false;
147         }
148         return true;
149 }
150
151 /*
152 ================
153 DialogEntityDefEditor::UpdateStatusBar
154 ================
155 */
156 void DialogEntityDefEditor::UpdateStatusBar( void ) {
157         if ( decl ) {
158                 statusBar.SetWindowText( "Editing decl" );
159         }
160 }
161
162 /*
163 ================
164 DialogEntityDefEditor::LoadDecl
165 ================
166 */
167 void DialogEntityDefEditor::LoadDecl( idDeclEntityDef *decl ) {
168         int numLines = 0;
169         CRect rect;
170
171         this->decl = decl;
172
173         // Fill up the spawnclass box with all spawn classes
174         /*
175         idTypeInfo *c = idClass::GetClass("idClass");
176         for (; c; c = c->next) {
177                 spawnclassCombo.AddString(c->classname);
178         }
179         */
180
181         // Fill up the inherit box with all entitydefs
182         int numDecls = declManager->GetNumDecls(DECL_ENTITYDEF);
183         for (int i=0; i<numDecls; i++) {
184                 const idDecl *d = declManager->DeclByIndex(DECL_ENTITYDEF, i, false);
185                 if (d) {
186                         inheritCombo.AddString(d->GetName());
187                 }
188         }
189
190         firstLine = decl->GetLineNum();
191
192         char *declText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) );
193         decl->GetText( declText );
194
195         PopulateLists( declText );
196
197         SetWindowText( va( "EntityDef Editor (%s, line %d)", decl->GetFileName(), decl->GetLineNum() ) );
198
199         // Hack to get it to reflow the window
200         GetWindowRect( rect );
201         rect.bottom++;
202         MoveWindow( rect );
203
204         testButton.EnableWindow( FALSE );
205         okButton.EnableWindow( FALSE );
206
207         UpdateStatusBar();
208 }
209
210 /*
211 =================
212 DialogEntityDefEditor::PopulateLists
213 =================
214 */
215 void DialogEntityDefEditor::PopulateLists( const char *declText, const int textLength )
216 {
217         idLexer src;
218         idToken token, token2;
219
220         idDict dict;
221
222         src.LoadMemory( declText, textLength, decl->GetFileName(), firstLine);
223         src.SetFlags( DECL_LEXER_FLAGS );
224         src.SkipUntilString( "{" );
225
226         while (1) {
227                 if ( !src.ReadToken( &token ) ) {
228                         break;
229                 }
230
231                 if ( !token.Icmp( "}" ) ) {
232                         break;
233                 }
234                 if ( token.type != TT_STRING ) {
235                         src.Warning( "Expected quoted string, but found '%s'", token.c_str() );
236                         break;
237                 }
238
239                 if ( !src.ReadToken( &token2 ) ) {
240                         src.Warning( "Unexpected end of file" );
241                         break;
242                 }
243
244                 if ( dict.FindKey( token ) ) {
245                         src.Warning( "'%s' already defined", token.c_str() );
246                 }
247                 dict.Set( token, token2 );
248         }
249
250         // Get the parent, and remove the 'inherit' key so it doesn't show up in the list
251         // We currently don't support multiple inheritence properly, but nothing uses it anyway
252         idStr inherit;
253         const idKeyValue *inheritKeyVal = dict.FindKey("inherit");
254         if (inheritKeyVal) {
255                 inherit = inheritKeyVal->GetValue();
256                 dict.Delete(inheritKeyVal->GetKey());
257         }
258
259         idStr spawnclass = dict.GetString("spawnclass", "");
260         dict.Delete("spawnclass");
261
262         keyValsList.ResetContent();
263
264         // Fill up the list with all the main info
265         size_t numPairs = dict.Size();
266         for (unsigned int i=0; i<numPairs; i++) {
267                 const idKeyValue *keyVal = dict.GetKeyVal(i);
268                 if (keyVal) {
269                         keyValsList.AddPropItem(new CPropertyItem(keyVal->GetKey().c_str(), keyVal->GetValue().c_str(), PIT_EDIT, ""));
270                 }
271         }
272
273         //inheritCombo.SelectString(0, inherit);
274         SetInherit(inherit);
275         inheritCombo.SelectString(0, inherit);
276
277         declNameEdit.SetWindowText(decl->GetName());
278         int index = spawnclassCombo.FindString(0, spawnclass);
279         if (index == CB_ERR) {
280                 index = spawnclassCombo.AddString(spawnclass);
281         }
282         spawnclassCombo.SetCurSel(index);
283 }
284
285 /*
286 =================
287 DialogEntityDefEditor::SetInherit
288 =================
289 */
290
291 void DialogEntityDefEditor::SetInherit(idStr &inherit)
292 {
293         CWaitCursor wc;
294
295         for (int i=0; i<keyValsList.GetCount(); i++) {
296                 CPropertyItem* pItem = (CPropertyItem*)keyValsList.GetItemDataPtr(i);
297                 if (pItem) {
298                         if (pItem->m_propName[0] == '*') {
299                                 delete pItem;
300                                 keyValsList.DeleteString(i);
301                                 i--;
302                         }
303                 }
304         }
305
306         CString spawnclass;
307         // Fill up the rest of the box with inherited info
308         if (!inherit.IsEmpty()) {
309                 const idDecl *temp = declManager->FindType(DECL_ENTITYDEF, inherit, false);
310                 const idDeclEntityDef *parent = static_cast<const idDeclEntityDef *>(temp);
311                 if (parent) {
312                         size_t numPairs = parent->dict.Size();
313                         for (unsigned int i=0; i<numPairs; i++) {
314                                 const idKeyValue *keyVal = parent->dict.GetKeyVal(i);
315                                 if (keyVal) {
316                                         if (spawnclass.IsEmpty() && keyVal->GetKey() == "spawnclass") {
317                                                 spawnclass = keyVal->GetValue();
318                                         }
319                                         else {
320                                                 CString key = keyVal->GetKey();
321                                                 key = "*" + key;
322                                                 keyValsList.AddPropItem(new CPropertyItem(key, keyVal->GetValue().c_str(), PIT_EDIT, ""));
323                                         }
324                                 }
325                         }
326                 }
327         }
328 }
329
330 /*
331 ================
332 DialogEntityDefEditor::OnInitDialog
333 ================
334 */
335 BOOL DialogEntityDefEditor::OnInitDialog()  {
336
337         com_editors |= EDITOR_ENTITYDEF;
338
339         CDialog::OnInitDialog();
340
341         // load accelerator table
342         m_hAccel = ::LoadAccelerators( AfxGetResourceHandle(), MAKEINTRESOURCE( IDR_ACCELERATOR_DECLEDITOR ) );
343
344         // create status bar
345         statusBar.CreateEx( SBARS_SIZEGRIP, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, initialRect, this, AFX_IDW_STATUS_BAR );
346
347         GetClientRect( initialRect );
348
349         EnableToolTips( TRUE );
350
351         testButton.EnableWindow( FALSE );
352         okButton.EnableWindow( FALSE );
353
354         UpdateStatusBar();
355
356         return FALSE; // return TRUE unless you set the focus to a control
357                       // EXCEPTION: OCX Property Pages should return FALSE
358 }
359
360
361 BEGIN_MESSAGE_MAP(DialogEntityDefEditor, CDialog)
362         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
363         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
364         ON_WM_DESTROY()
365         ON_WM_ACTIVATE()
366         ON_WM_MOVE()
367         ON_WM_SIZE()
368         ON_WM_SIZING()
369         ON_WM_SETFOCUS()
370         ON_CBN_EDITCHANGE(IDC_ENTITYDEFEDITOR_COMBO_INHERIT, OnInheritChange)
371         ON_CBN_SELCHANGE(IDC_ENTITYDEFEDITOR_COMBO_INHERIT, OnInheritChange)
372         ON_CBN_EDITCHANGE(IDC_ENTITYDEFEDITOR_COMBO_SPAWNCLASS, OnEditChange)
373         ON_EN_CHANGE(IDC_ENTITYDEFEDITOR_EDIT_DECLNAME, OnEditChange)
374         ON_NOTIFY(EN_MSGFILTER, IDC_DECLEDITOR_EDIT_TEXT, OnEnInputEdit)
375
376         ON_LBN_SELCHANGE(IDC_ENTITYDEFEDITOR_LIST_KEYVALS, OnKeyValChange)
377
378         ON_BN_CLICKED(IDC_ENTITYDEFEDITOR_BUTTON_ADD, OnBnClickedAdd)
379         ON_BN_CLICKED(IDC_ENTITYDEFEDITOR_BUTTON_DELETE, OnBnClickedDelete)
380
381         ON_BN_CLICKED(IDC_DECLEDITOR_BUTTON_TEST, OnBnClickedTest)
382         ON_BN_CLICKED(IDOK, OnBnClickedOk)
383         ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel)
384
385 END_MESSAGE_MAP()
386
387
388 // DialogEntityDefEditor message handlers
389
390 /*
391 ================
392 DialogEntityDefEditor::OnActivate
393 ================
394 */
395 void DialogEntityDefEditor::OnActivate( UINT nState, CWnd *pWndOther, BOOL bMinimized ) {
396         CDialog::OnActivate( nState, pWndOther, bMinimized );
397 }
398
399 /*
400 ================
401 DialogEntityDefEditor::OnToolTipNotify
402 ================
403 */
404 BOOL DialogEntityDefEditor::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
405         return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult );
406 }
407
408 /*
409 ================
410 DialogEntityDefEditor::OnSetFocus
411 ================
412 */
413 void DialogEntityDefEditor::OnSetFocus( CWnd *pOldWnd ) {
414         CDialog::OnSetFocus( pOldWnd );
415 }
416
417 /*
418 ================
419 DialogEntityDefEditor::OnDestroy
420 ================
421 */
422 void DialogEntityDefEditor::OnDestroy() {
423         return CDialog::OnDestroy();
424 }
425
426 /*
427 ================
428 DialogEntityDefEditor::OnMove
429 ================
430 */
431 void DialogEntityDefEditor::OnMove( int x, int y ) {
432         if ( GetSafeHwnd() ) {
433                 CRect rct;
434                 GetWindowRect( rct );
435                 // FIXME: save position
436         }
437         CDialog::OnMove( x, y );
438 }
439
440 /*
441 ================
442 DialogEntityDefEditor::OnSize
443 ================
444 */
445 #define BORDER_SIZE                     4
446 #define BUTTON_SPACE            4
447 #define CONTROL_HEIGHT          24
448 #define TOOLBAR_HEIGHT          24
449
450 void DialogEntityDefEditor::OnSize( UINT nType, int cx, int cy ) {
451         CRect clientRect, rect;
452
453         LockWindowUpdate();
454
455         CDialog::OnSize( nType, cx, cy );
456
457         GetClientRect( clientRect );
458
459         if ( keyValsList.GetSafeHwnd() ) {
460                 keyValsList.GetClientRect( rect );
461                 rect.left = BORDER_SIZE;
462                 rect.right = clientRect.right - BORDER_SIZE;
463                 rect.top = (TOOLBAR_HEIGHT * 2) + (BUTTON_SPACE * 3);
464                 rect.bottom = clientRect.bottom - (TOOLBAR_HEIGHT * 4) - BUTTON_SPACE;
465                 keyValsList.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
466         }
467
468         int keyRowTop = clientRect.Height() - TOOLBAR_HEIGHT * 3 - CONTROL_HEIGHT;
469         int keyRowBottom = keyRowTop + CONTROL_HEIGHT;
470
471         int lineTop = clientRect.Height() - TOOLBAR_HEIGHT * 3 + (CONTROL_HEIGHT / 2);
472
473         int buttonRowTop = clientRect.Height() - TOOLBAR_HEIGHT - CONTROL_HEIGHT;
474         int buttonRowBottom = buttonRowTop + CONTROL_HEIGHT;
475
476         if ( keyLabel.GetSafeHwnd() ) {
477                 keyLabel.GetClientRect( rect );
478                 int width = rect.Width();
479                 rect.left = BORDER_SIZE;
480                 rect.right = BORDER_SIZE + width;
481                 rect.top = keyRowTop + 8;
482                 rect.bottom = keyRowBottom;
483                 keyLabel.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
484         }
485
486         if ( keyEdit.GetSafeHwnd() ) {
487                 keyEdit.GetClientRect( rect );
488                 rect.left = 40;
489                 rect.right = 40 + 200;
490                 rect.top = keyRowTop;
491                 rect.bottom = keyRowBottom;
492                 keyEdit.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
493         }
494
495
496         if ( addButton.GetSafeHwnd() ) {
497                 addButton.GetClientRect( rect );
498                 int width = rect.Width();
499                 rect.left = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - 2 * width;
500                 rect.right = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - width;
501                 rect.top = keyRowTop;
502                 rect.bottom = keyRowBottom;
503                 addButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
504         }
505
506         if ( delButton.GetSafeHwnd() ) {
507                 delButton.GetClientRect( rect );
508                 int width = rect.Width();
509                 rect.left = clientRect.Width() - BORDER_SIZE - width;
510                 rect.right = clientRect.Width() - BORDER_SIZE;
511                 rect.top = keyRowTop;
512                 rect.bottom = keyRowBottom;
513                 delButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
514         }
515
516         if ( line.GetSafeHwnd() ) {
517                 line.GetClientRect( rect );
518                 int height = rect.Height();
519                 rect.left = BORDER_SIZE;
520                 rect.right = clientRect.Width() - BORDER_SIZE;
521                 rect.top = lineTop;
522                 rect.bottom = lineTop + 3;
523                 line.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
524         }
525
526         if ( testButton.GetSafeHwnd() ) {
527                 testButton.GetClientRect( rect );
528                 int width = rect.Width();
529                 rect.left = BORDER_SIZE;
530                 rect.right = BORDER_SIZE + width;
531                 rect.top = buttonRowTop;
532                 rect.bottom = buttonRowBottom;
533                 testButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
534         }
535
536         if ( okButton.GetSafeHwnd() ) {
537                 okButton.GetClientRect( rect );
538                 int width = rect.Width();
539                 rect.left = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - 2 * width;
540                 rect.right = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - width;
541                 rect.top = buttonRowTop;
542                 rect.bottom = buttonRowBottom;
543                 okButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
544         }
545
546         if ( cancelButton.GetSafeHwnd() ) {
547                 cancelButton.GetClientRect( rect );
548                 int width = rect.Width();
549                 rect.left = clientRect.Width() - BORDER_SIZE - width;
550                 rect.right = clientRect.Width() - BORDER_SIZE;
551                 rect.top = buttonRowTop;
552                 rect.bottom = buttonRowBottom;
553                 cancelButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
554         }
555
556         if ( statusBar.GetSafeHwnd() ) {
557                 rect.left = clientRect.Width() - 2;
558                 rect.top = clientRect.Height() - 2;
559                 rect.right = clientRect.Width() - 2;
560                 rect.bottom = clientRect.Height() - 2;
561                 statusBar.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
562         }
563
564         UnlockWindowUpdate();
565 }
566
567 /*
568 ================
569 DialogEntityDefEditor::OnSizing
570 ================
571 */
572 void DialogEntityDefEditor::OnSizing( UINT nSide, LPRECT lpRect ) {
573         /*
574                 1 = left
575                 2 = right
576                 3 = top
577                 4 = left - top
578                 5 = right - top
579                 6 = bottom
580                 7 = left - bottom
581                 8 = right - bottom
582         */
583
584         CDialog::OnSizing( nSide, lpRect );
585
586         if ( ( nSide - 1 ) % 3 == 0 ) {
587                 if ( lpRect->right - lpRect->left < initialRect.Width() ) {
588                         lpRect->left = lpRect->right - initialRect.Width();
589                 }
590         } else if ( ( nSide - 2 ) % 3 == 0 ) {
591                 if ( lpRect->right - lpRect->left < initialRect.Width() ) {
592                         lpRect->right = lpRect->left + initialRect.Width();
593                 }
594         }
595         if ( nSide >= 3 && nSide <= 5 ) {
596                 if ( lpRect->bottom - lpRect->top < initialRect.Height() ) {
597                         lpRect->top = lpRect->bottom - initialRect.Height();
598                 }
599         } else if ( nSide >= 6 && nSide <= 9 ) {
600                 if ( lpRect->bottom - lpRect->top < initialRect.Height() ) {
601                         lpRect->bottom = lpRect->top + initialRect.Height();
602                 }
603         }
604 }
605
606 /*
607 ================
608 DialogEntityDefEditor::OnEditChange
609 ================
610 */
611 void DialogEntityDefEditor::OnEditChange( ) {
612         testButton.EnableWindow( TRUE );
613         okButton.EnableWindow( TRUE );
614 }
615
616 /*
617 ================
618 DialogEntityDefEditor::OnInheritChange
619 ================
620 */
621 void DialogEntityDefEditor::OnInheritChange( ) {
622         testButton.EnableWindow( TRUE );
623         okButton.EnableWindow( TRUE );
624
625         idStr inherit = "";
626
627         int sel = inheritCombo.GetCurSel();
628         if ( sel == CB_ERR ) {
629                 CString temp;
630                 inheritCombo.GetWindowText( temp );
631                 inherit = temp;
632         } else {
633                 CString temp;
634                 inheritCombo.GetLBText( sel, temp );
635                 inherit = temp;
636         }
637         SetInherit(inherit);
638 }
639
640
641 /*
642 ================
643 DialogEntityDefEditor::OnEnInputEdit
644 ================
645 */
646 void DialogEntityDefEditor::OnEnInputEdit( NMHDR *pNMHDR, LRESULT *pResult ) {
647         MSGFILTER *msgFilter = (MSGFILTER *)pNMHDR;
648
649         if ( msgFilter->msg != 512 && msgFilter->msg != 33 ) {
650                 UpdateStatusBar();
651         }
652
653         *pResult = 0;
654 }
655
656 /*
657 ================
658 DialogEntityDefEditor::BuildDeclText
659 ================
660 */
661
662 void DialogEntityDefEditor::BuildDeclText( idStr &declText )
663 {
664         CString declName;
665         declNameEdit.GetWindowText(declName);
666         CString inherit;
667         inheritCombo.GetWindowText(inherit);
668         CString spawnclass;
669         spawnclassCombo.GetWindowText(spawnclass);
670
671         declText = "entityDef " + declName + "\r{\r";
672         declText += "\"inherit\"\t\t\t\"" + inherit + "\"\r";
673         declText += "\"spawnclass\"\t\t\t\"" + spawnclass + "\"\r";
674         for (int i=0; i<keyValsList.GetCount(); i++) {
675                 CPropertyItem* pItem = (CPropertyItem*)keyValsList.GetItemDataPtr(i);
676                 if (pItem) {
677                         // Items with a * in front are inherited and shouldn't be written out
678                         if (pItem->m_propName[0] == '*') {
679                                 break;
680                         }
681                         declText += "\"" + pItem->m_propName + "\"\t\t\t\"" + pItem->m_curValue + "\"\r";
682                 }
683         }
684         declText += "}\r";
685
686         declText.Replace( "\r", "\r\n" );
687         declText.Insert( "\r\n\r\n", 0 );
688         declText.StripTrailing( "\r\n" );
689 }
690
691 /*
692 ================
693 DialogEntityDefEditor::OnBnClickedTest
694 ================
695 */
696 void DialogEntityDefEditor::OnBnClickedTest() {
697         idStr declText, oldDeclText;
698
699         if ( decl ) {
700
701                 BuildDeclText(declText);
702
703                 if ( !TestDecl( declText ) ) {
704                         return;
705                 }
706
707                 char *oldDeclText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) );
708                 decl->GetText( oldDeclText );
709                 decl->SetText( declText );
710                 decl->Invalidate();
711                 declManager->DeclByIndex( decl->GetType(), decl->Index(), true );
712                 decl->SetText( oldDeclText );
713                 decl->Invalidate();
714                 common->Printf( "tested %s\n", decl->GetName() );
715
716                 testButton.EnableWindow( FALSE );
717         }
718 }
719
720 /*
721 ================
722 DialogEntityDefEditor::OnBnClickedOk
723 ================
724 */
725 void DialogEntityDefEditor::OnBnClickedOk() {
726         if ( decl ) {
727
728                 idStr declText;
729                 BuildDeclText(declText);
730
731                 if ( !TestDecl( declText ) ) {
732                         return;
733                 }
734
735                 if ( decl->SourceFileChanged() ) {
736                         if ( MessageBox( va( "Declaration file %s has been modified outside of the editor.\r\nReload declarations and save?", decl->GetFileName() ),
737                                                         va( "Warning saving: %s", decl->GetFileName() ), MB_OKCANCEL | MB_ICONERROR ) != IDOK ) {
738                                 return;
739                         }
740                         declManager->Reload( false );
741                         DeclBrowserReloadDeclarations();
742                 }
743
744                 decl->SetText( declText );
745                 if ( !decl->ReplaceSourceFileText() ) {
746                         MessageBox( va( "Couldn't save: %s.\r\nMake sure the declaration file is not read-only.", decl->GetFileName() ),
747                                                 va( "Error saving: %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
748                         return;
749                 }
750                 decl->Invalidate();
751         }
752
753         okButton.EnableWindow( FALSE );
754 }
755
756 /*
757 ================
758 DialogEntityDefEditor::OnBnClickedCancel
759 ================
760 */
761 void DialogEntityDefEditor::OnBnClickedCancel() {
762         if ( okButton.IsWindowEnabled() ) {
763                 if ( MessageBox( "Cancel changes?", "Cancel", MB_YESNO | MB_ICONQUESTION ) != IDYES ) {
764                         return;
765                 }
766         }
767         OnCancel();
768 }
769
770 /*
771 ================
772 DialogEntityDefEditor::OnKeyValChange
773 ================
774 */
775 void DialogEntityDefEditor::OnKeyValChange() {
776         int sel = keyValsList.GetCurSel();
777         if (sel >= 0) {
778                 CPropertyItem *pItem = (CPropertyItem *)keyValsList.GetItemDataPtr(sel);
779                 keyEdit.SetWindowText(pItem->m_propName);
780         }
781 }
782
783 /*
784 ================
785 DialogEntityDefEditor::OnBnClickedAdd
786 ================
787 */
788 void DialogEntityDefEditor::OnBnClickedAdd() {
789         CString newKey;
790         keyEdit.GetWindowText(newKey);
791
792         int matchedInherit = -1;
793         int matchedKey = -1;
794
795         // See if this key already exists
796         for (int i=0; i<keyValsList.GetCount(); i++) {
797                 CPropertyItem* pItem = (CPropertyItem*)keyValsList.GetItemDataPtr(i);
798                 if (pItem) {
799                         // Items with a * in front are inherited and shouldn't be written out
800                         if (pItem->m_propName[0] == '*') {
801                                 if (newKey = pItem->m_propName.Mid(1)) {
802                                         matchedInherit = i;
803                                 }
804                         }
805                         else if (pItem->m_propName == newKey) {
806                                 matchedKey = i;
807                                 break;
808                         }
809                 }
810         }
811
812         if (matchedKey >= 0) {
813                 MessageBox("Key " + newKey + " already defined");
814                 return;
815         }
816
817         if (matchedInherit >= 0) {
818                 delete keyValsList.GetItemDataPtr(matchedInherit);
819                 keyValsList.DeleteString(matchedInherit);
820         }
821         keyValsList.AddPropItem(new CPropertyItem(newKey, "", PIT_EDIT, ""));
822 }
823
824 /*
825 ================
826 DialogEntityDefEditor::OnBnClickedDelete
827 ================
828 */
829 void DialogEntityDefEditor::OnBnClickedDelete() {
830         CString delKey;
831         keyEdit.GetWindowText(delKey);
832
833         int matchedInherit = -1;
834         int matchedKey = -1;
835
836         // See if this key already exists
837         for (int i=0; i<keyValsList.GetCount(); i++) {
838                 CPropertyItem* pItem = (CPropertyItem*)keyValsList.GetItemDataPtr(i);
839                 if (pItem) {
840                         // Items with a * in front are inherited and shouldn't be written out
841                         if (pItem->m_propName[0] == '*') {
842                                 if (delKey = pItem->m_propName.Mid(1)) {
843                                         matchedInherit = i;
844                                 }
845                         }
846                         else if (pItem->m_propName == delKey) {
847                                 matchedKey = i;
848                                 break;
849                         }
850                 }
851         }
852
853         if (matchedKey >= 0) {
854                 delete keyValsList.GetItemDataPtr(matchedKey);
855                 keyValsList.DeleteString(matchedKey);
856         }
857         else if (matchedInherit) {
858                 MessageBox("Cannot delete an inherited value");
859         }
860 }