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