/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ // PropertyComboBox.cpp : implementation file // #include "stdafx.h" #include "PropertyComboBox.h" #ifdef _DEBUG #undef new #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CPropertyComboBox CPropertyComboBox::CPropertyComboBox() { } CPropertyComboBox::~CPropertyComboBox() { // delete current property list FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itDel) { delete &itDel.Current(); } } void CPropertyComboBox::SetDialogPtr( CPropertyComboBar *pDialog) { m_pDialog = pDialog; DisableCombo(); } BEGIN_MESSAGE_MAP(CPropertyComboBox, CComboBox) //{{AFX_MSG_MAP(CPropertyComboBox) ON_WM_CONTEXTMENU() ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange) ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPropertyComboBox message handlers void CPropertyComboBox::OnContextMenu(CWnd* pWnd, CPoint point) { INDEX i=0; } void CPropertyComboBox::JoinProperties( CEntity *penEntity, BOOL bIntersect) { // if we should add all of this entity's properties (if this is first entity) if( !bIntersect) { // obtain entity class ptr CDLLEntityClass *pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass; // for all classes in hierarchy of this entity for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) { // for all properties for(INDEX iProperty=0; iPropertydec_ctProperties; iProperty++) { CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty]; // don't add properties with no name if( epProperty.ep_strName != CTString("") ) { CAnimData *pAD = NULL; // remember anim data if( epProperty.ep_eptType == CEntityProperty::EPT_ANIMATION) { pAD = penEntity->GetAnimData( epProperty.ep_slOffset); } // create current CPropertyID CPropertyID *pPropertyID = new CPropertyID( epProperty.ep_strName, epProperty.ep_eptType, &epProperty, pAD); // if we should add all of this entity's properties (if this is first entity) // and add it into list m_lhProperties.AddTail( pPropertyID->pid_lnNode); } } } } // in case of intersecting properties we should take one of existing properties in list // and see if investigating entity has property with same descriptive name // If not, remove it that existing property. else { FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itProp) { CTString strCurrentName = itProp->pid_strName; CEntityProperty::PropertyType eptCurrentType = itProp->pid_eptType; // mark that property with same name is not found BOOL bSameFound = FALSE; // obtain entity class ptr CDLLEntityClass *pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass; // for all classes in hierarchy of this entity for(; pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) { // for all properties for(INDEX iProperty=0; iPropertydec_ctProperties; iProperty++) { CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty]; CAnimData *pAD = NULL; // remember anim data if( epProperty.ep_eptType == CEntityProperty::EPT_ANIMATION) { pAD = penEntity->GetAnimData( epProperty.ep_slOffset); } // create current CPropertyID CPropertyID PropertyID = CPropertyID( epProperty.ep_strName, epProperty.ep_eptType, &epProperty, pAD); // is this property same as one we are investigating if( (strCurrentName == PropertyID.pid_strName) && (eptCurrentType == PropertyID.pid_eptType) ) { // if propperty is enum, enum ptr must also be the same if( itProp->pid_eptType == CEntityProperty::EPT_ENUM) { // only then, if( itProp->pid_penpProperty->ep_pepetEnumType == PropertyID.pid_penpProperty->ep_pepetEnumType) { // same property is found bSameFound = TRUE; } else { bSameFound = FALSE; } goto pcb_OutLoop_JoinProperties; } // if propperty is animation, anim data ptr must be the same else if( itProp->pid_eptType == CEntityProperty::EPT_ANIMATION) { if(itProp->pid_padAnimData == PropertyID.pid_padAnimData) { // same property is found bSameFound = TRUE; } else { bSameFound = FALSE; } goto pcb_OutLoop_JoinProperties; } else { // same property is found bSameFound = TRUE; goto pcb_OutLoop_JoinProperties; } } } } pcb_OutLoop_JoinProperties:; // if property with same name is not found if( !bSameFound) { // remove our investigating property from list itProp->pid_lnNode.Remove(); // and delete it delete &itProp.Current(); } } } } BOOL CPropertyComboBox::OnIdle(LONG lCount) { // get active document CWorldEditorDoc* pDoc = theApp.GetActiveDocument(); // if document ptr has changed // or if document was closed (pDoc == NULL and pLastDoc != NULL) // or if mode was changed // or if selection was changed from last OnIdle, refresh properties if( (m_pLastDoc != pDoc) || ((pDoc == NULL) && (m_pLastDoc != NULL)) || ((pDoc != NULL) && (m_iLastMode != pDoc->m_iMode)) || ((pDoc != NULL) && !pDoc->m_chSelections.IsUpToDate( m_udComboEntries)) ) { // refresh selected members message if( (pDoc != NULL)) { pDoc->SetStatusLineModeInfoMessage(); } // remove all combo entries ResetContent(); // if document exists and mode is entities if( (pDoc != NULL) && (pDoc->m_iMode == ENTITY_MODE) ) { // delete current property list FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itDel) { delete &itDel.Current(); } // lock selection's dynamic container pDoc->m_selEntitySelection.Lock(); // for each of the selected entities FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten) { // if this is first entity in dynamic container if( pDoc->m_selEntitySelection.Pointer(0) == iten) { // add all of its properties into joint list but don't intersect with existing ones JoinProperties( iten, FALSE); } else { // intersect entity's properties with existing ones JoinProperties( iten, TRUE); } } // unlock selection's dynamic container pDoc->m_selEntitySelection.Unlock(); if( pDoc->m_selEntitySelection.Count() != 0) { // ----------------- Add spawn flags property CPropertyID *ppidSpawnFlags = new CPropertyID( "Spawn flags (Alt+Shift+S)", CEntityProperty::EPT_SPAWNFLAGS, NULL, NULL); m_lhProperties.AddTail( ppidSpawnFlags->pid_lnNode); // ----------------- Add parent entity property CPropertyID *ppidParent = new CPropertyID( "Parent (Alt+Shift+A)", CEntityProperty::EPT_PARENT, NULL, NULL); m_lhProperties.AddTail( ppidParent->pid_lnNode); } // if there are some intersecting properties if( !m_lhProperties.IsEmpty()) { // add intersecting properties of selected entities into combo box FOREACHINLIST(CPropertyID, pid_lnNode, m_lhProperties, itProp) { char achrShortcutKey[ 64] = ""; if( itProp->pid_chrShortcutKey != 0) { sprintf( achrShortcutKey, " (%c)", itProp->pid_chrShortcutKey); } // add property name and shortcut key INDEX iAddedAs = AddString( CString(itProp->pid_strName + achrShortcutKey)); // set ptr to property ID object SetItemData( iAddedAs, (ULONG) &*itProp); // enable combo EnableWindow(); } } // if there are no properties to choose from else { DisableCombo(); } } // if there are no document or application is not in edit entitiy mode else { DisableCombo(); } // index of property that is selected (trying to keep the same property active) INDEX iSelectedProperty = 0; // for all members in combo box for( INDEX iMembers = 0; iMemberspid_strName == m_strLastPropertyName) { // mark this property as selected by default iSelectedProperty = iMembers; break; } } } // select entity 0 by default SetCurSel( iSelectedProperty); // mark possible document change m_pLastDoc = pDoc; // set new mode if( pDoc != NULL) { m_iLastMode = pDoc->m_iMode; } m_pDialog->ArrangeControls(); // if edit color property is active if( m_pDialog->m_EditColorCtrl.IsWindowVisible()) { // invalidate it so it will be refreshed properly m_pDialog->m_EditColorCtrl.Invalidate( FALSE); } m_udComboEntries.MarkUpdated(); } return TRUE; } void CPropertyComboBox::OnSelchange() { SelectProperty(); } void CPropertyComboBox::SelectProperty(void) { CPropertyID *ppidPropertyID = (CPropertyID *) GetItemData( GetCurSel()); // must be valid property ASSERT( ppidPropertyID != NULL); // remember name of this property as last selected property name m_strLastPropertyName = ppidPropertyID->pid_strName; // show/hide appropriate editing propterty controls m_pDialog->ArrangeControls(); } void CPropertyComboBox::DisableCombo() { // remove all combo entries ResetContent(); // set default message INDEX iAddedAs = AddString( L"None Available"); // set invalid ptr SetItemData( iAddedAs, NULL); // disable combo EnableWindow( FALSE); } void CPropertyComboBox::OnDropdown() { INDEX ctItems = GetCount(); if( ctItems == CB_ERR) return; CRect rectCombo; GetWindowRect( &rectCombo); PIX pixScreenHeight = ::GetSystemMetrics(SM_CYSCREEN); PIX pixMaxHeight = pixScreenHeight - rectCombo.top; m_pDialog->ScreenToClient( &rectCombo); PIX pixNewHeight = GetItemHeight(0)*(ctItems+2); rectCombo.bottom = rectCombo.top + ClampUp( pixNewHeight, pixMaxHeight); MoveWindow( rectCombo); }