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