//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Implements an autoselection combo box that color codes the text // based on whether the current selection represents a single entity, // multiple entities, or an unresolved entity targetname. // // The fonts are as follows: // // Single entity black, normal weight // Multiple entities black, bold // Unresolved red, normal weight // //=============================================================================// #include "stdafx.h" #include "MapEntity.h" #include "TargetNameCombo.h" #include "hammer.h" #include "mapdoc.h" #include "mapworld.h" // memdbgon must be the last include file in a .cpp file!!! #include #pragma warning( disable : 4355 ) BEGIN_MESSAGE_MAP(CTargetNameComboBox, CFilteredComboBox) //{{AFX_MSG_MAP(CTargetNameComboBox) //}}AFX_MSG_MAP END_MESSAGE_MAP() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTargetNameComboBox::CTargetNameComboBox( CFilteredComboBox::ICallbacks *pPassThru ) : BaseClass( this ) { m_pEntityList = NULL; m_pPassThru = pPassThru; } //----------------------------------------------------------------------------- // Purpose: Frees allocated memory. //----------------------------------------------------------------------------- CTargetNameComboBox::~CTargetNameComboBox(void) { FreeSubLists(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTargetNameComboBox::FreeSubLists(void) { POSITION pos = m_SubLists.GetHeadPosition(); while (pos != NULL) { CMapEntityList *pList = m_SubLists.GetNext(pos); delete pList; } m_SubLists.RemoveAll(); } void CTargetNameComboBox::CreateFonts() { // // Create a normal and bold font. // if (!m_BoldFont.m_hObject) { CFont &nf = GetNormalFont(); if ( nf.m_hObject ) { LOGFONT LogFont; nf.GetLogFont(&LogFont); LogFont.lfWeight = FW_BOLD; m_BoldFont.CreateFontIndirect(&LogFont); } } } CTargetNameComboBox* CTargetNameComboBox::Create( CFilteredComboBox::ICallbacks *pCallbacks, DWORD dwStyle, RECT rect, CWnd *pParentWnd, UINT nID ) { CTargetNameComboBox *pRet = new CTargetNameComboBox( pCallbacks ); pRet->BaseClass::Create( dwStyle, rect, pParentWnd, nID ); return pRet; } //----------------------------------------------------------------------------- // Purpose: Attaches an entity list to the combo box. This list will be used // for matching targetnames to entities in the world. // Input : pEntityList - The beauty of Hungarian notation and meaningful naming // makes this comment utterly unnecessary. //----------------------------------------------------------------------------- void CTargetNameComboBox::SetEntityList(const CMapEntityList *pEntityList) { // We want all notifications, even if the current text doesn't match an exact entity name. SetOnlyProvideSuggestions( false ); // Setup the list. m_pEntityList = pEntityList; FreeSubLists(); m_EntityLists.RemoveAll(); if (m_pEntityList != NULL) { FOR_EACH_OBJ( *m_pEntityList, pos ) { CMapEntity *pEntity = (CUtlReference)m_pEntityList->Element(pos); const char *pszTargetName = pEntity ? pEntity->GetKeyValue("targetname") : NULL; if (pszTargetName != NULL) { // // If the targetname is not in the combo box, add it to the combo as the // first entry in an entity list. The list is necessary because there // may be several entities in the map with the same targetname. // int nIndex = m_EntityLists.Find( pszTargetName ); if (nIndex == m_EntityLists.InvalidIndex()) { CMapEntityList *pList = new CMapEntityList; pList->AddToTail( pEntity ); m_EntityLists.Insert( pszTargetName, pList ); // // Keep track of all the sub lists so we can delete them later. // m_SubLists.AddTail(pList); } // // Else append the entity to the given targetname's list. // else { CMapEntityList *pList = m_EntityLists[nIndex]; pList->AddToTail(pEntity); } } } } // Setup the suggestions. CUtlVector suggestions; for ( int i=m_EntityLists.First(); i != m_EntityLists.InvalidIndex(); i=m_EntityLists.Next( i ) ) { suggestions.AddToTail( m_EntityLists.GetElementName( i ) ); } SetSuggestions( suggestions ); } CMapEntityList* CTargetNameComboBox::GetSubEntityList( const char *pName ) { int testIndex = m_EntityLists.Find( pName ); if ( testIndex != m_EntityLists.InvalidIndex() ) { return m_EntityLists[testIndex]; } return NULL; } void CTargetNameComboBox::OnTextChanged( const char *pText ) { // Make sure our fonts are created. CreateFonts(); // Update the fonts. int nCount = 0; CMapEntityList *pList = GetSubEntityList( pText ); if ( pList ) nCount = pList->Count(); // Figure out the font and color that we want. CFont *pWantedFont = &m_BoldFont; if ( (nCount == 0) || (nCount == 1) ) pWantedFont = &GetNormalFont(); COLORREF clrWanted = RGB(255,0,0); if ( nCount > 0 ) { clrWanted = RGB(0,0,0); } else { POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition(); while( pos != NULL ) { CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos ); CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc ); if ( pMapDoc ) { if ( pMapDoc->GetMapWorld()->FindEntityByName( pText ) != NULL ) { clrWanted = RGB( 0, 192, 192 ); break; } } } } SetEditControlFont( *pWantedFont ); SetEditControlTextColor( clrWanted ); // Pass it through to the owner if they want notification. if ( m_pPassThru ) m_pPassThru->OnTextChanged( pText ); }