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

#pragma hdrstop

#include "KeyBoard.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

__fastcall TKeyBoard::TKeyBoard(TComponent* Owner)
	: Vcl::Extctrls::TPanel(Owner)
{
	Height = 145;
	Width  = 430;
	Left = 150;
	Top = 500;

	m_pBmpWhiteDDown = new TBitmap();
	m_pBmpWhiteDDown->LoadFromResourceName(int(HInstance), "KBWhiteDDown");
	m_pBmpWhiteLDown = new TBitmap();
	m_pBmpWhiteLDown->LoadFromResourceName(int(HInstance), "KBWhiteLDown");
	m_pBmpWhiteRDown = new TBitmap();
	m_pBmpWhiteRDown->LoadFromResourceName(int(HInstance), "KBWhiteRDown");
	m_pBmpBlackDown = new TBitmap();
	m_pBmpBlackDown->LoadFromResourceName(int(HInstance), "KBBlackDown");
	m_nBlackWidth = m_pBmpBlackDown->Width;
	m_nBlackHeight = m_pBmpBlackDown->Height;
	m_nWhiteWidth = m_pBmpWhiteDDown->Width;
	m_nGroupWidth = m_nWhiteWidth * 7;

	m_aBlackHitTest[0].x1 = 12;
	m_aBlackHitTest[0].iKey = 1;
	m_aBlackHitTest[1].x1 = 32;
	m_aBlackHitTest[1].iKey = 3;
	m_aBlackHitTest[2].x1 = 72;
	m_aBlackHitTest[2].iKey = 6;
	m_aBlackHitTest[3].x1 = 92;
	m_aBlackHitTest[3].iKey = 8;
	m_aBlackHitTest[4].x1 = 112;
	m_aBlackHitTest[4].iKey = 10;

	for (int i = 0; i < 5; i++)
		m_aBlackHitTest[i].x2 = m_aBlackHitTest[i].x1 + m_pBmpBlackDown->Width;

	m_aKey[0].xPos = -1;
	m_aKey[0].pBmp = m_pBmpWhiteRDown;
	m_aKey[1].xPos = 12;
	m_aKey[1].pBmp = m_pBmpBlackDown;
	m_aKey[2].xPos = 19;
	m_aKey[2].pBmp = m_pBmpWhiteDDown;
	m_aKey[3].xPos = 32;
	m_aKey[3].pBmp = m_pBmpBlackDown;
	m_aKey[4].xPos = 39;
	m_aKey[4].pBmp = m_pBmpWhiteLDown;
	m_aKey[5].xPos = 59;
	m_aKey[5].pBmp = m_pBmpWhiteRDown;
	m_aKey[6].xPos = 72;
	m_aKey[6].pBmp = m_pBmpBlackDown;
	m_aKey[7].xPos = 79;
	m_aKey[7].pBmp = m_pBmpWhiteDDown;
	m_aKey[8].xPos = 92;
	m_aKey[8].pBmp = m_pBmpBlackDown;
	m_aKey[9].xPos = 99;
	m_aKey[9].pBmp = m_pBmpWhiteDDown;
	m_aKey[10].xPos = 112;
	m_aKey[10].pBmp = m_pBmpBlackDown;
	m_aKey[11].xPos = 119;
	m_aKey[11].pBmp = m_pBmpWhiteLDown;

	m_iPressGroup = m_iPressKey = -1;

	//背景
	m_ImgBrk = new TPngImage();
	m_ImgBrk->LoadFromResourceName(int(HInstance), "KeyBoard");

	m_imgKeyboard = new TImage(this);
	m_imgKeyboard->Parent = this;
	m_imgKeyboard->Picture->Assign(m_ImgBrk);
	m_imgKeyboard->Left = 0;
	m_imgKeyboard->Top = 0;
	m_imgKeyboard->Width = Width;
	m_imgKeyboard->Height = Height;

	m_imgKeyboard->Visible = true;

	//PaintBox
	m_pbKeyboard = new TPaintBox(this);
	m_pbKeyboard->Parent = this;
	m_pbKeyboard->Left = 6;
	m_pbKeyboard->Top = 19;			// Will be Change!
	m_pbKeyboard->Width = 420;
	m_pbKeyboard->Height = 121;
	m_pbKeyboard->OnPaint = KeyboardPaint;
	m_pbKeyboard->OnMouseDown = KeyboardMouseDown;
	m_pbKeyboard->OnMouseEnter = KeyboardMouseEnter;
	m_pbKeyboard->OnMouseLeave = KeyboardMouseLeave;
	m_pbKeyboard->OnMouseMove = KeyboardMouseMove;
	m_pbKeyboard->OnMouseUp = KeyboardMouseUp;
	m_pbKeyboard->Visible = true;

	//PNG Close
	m_ImgClose = new TPngImage();
	m_ImgClose->LoadFromResourceName(int(HInstance), "imgClose");

	m_PngClose = new TPNGButton(this);
	m_PngClose->Parent = this;
	m_PngClose->OnClick = CloseClick;
	m_PngClose->ImgStates = 3;
	m_PngClose->PngImg = m_ImgClose;
	m_PngClose->Top = 0;
	m_PngClose->Left = Width - 23;
    m_PngClose->Visible = true;
}

