]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/common/PropTree/PropTreeItem.cpp
hello world
[icculus/iodoom3.git] / neo / tools / common / PropTree / PropTreeItem.cpp
1 // PropTreeItem.cpp
2 //
3 //  Copyright (C) 1998-2001 Scott Ramsay
4 //      sramsay@gonavi.com
5 //      http://www.gonavi.com
6 //
7 //  This material is provided "as is", with absolutely no warranty expressed
8 //  or implied. Any use is at your own risk.
9 // 
10 //  Permission to use or copy this software for any purpose is hereby granted 
11 //  without fee, provided the above notices are retained on all copies.
12 //  Permission to modify the code and to distribute modified code is granted,
13 //  provided the above notices are retained, and a notice that the code was
14 //  modified is included with the above copyright notice.
15 // 
16 //      If you use this code, drop me an email.  I'd like to know if you find the code
17 //      useful.
18
19 //#include "stdafx.h"
20 #include "../../../idlib/precompiled.h"
21 #pragma hdrstop
22
23 #include "PropTree.h"
24
25 #include "PropTreeItem.h"
26
27 #define PROPTREEITEM_DEFHEIGHT                  21                      // default heigt of an item
28 #define PROPTREEITEM_SPACE                              5                       // default horz spacing
29 #define PROPTREEITEM_EXPANDBOX                  9                       // size of the expand box
30 #define PROPTREEITEM_CHECKBOX                   14                      // size of the check box
31 #define PROPTREEITEM_EXPANDCOLUMN               16                      // width of the expand column
32 #define PNINDENT                                                16                      // child level indent
33
34 #define PROPTREEITEM_EXPANDBOXHALF              (PROPTREEITEM_EXPANDBOX/2)
35
36
37 /////////////////////////////////////////////////////////////////////////////
38 // drawing helper functions
39 //
40
41 // draw a dotted horizontal line
42 static void _DotHLine(HDC hdc, LONG x, LONG y, LONG w)
43 {
44         for (; w>0; w-=2, x+=2)
45                 SetPixel(hdc, x, y, GetSysColor(COLOR_BTNSHADOW));
46 }
47
48
49 // draw the plus/minus button
50 static void _DrawExpand(HDC hdc, LONG x, LONG y, BOOL bExpand, BOOL bFill)
51 {
52         HPEN hPen;
53         HPEN oPen;
54         HBRUSH oBrush;
55
56         hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
57         oPen = (HPEN)SelectObject(hdc, hPen);
58         oBrush = (HBRUSH)SelectObject(hdc, GetStockObject(bFill ? WHITE_BRUSH : NULL_BRUSH));
59
60         Rectangle(hdc, x, y, x + PROPTREEITEM_EXPANDBOX, y + PROPTREEITEM_EXPANDBOX);
61         SelectObject(hdc, GetStockObject(BLACK_PEN));
62
63         if (!bExpand)
64         {
65                 MoveToEx(hdc, x + PROPTREEITEM_EXPANDBOXHALF, y + 2, NULL);
66                 LineTo(hdc, x + PROPTREEITEM_EXPANDBOXHALF, y + PROPTREEITEM_EXPANDBOX - 2);
67         }
68
69         MoveToEx(hdc, x + 2, y + PROPTREEITEM_EXPANDBOXHALF, NULL);
70         LineTo(hdc, x + PROPTREEITEM_EXPANDBOX - 2, y + PROPTREEITEM_EXPANDBOXHALF);
71
72         SelectObject(hdc, oPen);
73         SelectObject(hdc, oBrush);
74         DeleteObject(hPen);
75 }
76
77 /////////////////////////////////////////////////////////////////////////////
78 // CPropTreeItem
79 //
80
81 CPropTreeItem::CPropTreeItem() :
82         m_pProp(NULL),
83         m_sLabel(_T("")),
84         m_sInfo(_T("")),
85         m_loc(0,0),
86         m_rc(0,0,0,0),
87         m_lParam(0),
88         m_nCtrlID(0),
89         m_dwState(0),
90         m_bActivated(FALSE),
91         m_bCommitOnce(FALSE),
92         m_rcExpand(0,0,0,0),
93         m_rcCheckbox(0,0,0,0),
94         m_rcButton(0,0,0,0),
95         m_pParent(NULL),
96         m_pSibling(NULL),
97         m_pChild(NULL),
98         m_pVis(NULL)
99 {
100 }
101
102
103 CPropTreeItem::~CPropTreeItem()
104 {
105 }
106
107
108 BOOL CPropTreeItem::IsExpanded()
109 {
110         return (m_dwState & TreeItemExpanded) ? TRUE : FALSE;
111 }
112
113
114 BOOL CPropTreeItem::IsSelected()
115 {
116         return (m_dwState & TreeItemSelected) ? TRUE : FALSE;
117 }
118
119
120 BOOL CPropTreeItem::IsChecked()
121 {
122         return (m_dwState & TreeItemChecked) ? TRUE : FALSE;
123 }
124
125
126 BOOL CPropTreeItem::IsReadOnly()
127 {
128         return (m_dwState & TreeItemReadOnly) ? TRUE : FALSE;
129 }
130
131
132 BOOL CPropTreeItem::IsActivated()
133 {
134         return (m_dwState & TreeItemActivated) ? TRUE : FALSE;
135 }
136
137
138 void CPropTreeItem::Select(BOOL bSelect)
139 {
140         if (bSelect)
141                 m_dwState |= TreeItemSelected;
142         else
143                 m_dwState &= ~TreeItemSelected;
144 }
145
146
147 void CPropTreeItem::Expand(BOOL bExpand)
148 {
149         if (bExpand)
150                 m_dwState |= TreeItemExpanded;
151         else
152                 m_dwState &= ~TreeItemExpanded;
153 }
154
155
156 void CPropTreeItem::Check(BOOL bCheck)
157 {
158         if (bCheck)
159                 m_dwState |= TreeItemChecked;
160         else
161                 m_dwState &= ~TreeItemChecked;
162 }
163
164
165 void CPropTreeItem::ReadOnly(BOOL bReadOnly)
166 {
167         if (bReadOnly)
168                 m_dwState |= TreeItemReadOnly;
169         else
170                 m_dwState &= ~TreeItemReadOnly;
171 }
172
173
174 BOOL CPropTreeItem::IsCheckBox()
175 {
176         return (m_dwState & TreeItemCheckbox) ? TRUE : FALSE;
177 }
178
179
180 void CPropTreeItem::HasCheckBox(BOOL bCheckbox)
181 {
182         if (bCheckbox)
183                 m_dwState |= TreeItemCheckbox;
184         else
185                 m_dwState &= ~TreeItemCheckbox;
186 }
187
188
189 BOOL CPropTreeItem::HitExpand(const POINT& pt)
190 {
191         return m_rcExpand.PtInRect(pt);
192 }
193
194
195 BOOL CPropTreeItem::HitCheckBox(const POINT& pt)
196 {
197         return m_rcCheckbox.PtInRect(pt);
198 }
199
200
201 BOOL CPropTreeItem::IsRootLevel()
202 {
203         ASSERT(m_pProp!=NULL);
204         return GetParent() == m_pProp->GetRootItem();
205 }
206
207
208 LONG CPropTreeItem::GetTotalHeight()
209 {
210         CPropTreeItem* pItem;
211         LONG nHeight;
212
213         nHeight = GetHeight();
214
215         if (IsExpanded())
216         {
217                 for (pItem = GetChild(); pItem; pItem = pItem->GetSibling())
218                         nHeight += pItem->GetTotalHeight();
219         }
220
221         return nHeight;
222 }
223
224
225 void CPropTreeItem::SetLabelText(LPCTSTR sLabel)
226 {
227         m_sLabel = sLabel;
228 }
229
230
231 LPCTSTR CPropTreeItem::GetLabelText()
232 {
233         return m_sLabel;
234 }
235
236
237 void CPropTreeItem::SetInfoText(LPCTSTR sInfo)
238 {
239         m_sInfo = sInfo;
240 }
241
242
243 LPCTSTR CPropTreeItem::GetInfoText()
244 {
245         return m_sInfo;
246 }
247
248
249 void CPropTreeItem::SetCtrlID(UINT nCtrlID)
250 {
251         m_nCtrlID = nCtrlID;
252 }
253
254
255 UINT CPropTreeItem::GetCtrlID()
256 {
257         return m_nCtrlID;
258 }
259
260
261 LONG CPropTreeItem::GetHeight()
262 {
263         return PROPTREEITEM_DEFHEIGHT;
264 }
265
266
267 LPARAM CPropTreeItem::GetItemValue()
268 {
269         // no items are assocatied with this type
270         return 0L;
271 }
272
273
274 void CPropTreeItem::SetItemValue(LPARAM)
275 {
276         // no items are assocatied with this type
277 }
278
279
280 void CPropTreeItem::OnMove()
281 {
282         // no attributes, do nothing
283 }
284
285
286 void CPropTreeItem::OnRefresh()
287 {
288         // no attributes, do nothing
289 }
290
291
292 void CPropTreeItem::OnCommit()
293 {
294         // no attributes, do nothing
295 }
296
297
298 void CPropTreeItem::Activate(int activateType, CPoint point)
299 {
300         m_bActivated = TRUE;
301         m_bCommitOnce = FALSE;
302
303         OnActivate(activateType, point);
304 }
305
306
307 void CPropTreeItem::CommitChanges()
308 {
309         m_bActivated = FALSE;
310
311         if (m_bCommitOnce)
312                 return;
313
314         m_bCommitOnce = TRUE;
315
316         ASSERT(m_pProp!=NULL);
317
318         OnCommit();
319
320         m_pProp->SendNotify(PTN_ITEMCHANGED, this);
321         m_pProp->RefreshItems(this);
322 }
323
324
325 void CPropTreeItem::OnActivate(int activateType, CPoint point)
326 {
327         // no attributes, do nothing
328 }
329
330
331 void CPropTreeItem::SetPropOwner(CPropTree* pProp)
332 {
333         m_pProp = pProp;
334 }
335
336
337 const POINT& CPropTreeItem::GetLocation()
338 {
339         return m_loc;
340 }
341
342
343 CPropTreeItem* CPropTreeItem::GetParent()
344 {
345         return m_pParent;
346 }
347
348
349 CPropTreeItem* CPropTreeItem::GetSibling()
350 {
351         return m_pSibling;
352 }
353
354
355 CPropTreeItem* CPropTreeItem::GetChild()
356 {
357         return m_pChild;
358 }
359
360
361 CPropTreeItem* CPropTreeItem::GetNextVisible()
362 {
363         return m_pVis;
364 }
365
366
367 void CPropTreeItem::SetParent(CPropTreeItem* pParent)
368 {
369         m_pParent = pParent;
370 }
371
372
373 void CPropTreeItem::SetSibling(CPropTreeItem* pSibling)
374 {
375         m_pSibling = pSibling;
376 }
377
378
379 void CPropTreeItem::SetChild(CPropTreeItem* pChild)
380 {
381         m_pChild = pChild;
382 }
383
384
385 void CPropTreeItem::SetNextVisible(CPropTreeItem* pVis)
386 {
387         m_pVis = pVis;
388 }
389
390
391 LONG CPropTreeItem::DrawItem(CDC* pDC, const RECT& rc, LONG x, LONG y)
392 {
393         CPoint pt;
394         LONG nTotal, nCol, ey;
395         CRect drc, ir;
396
397         ASSERT(m_pProp!=NULL);
398
399         // Add TreeItem the list of visble items
400         m_pProp->AddToVisibleList(this);
401
402         // store the item's location
403         m_loc = CPoint(x, y);
404
405         // store the items rectangle position
406         m_rc.SetRect(m_pProp->GetOrigin().x + PROPTREEITEM_SPACE, m_loc.y, rc.right, m_loc.y + GetHeight()-1);
407         m_rc.OffsetRect(0, -m_pProp->GetOrigin().y);
408
409         // init temp drawing variables
410         nTotal = GetHeight();
411         ey = (nTotal >> 1) - (PROPTREEITEM_EXPANDBOX >> 1) - 2;
412
413         bool bCheck = false;
414
415         // convert item coordinates to screen coordinates
416         pt = m_loc;
417         pt.y -= m_pProp->GetOrigin().y;
418         nCol = m_pProp->GetOrigin().x;
419
420         if (IsRootLevel())
421                 drc.SetRect(pt.x + PROPTREEITEM_EXPANDCOLUMN, pt.y, rc.right, pt.y + nTotal);
422         else
423                 drc.SetRect(pt.x + PROPTREEITEM_EXPANDCOLUMN, pt.y, nCol, pt.y + nTotal);
424
425         // root level items are shaded
426         if (IsRootLevel())
427         {
428                 HGDIOBJ hOld = pDC->SelectObject(GetSysColorBrush(COLOR_BTNFACE));
429                 pDC->PatBlt(rc.left, drc.top, rc.right - rc.left + 1, drc.Height(), PATCOPY);
430                 pDC->SelectObject(hOld);
431         }
432
433         // calc/draw expand box position
434         if (GetChild())
435         {
436                 m_rcExpand.left = PROPTREEITEM_EXPANDCOLUMN/2 - PROPTREEITEM_EXPANDBOXHALF;
437                 m_rcExpand.top = m_loc.y + ey;
438                 m_rcExpand.right = m_rcExpand.left + PROPTREEITEM_EXPANDBOX - 1;
439                 m_rcExpand.bottom = m_rcExpand.top + PROPTREEITEM_EXPANDBOX - 1;
440
441                 ir = m_rcExpand;
442                 ir.OffsetRect(0, -m_pProp->GetOrigin().y);
443                 _DrawExpand(pDC->m_hDC, ir.left, ir.top, IsExpanded(), !IsRootLevel());
444         }
445         else
446                 m_rcExpand.SetRectEmpty();
447
448         // calc/draw check box position
449         if (IsCheckBox())
450         {
451                 bCheck = true;
452
453                 ir.left = drc.left + PROPTREEITEM_SPACE;
454                 ir.top = m_loc.y + ey;
455
456                 ir.right = ir.left + PROPTREEITEM_CHECKBOX;
457                 ir.bottom = ir.top + PROPTREEITEM_CHECKBOX;
458
459                 m_rcCheckbox = ir;
460         }
461         else
462                 m_rcCheckbox.SetRectEmpty();
463
464         HRGN hRgn = NULL;
465
466         // create a clipping region for the label
467         if (!IsRootLevel())
468         {
469                 hRgn = CreateRectRgn(drc.left, drc.top, drc.right, drc.bottom);
470                 SelectClipRgn(pDC->m_hDC, hRgn);
471         }
472
473         // calc label position
474         ir = drc;
475         ir.left += PROPTREEITEM_SPACE;
476
477         // offset the label text if item has a check box
478         if (bCheck)
479                 OffsetRect(&ir, PROPTREEITEM_CHECKBOX + PROPTREEITEM_SPACE * 2, 0);
480
481         // draw label
482         if (!m_sLabel.IsEmpty())
483         {
484                 if (IsRootLevel())
485                         pDC->SelectObject(CPropTree::GetBoldFont());
486                 else
487                         pDC->SelectObject(CPropTree::GetNormalFont());
488
489                 pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));
490                 pDC->SetBkMode(TRANSPARENT);
491                 pDC->DrawText(m_sLabel, &ir, DT_SINGLELINE|DT_VCENTER|DT_CALCRECT);
492
493                 // draw the text highlighted if selected
494                 if (IsSelected())
495                 {
496                         HGDIOBJ oPen = pDC->SelectObject(GetStockObject(NULL_PEN));
497                         HGDIOBJ oBrush = pDC->SelectObject(GetSysColorBrush(COLOR_HIGHLIGHT));
498                         
499                         CRect dr;
500                         dr = drc;
501                         dr.left = PROPTREEITEM_EXPANDCOLUMN;
502                         
503                         pDC->Rectangle(&dr);
504                         
505                         pDC->SelectObject(oPen);
506                         pDC->SelectObject(oBrush);
507
508                         pDC->SetTextColor(GetSysColor(COLOR_BTNHIGHLIGHT));
509                 }
510
511                 // check if we need to draw the text as disabled
512                 if (!m_pProp->IsWindowEnabled())
513                         pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
514
515                 pDC->DrawText(m_sLabel, &ir, DT_SINGLELINE|DT_VCENTER);
516         }
517
518         // draw check box frame
519         if (IsCheckBox())
520         {
521                 ir = m_rcCheckbox;
522                 ir.OffsetRect(0, -m_pProp->GetOrigin().y);
523                 pDC->DrawFrameControl(&ir, DFC_BUTTON, DFCS_BUTTONCHECK | (IsChecked() ? DFCS_CHECKED : 0));
524         }
525
526         // remove clip region
527         if (hRgn)
528         {
529                 SelectClipRgn(pDC->m_hDC, NULL);
530                 DeleteObject(hRgn);
531         }
532
533         // draw horzontal sep
534         _DotHLine(pDC->m_hDC, PROPTREEITEM_EXPANDCOLUMN, pt.y + nTotal - 1, rc.right - PROPTREEITEM_EXPANDCOLUMN + 1);
535
536         // draw separators
537         if (!IsRootLevel())
538         {
539                 // column sep
540                 CPen pn1(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
541                 CPen* pOld;
542
543                 pOld = pDC->SelectObject(&pn1);
544                 pDC->MoveTo(nCol, drc.top);
545                 pDC->LineTo(nCol, drc.bottom);
546
547                 CPen pn2(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
548                 pDC->SelectObject(&pn2);
549                 pDC->MoveTo(nCol + 1, drc.top);
550                 pDC->LineTo(nCol + 1, drc.bottom);
551
552                 pDC->SelectObject(pOld);
553         }
554
555         // draw attribute
556         if (!IsRootLevel())
557         {
558                 // create clip region
559                 hRgn = CreateRectRgn(m_rc.left, m_rc.top, m_rc.right, m_rc.bottom);
560                 SelectClipRgn(pDC->m_hDC, hRgn);
561                 
562                 DrawAttribute(pDC, m_rc);
563
564                 SelectClipRgn(pDC->m_hDC, NULL);
565                 DeleteObject(hRgn);
566         }
567
568         // draw children
569         if (GetChild() && IsExpanded())
570         {
571                 y += nTotal;
572
573                 CPropTreeItem* pNext;
574
575                 for (pNext = GetChild(); pNext; pNext = pNext->GetSibling())
576                 {
577                         LONG nHeight = pNext->DrawItem(pDC, rc, x + (IsRootLevel() ? 0 : PNINDENT), y);
578                         nTotal += nHeight;
579                         y += nHeight;
580                 }
581         }
582
583         return nTotal;
584 }
585
586
587 void CPropTreeItem::DrawAttribute(CDC*, const RECT&)
588 {
589         // no attributes are assocatied with this type
590 }