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

#include "ComboBoxComponent.h"

//---------------------------------------------------------------------------
#define CP_ITEM_SLECTED 		    RGB(67, 73, 80)
#define CP_ITEM_UNSLECTED 		    RGB(39, 42, 47)
//---------------------------------------------------------------------------
__fastcall TComboBoxItem::TComboBoxItem(String Caption, TItemClickEvent OnItemClick)
{
    FCaption = Caption;
	FOnItemClick = OnItemClick;
	FTag = 0;
}
//---------------------------------------------------------------------------
void __fastcall TComboBoxItem::DrawItem(TCanvas *Canvas, TRect Rect, bool Selected)
{
	if(Selected)
		Canvas->Brush->Color = CP_ITEM_SLECTED;
	else
        Canvas->Brush->Color = CP_ITEM_UNSLECTED;

    /* 绘制背景 */
    Canvas->FillRect(Rect);

	/* 绘制文字 */
	int var_TextRectTop = Rect.Top + (Rect.Height() - Canvas->TextHeight(FCaption)) / 2;

	TRect var_TextRect(4, var_TextRectTop, Rect.Right - 4, Rect.Bottom);

	Canvas->TextRect(var_TextRect, FCaption);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//#define CP_BORDER 		    RGB(29, 31, 35)
#define CP_BORDER 		    RGB(106, 111, 117)
#define CP_BACKGRND	        RGB(39, 42, 47)

#define CP_BORDER_HL	    RGB(30, 32, 36)
#define CP_BACKGRND_HL	    RGB(67, 73, 80)

#define CP_TXT_NOR          RGB(213, 221, 232)
#define CP_TXT_DISABLE      RGB(100, 108, 119)
#define CP_BREAK		    RGB(100, 108, 119)
#define CP_BOARD_FILL       RGB(76, 82, 91)

#define MIN(x, y)			((x) < (y) ? (x) : (y))
#define MAX(x, y)			((x) > (y) ? (x) : (y))
//---------------------------------------------------------------------------
__fastcall TDropListView::TDropListView(TComponent *Owner) : TWinControl(Owner)
{
	m_Canvas = new TControlCanvas();
    m_Canvas->Control = this;
    m_Canvas->Font->Color = RGB(156, 170, 189);

    m_ItemRectList 	= new TList();
    m_ItemList 		= new TList();

    FOnHide = NULL;
    FOnShow = NULL;

    FItemHeight 	= 16;
    FItemWidth 		= 99;
    FDefItemIndex 	= -1;
    FShowItemsCount = 10;
    DoShowItemsChange();

    m_CurrentItemIndex 	= 0;
    m_RealShowCount 	= 0;

    m_BeginIndex = 0;

    m_ScrollBar = NULL;

    SetDesignVisible(false);
    Ctl3D = false;
    ParentBackground = false;
    ParentBiDiMode = false;
    ParentColor = false;
    ParentCustomHint = false;
    ParentDoubleBuffered = false;
    ParentFont = true;
    ParentShowHint = false;

    CreateScrollBar();
}
//---------------------------------------------------------------------------
__fastcall TDropListView::~TDropListView()
{
	if(m_ItemRectList)
    {
        delete m_ItemRectList;
        m_ItemRectList = NULL;
    }

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

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

	if(m_Canvas)
    {
        delete m_Canvas;
        m_Canvas = NULL;
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::AddItem(TComboBoxItem* Item)
{
    m_ItemList->Add(Item);

    DoItemsCountChange();
}
//---------------------------------------------------------------------------
int __fastcall TDropListView::CalcListHeight()
{
	if(ItemsCount == 0)
    	return 10;
    else
    	return FItemHeight * m_RealShowCount;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::Clear()
{
    m_ItemList->Clear();
    FDefItemIndex = -1;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::CreateParams(TCreateParams &Params)
{
    TWinControl::CreateParams(Params);

    Params.Style = 0;

    Params.Style = WS_POPUP;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::CreateScrollBar()
{
    m_ScrollBar = new TDropListScrollBar(NULL);
    m_ScrollBar->Parent = this;
    m_ScrollBar->Visible = false;
    m_ScrollBar->m_pWndCtrl = this;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::CreateWnd()
{
	TWinControl::CreateWnd();
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::SetFontSize(int sz)
{
	m_Canvas->Font->Size = sz;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::SetFont(String name, int sz)
{
	m_Canvas->Font->Name = name;
	m_Canvas->Font->Size = sz;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::DoItemClicked(int Index)
{
	FDefItemIndex = Index;
	GetItem(FDefItemIndex)->OnItemClicked(GetItem(FDefItemIndex), FDefItemIndex);
    Hide();
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::DoItemsCountChange()
{
    m_RealShowCount = MIN(FShowItemsCount, ItemsCount);

    m_EndIndex = m_BeginIndex + m_RealShowCount;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::DoItemSelect(int Index)
{
    if(Index != m_CurrentItemIndex)
    {
    	/* 还原上一次选中项 */
        if(m_CurrentItemIndex >= m_BeginIndex && m_CurrentItemIndex < m_EndIndex)
        {
            GetItem(m_CurrentItemIndex)->DrawItem(m_Canvas,
                *GetItemRect(m_CurrentItemIndex - m_BeginIndex), false);
        }
        /* 更新当前选择项 */
        m_CurrentItemIndex = Index;
        /* 重绘选中项 */
        GetItem(m_CurrentItemIndex)->DrawItem(m_Canvas,
        	*GetItemRect(m_CurrentItemIndex - m_BeginIndex), true);
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::DoKeyUpDown(int Index)
{
    if(Index < m_BeginIndex)
    {
        int var_eIndex = Index + 1;

        if(var_eIndex < m_RealShowCount)
            ScrollPos(0);
        else
    		ScrollPos(var_eIndex - m_RealShowCount);
    }

    if(Index >= m_EndIndex)
    {
        int var_eIndex = Index + m_RealShowCount;

        if(var_eIndex > ItemsCount)
            ScrollPos(ItemsCount - m_RealShowCount);
        else
    		ScrollPos(var_eIndex - m_RealShowCount);
    }

    DoItemSelect(Index);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::DoShowItemsChange()
{
    m_ItemRectList->Clear();

    for(int i = 0; i < FShowItemsCount; i++)
    {
    	int var_ItemTop = i * FItemHeight;
        int var_ItemBottom = var_ItemTop + FItemHeight;

     	m_ItemRectList->Add(new TRect(1, var_ItemTop + 1, FItemWidth, var_ItemBottom - 1));
    }

    DoItemsCountChange();
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::Hide()
{
    TWinControl::Hide();

    SetActiveWindow(m_pActiveWnd);

    if(FOnHide) FOnHide(this);
}
//---------------------------------------------------------------------------
int __fastcall TDropListView::GetItemsCount()
{
	if(m_ItemList)
    	return m_ItemList->Count;
    else
    	return -1;
}
//---------------------------------------------------------------------------
TComboBoxItem *__fastcall TDropListView::GetItem(int Index)
{
	if(ItemsCount == 0 || Index < 0 || Index > ItemsCount)
    	return NULL;
    else
    	return (TComboBoxItem *)m_ItemList->Items[Index];
}
//---------------------------------------------------------------------------
TRect *__fastcall TDropListView::GetItemRect(int Index)
{
    return (TRect *)m_ItemRectList->Items[Index];
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
{
    TWinControl::MouseDown(Button, Shift, X, Y);

    TRect cl_Rect = GetClientRect();

    if(X >= 0 && X <= cl_Rect.Right && Y >= 0 && Y <= cl_Rect.Bottom && ItemsCount > 0)
    {
    	if(Button == 0 && X < FItemWidth)
        {
            int var_DefItemIndex = Y / FItemHeight + m_BeginIndex;

            if(m_CurrentItemIndex != var_DefItemIndex)
                DoItemSelect(var_DefItemIndex);
            else
            	DoItemClicked(var_DefItemIndex);
        }
    }
    else
    {
        Hide();
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::MouseMove(TShiftState Shift, int X, int Y)
{
    TWinControl::MouseMove(Shift, X, Y);

    if(m_MouseX == X && m_MouseY == Y) return;

    m_MouseX = X;
    m_MouseY = Y;

    TRect var_Rect = GetClientRect();

    if(X >= 0 && X < FItemWidth && Y >= 0 && Y < var_Rect.Bottom && ItemsCount > 0)
    	DoItemSelect(Y / FItemHeight + m_BeginIndex);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
{
    TWinControl::MouseUp(Button, Shift, X, Y);

    TRect cl_Rect = GetClientRect();

    if(X >= 0 && X <= cl_Rect.Right && Y >= 0 && Y <= cl_Rect.Bottom)
    {
    	if(Visible && ItemsCount > 0 && Button == 0 && X < FItemWidth)
        {
            int var_DefItemIndex = Y / FItemHeight + m_BeginIndex;

            if(m_CurrentItemIndex != var_DefItemIndex)
                DoItemSelect(var_DefItemIndex);
            else
            	DoItemClicked(var_DefItemIndex);
        }
    }
    else
    {
        if(Visible) Hide();
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::PaintWindow(HDC DC)
{
	if(ItemsCount == 0) return;

    m_Canvas->Lock();
    for(int Index = m_BeginIndex; Index < m_EndIndex; Index++)
    {
    	int var_ShowIndex = Index - m_BeginIndex;

        if(Index == m_CurrentItemIndex)
        	GetItem(Index)->DrawItem(m_Canvas, *GetItemRect(var_ShowIndex), true);
        else
        	GetItem(Index)->DrawItem(m_Canvas, *GetItemRect(var_ShowIndex), false);
    }
    m_Canvas->Unlock();
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::RemoveItem(int Index)
{
    if(ItemsCount == 0 || Index < 0 || Index > ItemsCount)
    	return;

	if(Index == FDefItemIndex)
    	FDefItemIndex = -1;
    else if(Index > FDefItemIndex)
    	FDefItemIndex--;

    m_ItemList->Delete(Index);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::ScrollPos(int Pos)
{
	if(Pos >= 0 && Pos < ItemsCount)
    {
        int var_bIndex = Pos;
        int var_eIndex = Pos + m_RealShowCount;

        if(var_eIndex > ItemsCount)
        {
            var_eIndex = ItemsCount;
            var_bIndex = var_eIndex - m_RealShowCount;
        }

        if(var_bIndex != m_BeginIndex)
        {
        	m_BeginIndex = var_bIndex;
            m_EndIndex = var_eIndex;

        	PaintWindow(NULL);
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::SetShowItemsCount(int Value)
{
	if(FShowItemsCount != Value)
    {
    	FShowItemsCount = Value;

        DoShowItemsChange();
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::Show()
{
    TWinControl::Show();

    m_pActiveWnd = GetActiveWindow();
    SetActiveWindow(Handle);

    //if(FDefItemIndex == -1)
    	//m_CurrentItemIndex = 0;
    //else
		m_CurrentItemIndex = FDefItemIndex;

    if(m_CurrentItemIndex == -1)
    {
		m_BeginIndex = 0;
		m_EndIndex = m_RealShowCount;
        ScrollPos(0);
	}
    else
	{
		m_BeginIndex = m_CurrentItemIndex;
		m_EndIndex = m_CurrentItemIndex + m_RealShowCount;

		if(m_EndIndex > ItemsCount)
		{
			m_EndIndex = ItemsCount;
			m_BeginIndex = m_EndIndex - m_RealShowCount;
        }

		if(m_CurrentItemIndex < m_BeginIndex || m_CurrentItemIndex >= m_EndIndex)
        {
			int var_eIndex = m_CurrentItemIndex + 1;

			if(var_eIndex < m_RealShowCount)
                ScrollPos(m_BeginIndex);
            else
				ScrollPos(m_EndIndex - m_RealShowCount);
        }
    }

    if(ItemsCount == 0)
    	Height = 10;
    else
    	Height = FItemHeight * m_RealShowCount;

    if(m_ScrollBar)
    {
        m_ScrollBar->Height = Height - 2;
		m_ScrollBar->Left = Width - m_ScrollBar->Width - 1;
		m_ScrollBar->Top = 1;

        if(m_RealShowCount < ItemsCount)
        {
        	m_ScrollBar->Visible = true;
            FItemWidth = m_ScrollBar->Left;
            m_ScrollBar->SetRange(0, ItemsCount - 1);
        	m_ScrollBar->SetPageSize(m_RealShowCount);
        	m_ScrollBar->SetPosition(m_BeginIndex);
            DoShowItemsChange();
        }
        else
        {
        	m_ScrollBar->Visible = false;
            FItemWidth = Width - 1;
            DoShowItemsChange();
        }
    }

    if(FOnShow) FOnShow(this);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMEraseBkgnd(TWMEraseBkgnd &Message)
{
	TCanvas* var_BKCanvas = new TCanvas();
    var_BKCanvas->Handle  = Message.DC;

    TRect var_Rect = GetClientRect();

    var_BKCanvas->Brush->Color = CP_BACKGRND;	// 绘制底色
    var_BKCanvas->FillRect(var_Rect);

    var_BKCanvas->Brush->Color = CP_BORDER;		// 绘制边框
    var_BKCanvas->FrameRect(var_Rect);

    delete var_BKCanvas;
    var_BKCanvas = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMKeyDown(TWMKeyDown &Message)
{
	if(ItemsCount == 0) return;

    if(Message.CharCode ==  VK_UP)
    {
    	int var_Index = m_CurrentItemIndex - 1;
        if(var_Index < 0) var_Index = 0;

        DoKeyUpDown(var_Index);
    }
    else if(Message.CharCode ==  VK_DOWN)
    {
    	int var_Index = m_CurrentItemIndex + 1;
        if(var_Index >= ItemsCount) var_Index = ItemsCount - 1;

        DoKeyUpDown(var_Index);
    }
    else if(Message.CharCode == VK_ESCAPE)
    {
        Hide();
    }
    else if(Message.CharCode == VK_RETURN)
    {
        DoItemClicked(m_CurrentItemIndex);
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMKillFocus(TMessage &Message)
{
    Hide();
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMLButtonDown(TWMLButtonDown &Message)
{
    TWinControl::Dispatch(&Message);

    if(m_ScrollBar)
    {
    }
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMMouseWheel(TWMMouseWheel &Message)
{
	UINT nSBCode;

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

    if(m_ScrollBar->Visible)
    	Perform(WM_VSCROLL, MAKELONG(nSBCode, 0), NULL);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMPaint(TWMPaint &Message)
{
    PaintHandler(Message);
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMSetFocus(TMessage &Message)
{
}
//---------------------------------------------------------------------------
void __fastcall TDropListView::WMVScroll(TWMScroll &Message)
{
    int minpos, maxpos, page, curpos;

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

    page = m_ScrollBar->GetPageSize();
    curpos = m_ScrollBar->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 != m_ScrollBar->Handle)
    {
        m_ScrollBar->SetPosition(curpos);
    }

    ScrollPos(curpos);
}
//---------------------------------------------------------------------------