//-----------------------------------------------------------------------------
// File: flextree.h
//
// Desc: Implements a tree class, similar to a Windows tree control,
//       based on CFlexWnd.  It is used by the page to display the action
//       list when the user wishes to assign an action to a control.
//
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------

#ifndef __FLEXTREE_H__
#define __FLEXTREE_H__


#include "flexscrollbar.h"


class CFTItem;
class CFlexTree;


typedef struct {
	CFlexTree *pTree;
	CFTItem *pItem, *pOldItem;
	POINT point;
	HDC hDC;
	WPARAM fwKeys;
	BOOL bLeft;
} FLEXTREENOTIFY;

enum {
	FTN_CLICK,
	FTN_OWNERDRAW,
	FTN_SELCHANGED,
	FTN_MOUSEOVER
};

enum {
	CLMF_NONE =			0x00000000,
	CLMF_TEXTCOLOR =	0x00000001,
	CLMF_BKCOLOR =		0x00000002,
	CLMF_BKMODE =		0x00000004,
	CLMF_BKEXTENDS =	0x00000008,
	CLMF_FONT =			0x00000010,
	CLMF_LINECOLOR = 0x00000020,
	CLMF_ALL =			0x0000003f
};

struct _CAPTIONLOOK;
typedef struct _CAPTIONLOOK {
	_CAPTIONLOOK() : dwSize(sizeof(_CAPTIONLOOK)), dwMask(CLMF_NONE),
		rgbTextColor(RGB(0,0,0)), rgbBkColor(RGB(255,255,255)), rgbLineColor(RGB(255,0,0)), nBkMode(TRANSPARENT),
		bBkExtends(FALSE), hFont(NULL) {}
	DWORD dwSize;
	DWORD dwMask;
	COLORREF rgbTextColor, rgbBkColor, rgbLineColor, nBkMode;
	BOOL bBkExtends;
	HFONT hFont;
} CAPTIONLOOK;

typedef enum {
	ATTACH_FIRSTCHILD,
	ATTACH_LASTCHILD,
	ATTACH_FIRSTSIBLING,
	ATTACH_LASTSIBLING,
	ATTACH_BEFORE,
	ATTACH_AFTER
} ATTACHREL;


class CFlexTree : public CFlexWnd
{
friend class CFTItem;
public:
	CFlexTree();
	~CFlexTree();

	// creation
	BOOL Create(HWND hParent, const RECT &, BOOL bVisible = TRUE, BOOL bOwnerDraw = FALSE);

	// look
	void SetScrollBarColors(COLORREF bk, COLORREF fill, COLORREF line);
	void SetDefCaptionLook(const CAPTIONLOOK &, BOOL bSel = FALSE);
	void GetDefCaptionLook(CAPTIONLOOK &, BOOL bSel = FALSE) const;
	void SetDefMargin(const RECT &);
	void GetDefMargin(RECT &) const;
	void SetRootChildIndent(int);
	int GetRootChildIndent() const;
	void SetDefChildIndent(int);
	int GetDefChildIndent() const;
	void SetBkColor(COLORREF);
	COLORREF GetBkColor() const;

	// adding default type items
	CFTItem *DefAddItem(LPCTSTR tszCaption, CFTItem *to, ATTACHREL rel = ATTACH_AFTER);
	CFTItem *DefAddItem(LPCTSTR tszCaption, ATTACHREL rel = ATTACH_AFTER);

	// freeing
	void FreeAll();

	// root access
	operator CFTItem *() const {return m_pRoot;}
	CFTItem *GetRoot() const {return m_pRoot;}

	// access
	CFTItem *GetFirstItem() const;
	CFTItem *GetLastItem() const;
	CFTItem *GetFirstVisibleItem() const;
	CFTItem *GetItemFromPoint(POINT point) const;

	// selection
	void SetCurSel(CFTItem *);
	CFTItem *GetCurSel() const;

	// finding
	CFTItem *FindItem(const GUID &guid, void *pUserData) const;
	CFTItem *FindItemEx(const GUID &guid, DWORD dwFindType, void *pVoid) const;

protected:
	virtual BOOL OnEraseBkgnd(HDC hDC) {return TRUE;}
	virtual void OnPaint(HDC hDC);
	virtual void OnMouseOver(POINT point, WPARAM fwKeys);
	virtual void OnClick(POINT point, WPARAM fwKeys, BOOL bLeft);
	virtual void OnWheel(POINT point, WPARAM wParam);
	virtual LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

	// event notification firing
	void FireClick(CFTItem *pItem, POINT point, WPARAM fwKeys, BOOL bLeft);
	BOOL FireOwnerDraw(CFTItem *pItem, HDC hDC);
	void FireSelChanged(CFTItem *pItem, CFTItem *pOld);

private:
	CFTItem *m_pRoot;	// root item
	CFTItem *m_pCurSel;	// selected item
	CFTItem *m_pLastAdded;
	BOOL m_bOwnerDraw;
	POINT m_ptScrollOrigin;
	COLORREF m_rgbBkColor;
	CAPTIONLOOK m_clDefNormal, m_clDefSelected;
	RECT m_defmargin;
	int m_nDefChildIndent;

	// scrolling
	int m_nVertSBWidth;
	int m_nHorzSBHeight;
	BOOL m_bVertSB, m_bHorzSB;
	CFlexScrollBar m_VertSB, m_HorzSB;
	int m_nTotalWidth;

