PropertyComboBox.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. // PropertyComboBox.cpp : implementation file
  13. //
  14. #include "stdafx.h"
  15. #include "PropertyComboBox.h"
  16. #ifdef _DEBUG
  17. #undef new
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CPropertyComboBox
  24. CPropertyComboBox::CPropertyComboBox()
  25. {
  26. }
  27. CPropertyComboBox::~CPropertyComboBox()
  28. {
  29. // delete current property list
  30. FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itDel)
  31. {
  32. delete &itDel.Current();
  33. }
  34. }
  35. void CPropertyComboBox::SetDialogPtr( CPropertyComboBar *pDialog)
  36. {
  37. m_pDialog = pDialog;
  38. DisableCombo();
  39. }
  40. BEGIN_MESSAGE_MAP(CPropertyComboBox, CComboBox)
  41. //{{AFX_MSG_MAP(CPropertyComboBox)
  42. ON_WM_CONTEXTMENU()
  43. ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange)
  44. ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)
  45. //}}AFX_MSG_MAP
  46. END_MESSAGE_MAP()
  47. /////////////////////////////////////////////////////////////////////////////
  48. // CPropertyComboBox message handlers
  49. void CPropertyComboBox::OnContextMenu(CWnd* pWnd, CPoint point)
  50. {
  51. INDEX i=0;
  52. }
  53. void CPropertyComboBox::JoinProperties( CEntity *penEntity, BOOL bIntersect)
  54. {
  55. // if we should add all of this entity's properties (if this is first entity)
  56. if( !bIntersect)
  57. {
  58. // obtain entity class ptr
  59. CDLLEntityClass *pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass;
  60. // for all classes in hierarchy of this entity
  61. for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
  62. {
  63. // for all properties
  64. for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
  65. {
  66. CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
  67. // don't add properties with no name
  68. if( epProperty.ep_strName != CTString("") )
  69. {
  70. CAnimData *pAD = NULL;
  71. // remember anim data
  72. if( epProperty.ep_eptType == CEntityProperty::EPT_ANIMATION)
  73. {
  74. pAD = penEntity->GetAnimData( epProperty.ep_slOffset);
  75. }
  76. // create current CPropertyID
  77. CPropertyID *pPropertyID = new CPropertyID( epProperty.ep_strName,
  78. epProperty.ep_eptType, &epProperty, pAD);
  79. // if we should add all of this entity's properties (if this is first entity)
  80. // and add it into list
  81. m_lhProperties.AddTail( pPropertyID->pid_lnNode);
  82. }
  83. }
  84. }
  85. }
  86. // in case of intersecting properties we should take one of existing properties in list
  87. // and see if investigating entity has property with same descriptive name
  88. // If not, remove it that existing property.
  89. else
  90. {
  91. FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itProp)
  92. {
  93. CTString strCurrentName = itProp->pid_strName;
  94. CEntityProperty::PropertyType eptCurrentType = itProp->pid_eptType;
  95. // mark that property with same name is not found
  96. BOOL bSameFound = FALSE;
  97. // obtain entity class ptr
  98. CDLLEntityClass *pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass;
  99. // for all classes in hierarchy of this entity
  100. for(; pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
  101. {
  102. // for all properties
  103. for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
  104. {
  105. CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
  106. CAnimData *pAD = NULL;
  107. // remember anim data
  108. if( epProperty.ep_eptType == CEntityProperty::EPT_ANIMATION)
  109. {
  110. pAD = penEntity->GetAnimData( epProperty.ep_slOffset);
  111. }
  112. // create current CPropertyID
  113. CPropertyID PropertyID = CPropertyID( epProperty.ep_strName, epProperty.ep_eptType,
  114. &epProperty, pAD);
  115. // is this property same as one we are investigating
  116. if( (strCurrentName == PropertyID.pid_strName) &&
  117. (eptCurrentType == PropertyID.pid_eptType) )
  118. {
  119. // if propperty is enum, enum ptr must also be the same
  120. if( itProp->pid_eptType == CEntityProperty::EPT_ENUM)
  121. {
  122. // only then,
  123. if( itProp->pid_penpProperty->ep_pepetEnumType ==
  124. PropertyID.pid_penpProperty->ep_pepetEnumType)
  125. {
  126. // same property is found
  127. bSameFound = TRUE;
  128. }
  129. else
  130. {
  131. bSameFound = FALSE;
  132. }
  133. goto pcb_OutLoop_JoinProperties;
  134. }
  135. // if propperty is animation, anim data ptr must be the same
  136. else if( itProp->pid_eptType == CEntityProperty::EPT_ANIMATION)
  137. {
  138. if(itProp->pid_padAnimData == PropertyID.pid_padAnimData)
  139. {
  140. // same property is found
  141. bSameFound = TRUE;
  142. }
  143. else
  144. {
  145. bSameFound = FALSE;
  146. }
  147. goto pcb_OutLoop_JoinProperties;
  148. }
  149. else
  150. {
  151. // same property is found
  152. bSameFound = TRUE;
  153. goto pcb_OutLoop_JoinProperties;
  154. }
  155. }
  156. }
  157. }
  158. pcb_OutLoop_JoinProperties:;
  159. // if property with same name is not found
  160. if( !bSameFound)
  161. {
  162. // remove our investigating property from list
  163. itProp->pid_lnNode.Remove();
  164. // and delete it
  165. delete &itProp.Current();
  166. }
  167. }
  168. }
  169. }
  170. BOOL CPropertyComboBox::OnIdle(LONG lCount)
  171. {
  172. // get active document
  173. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  174. // if document ptr has changed
  175. // or if document was closed (pDoc == NULL and pLastDoc != NULL)
  176. // or if mode was changed
  177. // or if selection was changed from last OnIdle, refresh properties
  178. if( (m_pLastDoc != pDoc) ||
  179. ((pDoc == NULL) && (m_pLastDoc != NULL)) ||
  180. ((pDoc != NULL) && (m_iLastMode != pDoc->m_iMode)) ||
  181. ((pDoc != NULL) && !pDoc->m_chSelections.IsUpToDate( m_udComboEntries)) )
  182. {
  183. // refresh selected members message
  184. if( (pDoc != NULL))
  185. {
  186. pDoc->SetStatusLineModeInfoMessage();
  187. }
  188. // remove all combo entries
  189. ResetContent();
  190. // if document exists and mode is entities
  191. if( (pDoc != NULL) && (pDoc->m_iMode == ENTITY_MODE) )
  192. {
  193. // delete current property list
  194. FORDELETELIST(CPropertyID, pid_lnNode, m_lhProperties, itDel)
  195. {
  196. delete &itDel.Current();
  197. }
  198. // lock selection's dynamic container
  199. pDoc->m_selEntitySelection.Lock();
  200. // for each of the selected entities
  201. FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
  202. {
  203. // if this is first entity in dynamic container
  204. if( pDoc->m_selEntitySelection.Pointer(0) == iten)
  205. {
  206. // add all of its properties into joint list but don't intersect with existing ones
  207. JoinProperties( iten, FALSE);
  208. }
  209. else
  210. {
  211. // intersect entity's properties with existing ones
  212. JoinProperties( iten, TRUE);
  213. }
  214. }
  215. // unlock selection's dynamic container
  216. pDoc->m_selEntitySelection.Unlock();
  217. if( pDoc->m_selEntitySelection.Count() != 0)
  218. {
  219. // ----------------- Add spawn flags property
  220. CPropertyID *ppidSpawnFlags = new CPropertyID( "Spawn flags (Alt+Shift+S)",
  221. CEntityProperty::EPT_SPAWNFLAGS, NULL, NULL);
  222. m_lhProperties.AddTail( ppidSpawnFlags->pid_lnNode);
  223. // ----------------- Add parent entity property
  224. CPropertyID *ppidParent = new CPropertyID( "Parent (Alt+Shift+A)",
  225. CEntityProperty::EPT_PARENT, NULL, NULL);
  226. m_lhProperties.AddTail( ppidParent->pid_lnNode);
  227. }
  228. // if there are some intersecting properties
  229. if( !m_lhProperties.IsEmpty())
  230. {
  231. // add intersecting properties of selected entities into combo box
  232. FOREACHINLIST(CPropertyID, pid_lnNode, m_lhProperties, itProp)
  233. {
  234. char achrShortcutKey[ 64] = "";
  235. if( itProp->pid_chrShortcutKey != 0)
  236. {
  237. sprintf( achrShortcutKey, " (%c)", itProp->pid_chrShortcutKey);
  238. }
  239. // add property name and shortcut key
  240. INDEX iAddedAs = AddString( CString(itProp->pid_strName + achrShortcutKey));
  241. // set ptr to property ID object
  242. SetItemData( iAddedAs, (ULONG) &*itProp);
  243. // enable combo
  244. EnableWindow();
  245. }
  246. }
  247. // if there are no properties to choose from
  248. else
  249. {
  250. DisableCombo();
  251. }
  252. }
  253. // if there are no document or application is not in edit entitiy mode
  254. else
  255. {
  256. DisableCombo();
  257. }
  258. // index of property that is selected (trying to keep the same property active)
  259. INDEX iSelectedProperty = 0;
  260. // for all members in combo box
  261. for( INDEX iMembers = 0; iMembers<GetCount(); iMembers++)
  262. {
  263. CPropertyID *ppidPropertyID = (CPropertyID *) GetItemData( iMembers);
  264. // if this is valid property
  265. if( ppidPropertyID != NULL)
  266. {
  267. // if name of this property is same as last selected property name
  268. if( ppidPropertyID->pid_strName == m_strLastPropertyName)
  269. {
  270. // mark this property as selected by default
  271. iSelectedProperty = iMembers;
  272. break;
  273. }
  274. }
  275. }
  276. // select entity 0 by default
  277. SetCurSel( iSelectedProperty);
  278. // mark possible document change
  279. m_pLastDoc = pDoc;
  280. // set new mode
  281. if( pDoc != NULL)
  282. {
  283. m_iLastMode = pDoc->m_iMode;
  284. }
  285. m_pDialog->ArrangeControls();
  286. // if edit color property is active
  287. if( m_pDialog->m_EditColorCtrl.IsWindowVisible())
  288. {
  289. // invalidate it so it will be refreshed properly
  290. m_pDialog->m_EditColorCtrl.Invalidate( FALSE);
  291. }
  292. m_udComboEntries.MarkUpdated();
  293. }
  294. return TRUE;
  295. }
  296. void CPropertyComboBox::OnSelchange()
  297. {
  298. SelectProperty();
  299. }
  300. void CPropertyComboBox::SelectProperty(void)
  301. {
  302. CPropertyID *ppidPropertyID = (CPropertyID *) GetItemData( GetCurSel());
  303. // must be valid property
  304. ASSERT( ppidPropertyID != NULL);
  305. // remember name of this property as last selected property name
  306. m_strLastPropertyName = ppidPropertyID->pid_strName;
  307. // show/hide appropriate editing propterty controls
  308. m_pDialog->ArrangeControls();
  309. }
  310. void CPropertyComboBox::DisableCombo()
  311. {
  312. // remove all combo entries
  313. ResetContent();
  314. // set default message
  315. INDEX iAddedAs = AddString( L"None Available");
  316. // set invalid ptr
  317. SetItemData( iAddedAs, NULL);
  318. // disable combo
  319. EnableWindow( FALSE);
  320. }
  321. void CPropertyComboBox::OnDropdown()
  322. {
  323. INDEX ctItems = GetCount();
  324. if( ctItems == CB_ERR) return;
  325. CRect rectCombo;
  326. GetWindowRect( &rectCombo);
  327. PIX pixScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
  328. PIX pixMaxHeight = pixScreenHeight - rectCombo.top;
  329. m_pDialog->ScreenToClient( &rectCombo);
  330. PIX pixNewHeight = GetItemHeight(0)*(ctItems+2);
  331. rectCombo.bottom = rectCombo.top + ClampUp( pixNewHeight, pixMaxHeight);
  332. MoveWindow( rectCombo);
  333. }