__fastcall TKeyBoard::~TKeyBoard()
{
	delete m_PngClose;
	m_PngClose = NULL;

	delete m_imgKeyboard;
	m_imgKeyboard = NULL;

	delete m_pbKeyboard;
	m_pbKeyboard = NULL;

	delete m_pBmpWhiteDDown;
	m_pBmpWhiteDDown = NULL;

	delete m_pBmpWhiteLDown;
	m_pBmpWhiteLDown = NULL;

	delete m_pBmpWhiteRDown;
	m_pBmpWhiteRDown = NULL;

	delete m_pBmpBlackDown;
	m_pBmpBlackDown = NULL;

	delete m_imgFirst;
	m_imgFirst = NULL;

	delete m_imgSecond;
	m_imgSecond = NULL;

	delete m_imgThird;
	m_imgThird = NULL;

	delete m_imgForth;
	m_imgForth = NULL;

	delete m_ImgClose;          //关闭
	m_ImgClose = NULL;

	delete m_ImgBrk;            //钢琴背景
	m_ImgBrk = NULL;
}

// 模拟键盘相关
int TKeyBoard::KeyboardGetPressKey(int X, int Y) {
	short iPressKey = -1, iPressGroup = X / m_nGroupWidth;
	int xInGroup = X % m_nGroupWidth;

	int iWhite = xInGroup / m_nWhiteWidth;
	if (iWhite < 3)
		iPressKey = iWhite * 2;
	else
		iPressKey = iWhite * 2 - 1;

	if (Y < m_nBlackHeight) {
		for (int i = 0; i < 5; i++) {
			if (xInGroup >= m_aBlackHitTest[i].x1 && xInGroup <
				m_aBlackHitTest[i].x2) {
				iPressKey = m_aBlackHitTest[i].iKey;
				break;
			}
		}
	}

	return MAKELONG(iPressKey, iPressGroup);
}


void __fastcall TKeyBoard::KeyboardPaint(TObject *Sender)
{
	//
	if (m_bKeyDown) {
		int xPos = m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos;
		m_pbKeyboard->Canvas->Draw(xPos, 0, m_aKey[m_iPressKey].pBmp);
	}
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::KeyboardMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
	//mouseup
	if (Button == mbLeft && m_bKeyDown) {
		m_bKeyDown = false;

		f_MM_RealTimeMIDINoteOff(m_iPressGroup*12 + m_iPressKey + 48);

		TRect rect;
		rect.init(m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 6,
					19,
					m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 26,
					m_pbKeyboard->Height+19);

		m_iPressGroup = m_iPressKey = -1;

		InvalidateRect(m_pbKeyboard->Parent->Handle,&rect,true);
//		m_pbKeyboard->Invalidate();
	}
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::KeyboardMouseMove(TObject *Sender, TShiftState Shift, int X,
          int Y)
{
	if (m_bKeyDown && X >= 0 && Y >= 0 && X < m_pbKeyboard->Width && Y <
		m_pbKeyboard->Height) {
		int iKey = KeyboardGetPressKey(X, Y);
		int iPressGroup = HIWORD(iKey);
		int iPressKey = LOWORD(iKey);

		if (iPressGroup != m_iPressGroup || iPressKey != m_iPressKey) {
			HRESULT hRet = f_MM_RealTimeMIDINoteOff(m_iPressGroup * 12 + m_iPressKey + 48);
			hRet = f_MM_RealTimeMIDINoteOn( iPressGroup * 12 + iPressKey + 48);

            TRect rect;

			//更新原来区域
			rect.init(m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 6,
					19,
					m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 26,
					m_pbKeyboard->Height+19);

			InvalidateRect(m_pbKeyboard->Parent->Handle,&rect,true);

			m_iPressGroup = iPressGroup;
			m_iPressKey = iPressKey;

			//更新新区域
			rect.init(m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 6,
					19,
					m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 26,
					m_pbKeyboard->Height+19);

			InvalidateRect(m_pbKeyboard->Parent->Handle,&rect,true);

//			m_pbKeyboard->Invalidate();
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::KeyboardMouseLeave(TObject *Sender)
{
   //
   Screen->Cursor = crDefault;
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::KeyboardMouseEnter(TObject *Sender)
{
	//
	Screen->Cursor = crHandPoint;
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::KeyboardMouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
   //	TMouseButton Button, TShiftState Shift, int X, int Y) {
	if (Sender == m_pbKeyboard && Button == mbLeft) {
		m_bKeyDown = true;

		int iKey = KeyboardGetPressKey(X, Y);
		int iPressGroup = HIWORD(iKey);
		int iPressKey = LOWORD(iKey);

		if (iPressGroup != m_iPressGroup || iPressKey != m_iPressKey) {
			m_iPressGroup = iPressGroup;
			m_iPressKey = iPressKey;

			HRESULT hRet =
				f_MM_RealTimeMIDINoteOn(m_iPressGroup * 12 + m_iPressKey + 48);

			TRect rect;
			rect.init(m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 6,
					19,
					m_iPressGroup * m_nGroupWidth + m_aKey[m_iPressKey].xPos + 26,
					m_pbKeyboard->Height+19);

			InvalidateRect(m_pbKeyboard->Parent->Handle,&rect,true);
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TKeyBoard::ShowKeyboard( bool bShow )
{
	if( bShow ){
		// 创建模拟键盘设备
		HRESULT hResult = f_MM_CreateRealTimeMIDIStream( false );
		if (hResult != S_OK) {
			DebugPrint("Create realtime midi stream error.\n");
		}
		else{
			this->Show();
		}
	}
	else if( !bShow ){
		this->Hide();

		// 释放模拟键盘设备
		HRESULT hResult = f_MM_FreeRealTimeMIDIStream();
		if (hResult != S_OK) {
			DebugPrint("Free realtime midi stream error.\n");
		}
	}
}

void __fastcall TKeyBoard::CloseClick(System::TObject* Sender)
{
//   	ShowKeyboard( false );
		Application->MainForm->Perform(	UM_SHOW_KB, NULL, NULL );
}