	// helpers
	BOOL m_bNeedPaintBkgnd;
	void SetDirty();
	void InternalPaint(HDC hDC);
	BOOL m_bDirty;
	void Calc();
	void CalcItems();
	BOOL IsMine(CFTItem *pItem);
	void LosePointer(CFTItem *pItem);
};

class CFTItem
{
friend class CFlexTree;
public:
	CFTItem();
	~CFTItem();

	// operations
	BOOL IsOut() const;
	BOOL IsExpanded() const {return m_bExpanded;}
	void Expand(BOOL bAll = FALSE);
	void ExpandAll() {Expand(TRUE);}
	void Collapse(BOOL bAll = FALSE);
	void CollapseAll() {Collapse(TRUE);}
	void EnsureVisible();
	void Invalidate();
	
	// caption
	void SetCaptionLook(const CAPTIONLOOK &, BOOL bSel = FALSE);
	void GetCaptionLook(CAPTIONLOOK &, BOOL bSel = FALSE) const;
	void SetCaption(LPCTSTR);
	LPCTSTR GetCaption() const;
	BOOL HasCaption() const {return GetCaption() != NULL;}
	void SetMargin(const RECT &);
	void GetMargin(RECT &) const;

	// attach/detachment
	void Detach();			// detaches this leaf/branch from parent.  (does not affect children, who may still be attached to this)
	void FreeChildren();	// detach and free each child (which in turn frees all their's, etc.)
	BOOL Attach(CFTItem *to, ATTACHREL rel);
	BOOL Attach(CFTItem &to, ATTACHREL rel) {return Attach(&to, rel);}
	BOOL IsOnTree() const;
	BOOL IsAttached() const;
	BOOL IsAlone() const;

	// family access
	CFlexTree *GetTree() const {return m_pTree;}
	CFTItem *GetParent() const {return m_pParent;}
	CFTItem *GetPrevSibling() const {return m_pPrev;}
	CFTItem *GetNextSibling() const {return m_pNext;}
	CFTItem *GetFirstChild() const {return m_pFirst;}
	CFTItem *GetLastChild() const {return m_pLast;}
	CFTItem *GetNextOut() const;
	CFTItem *GetNext(BOOL bOutOnly = FALSE) const;
	BOOL HasChildren() const {return m_pFirst != NULL;}

	// dimension access
	void GetItemRect(RECT &) const;
	void GetBranchRect(RECT &) const;

	// user guid/data operations
	BOOL IsUserGUID(const GUID &check) const {return IsEqualGUID(m_UserGUID, check);}
	void SetUserGUID(const GUID &set)  {m_UserGUID = set;}
	const GUID &GetUserGUID() const {return m_UserGUID;}
	void SetUserData(void *p) {m_pUserData = p;}
	void *GetUserData() const {return m_pUserData;}

	// selection
	BOOL IsSelected() const;

	// owner draw
	void PaintInto(HDC hDC);

protected:
	// internal/derived-customization operations
	void SetWidth(int);
	int GetWidth() const {return m_nWidth;}
	void SetHeight(int);
	int GetHeight() const {return m_nHeight;}
	void SetIndent(int);
	int GetIndent() const {return m_nIndent;}
	void SetChildIndent(int);
	int GetChildIndent() const {return m_nChildIndent;}

	// customization
	virtual void OnPaint(HDC hDC);
	virtual void OnMouseOver(POINT point, WPARAM fwKeys) {}
	virtual void OnClick(POINT point, WPARAM fwKeys, BOOL bLeft);

	// expansion customization
public: virtual BOOL IsExpandable() {return GetFirstChild() != NULL;}
protected:
	virtual void OnExpand() {}
	virtual void OnCollapse() {}

	// finding
	virtual BOOL FoundItem(DWORD dwUser, void *pUser) const {return FALSE;}

	// event notification firing
	void FireClick(POINT point, WPARAM fwKeys, BOOL bLeft);
	BOOL FireOwnerDraw(HDC hDC);

private:
	// caption
	LPTSTR m_ptszCaption;
	CAPTIONLOOK m_clNormal, m_clSelected;
	RECT m_margin;

	// user data
	GUID m_UserGUID;
	void *m_pUserData;

	// raw characteristics
	int m_nWidth;       // item's width (used only to provide horizontal scrolling as necessary)
	int m_nHeight;      // item's height (not including children)
	int m_nIndent;      // indent of this item relative to parent's child indent origin (full origin = this + parent origin + parent child indent)
	int m_nChildIndent; // indentation of this item's children (relative to this's origin)

	// calced characteristics
	int m_nBranchHeight;  // height of item and all currently expanded children

	// calced positioning
	POINT m_origin;  // relative to ideal tree origin

	// state
	BOOL m_bExpanded;  // is branch expanded/children shown?

	// family
	CFlexTree *m_pTree;
	CFTItem *m_pParent, *m_pPrev, *m_pNext, *m_pFirst, *m_pLast;

	// root
	BOOL IsRoot() const;
	void SetRoot(CFlexTree *);

	// helpers
	void SetTree(CFlexTree *);
	BOOL Attach(CFTItem *pParent, CFTItem *pPrev, CFTItem *pNext);
	void SetTreeDirty(CFlexTree *pTree = NULL);
	void RecalcText();
	void Init();
	void SelChangedInternal();
	void InternalExpand(BOOL bExpand, BOOL bAll);
};


#endif //__FLEXTREE_H__