/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . 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. 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. =========================================================================== */ #include "../../idlib/precompiled.h" #pragma hdrstop #include "../../sys/win32/rc/Common_resource.h" #include "../../sys/win32/rc/DeclEditor_resource.h" #include "../comafx/CPathTreeCtrl.h" #include "DialogDeclBrowser.h" #include "DialogDeclEditor.h" #include "DialogEntityDefEditor.h" #ifdef ID_DEBUG_MEMORY #undef new #undef DEBUG_NEW #define DEBUG_NEW new #endif // DialogEntityDefEditor dialog toolTip_t DialogEntityDefEditor::toolTips[] = { { IDC_DECLEDITOR_BUTTON_TEST, "Test Decl" }, { IDOK, "Save Decl" }, { IDCANCEL, "Cancel" }, { 0, NULL } }; IMPLEMENT_DYNAMIC(DialogEntityDefEditor, CDialog) /* ================ DialogEntityDefEditor::DialogEntityDefEditor ================ */ DialogEntityDefEditor::DialogEntityDefEditor( CWnd* pParent /*=NULL*/ ) : CDialog(DialogEntityDefEditor::IDD, pParent) , decl(NULL) , firstLine(0) { } /* ================ DialogEntityDefEditor::~DialogEntityDefEditor ================ */ DialogEntityDefEditor::~DialogEntityDefEditor() { } /* ================ DialogEntityDefEditor::DoDataExchange ================ */ void DialogEntityDefEditor::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(DialogEntityDefEditor) DDX_Control(pDX, IDC_ENTITYDEFEDITOR_EDIT_DECLNAME, declNameEdit); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_COMBO_INHERIT, inheritCombo); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_COMBO_SPAWNCLASS, spawnclassCombo); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_LIST_KEYVALS, keyValsList); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_STATIC_KEY, keyLabel); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_EDIT_KEY, keyEdit); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_BUTTON_ADD, addButton); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_BUTTON_DELETE, delButton); DDX_Control(pDX, IDC_ENTITYDEFEDITOR_LINE, line); DDX_Control(pDX, IDC_DECLEDITOR_BUTTON_TEST, testButton); DDX_Control(pDX, IDOK, okButton); DDX_Control(pDX, IDCANCEL, cancelButton); //}}AFX_DATA_MAP } /* ================ DialogEntityDefEditor::PreTranslateMessage ================ */ BOOL DialogEntityDefEditor::PreTranslateMessage( MSG* pMsg ) { if ( WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST ) { if ( m_hAccel && ::TranslateAccelerator( m_hWnd, m_hAccel, pMsg ) ) { return TRUE; } } return CWnd::PreTranslateMessage(pMsg); } /* ================ DialogEntityDefEditor::TestDecl ================ */ bool DialogEntityDefEditor::TestDecl( const idStr &declText ) { idLexer src( LEXFL_NOSTRINGCONCAT ); idToken token; int indent; src.LoadMemory( declText, declText.Length(), "decl text" ); indent = 0; while( src.ReadToken( &token ) ) { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; } } if ( indent < 0 ) { MessageBox( "Missing opening brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR ); return false; } if ( indent > 0 ) { MessageBox( "Missing closing brace!", va( "Error saving %s", decl->GetFileName() ), MB_OK | MB_ICONERROR ); return false; } return true; } /* ================ DialogEntityDefEditor::UpdateStatusBar ================ */ void DialogEntityDefEditor::UpdateStatusBar( void ) { if ( decl ) { statusBar.SetWindowText( "Editing decl" ); } } /* ================ DialogEntityDefEditor::LoadDecl ================ */ void DialogEntityDefEditor::LoadDecl( idDeclEntityDef *decl ) { int numLines = 0; CRect rect; this->decl = decl; // Fill up the spawnclass box with all spawn classes /* idTypeInfo *c = idClass::GetClass("idClass"); for (; c; c = c->next) { spawnclassCombo.AddString(c->classname); } */ // Fill up the inherit box with all entitydefs int numDecls = declManager->GetNumDecls(DECL_ENTITYDEF); for (int i=0; iDeclByIndex(DECL_ENTITYDEF, i, false); if (d) { inheritCombo.AddString(d->GetName()); } } firstLine = decl->GetLineNum(); char *declText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) ); decl->GetText( declText ); PopulateLists( declText ); SetWindowText( va( "EntityDef Editor (%s, line %d)", decl->GetFileName(), decl->GetLineNum() ) ); // Hack to get it to reflow the window GetWindowRect( rect ); rect.bottom++; MoveWindow( rect ); testButton.EnableWindow( FALSE ); okButton.EnableWindow( FALSE ); UpdateStatusBar(); } /* ================= DialogEntityDefEditor::PopulateLists ================= */ void DialogEntityDefEditor::PopulateLists( const char *declText, const int textLength ) { idLexer src; idToken token, token2; idDict dict; src.LoadMemory( declText, textLength, decl->GetFileName(), firstLine); src.SetFlags( DECL_LEXER_FLAGS ); src.SkipUntilString( "{" ); while (1) { if ( !src.ReadToken( &token ) ) { break; } if ( !token.Icmp( "}" ) ) { break; } if ( token.type != TT_STRING ) { src.Warning( "Expected quoted string, but found '%s'", token.c_str() ); break; } if ( !src.ReadToken( &token2 ) ) { src.Warning( "Unexpected end of file" ); break; } if ( dict.FindKey( token ) ) { src.Warning( "'%s' already defined", token.c_str() ); } dict.Set( token, token2 ); } // Get the parent, and remove the 'inherit' key so it doesn't show up in the list // We currently don't support multiple inheritence properly, but nothing uses it anyway idStr inherit; const idKeyValue *inheritKeyVal = dict.FindKey("inherit"); if (inheritKeyVal) { inherit = inheritKeyVal->GetValue(); dict.Delete(inheritKeyVal->GetKey()); } idStr spawnclass = dict.GetString("spawnclass", ""); dict.Delete("spawnclass"); keyValsList.ResetContent(); // Fill up the list with all the main info size_t numPairs = dict.Size(); for (unsigned int i=0; iGetKey().c_str(), keyVal->GetValue().c_str(), PIT_EDIT, "")); } } //inheritCombo.SelectString(0, inherit); SetInherit(inherit); inheritCombo.SelectString(0, inherit); declNameEdit.SetWindowText(decl->GetName()); int index = spawnclassCombo.FindString(0, spawnclass); if (index == CB_ERR) { index = spawnclassCombo.AddString(spawnclass); } spawnclassCombo.SetCurSel(index); } /* ================= DialogEntityDefEditor::SetInherit ================= */ void DialogEntityDefEditor::SetInherit(idStr &inherit) { CWaitCursor wc; for (int i=0; im_propName[0] == '*') { delete pItem; keyValsList.DeleteString(i); i--; } } } CString spawnclass; // Fill up the rest of the box with inherited info if (!inherit.IsEmpty()) { const idDecl *temp = declManager->FindType(DECL_ENTITYDEF, inherit, false); const idDeclEntityDef *parent = static_cast(temp); if (parent) { size_t numPairs = parent->dict.Size(); for (unsigned int i=0; idict.GetKeyVal(i); if (keyVal) { if (spawnclass.IsEmpty() && keyVal->GetKey() == "spawnclass") { spawnclass = keyVal->GetValue(); } else { CString key = keyVal->GetKey(); key = "*" + key; keyValsList.AddPropItem(new CPropertyItem(key, keyVal->GetValue().c_str(), PIT_EDIT, "")); } } } } } } /* ================ DialogEntityDefEditor::OnInitDialog ================ */ BOOL DialogEntityDefEditor::OnInitDialog() { com_editors |= EDITOR_ENTITYDEF; CDialog::OnInitDialog(); // load accelerator table m_hAccel = ::LoadAccelerators( AfxGetResourceHandle(), MAKEINTRESOURCE( IDR_ACCELERATOR_DECLEDITOR ) ); // create status bar statusBar.CreateEx( SBARS_SIZEGRIP, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, initialRect, this, AFX_IDW_STATUS_BAR ); GetClientRect( initialRect ); EnableToolTips( TRUE ); testButton.EnableWindow( FALSE ); okButton.EnableWindow( FALSE ); UpdateStatusBar(); return FALSE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } BEGIN_MESSAGE_MAP(DialogEntityDefEditor, CDialog) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify) ON_WM_DESTROY() ON_WM_ACTIVATE() ON_WM_MOVE() ON_WM_SIZE() ON_WM_SIZING() ON_WM_SETFOCUS() ON_CBN_EDITCHANGE(IDC_ENTITYDEFEDITOR_COMBO_INHERIT, OnInheritChange) ON_CBN_SELCHANGE(IDC_ENTITYDEFEDITOR_COMBO_INHERIT, OnInheritChange) ON_CBN_EDITCHANGE(IDC_ENTITYDEFEDITOR_COMBO_SPAWNCLASS, OnEditChange) ON_EN_CHANGE(IDC_ENTITYDEFEDITOR_EDIT_DECLNAME, OnEditChange) ON_NOTIFY(EN_MSGFILTER, IDC_DECLEDITOR_EDIT_TEXT, OnEnInputEdit) ON_LBN_SELCHANGE(IDC_ENTITYDEFEDITOR_LIST_KEYVALS, OnKeyValChange) ON_BN_CLICKED(IDC_ENTITYDEFEDITOR_BUTTON_ADD, OnBnClickedAdd) ON_BN_CLICKED(IDC_ENTITYDEFEDITOR_BUTTON_DELETE, OnBnClickedDelete) ON_BN_CLICKED(IDC_DECLEDITOR_BUTTON_TEST, OnBnClickedTest) ON_BN_CLICKED(IDOK, OnBnClickedOk) ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) END_MESSAGE_MAP() // DialogEntityDefEditor message handlers /* ================ DialogEntityDefEditor::OnActivate ================ */ void DialogEntityDefEditor::OnActivate( UINT nState, CWnd *pWndOther, BOOL bMinimized ) { CDialog::OnActivate( nState, pWndOther, bMinimized ); } /* ================ DialogEntityDefEditor::OnToolTipNotify ================ */ BOOL DialogEntityDefEditor::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) { return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult ); } /* ================ DialogEntityDefEditor::OnSetFocus ================ */ void DialogEntityDefEditor::OnSetFocus( CWnd *pOldWnd ) { CDialog::OnSetFocus( pOldWnd ); } /* ================ DialogEntityDefEditor::OnDestroy ================ */ void DialogEntityDefEditor::OnDestroy() { return CDialog::OnDestroy(); } /* ================ DialogEntityDefEditor::OnMove ================ */ void DialogEntityDefEditor::OnMove( int x, int y ) { if ( GetSafeHwnd() ) { CRect rct; GetWindowRect( rct ); // FIXME: save position } CDialog::OnMove( x, y ); } /* ================ DialogEntityDefEditor::OnSize ================ */ #define BORDER_SIZE 4 #define BUTTON_SPACE 4 #define CONTROL_HEIGHT 24 #define TOOLBAR_HEIGHT 24 void DialogEntityDefEditor::OnSize( UINT nType, int cx, int cy ) { CRect clientRect, rect; LockWindowUpdate(); CDialog::OnSize( nType, cx, cy ); GetClientRect( clientRect ); if ( keyValsList.GetSafeHwnd() ) { keyValsList.GetClientRect( rect ); rect.left = BORDER_SIZE; rect.right = clientRect.right - BORDER_SIZE; rect.top = (TOOLBAR_HEIGHT * 2) + (BUTTON_SPACE * 3); rect.bottom = clientRect.bottom - (TOOLBAR_HEIGHT * 4) - BUTTON_SPACE; keyValsList.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } int keyRowTop = clientRect.Height() - TOOLBAR_HEIGHT * 3 - CONTROL_HEIGHT; int keyRowBottom = keyRowTop + CONTROL_HEIGHT; int lineTop = clientRect.Height() - TOOLBAR_HEIGHT * 3 + (CONTROL_HEIGHT / 2); int buttonRowTop = clientRect.Height() - TOOLBAR_HEIGHT - CONTROL_HEIGHT; int buttonRowBottom = buttonRowTop + CONTROL_HEIGHT; if ( keyLabel.GetSafeHwnd() ) { keyLabel.GetClientRect( rect ); int width = rect.Width(); rect.left = BORDER_SIZE; rect.right = BORDER_SIZE + width; rect.top = keyRowTop + 8; rect.bottom = keyRowBottom; keyLabel.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( keyEdit.GetSafeHwnd() ) { keyEdit.GetClientRect( rect ); rect.left = 40; rect.right = 40 + 200; rect.top = keyRowTop; rect.bottom = keyRowBottom; keyEdit.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( addButton.GetSafeHwnd() ) { addButton.GetClientRect( rect ); int width = rect.Width(); rect.left = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - 2 * width; rect.right = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - width; rect.top = keyRowTop; rect.bottom = keyRowBottom; addButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( delButton.GetSafeHwnd() ) { delButton.GetClientRect( rect ); int width = rect.Width(); rect.left = clientRect.Width() - BORDER_SIZE - width; rect.right = clientRect.Width() - BORDER_SIZE; rect.top = keyRowTop; rect.bottom = keyRowBottom; delButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( line.GetSafeHwnd() ) { line.GetClientRect( rect ); int height = rect.Height(); rect.left = BORDER_SIZE; rect.right = clientRect.Width() - BORDER_SIZE; rect.top = lineTop; rect.bottom = lineTop + 3; line.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( testButton.GetSafeHwnd() ) { testButton.GetClientRect( rect ); int width = rect.Width(); rect.left = BORDER_SIZE; rect.right = BORDER_SIZE + width; rect.top = buttonRowTop; rect.bottom = buttonRowBottom; testButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( okButton.GetSafeHwnd() ) { okButton.GetClientRect( rect ); int width = rect.Width(); rect.left = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - 2 * width; rect.right = clientRect.Width() - BORDER_SIZE - BUTTON_SPACE - width; rect.top = buttonRowTop; rect.bottom = buttonRowBottom; okButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( cancelButton.GetSafeHwnd() ) { cancelButton.GetClientRect( rect ); int width = rect.Width(); rect.left = clientRect.Width() - BORDER_SIZE - width; rect.right = clientRect.Width() - BORDER_SIZE; rect.top = buttonRowTop; rect.bottom = buttonRowBottom; cancelButton.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } if ( statusBar.GetSafeHwnd() ) { rect.left = clientRect.Width() - 2; rect.top = clientRect.Height() - 2; rect.right = clientRect.Width() - 2; rect.bottom = clientRect.Height() - 2; statusBar.MoveWindow( rect.left, rect.top, rect.Width(), rect.Height() ); } UnlockWindowUpdate(); } /* ================ DialogEntityDefEditor::OnSizing ================ */ void DialogEntityDefEditor::OnSizing( UINT nSide, LPRECT lpRect ) { /* 1 = left 2 = right 3 = top 4 = left - top 5 = right - top 6 = bottom 7 = left - bottom 8 = right - bottom */ CDialog::OnSizing( nSide, lpRect ); if ( ( nSide - 1 ) % 3 == 0 ) { if ( lpRect->right - lpRect->left < initialRect.Width() ) { lpRect->left = lpRect->right - initialRect.Width(); } } else if ( ( nSide - 2 ) % 3 == 0 ) { if ( lpRect->right - lpRect->left < initialRect.Width() ) { lpRect->right = lpRect->left + initialRect.Width(); } } if ( nSide >= 3 && nSide <= 5 ) { if ( lpRect->bottom - lpRect->top < initialRect.Height() ) { lpRect->top = lpRect->bottom - initialRect.Height(); } } else if ( nSide >= 6 && nSide <= 9 ) { if ( lpRect->bottom - lpRect->top < initialRect.Height() ) { lpRect->bottom = lpRect->top + initialRect.Height(); } } } /* ================ DialogEntityDefEditor::OnEditChange ================ */ void DialogEntityDefEditor::OnEditChange( ) { testButton.EnableWindow( TRUE ); okButton.EnableWindow( TRUE ); } /* ================ DialogEntityDefEditor::OnInheritChange ================ */ void DialogEntityDefEditor::OnInheritChange( ) { testButton.EnableWindow( TRUE ); okButton.EnableWindow( TRUE ); idStr inherit = ""; int sel = inheritCombo.GetCurSel(); if ( sel == CB_ERR ) { CString temp; inheritCombo.GetWindowText( temp ); inherit = temp; } else { CString temp; inheritCombo.GetLBText( sel, temp ); inherit = temp; } SetInherit(inherit); } /* ================ DialogEntityDefEditor::OnEnInputEdit ================ */ void DialogEntityDefEditor::OnEnInputEdit( NMHDR *pNMHDR, LRESULT *pResult ) { MSGFILTER *msgFilter = (MSGFILTER *)pNMHDR; if ( msgFilter->msg != 512 && msgFilter->msg != 33 ) { UpdateStatusBar(); } *pResult = 0; } /* ================ DialogEntityDefEditor::BuildDeclText ================ */ void DialogEntityDefEditor::BuildDeclText( idStr &declText ) { CString declName; declNameEdit.GetWindowText(declName); CString inherit; inheritCombo.GetWindowText(inherit); CString spawnclass; spawnclassCombo.GetWindowText(spawnclass); declText = "entityDef " + declName + "\r{\r"; declText += "\"inherit\"\t\t\t\"" + inherit + "\"\r"; declText += "\"spawnclass\"\t\t\t\"" + spawnclass + "\"\r"; for (int i=0; im_propName[0] == '*') { break; } declText += "\"" + pItem->m_propName + "\"\t\t\t\"" + pItem->m_curValue + "\"\r"; } } declText += "}\r"; declText.Replace( "\r", "\r\n" ); declText.Insert( "\r\n\r\n", 0 ); declText.StripTrailing( "\r\n" ); } /* ================ DialogEntityDefEditor::OnBnClickedTest ================ */ void DialogEntityDefEditor::OnBnClickedTest() { idStr declText, oldDeclText; if ( decl ) { BuildDeclText(declText); if ( !TestDecl( declText ) ) { return; } char *oldDeclText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) ); decl->GetText( oldDeclText ); decl->SetText( declText ); decl->Invalidate(); declManager->DeclByIndex( decl->GetType(), decl->Index(), true ); decl->SetText( oldDeclText ); decl->Invalidate(); common->Printf( "tested %s\n", decl->GetName() ); testButton.EnableWindow( FALSE ); } } /* ================ DialogEntityDefEditor::OnBnClickedOk ================ */ void DialogEntityDefEditor::OnBnClickedOk() { if ( decl ) { idStr declText; BuildDeclText(declText); if ( !TestDecl( declText ) ) { return; } if ( decl->SourceFileChanged() ) { if ( MessageBox( va( "Declaration file %s has been modified outside of the editor.\r\nReload declarations and save?", decl->GetFileName() ), va( "Warning saving: %s", decl->GetFileName() ), MB_OKCANCEL | MB_ICONERROR ) != IDOK ) { return; } declManager->Reload( false ); DeclBrowserReloadDeclarations(); } decl->SetText( declText ); if ( !decl->ReplaceSourceFileText() ) { MessageBox( va( "Couldn't save: %s.\r\nMake sure the declaration file is not read-only.", decl->GetFileName() ), va( "Error saving: %s", decl->GetFileName() ), MB_OK | MB_ICONERROR ); return; } decl->Invalidate(); } okButton.EnableWindow( FALSE ); } /* ================ DialogEntityDefEditor::OnBnClickedCancel ================ */ void DialogEntityDefEditor::OnBnClickedCancel() { if ( okButton.IsWindowEnabled() ) { if ( MessageBox( "Cancel changes?", "Cancel", MB_YESNO | MB_ICONQUESTION ) != IDYES ) { return; } } OnCancel(); } /* ================ DialogEntityDefEditor::OnKeyValChange ================ */ void DialogEntityDefEditor::OnKeyValChange() { int sel = keyValsList.GetCurSel(); if (sel >= 0) { CPropertyItem *pItem = (CPropertyItem *)keyValsList.GetItemDataPtr(sel); keyEdit.SetWindowText(pItem->m_propName); } } /* ================ DialogEntityDefEditor::OnBnClickedAdd ================ */ void DialogEntityDefEditor::OnBnClickedAdd() { CString newKey; keyEdit.GetWindowText(newKey); int matchedInherit = -1; int matchedKey = -1; // See if this key already exists for (int i=0; im_propName[0] == '*') { if (newKey = pItem->m_propName.Mid(1)) { matchedInherit = i; } } else if (pItem->m_propName == newKey) { matchedKey = i; break; } } } if (matchedKey >= 0) { MessageBox("Key " + newKey + " already defined"); return; } if (matchedInherit >= 0) { delete keyValsList.GetItemDataPtr(matchedInherit); keyValsList.DeleteString(matchedInherit); } keyValsList.AddPropItem(new CPropertyItem(newKey, "", PIT_EDIT, "")); } /* ================ DialogEntityDefEditor::OnBnClickedDelete ================ */ void DialogEntityDefEditor::OnBnClickedDelete() { CString delKey; keyEdit.GetWindowText(delKey); int matchedInherit = -1; int matchedKey = -1; // See if this key already exists for (int i=0; im_propName[0] == '*') { if (delKey = pItem->m_propName.Mid(1)) { matchedInherit = i; } } else if (pItem->m_propName == delKey) { matchedKey = i; break; } } } if (matchedKey >= 0) { delete keyValsList.GetItemDataPtr(matchedKey); keyValsList.DeleteString(matchedKey); } else if (matchedInherit) { MessageBox("Cannot delete an inherited value"); } }