//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "ListViewMove.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#define LINE_LEN 2

#define LP_ITEM_OVER		RGB(67, 73, 80)
#define LP_ITEM_SELECTED	RGB(0, 0, 0)
#define LP_ITEM_DEF			RGB(39, 42, 47)

#define FontClolor  		TColor(0xBDAA9C)
#define FramColor   	    RGB(23, 23, 23)

static const COLORREF CLR_LINE_D = RGB( 18,  19,  21 ),
					  CLR_LINE_L = RGB( 140, 141, 145 );
//---------------------------------------------------------------------------
__fastcall TListViewMove::TListViewMove(TComponent* Owner)
		: TListViewBase( Owner )
{
	m_LstData = new TList();;

	m_pMovLine = new TBitmap();
	m_pMovLine->SetSize(LINE_LEN, LINE_LEN);
	m_pMovLine->Canvas->Brush->Style = bsClear;
	for( int indexY=0; indexY<LINE_LEN; indexY++ )
	{
		bool bLine = (indexY%2==0)?true:false;
		for( int indexX=0; indexX<LINE_LEN; indexX++ )
		{
			bool bEven = (indexX%2==0)?true:false;
			if(bLine) bEven = !bEven;

			m_pMovLine->Canvas->Pixels[indexX][indexY] =
			(bEven==true)?CLR_LINE_D:CLR_LINE_L;
		}
	}
	m_iSrc = m_iDes = -1;
	m_pMovBmp   = new TBitmap();
	m_pMovPanel = new TPanelDB(this);
	m_pMovPanel->Parent = this;
	m_pMovPanel->OnPaintBKG = DoMovPaint;
	m_pMovPanel->Visible = false;

	RightCellChange = true;
	bMovBottom = false;
}
//---------------------------------------------------------------------------
__fastcall TListViewMove::~TListViewMove()
{
	SAFE_DELETE(m_pMovLine);
	SAFE_DELETE(m_pMovBmp);
	SAFE_DELETE(m_pMovPanel);

	NULL_RETURN(m_LstData)
	for( int i=0; i<m_LstData->Count; i++ ) {

		DATAInfo *pInfo = (DATAInfo *)(m_LstData->Items[i]);
		SAFE_DELETE(pInfo)
	}
	m_LstData->Clear();
	SAFE_DELETE(m_LstData);
}
//---------------------------------------------------------------------------
int __fastcall TListViewMove::DoCellHgt(TTableView *Sender, int index)
{
	return CELL_HEIGHT;
}
//---------------------------------------------------------------------------
int __fastcall TListViewMove::DoMDNum(TTableView *Sender)
{
	NULL_RETURN0(m_LstData)

	return m_LstData->Count;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoDrawBKG(TPanelDB *Sender, TCanvas *pCanvas, TRect rtBKG)
{
	pCanvas->Brush->Color = LP_ITEM_DEF;
	pCanvas->FillRect(rtBKG);
	rtBKG = TRect(0, 0, Sender->Width, Sender->Height);
	pCanvas->Brush->Color = FramColor;
	pCanvas->Pen->Color = FramColor;
	pCanvas->FrameRect(rtBKG);
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoTitle(TTableView *Sender)
{
	TPanelDB *pTitle = new TPanelDB(this);
	pTitle->SetBounds(0, 0, Width, 1);
	pTitle->Color = FramColor;
	return (int)pTitle;
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoBottom(TTableView *Sender)
{
	TPanelDB *pBottom = new TPanelDB(this);
	pBottom->SetBounds(0, Height-1, Width, 1);
	pBottom->Color = FramColor;
	return (int)pBottom;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoCellDraw(TStateBtn *sender, int BsTmp, TRect rtTmp, TCanvas *pCanvas)
{
	NULL_RETURN(sender)

	DATAInfo *pInfo  = (DATAInfo *)sender->m_Data;
	String strCaption = pInfo->caption;
	TSize szFont = pCanvas->TextExtent(strCaption);

	if( Bs_NORMAL==BsTmp ) {
		 pCanvas->Brush->Color = LP_ITEM_DEF;
	}else if( Bs_ENTER==BsTmp ){
		 pCanvas->Brush->Color = LP_ITEM_OVER;
	}else if( Bs_DOWN==BsTmp ){
		 pCanvas->Brush->Color = LP_ITEM_SELECTED;
	}

	if( BsTmp==Bs_ENTER ||
		BsTmp==Bs_DOWN )
	{
		pCanvas->FillRect(rtTmp);
	}
	pCanvas->Brush->Style = bsClear;
	pCanvas->Font->Color = FontClolor;

	//----´¦Àí×Ö·û¹ý³¤------
	int nBorder = 4;
	int nWidth  = m_nCapWidth-nBorder*2;
	if( nWidth>0 ){
		szFont = pCanvas->TextExtent(strCaption);
		if( szFont.Width>nWidth ){
			UnicodeString strShorty = strCaption;
			while( pCanvas->TextWidth( strShorty )>nWidth ){
					strShorty = strShorty.SubString( 1, strShorty.Length()-2 );
			}

			strCaption = strShorty;
			strCaption+="...";
			szFont = pCanvas->TextExtent(strCaption);
		}
		//-----------
		pCanvas->TextOutW( m_nCapLeft+nBorder+(nWidth-szFont.Width)/2,
				rtTmp.Top+(rtTmp.Height()-szFont.Height)/2,
				strCaption);
	}
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoCellData(TStateBtn *sender)
{
	NULL_RETURN0(m_LstData)
	NULL_RETURN0(sender)

	sender->SetData(m_LstData->Items[sender->Index]);
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoCellDBClick(TStateBtn *sender)
{
	NULL_RETURN(sender)

	if(FOnItemDBLClick) {

		DATAInfo *pInfo  = (DATAInfo *)sender->m_Data;
		FOnItemDBLClick(sender->Index, pInfo->bOn);
    }
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoIconDraw(TStateBtn *sender, int BsTmp, TRect rtTmp, TCanvas *pCanvas)
{
	NULL_RETURN(sender)

	TGraphic *pIMG = (TGraphic *)sender->m_Data;
	int iWidth  = pIMG->Width/3;

	int	nTrans  =
		BsTmp==Bs_NORMAL ? 0:
		BsTmp==Bs_ENTER  ? (-iWidth):
		BsTmp==Bs_DOWN   ? (-2*iWidth):(-3*iWidth);

	if( 0==sender->Index ) {
		DATAInfo *pInfo  = (DATAInfo *)(sender->m_PAR->m_Data);
		if( pInfo->bOn ) {
			pIMG = m_pImgOn;
		}
	}

	if( Bs_NORMAL==BsTmp ||
		Bs_ENTER==BsTmp ||
		Bs_DOWN==BsTmp )
	{
		HRGN rgnClip = CreateRectRgn( rtTmp.Left, rtTmp.Top,
			rtTmp.Left+rtTmp.Width(), rtTmp.Top+rtTmp.Height() );

		SelectClipRgn( pCanvas->Handle, rgnClip );
		pCanvas->Draw(rtTmp.Left+nTrans, rtTmp.Top, pIMG);
		SelectClipRgn( pCanvas->Handle, NULL );
		DeleteObject(rgnClip);
	}
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoIconData(TStateBtn *sender)
{
	NULL_RETURN0(sender)

	if( 0==sender->Index ) {
		sender->SetData(m_pImgOff);
	}
	else if(1==sender->Index) {
       	sender->SetData(m_pImgDel);
	}
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoIconsNum(TStateBtn *parent)
{
	return 2;
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoIconsBounds(TStateBtn *sender, TRect &rtBounds)
{
	NULL_RETURN0(sender)

	TGraphic *pTmp = (TGraphic *)sender->m_Data;

	int iLeft, iTop, iWidth, iHeight;
	iWidth  = pTmp->Width/3;
	iHeight = pTmp->Height;
	iTop    = (CELL_HEIGHT-pTmp->Height)/2;
	if( 0==sender->Index ) {
		iLeft   = 5;
		m_nCapLeft = iLeft+iWidth;
	}
	else if(1==sender->Index) {
		iLeft   = m_RtContent.Left + m_RtContent.Width() - pTmp->Width/3 - 5;
		m_nCapWidth = iLeft - m_nCapLeft;
    }

	rtBounds = TRect(iLeft, iTop, iLeft+iWidth, iTop+iHeight);

	return 0;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoIconLClick(TStateBtn *sender)
{
	NULL_RETURN(sender)

	TStateBtn *parent = sender->m_PAR;
	int index = parent->Index;

	DATAInfo *pInfo  = (DATAInfo *)parent->m_Data;
	bool bOn = pInfo->bOn;

	if( 0==sender->Index ) {

		pInfo->bOn = !bOn;
		if(FOnItemStateChange) FOnItemStateChange( index, !bOn );
	}
	else if(1==sender->Index) {

		if(FOnItemDelete && FOnItemDelete( index, -1 ) ) {

			DeleteItem(index);
		}
		else {
			sender->Enter = false;
			sender->Down  = false;
			sender->Paint();
			TRect rt = sender->GetBounds();
			RECT rtInvalid;
			rtInvalid.left = rt.Left;
			rtInvalid.top  = rt.Top;
			rtInvalid.right = rt.Right;
			rtInvalid.left = rt.Bottom;
			InvalidateRect(this->Handle, &rtInvalid, false);
		}
	}
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoClickL(TStateBtn *Sender, TPoint pt)
{
	if(Sender && Sender->m_PAR)
		Sender = Sender->m_PAR;

	m_pMovBmp->SetSize(Sender->Width, Sender->Height);
	StretchBlt(m_pMovBmp->Canvas->Handle,
			   0, 0, Sender->Width, Sender->Height,
			   m_CanvasDr->Handle,
			   Sender->Left, Sender->Top, Sender->Width, Sender->Height,
			   SRCCOPY);
	m_pMovPanel->SetBounds(Sender->Left, Sender->Top, Sender->Width, Sender->Height);

	return 0;
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoClickLP(TStateBtn *Sender, TPoint pt)
{
	if( m_iSrc!=-1 && m_iDes!=-1 ) {

		m_pMovPanel->Visible = false;

		if( OnItemMoveEnd && OnItemMoveEnd( m_iSrc, m_iDes ) ) {

			if( m_iSrc<m_iDes )
				m_iDes -= 1;
			m_LstData->Move(m_iSrc, m_iDes);
			this->IndSel = m_iDes;
			this->ReloadData( GetCellBeg() );
        }
	}

	m_iSrc = m_iDes = -1;
	Screen->Cursor = crDefault;
	bMovBottom = false;

	return 0;
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoMDMOV(TStateBtn *Src, TStateBtn *Des, TPoint pt)
{
	if( Src && NULL!=Src->m_PAR )
		return 0;

	if(Des && Des->m_PAR)
		Des = Des->m_PAR;

	if(Src && Des && (Src!=Des||Src->Index!=IndSel) && PtInRect( m_RtContent, pt ) ) {

		m_iSrc = IndSel;
		m_iDes = Des->Index;
		TRect rtLine;
		rtLine.Left  = Des->Left;
		rtLine.Top   = Des->Top;
		rtLine.Right = Des->Left+Des->Width;
		rtLine.Bottom = Des->Top+LINE_LEN;
		Canvas->Brush->Bitmap = m_pMovLine;
		Canvas->FillRect(rtLine);

		m_pMovPanel->Top = pt.Y;
		m_pMovPanel->Visible = true;

		if( OnItemMoveIng ) {
			if( OnItemMoveIng( m_iSrc, m_iDes ) ) {
				Screen->Cursor = crDrag;
			}
			else {
				Screen->Cursor = crNoDrop;
				m_iDes = -1;
			}
		}
		else {
          	Screen->Cursor = crDrag;
		}
		bMovBottom = false;
	}
	else if( !bMovBottom ){
		m_iDes = -1;
		m_pMovPanel->Visible = false;
		if( -1!=m_iSrc )
			Screen->Cursor = crNoDrop;
		if(!Src && !Des) {
			Screen->Cursor = crDefault;
			m_iSrc = m_iDes = -1;
        }
	}

	return 0;
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoMDBottom(TTableView *Sender)
{
	if( -1!=m_iSrc  )
	{
		TStateBtn *Des = GetCellAds(Count-1);
		if( Des && Des->Index!=IndSel )
		{
			bMovBottom = true;

			m_iSrc = IndSel;
			m_iDes = Des->Index+1;
			TRect rtLine;
			rtLine.Left  = Des->Left;
			rtLine.Top   = Des->Top+Des->Height-LINE_LEN;
			rtLine.Right = Des->Left+Des->Width;
			rtLine.Bottom = rtLine.Top+LINE_LEN;
			Canvas->Brush->Bitmap = m_pMovLine;
			Canvas->FillRect(rtLine);

			m_pMovPanel->Top = Des->Top+Des->Height;
			m_pMovPanel->Visible = true;

			if( OnItemMoveIng ) {
				if( OnItemMoveIng( m_iSrc, m_iDes ) ) {
					Screen->Cursor = crDrag;
				}
				else {
					Screen->Cursor = crNoDrop;
					m_iDes = -1;
				}
			}
			else {
				Screen->Cursor = crDrag;
			}
		}
	}
	return 0;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DoMovPaint(TPanelDB *Sender, TCanvas *pCanvas, TRect rtBKG)
{
	TPanel *panel = (TPanel *)Sender;
	TRect rtThis   = TRect(0, 0, panel->Width, panel->Height);
	SetBkMode( pCanvas->Handle, TRANSPARENT);
	StyleServices()->DrawParentBackground( panel->Handle, pCanvas->Handle, NULL, false, rtThis);

	BLENDFUNCTION BFun;
	BFun.BlendOp              = AC_SRC_OVER;
	BFun.BlendFlags           = 0;
	BFun.SourceConstantAlpha  = 100;
	BFun.AlphaFormat 		  = 0;

	::AlphaBlend( pCanvas->Handle,
		0, 0, rtThis.Width(), rtThis.Height(),
		m_pMovBmp->Canvas->Handle,
		0, 0, m_pMovBmp->Width, m_pMovBmp->Height,
		BFun);
}
//---------------------------------------------------------------------------
int  __fastcall TListViewMove::DoClickR(TStateBtn *Sender, TPoint pt)
{
	NULL_RETURN0(Sender)

	if(FOnItemRightClick && !Sender->m_PAR) {

		DATAInfo *pInfo  = (DATAInfo *)Sender->m_Data;
		FOnItemRightClick(Sender->Index, pInfo->bOn, pt);
	}
	return 0;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::AddIcon(TPngImage *pImgDel, TPngImage *pImgOff, TPngImage *pImgOn)
{
	m_pImgDel    = pImgDel;
	m_pImgOff    = pImgOff;
	m_pImgOn     = pImgOn;
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::AddItem(String caption, bool bOn, bool bPaint, int insertIndex)
{
	NULL_RETURN(m_LstData)

	DATAInfo *pInfo = new DATAInfo(caption, bOn);
	if( insertIndex<0 || insertIndex>m_LstData->Count )
		insertIndex = m_LstData->Count;
	if(0<=insertIndex && insertIndex<=m_LstData->Count )
		m_LstData->Insert(insertIndex, pInfo);

	if( bPaint ) {

		IndSel = insertIndex;
		if( IsCellVisible(insertIndex) )
			ReloadData( GetCellBeg() );
		else
			ReloadData( insertIndex );
	}
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::DeleteItem(int index, bool bPaint)
{
	NULL_RETURN(m_LstData)

	if( 0<=index && index<m_LstData->Count ) {

		DATAInfo *pInfo = (DATAInfo *)(m_LstData->Items[index]);
		SAFE_DELETE(pInfo)
		m_LstData->Delete(index);

		if( bPaint ) {
			IndSel  = NOSET;
			if( IsCellVisible(index) )
				ReloadData( GetCellBeg() );
			else
				ReloadData( index-1 );
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::MoveItems(int srcIndex, int desIndex)
{
	NULL_RETURN(m_LstData)

	if(srcIndex<0) srcIndex = 0;
	else if(srcIndex>=m_LstData->Count ) {
		srcIndex = m_LstData->Count-1;
	}
	if(desIndex<0) desIndex = 0;
	else if(desIndex>=m_LstData->Count ) {
		desIndex = m_LstData->Count-1;
	}

	if( srcIndex==desIndex ) return;

	if( 0<=srcIndex && srcIndex<m_LstData->Count &&
		0<=desIndex && desIndex<m_LstData->Count ) {
		m_LstData->Move(srcIndex, desIndex);
		IndSel = desIndex;
		ReloadData( desIndex );
	}
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::ClearAllItems()
{
	NULL_RETURN(m_LstData)

	for( int i=0; i<m_LstData->Count; i++ ) {

		DATAInfo *pInfo = (DATAInfo *)(m_LstData->Items[i]);
		SAFE_DELETE(pInfo)
	}
	m_LstData->Clear();

	this->ReloadData();
}
//---------------------------------------------------------------------------
void __fastcall TListViewMove::SetItemState(int index, bool bOn, bool bPaint)
{
	if( 0<=index && index<m_LstData->Count ) {

		DATAInfo *pInfo = (DATAInfo *)(m_LstData->Items[index]);
		pInfo->bOn = bOn;

		if( bPaint ) {
			if( IsCellVisible(index) ) ReloadData( GetCellBeg() );
			else                       ReloadData( index );
		}
	}
}
//---------------------------------------------------------------------------
int __fastcall TListViewMove::GetItemState(int index)
{
	if( 0<=index && index<m_LstData->Count ) {
		DATAInfo *pInfo = (DATAInfo *)(m_LstData->Items[index]);
		return pInfo->bOn;
	}
	return -1;
}
//---------------------------------------------------------------------------

