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 "tools/edit_gui_common.h"
21
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
_DotHLine(HDC hdc,LONG x,LONG y,LONG w)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
_DrawExpand(HDC hdc,LONG x,LONG y,BOOL bExpand,BOOL bFill)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
CPropTreeItem()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
~CPropTreeItem()103 CPropTreeItem::~CPropTreeItem()
104 {
105 }
106
107
IsExpanded()108 BOOL CPropTreeItem::IsExpanded()
109 {
110 return (m_dwState & TreeItemExpanded) ? TRUE : FALSE;
111 }
112
113
IsSelected()114 BOOL CPropTreeItem::IsSelected()
115 {
116 return (m_dwState & TreeItemSelected) ? TRUE : FALSE;
117 }
118
119
IsChecked()120 BOOL CPropTreeItem::IsChecked()
121 {
122 return (m_dwState & TreeItemChecked) ? TRUE : FALSE;
123 }
124
125
IsReadOnly()126 BOOL CPropTreeItem::IsReadOnly()
127 {
128 return (m_dwState & TreeItemReadOnly) ? TRUE : FALSE;
129 }
130
131
IsActivated()132 BOOL CPropTreeItem::IsActivated()
133 {
134 return (m_dwState & TreeItemActivated) ? TRUE : FALSE;
135 }
136
137
Select(BOOL bSelect)138 void CPropTreeItem::Select(BOOL bSelect)
139 {
140 if (bSelect)
141 m_dwState |= TreeItemSelected;
142 else
143 m_dwState &= ~TreeItemSelected;
144 }
145
146
Expand(BOOL bExpand)147 void CPropTreeItem::Expand(BOOL bExpand)
148 {
149 if (bExpand)
150 m_dwState |= TreeItemExpanded;
151 else
152 m_dwState &= ~TreeItemExpanded;
153 }
154
155
Check(BOOL bCheck)156 void CPropTreeItem::Check(BOOL bCheck)
157 {
158 if (bCheck)
159 m_dwState |= TreeItemChecked;
160 else
161 m_dwState &= ~TreeItemChecked;
162 }
163
164
ReadOnly(BOOL bReadOnly)165 void CPropTreeItem::ReadOnly(BOOL bReadOnly)
166 {
167 if (bReadOnly)
168 m_dwState |= TreeItemReadOnly;
169 else
170 m_dwState &= ~TreeItemReadOnly;
171 }
172
173
IsCheckBox()174 BOOL CPropTreeItem::IsCheckBox()
175 {
176 return (m_dwState & TreeItemCheckbox) ? TRUE : FALSE;
177 }
178
179
HasCheckBox(BOOL bCheckbox)180 void CPropTreeItem::HasCheckBox(BOOL bCheckbox)
181 {
182 if (bCheckbox)
183 m_dwState |= TreeItemCheckbox;
184 else
185 m_dwState &= ~TreeItemCheckbox;
186 }
187
188
HitExpand(const POINT & pt)189 BOOL CPropTreeItem::HitExpand(const POINT& pt)
190 {
191 return m_rcExpand.PtInRect(pt);
192 }
193
194
HitCheckBox(const POINT & pt)195 BOOL CPropTreeItem::HitCheckBox(const POINT& pt)
196 {
197 return m_rcCheckbox.PtInRect(pt);
198 }
199
200
IsRootLevel()201 BOOL CPropTreeItem::IsRootLevel()
202 {
203 ASSERT(m_pProp!=NULL);
204 return GetParent() == m_pProp->GetRootItem();
205 }
206
207
GetTotalHeight()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
SetLabelText(LPCTSTR sLabel)225 void CPropTreeItem::SetLabelText(LPCTSTR sLabel)
226 {
227 m_sLabel = sLabel;
228 }
229
230
GetLabelText()231 LPCTSTR CPropTreeItem::GetLabelText()
232 {
233 return m_sLabel;
234 }
235
236
SetInfoText(LPCTSTR sInfo)237 void CPropTreeItem::SetInfoText(LPCTSTR sInfo)
238 {
239 m_sInfo = sInfo;
240 }
241
242
GetInfoText()243 LPCTSTR CPropTreeItem::GetInfoText()
244 {
245 return m_sInfo;
246 }
247
248
SetCtrlID(UINT nCtrlID)249 void CPropTreeItem::SetCtrlID(UINT nCtrlID)
250 {
251 m_nCtrlID = nCtrlID;
252 }
253
254
GetCtrlID()255 UINT CPropTreeItem::GetCtrlID()
256 {
257 return m_nCtrlID;
258 }
259
260
GetHeight()261 LONG CPropTreeItem::GetHeight()
262 {
263 return PROPTREEITEM_DEFHEIGHT;
264 }
265
266
GetItemValue()267 LPARAM CPropTreeItem::GetItemValue()
268 {
269 // no items are assocatied with this type
270 return 0L;
271 }
272
273
SetItemValue(LPARAM)274 void CPropTreeItem::SetItemValue(LPARAM)
275 {
276 // no items are assocatied with this type
277 }
278
279
OnMove()280 void CPropTreeItem::OnMove()
281 {
282 // no attributes, do nothing
283 }
284
285
OnRefresh()286 void CPropTreeItem::OnRefresh()
287 {
288 // no attributes, do nothing
289 }
290
291
OnCommit()292 void CPropTreeItem::OnCommit()
293 {
294 // no attributes, do nothing
295 }
296
297
Activate(int activateType,CPoint point)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
CommitChanges()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
OnActivate(int activateType,CPoint point)325 void CPropTreeItem::OnActivate(int activateType, CPoint point)
326 {
327 // no attributes, do nothing
328 }
329
330
SetPropOwner(CPropTree * pProp)331 void CPropTreeItem::SetPropOwner(CPropTree* pProp)
332 {
333 m_pProp = pProp;
334 }
335
336
GetLocation()337 const POINT& CPropTreeItem::GetLocation()
338 {
339 return m_loc;
340 }
341
342
GetParent()343 CPropTreeItem* CPropTreeItem::GetParent()
344 {
345 return m_pParent;
346 }
347
348
GetSibling()349 CPropTreeItem* CPropTreeItem::GetSibling()
350 {
351 return m_pSibling;
352 }
353
354
GetChild()355 CPropTreeItem* CPropTreeItem::GetChild()
356 {
357 return m_pChild;
358 }
359
360
GetNextVisible()361 CPropTreeItem* CPropTreeItem::GetNextVisible()
362 {
363 return m_pVis;
364 }
365
366
SetParent(CPropTreeItem * pParent)367 void CPropTreeItem::SetParent(CPropTreeItem* pParent)
368 {
369 m_pParent = pParent;
370 }
371
372
SetSibling(CPropTreeItem * pSibling)373 void CPropTreeItem::SetSibling(CPropTreeItem* pSibling)
374 {
375 m_pSibling = pSibling;
376 }
377
378
SetChild(CPropTreeItem * pChild)379 void CPropTreeItem::SetChild(CPropTreeItem* pChild)
380 {
381 m_pChild = pChild;
382 }
383
384
SetNextVisible(CPropTreeItem * pVis)385 void CPropTreeItem::SetNextVisible(CPropTreeItem* pVis)
386 {
387 m_pVis = pVis;
388 }
389
390
DrawItem(CDC * pDC,const RECT & rc,LONG x,LONG y)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
DrawAttribute(CDC *,const RECT &)587 void CPropTreeItem::DrawAttribute(CDC*, const RECT&)
588 {
589 // no attributes are assocatied with this type
590 }
591