2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../../sys/win32/rc/Common_resource.h"
33 #include "../../sys/win32/rc/DeclEditor_resource.h"
35 #include "../comafx/DialogGoToLine.h"
36 #include "../comafx/CPathTreeCtrl.h"
37 #include "DialogDeclBrowser.h"
38 #include "DialogDeclEditor.h"
40 #ifdef ID_DEBUG_MEMORY
47 // DialogDeclEditor dialog
49 static UINT FindDialogMessage = ::RegisterWindowMessage( FINDMSGSTRING );
51 toolTip_t DialogDeclEditor::toolTips[] = {
52 { IDC_DECLEDITOR_BUTTON_TEST, "test decl" },
53 { IDOK, "save decl" },
54 { IDCANCEL, "cancel" },
59 IMPLEMENT_DYNAMIC(DialogDeclEditor, CDialog)
63 DialogDeclEditor::DialogDeclEditor
66 DialogDeclEditor::DialogDeclEditor( CWnd* pParent /*=NULL*/ )
67 : CDialog(DialogDeclEditor::IDD, pParent)
70 , matchWholeWords(false)
78 DialogDeclEditor::~DialogDeclEditor
81 DialogDeclEditor::~DialogDeclEditor() {
86 DialogDeclEditor::DoDataExchange
89 void DialogDeclEditor::DoDataExchange(CDataExchange* pDX) {
90 CDialog::DoDataExchange(pDX);
91 //{{AFX_DATA_MAP(DialogDeclEditor)
92 DDX_Control(pDX, IDC_DECLEDITOR_EDIT_TEXT, declEdit);
93 DDX_Control(pDX, IDC_DECLEDITOR_BUTTON_TEST, testButton);
94 DDX_Control(pDX, IDOK, okButton);
95 DDX_Control(pDX, IDCANCEL, cancelButton);
101 DialogDeclEditor::PreTranslateMessage
104 BOOL DialogDeclEditor::PreTranslateMessage( MSG* pMsg ) {
105 if ( WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST ) {
106 if ( m_hAccel && ::TranslateAccelerator( m_hWnd, m_hAccel, pMsg ) ) {
110 return CWnd::PreTranslateMessage(pMsg);
115 DialogDeclEditor::TestDecl
118 bool DialogDeclEditor::TestDecl( const idStr &declText ) {
119 idLexer src( LEXFL_NOSTRINGCONCAT );
123 src.LoadMemory( declText, declText.Length(), "decl text" );
126 while( src.ReadToken( &token ) ) {
127 if ( token == "{" ) {
129 } else if ( token == "}" ) {
135 MessageBox( "Missing opening brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
139 MessageBox( "Missing closing brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
147 DialogDeclEditor::UpdateStatusBar
150 void DialogDeclEditor::UpdateStatusBar( void ) {
151 int line, column, character;
154 declEdit.GetCursorPos( line, column, character );
155 statusBar.SetWindowText( va( "Line: %d, Column: %d, Character: %d", decl->GetLineNum() + line, column, character ) );
161 DialogDeclEditor::LoadDecl
164 void DialogDeclEditor::LoadDecl( idDecl *decl ) {
166 int numCharsPerLine = 0;
167 int maxCharsPerLine = 0;
173 switch( decl->GetType() ) {
175 declEdit.SetStringColor( SRE_COLOR_BLUE, SRE_COLOR_DARK_CYAN );
176 declEdit.LoadKeyWordsFromFile( "editors/entity.def" );
179 declEdit.LoadKeyWordsFromFile( "editors/material.def" );
182 declEdit.LoadKeyWordsFromFile( "editors/skin.def" );
185 declEdit.LoadKeyWordsFromFile( "editors/sound.def" );
188 declEdit.LoadKeyWordsFromFile( "editors/fx.def" );
191 declEdit.LoadKeyWordsFromFile( "editors/particle.def" );
194 declEdit.LoadKeyWordsFromFile( "editors/af.def" );
197 declEdit.LoadKeyWordsFromFile( "editors/table.def" );
200 declEdit.LoadKeyWordsFromFile( "editors/model.def" );
203 declEdit.LoadKeyWordsFromFile( va( "editors/%s.def", declManager->GetDeclNameFromType( decl->GetType() ) ) );
207 firstLine = decl->GetLineNum();
209 char *localDeclText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) );
210 decl->GetText( localDeclText );
211 declText = localDeclText;
213 // clean up new-line crapola
214 declText.Replace( "\r", "" );
215 declText.Replace( "\n", "\r" );
216 declText.Replace( "\v", "\r" );
217 declText.StripLeading( '\r' );
218 declText.Append( "\r" );
220 declEdit.SetText( declText );
222 for( const char *ptr = declText.c_str(); *ptr; ptr++ ) {
223 if ( *ptr == '\r' ) {
224 if ( numCharsPerLine > maxCharsPerLine ) {
225 maxCharsPerLine = numCharsPerLine;
229 } else if ( *ptr == '\t' ) {
230 numCharsPerLine += TAB_SIZE;
236 SetWindowText( va( "Declaration Editor (%s, line %d)", decl->GetFileName(), decl->GetLineNum() ) );
238 rect.left = initialRect.left;
239 rect.right = rect.left + maxCharsPerLine * FONT_WIDTH + 32;
240 rect.top = initialRect.top;
241 rect.bottom = rect.top + numLines * (FONT_HEIGHT+8) + 24 + 56;
242 if ( rect.right < initialRect.right ) {
243 rect.right = initialRect.right;
244 } else if ( rect.right - rect.left > 1024 ) {
245 rect.right = rect.left + 1024;
247 if ( rect.bottom < initialRect.bottom ) {
248 rect.bottom = initialRect.bottom;
249 } else if ( rect.bottom - rect.top > 768 ) {
250 rect.bottom = rect.top + 768;
254 testButton.EnableWindow( FALSE );
255 okButton.EnableWindow( FALSE );
264 DialogDeclEditor::OnInitDialog
267 BOOL DialogDeclEditor::OnInitDialog() {
269 com_editors |= EDITOR_DECL;
271 CDialog::OnInitDialog();
273 // load accelerator table
274 m_hAccel = ::LoadAccelerators( AfxGetResourceHandle(), MAKEINTRESOURCE( IDR_ACCELERATOR_DECLEDITOR ) );
277 statusBar.CreateEx( SBARS_SIZEGRIP, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, initialRect, this, AFX_IDW_STATUS_BAR );
281 GetClientRect( initialRect );
283 EnableToolTips( TRUE );
285 testButton.EnableWindow( FALSE );
286 okButton.EnableWindow( FALSE );
290 return FALSE; // return TRUE unless you set the focus to a control
291 // EXCEPTION: OCX Property Pages should return FALSE
295 BEGIN_MESSAGE_MAP(DialogDeclEditor, CDialog)
296 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
297 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
304 ON_COMMAND(ID_EDIT_FIND, OnEditFind)
305 ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
306 ON_COMMAND(ID_DECLEDITOR_FIND_NEXT, OnEditFindNext)
307 ON_COMMAND(ID_DECLEDITOR_GOTOLINE, OnEditGoToLine)
308 ON_REGISTERED_MESSAGE(FindDialogMessage, OnFindDialogMessage)
309 ON_NOTIFY(EN_CHANGE, IDC_DECLEDITOR_EDIT_TEXT, OnEnChangeEdit)
310 ON_NOTIFY(EN_MSGFILTER, IDC_DECLEDITOR_EDIT_TEXT, OnEnInputEdit)
311 ON_BN_CLICKED(IDC_DECLEDITOR_BUTTON_TEST, OnBnClickedTest)
312 ON_BN_CLICKED(IDOK, OnBnClickedOk)
313 ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel)
317 // DialogDeclEditor message handlers
321 DialogDeclEditor::OnActivate
324 void DialogDeclEditor::OnActivate( UINT nState, CWnd *pWndOther, BOOL bMinimized ) {
325 CDialog::OnActivate( nState, pWndOther, bMinimized );
330 DialogDeclEditor::OnToolTipNotify
333 BOOL DialogDeclEditor::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
334 return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult );
339 DialogDeclEditor::OnSetFocus
342 void DialogDeclEditor::OnSetFocus( CWnd *pOldWnd ) {
343 CDialog::OnSetFocus( pOldWnd );
348 DialogDeclEditor::OnDestroy
351 void DialogDeclEditor::OnDestroy() {
352 return CDialog::OnDestroy();
357 DialogDeclEditor::OnMove
360 void DialogDeclEditor::OnMove( int x, int y ) {
361 if ( GetSafeHwnd() ) {
363 GetWindowRect( rct );
364 // FIXME: save position
366 CDialog::OnMove( x, y );
371 DialogDeclEditor::OnSize
374 #define BORDER_SIZE 0
375 #define BUTTON_SPACE 4
376 #define TOOLBAR_HEIGHT 24
378 void DialogDeclEditor::OnSize( UINT nType, int cx, int cy ) {
379 CRect clientRect, rect;
383 CDialog::OnSize( nType, cx, cy );
385 GetClientRect( clientRect );
387 if ( declEdit.GetSafeHwnd() ) {
388 rect.left = BORDER_SIZE;
389 rect.top = BORDER_SIZE;
390 rect.right = clientRect.Width() - BORDER_SIZE;
391 rect.bottom = clientRect.Height() - 56;
392 declEdit.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
395 if ( testButton.GetSafeHwnd() ) {
396 testButton.GetClientRect( rect );
397 int width = rect.Width();
398 int height = rect.Height();
399 rect.left = BORDER_SIZE;
400 rect.top = clientRect.Height() - TOOLBAR_HEIGHT - height;
401 rect.right = BORDER_SIZE + width;
402 rect.bottom = clientRect.Height() - TOOLBAR_HEIGHT;
403 testButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
406 if ( okButton.GetSafeHwnd() ) {
407 okButton.GetClientRect( rect );
408 int width = rect.Width();
409 int height = rect.Height();
410 rect.left = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - 2 * width;
411 rect.top = clientRect.Height() - TOOLBAR_HEIGHT - height;
412 rect.right = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - width;
413 rect.bottom = clientRect.Height() - TOOLBAR_HEIGHT;
414 okButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
417 if ( cancelButton.GetSafeHwnd() ) {
418 cancelButton.GetClientRect( rect );
419 int width = rect.Width();
420 int height = rect.Height();
421 rect.left = clientRect.Width() - BORDER_SIZE - width;
422 rect.top = clientRect.Height() - TOOLBAR_HEIGHT - height;
423 rect.right = clientRect.Width() - BORDER_SIZE;
424 rect.bottom = clientRect.Height() - TOOLBAR_HEIGHT;
425 cancelButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
428 if ( statusBar.GetSafeHwnd() ) {
429 rect.left = clientRect.Width() - 2;
430 rect.top = clientRect.Height() - 2;
431 rect.right = clientRect.Width() - 2;
432 rect.bottom = clientRect.Height() - 2;
433 statusBar.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() );
436 UnlockWindowUpdate();
441 DialogDeclEditor::OnSizing
444 void DialogDeclEditor::OnSizing( UINT nSide, LPRECT lpRect ) {
456 CDialog::OnSizing( nSide, lpRect );
458 if ( ( nSide - 1 ) % 3 == 0 ) {
459 if ( lpRect->right - lpRect->left < initialRect.Width() ) {
460 lpRect->left = lpRect->right - initialRect.Width();
462 } else if ( ( nSide - 2 ) % 3 == 0 ) {
463 if ( lpRect->right - lpRect->left < initialRect.Width() ) {
464 lpRect->right = lpRect->left + initialRect.Width();
467 if ( nSide >= 3 && nSide <= 5 ) {
468 if ( lpRect->bottom - lpRect->top < initialRect.Height() ) {
469 lpRect->top = lpRect->bottom - initialRect.Height();
471 } else if ( nSide >= 6 && nSide <= 9 ) {
472 if ( lpRect->bottom - lpRect->top < initialRect.Height() ) {
473 lpRect->bottom = lpRect->top + initialRect.Height();
480 DialogDeclEditor::OnEditGoToLine
483 void DialogDeclEditor::OnEditGoToLine() {
484 DialogGoToLine goToLineDlg;
486 goToLineDlg.SetRange( firstLine, firstLine + declEdit.GetLineCount() - 1 );
487 if ( goToLineDlg.DoModal() != IDOK ) {
490 declEdit.GoToLine( goToLineDlg.GetLine() - firstLine );
495 DialogDeclEditor::OnEditFind
498 void DialogDeclEditor::OnEditFind() {
500 CString selText = declEdit.GetSelText();
501 if ( selText.GetLength() ) {
506 // create find/replace dialog
507 findDlg = new CFindReplaceDialog(); // Must be created on the heap
508 findDlg->Create( TRUE, findStr, "", FR_DOWN, this );
514 DialogDeclEditor::OnEditFindNext
517 void DialogDeclEditor::OnEditFindNext() {
518 if ( declEdit.FindNext( findStr, matchCase, matchWholeWords, searchForward ) ) {
521 AfxMessageBox( "The specified text was not found.", MB_OK | MB_ICONINFORMATION, 0 );
527 DialogDeclEditor::OnEditReplace
530 void DialogDeclEditor::OnEditReplace() {
532 CString selText = declEdit.GetSelText();
533 if ( selText.GetLength() ) {
537 // create find/replace dialog
539 findDlg = new CFindReplaceDialog(); // Must be created on the heap
540 findDlg->Create( FALSE, findStr, "", FR_DOWN, this );
546 DialogDeclEditor::OnFindDialogMessage
549 LRESULT DialogDeclEditor::OnFindDialogMessage( WPARAM wParam, LPARAM lParam ) {
550 if ( findDlg == NULL ) {
554 if ( findDlg->IsTerminating() ) {
559 if( findDlg->FindNext() ) {
560 findStr = findDlg->GetFindString();
561 matchCase = findDlg->MatchCase() != FALSE;
562 matchWholeWords = findDlg->MatchWholeWord() != FALSE;
563 searchForward = findDlg->SearchDown() != FALSE;
568 if ( findDlg->ReplaceCurrent() ) {
569 long selStart, selEnd;
571 replaceStr = findDlg->GetReplaceString();
573 declEdit.GetSel( selStart, selEnd );
574 if ( selEnd > selStart ) {
575 declEdit.ReplaceSel( replaceStr, TRUE );
579 if ( findDlg->ReplaceAll() ) {
580 replaceStr = findDlg->GetReplaceString();
581 findStr = findDlg->GetFindString();
582 matchCase = findDlg->MatchCase() != FALSE;
583 matchWholeWords = findDlg->MatchWholeWord() != FALSE;
585 int numReplaces = declEdit.ReplaceAll( findStr, replaceStr, matchCase, matchWholeWords );
586 if ( numReplaces == 0 ) {
587 AfxMessageBox( "The specified text was not found.", MB_OK | MB_ICONINFORMATION, 0 );
589 AfxMessageBox( va( "Replaced %d occurances.", numReplaces ), MB_OK | MB_ICONINFORMATION, 0 );
598 DialogDeclEditor::OnEnChangeEdit
601 void DialogDeclEditor::OnEnChangeEdit( NMHDR *pNMHDR, LRESULT *pResult ) {
602 testButton.EnableWindow( TRUE );
603 okButton.EnableWindow( TRUE );
608 DialogDeclEditor::OnEnInputEdit
611 void DialogDeclEditor::OnEnInputEdit( NMHDR *pNMHDR, LRESULT *pResult ) {
612 MSGFILTER *msgFilter = (MSGFILTER *)pNMHDR;
614 if ( msgFilter->msg != 512 && msgFilter->msg != 33 ) {
623 DialogDeclEditor::OnBnClickedTest
626 void DialogDeclEditor::OnBnClickedTest() {
631 declEdit.GetText( declText );
633 // clean up new-line crapola
634 declText.Replace( "\n", "" );
635 declText.Replace( "\r", "\r\n" );
636 declText.Replace( "\v", "\r\n" );
637 declText.StripLeading( "\r\n" );
638 declText.Insert( "\r\n\r\n", 0 );
639 declText.StripTrailing( "\r\n" );
641 if ( !TestDecl( declText ) ) {
645 char *oldDeclText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) );
646 decl->GetText( oldDeclText );
647 decl->SetText( declText );
649 declManager->DeclByIndex( decl->GetType(), decl->Index(), true );
650 decl->SetText( oldDeclText );
652 common->Printf( "tested %s\n", decl->GetName() );
654 testButton.EnableWindow( FALSE );
660 DialogDeclEditor::OnBnClickedOk
663 void DialogDeclEditor::OnBnClickedOk() {
668 declEdit.GetText( declText );
670 // clean up new-line crapola
671 declText.Replace( "\n", "" );
672 declText.Replace( "\r", "\r\n" );
673 declText.Replace( "\v", "\r\n" );
674 declText.StripLeading( "\r\n" );
675 declText.Insert( "\r\n\r\n", 0 );
676 declText.StripTrailing( "\r\n" );
678 if ( !TestDecl( declText ) ) {
682 if ( decl->SourceFileChanged() ) {
683 if ( MessageBox( va( "Declaration file %s has been modified outside of the editor.\r\nReload declarations and save?", decl->GetFileName() ),
684 va( "Warning saving: %s", decl->GetFileName() ), MB_OKCANCEL | MB_ICONERROR ) != IDOK ) {
687 declManager->Reload( false );
688 DeclBrowserReloadDeclarations();
691 decl->SetText( declText );
692 if ( !decl->ReplaceSourceFileText() ) {
693 MessageBox( va( "Couldn't save: %s.\r\nMake sure the declaration file is not read-only.", decl->GetFileName() ),
694 va( "Error saving: %s", decl->GetFileName() ), MB_OK | MB_ICONERROR );
700 okButton.EnableWindow( FALSE );
705 DialogDeclEditor::OnBnClickedCancel
708 void DialogDeclEditor::OnBnClickedCancel() {
709 if ( okButton.IsWindowEnabled() ) {
710 if ( MessageBox( "Cancel changes?", "Cancel", MB_YESNO | MB_ICONQUESTION ) != IDYES ) {