Serious-Engine/Sources/WorldEditor/PropertyComboBox.cpp

368 lines
12 KiB
C++
Raw Normal View History

2016-03-12 01:20:51 +01:00
/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
2016-03-11 14:57:17 +01:00
// 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; iProperty<pdecDLLClass->dec_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; iProperty<pdecDLLClass->dec_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; iMembers<GetCount(); iMembers++)
{
CPropertyID *ppidPropertyID = (CPropertyID *) GetItemData( iMembers);
// if this is valid property
if( ppidPropertyID != NULL)
{
// if name of this property is same as last selected property name
if( ppidPropertyID->pid_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);
}