//---------------------------------------------------------------------------

#pragma hdrstop

#include "ProgHandlePanel.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
#define ITEM_OVER		TColor(RGB(67, 73, 80))
#define ITEM_SELECTED	TColor(RGB(29, 31, 35))
#define ITEM_DEF		TColor(RGB(47, 50, 57))

#define ITEM_TEXT_COLOR		TColor(RGB(213, 221, 232))

#define BORDER 		    TColor(RGB(106, 111, 117))
#define BACKGRND		TColor(RGB(47, 50, 57))

#define BORDER_HL	    TColor(RGB(30, 32, 36))
#define BACKGRND_HL	    TColor(RGB(67, 73, 80))

#define TEXT_COLOR		TColor(RGB(213, 221, 232))
#define TEXT_DISABLE	TColor(RGB(100, 108, 119))
#define BREAK			TColor(RGB(100, 108, 119))
#define BOARD_FILL		TColor(RGB(76, 82, 91))

#define MIN(x, y)		((x) < (y) ? (x) : (y))
#define MAX(x, y)		((x) > (y) ? (x) : (y))

#define MARGIN			2
//---------------------------------------------------------------------------

/****************************************************************************
*
*	TProgHandleItem
*
*****************************************************************************/
__fastcall TProgHandleItem::TProgHandleItem(TProgHandlePanel *OwnerPanel, String Caption)
{
	if(mChildItem == NULL) {
		mChildItem = new TList();
    }

	mLevel = 0;
	FParent = NULL;
	FOwnerPanel = OwnerPanel;
	FCaption = Caption;

	FOwnerPanel->AddTopLevelItem(this);
}
//---------------------------------------------------------------------------
__fastcall TProgHandleItem::TProgHandleItem(TProgHandleItem *Parent, String Caption)
{
	if(mChildItem == NULL) {
		mChildItem = new TList();
	}

	FParent = Parent;
	FOwnerPanel = Parent->GetOwnerPanel();
	mLevel = Parent->mLevel + 1;
	FCaption = Caption;

	FParent->AddChild(this);
}
//---------------------------------------------------------------------------
__fastcall TProgHandleItem::~TProgHandleItem()
{
	if(mChildItem) {
		mChildItem->Clear();
		delete mChildItem;
		mChildItem = NULL;
	}

	if(mHeaderIconButton) {
		delete mHeaderIconButton;
		mHeaderIconButton = NULL;
	}

	if(mCheckBox) {
		delete mCheckBox;
		mCheckBox = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::AfterConstruction()
{
	FIsUnfold = true;
	FIsSelected = false;
	FIsFocus = false;
	FIsHidden = false;
	FIsChecked = true;

	mCanvas = NULL;

	mRect.init(0, 0, 0, 0);
	mValidRect.init(0, 0, 0, 0);
	mIconRect.init(0, 0, 0, 0);
	mCaptionRect.init(0, 0, 0, 0);

	mHeaderIconButton = new TPNGButton(FOwnerPanel);
	mHeaderIconButton->Parent = FOwnerPanel;
	mHeaderIconButton->ImgStates = 2;
	mHeaderIconButton->Visible = true;
	mHeaderIconButton->Width = 12;
	mHeaderIconButton->Height = 12;
	mHeaderIconButton->Top = -12;
	mHeaderIconButton->Left = -12;
	mHeaderIconButton->OnClick = DoHeaderClick;

	mCheckBox = new TPNGButton(FOwnerPanel);
	mCheckBox->Parent = FOwnerPanel;
	mCheckBox->ImgStates = 2;
	mCheckBox->Visible = true;
	mCheckBox->Top = -20;
	mCheckBox->Left = -20;
	mCheckBox->Width = 20;
	mCheckBox->Height = 20;
	mCheckBox->OnClick = DoCheckClick;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::DrawItem(TCanvas *Canvas, TRect Rect)
{
	if(mRect != Rect) {
		mRect = Rect;

		mValidRect = TRect(Rect);
		mValidRect.Left += mLevel * 20;

		mIconRect = TRect(mValidRect);
		mIconRect.Right = mIconRect.Left + 20;

		mCaptionRect = TRect(mValidRect);
		mCaptionRect.Left += 20;
	}

	mCanvas = Canvas;

	if(ChildCount > 0) {
		if(IsUnfold)
			mHeaderIconButton->PngImg->LoadFromResourceName((int)HInstance, L"imgUnfold");
		else
			mHeaderIconButton->PngImg->LoadFromResourceName((int)HInstance, L"imgFold");

		mHeaderIconButton->Top = mIconRect.Top + (mIconRect.Height() - 12) / 2;
		mHeaderIconButton->Left = mIconRect.Left + (mIconRect.Width() - 12) / 2;
	}
	else {
		if(FIsChecked)
			mCheckBox->PngImg->LoadFromResourceName((int)HInstance, L"imgItemChecked");
		else
			mCheckBox->PngImg->LoadFromResourceName((int)HInstance, L"imgItemUnchecked");

		mCheckBox->Top = mIconRect.Top;
		mCheckBox->Left = mIconRect.Left;
    }

	if(FIsSelected)
		mCanvas->Brush->Color = ITEM_SELECTED;
	else if(FIsFocus && !FIsSelected)
		mCanvas->Brush->Color = ITEM_OVER;
	else
		mCanvas->Brush->Color = ITEM_DEF;

	mCanvas->FillRect(mCaptionRect);

	mCanvas->Font->Color = ITEM_TEXT_COLOR;

	int textHeight = mCanvas->TextHeight(FCaption);

	int textLeft = mCaptionRect.Left + 4;
	int textTop = mCaptionRect.Top + (mCaptionRect.Height() - textHeight) / 2;
	int textRight = mCaptionRect.Right - 4;
	int textBottom = textTop + textHeight;

	TRect textRect(textLeft, textTop, textRight, textBottom);
	mCanvas->TextRect(textRect, FCaption);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::RedrawItem()
{
	if(mCanvas && !FIsHidden) {
		DrawItem(mCanvas, mRect);
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
{
	if(mCaptionRect.Contains(TPoint(X, Y))) {
		if(!FIsSelected){
			FIsSelected = true;
			RedrawItem();
			// 选择项
			FOwnerPanel->DoSelectedItem(this);
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::MouseMove(TShiftState Shift, int X, int Y)
{
	if(mCaptionRect.Contains(TPoint(X, Y))) {
		if(!FIsFocus) {
			FIsFocus = true;
			RedrawItem();
			// 当前项
			FOwnerPanel->DoCurrentItem(this);
		}
	}
	else{
		if(FIsFocus) {
			FIsFocus = false;
			RedrawItem();
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
{
	//
}
//---------------------------------------------------------------------------
TProgHandlePanel *TProgHandleItem::GetOwnerPanel()
{
    return FOwnerPanel;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::SetCaption(String Value)
{
	if(FCaption != Value) {
		FCaption = Value;
		RedrawItem();
		// 通知Panel：名称变化事件
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::SetUnfold(bool Value)
{
	if(FIsUnfold != Value) {
		FIsUnfold = Value;

		RedrawItem();
		// 通知Panel: 结构变化
		FOwnerPanel->DoItemChange(this);
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::DoHeaderClick(TObject *Sender)
{
    IsUnfold = !IsUnfold;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::DoCheckClick(TObject *Sender)
{
    IsChecked = !IsChecked;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::SetSelected(bool Value)
{
	if(FIsSelected != Value) {
		FIsSelected = Value;
		RedrawItem();
		// 通知Panel：选择变化事件
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::SetHidden(bool Value)
{
	if(FIsHidden != Value) {
		FIsHidden = Value;

		if(mHeaderIconButton)
			mHeaderIconButton->Visible = !Value;

		if(mCheckBox)
			mCheckBox->Visible = !Value;
    }
}
//---------------------------------------------------------------------------
void __fastcall TProgHandleItem::SetChecked(bool Value)
{
	if(FIsChecked != Value) {
		FIsChecked = Value;
		RedrawItem();
    }
}
//---------------------------------------------------------------------------
int __fastcall TProgHandleItem::GetChildCount()
{
	return mChildItem->Count;
}
//---------------------------------------------------------------------------
void TProgHandleItem::AddChild(TProgHandleItem *Child)
{
	mChildItem->Add(Child);
	// 通知Panel：Item个数变化
	FOwnerPanel->DoItemChange(this);
}
//---------------------------------------------------------------------------
TProgHandleItem *TProgHandleItem::Child(int Index)
{
	if(Index >= 0 && Index < ChildCount) {
		return (TProgHandleItem *)mChildItem->Items[Index];
	}

	return NULL;
}

/****************************************************************************
*
*	TProgHandlePanel
*
*****************************************************************************/
__fastcall TProgHandlePanel::TProgHandlePanel(TComponent *Owner) : TPanel(Owner)
{
	SetParentComponent(Owner);

	mTopLevelItemList 	= new TList();
	mItemRectList 		= new TList();
	mItemList 			= new TList();

	mCurrentItem = NULL;

	mEndIndex = 0;

	FItemHeight = 20;

	mScrollBar = new TSkinScrollBar(NULL);
	mScrollBar->Visible = false;
}
//---------------------------------------------------------------------------
__fastcall TProgHandlePanel::~TProgHandlePanel()
{
	if(mTopLevelItemList) {
		mTopLevelItemList->Clear();
		delete mTopLevelItemList;
		mTopLevelItemList = NULL;
	}

	if(mItemRectList) {
		mItemRectList->Clear();
		delete mItemRectList;
		mItemRectList = NULL;
	}

	if(mItemList) {
		mItemList->Clear();
		delete mItemList;
		mItemList = NULL;
	}

	if(mScrollBar) {
		delete mScrollBar;
		mScrollBar = NULL;
	}

	if(mCurrentItem) {
		delete mCurrentItem;
		mCurrentItem = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::AddTopLevelItem(TProgHandleItem* Item)
{
	mTopLevelItemList->Add(Item);
	DoItemChange(NULL);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::ScrollPos(int Pos)
{
	if(Pos >= 0 && Pos <= mItemList->Count - mRealShowCount) {
		if(mBeginIndex != Pos) {
			// 重置项
			mBeginIndex = Pos;
			mEndIndex = mBeginIndex + mRealShowCount;
			Paint();
		}
    }
}
//---------------------------------------------------------------------------
TProgHandleItem *TProgHandlePanel::GetItem(int Index)
{
	if(Index >= 0 && Index < mItemList->Count) {
		return (TProgHandleItem *) mItemList->Items[Index];
	}

	return NULL;
}
//---------------------------------------------------------------------------
TProgHandleItem *TProgHandlePanel::GetTopLevelItem(int Index)
{
	if(Index >= 0 && Index < mTopLevelItemList->Count) {
		return (TProgHandleItem *) mTopLevelItemList->Items[Index];
	}

	return NULL;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::RecalcItemsRect()
{
    //最大显示数
	mShowCount = (Height - 2 * MARGIN) / FItemHeight;
	// 记录显示区域
	mItemRectList->Clear();
	mItemRectList->Add(new TRect(MARGIN, MARGIN, Width - MARGIN, FItemHeight + MARGIN));
	for(int i = 1; i < mShowCount; i++) {
		int itemTop = i * FItemHeight + MARGIN;
		int itemBottom = itemTop + FItemHeight;

		mItemRectList->Add(new TRect(MARGIN, itemTop, Width - MARGIN, itemBottom));
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::Reset()
{
	mRealShowCount = MIN(mItemList->Count, mShowCount);
	mEndIndex = mBeginIndex + mRealShowCount;

	while(mEndIndex > mItemList->Count) {
		mBeginIndex--;
		mEndIndex--;
	}

	int Index = mBeginIndex;
	while(Index < mEndIndex) {
		TProgHandleItem *Item = (TProgHandleItem *)mItemList->Items[Index];
		if(Item->IsSelected)
			break;
		Index++;
	}

	if(Index == mEndIndex) {
        DoSelectedItem(NULL);
    }

	if(HandleAllocated()) {
		if(mItemList->Count > mShowCount) {
			mScrollBar->Visible = true;
			mScrollBar->SetRange(0, mItemList->Count - 1);
			mScrollBar->SetPageSize(mShowCount);
			mScrollBar->SetPosition(mBeginIndex);
			FItemWidth = Width - mScrollBar->Width - 20;
		}
		else {
			mScrollBar->Visible = false;
			FItemWidth = Width;
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::LoadItem(TProgHandleItem* Item)
{
	if(Item->Parent == NULL) {
		Item->IsHidden = false;
	}
	else {
        Item->IsHidden = (Item->Parent->IsHidden || !Item->Parent->IsUnfold);
	}

	if(!Item->IsHidden) {
        mItemList->Add(Item);
    }

	for(int i = 0; i < Item->ChildCount; i++) {
		TProgHandleItem *Child = Item->Child(i);
		LoadItem(Child);
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::WMSize(TWMSize &Message)
{
	mScrollBar->Height = Height - 2;
	mScrollBar->Top = 1;
	mScrollBar->Left = Width - mScrollBar->Width - 1;

	RecalcItemsRect();
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::WMEraseBkgnd(TWMEraseBkgnd &Message)
{
	TCanvas* tmpCanvas = new TCanvas();
	tmpCanvas->Handle  = Message.DC;

	tmpCanvas->Brush->Color = BACKGRND;	// 绘制底色
	tmpCanvas->FillRect(ClientRect);

	tmpCanvas->Brush->Color = BORDER;		// 绘制边框
	tmpCanvas->FrameRect(ClientRect);

	delete tmpCanvas;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::WMMouseWheel(TWMMouseWheel &Message)
{
	UINT nSBCode;

	if(Message.WheelDelta < 0) {
		nSBCode = SB_LINEDOWN;
    }
	else {
    	nSBCode = SB_LINEUP;
    }

    if(mScrollBar->Visible)
		Perform(WM_VSCROLL, MAKELONG(nSBCode, 0), NULL);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::CMMouseLeave(TMessage &Message)
{
	MouseMove(TShiftState(0), -1, -1);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::WMVScroll(TWMScroll &Message)
{
	int minpos, maxpos, page, curpos;

	mScrollBar->GetScrollRange(&minpos, &maxpos);

	page = mScrollBar->GetPageSize();
	curpos = mScrollBar->GetScrollPos();

    switch(Message.ScrollCode) {
	case SB_TOP:
        curpos = minpos;
		break;

	case SB_BOTTOM:
        curpos = maxpos - page + 1;
        break;

	case SB_ENDSCROLL:
        break;

	case SB_LINEUP:
		if(curpos > minpos) {
            curpos--;
		}
        break;

	case SB_LINEDOWN:
		if(curpos < maxpos - page + 1) {
            curpos++;
        }
        break;

	case SB_PAGEUP:
		if(curpos > minpos) {
            curpos = MAX(minpos, curpos - page);
        }
        break;

	case SB_PAGEDOWN:
		if(curpos < maxpos) {
            curpos = MIN(maxpos - page + 1, curpos + page);
        }
        break;

	case SB_THUMBPOSITION:
        curpos = Message.Pos;
        break;

	case SB_THUMBTRACK:
        curpos = Message.Pos;
        break;
	}

    if(Message.ScrollBar != mScrollBar->Handle) {
        mScrollBar->SetPosition(curpos);
    }

	ScrollPos(curpos);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::AfterConstruction()
{
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::CreateWnd()
{
	TPanel::CreateWnd();

	mScrollBar->Parent = this;
	mScrollBar->m_pWndCtrl = this;

	FItemWidth = Width;

	Reset();

	RecalcItemsRect();
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::Paint()
{
	Canvas->Lock();
	for(int Index = 0; Index < this->mItemList->Count; Index++) {
		TProgHandleItem *item = GetItem(Index);

		if(Index >= mBeginIndex && Index < mEndIndex) {
			item->IsHidden = false;

			TRect *Rect = (TRect *) mItemRectList->Items[Index - mBeginIndex];
			item->DrawItem(Canvas, *Rect);
		}
		else {
			item->IsHidden = true;
        }
	}
	Canvas->Unlock();
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
{
	TPanel::MouseDown(Button, Shift, X, Y);
	for(int Index = mBeginIndex; Index < mEndIndex; Index++) {
		TProgHandleItem *item = GetItem(Index);
		item->MouseDown(Button, Shift, X, Y);
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::MouseMove(TShiftState Shift, int X, int Y)
{
	TPanel::MouseMove(Shift, X, Y);
	for(int Index = mBeginIndex; Index < mEndIndex; Index++) {
		TProgHandleItem *item = GetItem(Index);
		item->MouseMove(Shift, X, Y);
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
{
	TPanel::MouseUp(Button, Shift, X, Y);
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::DoItemChange(TObject *Sender)
{
	mItemList->Clear();
	for(int i = 0; i < mTopLevelItemList->Count; i++) {
		TProgHandleItem *Item = GetTopLevelItem(i);
		LoadItem(Item);
	}

	if(HandleAllocated()) {
		Reset();
		Repaint();
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::DoSelectedItem(TObject *Sender)
{
	TProgHandleItem *Item = (TProgHandleItem *)Sender;

	if(mCurrentItem != Sender) {
		if(mCurrentItem)
			mCurrentItem->IsSelected = false;

		mCurrentItem = Item;
	}

	if(FOnSelectedItem) {
		FOnSelectedItem(Sender);
	}
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::DoCurrentItem(TObject *Sender)
{
}
//---------------------------------------------------------------------------
int __fastcall TProgHandlePanel::GetTopLevelItemCount()
{
	return mTopLevelItemList->Count;
}
//---------------------------------------------------------------------------
void __fastcall TProgHandlePanel::SetTextFont(String name, int size)
{
	Canvas->Font->Name = name;
	Canvas->Font->Size = size;
}
//---------------------------------------------------------------------------

