PropertyList.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "qe3.h"
  23. #include "Radiant.h"
  24. #include "PropertyList.h"
  25. #include "../comafx/DialogColorPicker.h"
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CPropertyList
  33. CPropertyList::CPropertyList() {
  34. measureItem = NULL;
  35. updateInspectors = false;
  36. }
  37. CPropertyList::~CPropertyList() {
  38. }
  39. BEGIN_MESSAGE_MAP(CPropertyList, CListBox)
  40. //{{AFX_MSG_MAP(CPropertyList)
  41. ON_WM_CREATE()
  42. ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelchange)
  43. ON_WM_LBUTTONUP()
  44. ON_WM_KILLFOCUS()
  45. ON_WM_LBUTTONDOWN()
  46. ON_WM_MOUSEMOVE()
  47. //}}AFX_MSG_MAP
  48. ON_CBN_CLOSEUP(IDC_PROPCMBBOX, OnKillfocusCmbBox)
  49. ON_CBN_SELCHANGE(IDC_PROPCMBBOX, OnSelchangeCmbBox)
  50. ON_EN_KILLFOCUS(IDC_PROPEDITBOX, OnKillfocusEditBox)
  51. ON_EN_CHANGE(IDC_PROPEDITBOX, OnChangeEditBox)
  52. ON_BN_CLICKED(IDC_PROPBTNCTRL, OnButton)
  53. END_MESSAGE_MAP()
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CPropertyList message handlers
  56. BOOL CPropertyList::PreCreateWindow(CREATESTRUCT& cs) {
  57. if (!CListBox::PreCreateWindow(cs)) {
  58. return FALSE;
  59. }
  60. cs.style &= ~(LBS_OWNERDRAWVARIABLE | LBS_SORT);
  61. cs.style |= LBS_OWNERDRAWFIXED;
  62. m_bTracking = FALSE;
  63. m_nDivider = 0;
  64. m_bDivIsSet = FALSE;
  65. return TRUE;
  66. }
  67. void CPropertyList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) {
  68. if (measureItem && !measureItem->m_curValue.IsEmpty()) {
  69. CRect rect;
  70. GetClientRect(rect);
  71. if (m_nDivider==0) {
  72. m_nDivider = rect.Width() / 2;
  73. }
  74. rect.left = m_nDivider;
  75. CDC * dc = GetDC();
  76. dc->DrawText(measureItem->m_curValue, rect, DT_CALCRECT | DT_LEFT | DT_WORDBREAK);
  77. ReleaseDC(dc);
  78. lpMeasureItemStruct->itemHeight = (rect.Height() >= 20) ? rect.Height() : 20; //pixels
  79. } else {
  80. lpMeasureItemStruct->itemHeight = 20; //pixels
  81. }
  82. }
  83. void CPropertyList::DrawItem(LPDRAWITEMSTRUCT lpDIS) {
  84. CDC dc;
  85. dc.Attach(lpDIS->hDC);
  86. CRect rectFull = lpDIS->rcItem;
  87. CRect rect = rectFull;
  88. if (m_nDivider==0) {
  89. m_nDivider = rect.Width() / 2;
  90. }
  91. rect.left = m_nDivider;
  92. CRect rect2 = rectFull;
  93. rect2.right = rect.left - 1;
  94. UINT nIndex = lpDIS->itemID;
  95. if (nIndex != (UINT) -1) {
  96. //get the CPropertyItem for the current row
  97. CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(nIndex);
  98. //draw two rectangles, one for each row column
  99. if (pItem->m_nItemType == PIT_VAR) {
  100. dc.FillSolidRect(rect2,RGB(220,220,220));
  101. } else {
  102. dc.FillSolidRect(rect2,RGB(192,192,192));
  103. }
  104. dc.DrawEdge(rect2,EDGE_SUNKEN,BF_BOTTOMRIGHT);
  105. dc.DrawEdge(rect,EDGE_SUNKEN,BF_BOTTOM);
  106. if (lpDIS->itemState == ODS_SELECTED) {
  107. dc.DrawFocusRect(rect2);
  108. }
  109. //write the property name in the first rectangle
  110. dc.SetBkMode(TRANSPARENT);
  111. dc.DrawText(pItem->m_propName,CRect(rect2.left+3,rect2.top+3,
  112. rect2.right-3,rect2.bottom+3),
  113. DT_LEFT | DT_SINGLELINE);
  114. //write the initial property value in the second rectangle
  115. dc.DrawText(pItem->m_curValue,CRect(rect.left+3,rect.top+3, rect.right+3,rect.bottom+3), DT_LEFT | (pItem->m_nItemType == PIT_VAR) ? DT_WORDBREAK : DT_SINGLELINE);
  116. }
  117. dc.Detach();
  118. }
  119. int CPropertyList::AddItem(CString txt) {
  120. measureItem = NULL;
  121. int nIndex = AddString(txt);
  122. return nIndex;
  123. }
  124. int CPropertyList::AddPropItem(CPropertyItem* pItem) {
  125. if (pItem->m_nItemType == PIT_VAR) {
  126. measureItem = pItem;
  127. } else {
  128. measureItem = NULL;
  129. }
  130. int nIndex = AddString(_T(""));
  131. measureItem = NULL;
  132. SetItemDataPtr(nIndex,pItem);
  133. return nIndex;
  134. }
  135. int CPropertyList::OnCreate(LPCREATESTRUCT lpCreateStruct) {
  136. if (CListBox::OnCreate(lpCreateStruct) == -1) {
  137. return -1;
  138. }
  139. m_bDivIsSet = FALSE;
  140. m_nDivider = 0;
  141. m_bTracking = FALSE;
  142. m_hCursorSize = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
  143. m_hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  144. m_SSerif8Font.CreatePointFont(80,_T("MS Sans Serif"));
  145. return 0;
  146. }
  147. void CPropertyList::OnSelchange() {
  148. CRect rect;
  149. CString lBoxSelText;
  150. static int recurse = 0;
  151. //m_curSel = GetCurSel();
  152. GetItemRect(m_curSel,rect);
  153. rect.left = m_nDivider;
  154. CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
  155. if (updateInspectors) {
  156. g_Inspectors->entityDlg.SetKeyVal(pItem->m_propName, pItem->m_curValue);
  157. }
  158. if (m_btnCtrl) {
  159. m_btnCtrl.ShowWindow(SW_HIDE);
  160. }
  161. if (pItem->m_nItemType==PIT_COMBO) {
  162. //display the combo box. If the combo box has already been
  163. //created then simply move it to the new location, else create it
  164. m_nLastBox = 0;
  165. if (m_cmbBox) {
  166. m_cmbBox.MoveWindow(rect);
  167. } else {
  168. rect.bottom += 300;
  169. m_cmbBox.Create(CBS_DROPDOWNLIST | WS_VSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER,rect,this,IDC_PROPCMBBOX);
  170. m_cmbBox.SetFont(&m_SSerif8Font);
  171. }
  172. //add the choices for this particular property
  173. CString cmbItems = pItem->m_cmbItems;
  174. lBoxSelText = pItem->m_curValue;
  175. m_cmbBox.ResetContent();
  176. m_cmbBox.AddString("");
  177. int i,i2;
  178. i=0;
  179. while ((i2=cmbItems.Find('|',i)) != -1) {
  180. m_cmbBox.AddString(cmbItems.Mid(i,i2-i));
  181. i=i2+1;
  182. }
  183. m_cmbBox.ShowWindow(SW_SHOW);
  184. //m_cmbBox.SetFocus();
  185. //jump to the property's current value in the combo box
  186. int j = m_cmbBox.FindStringExact(0,lBoxSelText);
  187. if (j != CB_ERR) {
  188. m_cmbBox.SetCurSel(j);
  189. } else {
  190. m_cmbBox.SetCurSel(0);
  191. }
  192. //m_cmbBox.ShowDropDown();
  193. }
  194. else if (pItem->m_nItemType==PIT_EDIT) {
  195. //display edit box
  196. m_nLastBox = 1;
  197. m_prevSel = m_curSel;
  198. rect.bottom -= 3;
  199. if (m_editBox) {
  200. m_editBox.MoveWindow(rect);
  201. } else {
  202. m_editBox.Create(ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER,rect,this,IDC_PROPEDITBOX);
  203. m_editBox.SetFont(&m_SSerif8Font);
  204. }
  205. lBoxSelText = pItem->m_curValue;
  206. m_editBox.ShowWindow(SW_SHOW);
  207. m_editBox.SetFocus();
  208. //set the text in the edit box to the property's current value
  209. bool b = updateInspectors;
  210. updateInspectors = false;
  211. m_editBox.SetWindowText(lBoxSelText);
  212. updateInspectors = b;
  213. } else if (pItem->m_nItemType != PIT_VAR) {
  214. DisplayButton(rect);
  215. }
  216. }
  217. void CPropertyList::DisplayButton(CRect region) {
  218. //displays a button if the property is a file/color/font chooser
  219. m_nLastBox = 2;
  220. m_prevSel = m_curSel;
  221. if (region.Width() > 25) {
  222. region.left = region.right - 25;
  223. }
  224. region.bottom -= 3;
  225. if (m_btnCtrl) {
  226. m_btnCtrl.MoveWindow(region);
  227. } else {
  228. m_btnCtrl.Create("...",BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,region,this,IDC_PROPBTNCTRL);
  229. m_btnCtrl.SetFont(&m_SSerif8Font);
  230. }
  231. m_btnCtrl.ShowWindow(SW_SHOW);
  232. m_btnCtrl.SetFocus();
  233. }
  234. void CPropertyList::ResetContent() {
  235. if (m_btnCtrl.GetSafeHwnd()) {
  236. m_btnCtrl.ShowWindow(SW_HIDE);
  237. }
  238. int c = this->GetCount();
  239. for (int i = 0; i < c; i++) {
  240. CPropertyItem *pi = reinterpret_cast<CPropertyItem*>(GetItemDataPtr(i));
  241. if (pi) {
  242. delete pi;
  243. }
  244. }
  245. CListBox::ResetContent();
  246. }
  247. void CPropertyList::OnKillFocus(CWnd* pNewWnd) {
  248. //m_btnCtrl.ShowWindow(SW_HIDE);
  249. CListBox::OnKillFocus(pNewWnd);
  250. }
  251. void CPropertyList::OnKillfocusCmbBox() {
  252. m_cmbBox.ShowWindow(SW_HIDE);
  253. Invalidate();
  254. }
  255. void CPropertyList::OnKillfocusEditBox() {
  256. CString newStr;
  257. m_editBox.ShowWindow(SW_HIDE);
  258. Invalidate();
  259. }
  260. void CPropertyList::OnSelchangeCmbBox() {
  261. CString selStr;
  262. if (m_cmbBox) {
  263. m_cmbBox.GetLBText(m_cmbBox.GetCurSel(),selStr);
  264. CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
  265. pItem->m_curValue = selStr;
  266. if (updateInspectors) {
  267. g_Inspectors->entityDlg.UpdateFromListBox();
  268. }
  269. }
  270. }
  271. void CPropertyList::OnChangeEditBox() {
  272. CString newStr;
  273. m_editBox.GetWindowText(newStr);
  274. CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
  275. pItem->m_curValue = newStr;
  276. }
  277. void CPropertyList::OnButton() {
  278. CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
  279. //display the appropriate common dialog depending on what type
  280. //of chooser is associated with the property
  281. if (pItem->m_nItemType == PIT_COLOR) {
  282. idVec3 color;
  283. sscanf(pItem->m_curValue, "%f %f %f", &color.x, &color.y, &color.z);
  284. COLORREF cr = (int)(color.x * 255) + (((int)(color.y * 255))<<8) + (((int)(color.z * 255))<<16);
  285. CDialogColorPicker dlg(cr);
  286. dlg.UpdateParent = UpdateRadiantColor;
  287. if (dlg.DoModal() == IDOK) {
  288. color.x = (dlg.GetColor() & 255)/255.0;
  289. color.y = ((dlg.GetColor() >> 8)&255)/255.0;
  290. color.z = ((dlg.GetColor() >> 16)&255)/255.0;
  291. pItem->m_curValue = color.ToString(4);
  292. }
  293. if (updateInspectors) {
  294. g_Inspectors->entityDlg.UpdateFromListBox();
  295. }
  296. m_btnCtrl.ShowWindow(SW_HIDE);
  297. Invalidate();
  298. } else if (pItem->m_nItemType == PIT_FILE) {
  299. CString SelectedFile;
  300. CString Filter("Gif Files (*.gif)|*.gif||");
  301. CFileDialog FileDlg(TRUE, NULL, NULL, NULL, Filter);
  302. CString currPath = pItem->m_curValue;
  303. FileDlg.m_ofn.lpstrTitle = "Select file";
  304. if (currPath.GetLength() > 0) {
  305. FileDlg.m_ofn.lpstrInitialDir = currPath.Left(currPath.GetLength() - currPath.ReverseFind('\\'));
  306. }
  307. if(IDOK == FileDlg.DoModal()) {
  308. SelectedFile = FileDlg.GetPathName();
  309. m_btnCtrl.ShowWindow(SW_HIDE);
  310. pItem->m_curValue = SelectedFile;
  311. Invalidate();
  312. }
  313. } else if (pItem->m_nItemType == PIT_FONT) {
  314. CFontDialog FontDlg(NULL,CF_EFFECTS | CF_SCREENFONTS,NULL,this);
  315. if(IDOK == FontDlg.DoModal()) {
  316. CString faceName = FontDlg.GetFaceName();
  317. m_btnCtrl.ShowWindow(SW_HIDE);
  318. pItem->m_curValue = faceName;
  319. Invalidate();
  320. }
  321. } else if (pItem->m_nItemType == PIT_MODEL) {
  322. CPreviewDlg *dlg = CEntityDlg::ShowModelChooser();
  323. if (dlg->returnCode == IDOK) {
  324. pItem->m_curValue = dlg->mediaName;
  325. m_btnCtrl.ShowWindow(SW_HIDE);
  326. if (updateInspectors) {
  327. g_Inspectors->entityDlg.UpdateFromListBox();
  328. }
  329. Invalidate();
  330. }
  331. } else if (pItem->m_nItemType == PIT_GUI) {
  332. CPreviewDlg *dlg = CEntityDlg::ShowGuiChooser();
  333. if (dlg->returnCode == IDOK) {
  334. pItem->m_curValue = dlg->mediaName;
  335. m_btnCtrl.ShowWindow(SW_HIDE);
  336. if (updateInspectors) {
  337. g_Inspectors->entityDlg.UpdateFromListBox();
  338. }
  339. Invalidate();
  340. }
  341. } else if (pItem->m_nItemType == PIT_MATERIAL) {
  342. CPreviewDlg *dlg = CEntityDlg::ShowMaterialChooser();
  343. if (dlg->returnCode == IDOK) {
  344. pItem->m_curValue = dlg->mediaName;
  345. m_btnCtrl.ShowWindow(SW_HIDE);
  346. if (updateInspectors) {
  347. g_Inspectors->entityDlg.UpdateFromListBox();
  348. }
  349. Invalidate();
  350. }
  351. }
  352. }
  353. void CPropertyList::OnLButtonUp(UINT nFlags, CPoint point) {
  354. if (m_bTracking) {
  355. //if columns were being resized then this indicates
  356. //that mouse is up so resizing is done. Need to redraw
  357. //columns to reflect their new widths.
  358. m_bTracking = FALSE;
  359. //if mouse was captured then release it
  360. if (GetCapture()==this) {
  361. ::ReleaseCapture();
  362. }
  363. ::ClipCursor(NULL);
  364. CClientDC dc(this);
  365. InvertLine(&dc,CPoint(point.x,m_nDivTop),CPoint(point.x,m_nDivBtm));
  366. //set the divider position to the new value
  367. m_nDivider = point.x;
  368. //redraw
  369. Invalidate();
  370. } else {
  371. BOOL loc;
  372. int i = ItemFromPoint(point,loc);
  373. m_curSel = i;
  374. CListBox::OnLButtonUp(nFlags, point);
  375. }
  376. }
  377. void CPropertyList::OnLButtonDown(UINT nFlags, CPoint point) {
  378. if ((point.x>=m_nDivider-5) && (point.x<=m_nDivider+5)) {
  379. //if mouse clicked on divider line, then start resizing
  380. ::SetCursor(m_hCursorSize);
  381. CRect windowRect;
  382. GetWindowRect(windowRect);
  383. windowRect.left += 10; windowRect.right -= 10;
  384. //do not let mouse leave the list box boundary
  385. ::ClipCursor(windowRect);
  386. if (m_cmbBox) {
  387. m_cmbBox.ShowWindow(SW_HIDE);
  388. }
  389. if (m_editBox) {
  390. m_editBox.ShowWindow(SW_HIDE);
  391. }
  392. CRect clientRect;
  393. GetClientRect(clientRect);
  394. m_bTracking = TRUE;
  395. m_nDivTop = clientRect.top;
  396. m_nDivBtm = clientRect.bottom;
  397. m_nOldDivX = point.x;
  398. CClientDC dc(this);
  399. InvertLine(&dc,CPoint(m_nOldDivX,m_nDivTop),CPoint(m_nOldDivX,m_nDivBtm));
  400. //capture the mouse
  401. SetCapture();
  402. } else {
  403. m_bTracking = FALSE;
  404. CListBox::OnLButtonDown(nFlags, point);
  405. }
  406. }
  407. void CPropertyList::OnMouseMove(UINT nFlags, CPoint point) {
  408. if (m_bTracking) {
  409. //move divider line to the mouse pos. if columns are
  410. //currently being resized
  411. CClientDC dc(this);
  412. //remove old divider line
  413. InvertLine(&dc,CPoint(m_nOldDivX,m_nDivTop),CPoint(m_nOldDivX,m_nDivBtm));
  414. //draw new divider line
  415. InvertLine(&dc,CPoint(point.x,m_nDivTop),CPoint(point.x,m_nDivBtm));
  416. m_nOldDivX = point.x;
  417. } else if ((point.x >= m_nDivider-5) && (point.x <= m_nDivider+5)) {
  418. //set the cursor to a sizing cursor if the cursor is over the row divider
  419. ::SetCursor(m_hCursorSize);
  420. } else {
  421. CListBox::OnMouseMove(nFlags, point);
  422. }
  423. }
  424. void CPropertyList::InvertLine(CDC* pDC,CPoint ptFrom,CPoint ptTo) {
  425. int nOldMode = pDC->SetROP2(R2_NOT);
  426. pDC->MoveTo(ptFrom);
  427. pDC->LineTo(ptTo);
  428. pDC->SetROP2(nOldMode);
  429. }
  430. void CPropertyList::PreSubclassWindow() {
  431. m_bDivIsSet = FALSE;
  432. m_nDivider = 0;
  433. m_bTracking = FALSE;
  434. m_curSel = 1;
  435. m_hCursorSize = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
  436. m_hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  437. m_SSerif8Font.CreatePointFont(80,_T("MS Sans Serif"));
  438. }
  439. void CPropertyList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {
  440. if (m_cmbBox) {
  441. m_cmbBox.ShowWindow(SW_HIDE);
  442. }
  443. if (m_editBox) {
  444. m_editBox.ShowWindow(SW_HIDE);
  445. }
  446. if (m_btnCtrl) {
  447. m_btnCtrl.ShowWindow(SW_HIDE);
  448. }
  449. Invalidate();
  450. CListBox::OnVScroll(nSBCode, nPos, pScrollBar);
  451. }