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

#include <vcl.h>
#pragma hdrstop

#include "VolumeFormUnit.h"
#include "GlobalUnit.h"
#include "Undo.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
//#pragma link "GeneralDialogPanel"
#pragma link "SkinTrackBar"
#pragma link "LineEdit"

#pragma resource "*.dfm"
TVolumeForm *VolumeForm;

#define    PLAY_TYPE		0x00
#define   INPUT_TYPE		0x01
#define COMPOSE_TYPE		0x04
#define   VOICE_TYPE		0x10

#define FramColor		TColor(0xAA9C91)
#define BkColor			TColor(0x453F3A)
#define GroupFrame      TColor(0x322F2B)
//---------------------------------------------------------------------------

__fastcall TVolumeForm::TVolumeForm(TComponent* Owner)
	: TForm(Owner)
{
	m_pTimer = NULL;
	m_bRecording = false;
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::DoFormMouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
	if(X <= 0 || Y <= 0 || X >= Width || Y >= Height)
    {
        ModalResult = mrCancel;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::DoFormShow(TObject *Sender)
{
    TPoint clientPos = ScreenToClient(Mouse->CursorPos);

	if(clientPos.X > 0 && clientPos.Y > 0 &&
		clientPos.X < Width && clientPos.Y < Height)
    {
    	m_IsMouseOver = true;
        MouseCapture = false;
    }
	else
    {
        m_IsMouseOver = false;
		MouseCapture = true;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::CMMouseEnter(TMessage &Message)
{
	TPoint clientPos = ScreenToClient(Mouse->CursorPos);

	if(clientPos.X >= 0 && clientPos.Y >= 0 &&
		clientPos.X <= Width && clientPos.Y <= Height && !m_IsMouseOver)
	{
    	m_IsMouseOver = true;

        if(MouseCapture)
        	MouseCapture = false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::CMMouseLeave(TMessage &Message)
{
	TPoint clientPos = ScreenToClient(Mouse->CursorPos);

    if(clientPos.X <= 0 || clientPos.Y <= 0 ||
    	clientPos.X >= Width || clientPos.Y >= Height)
    {
    	m_IsMouseOver = false;

        if(!MouseCapture)
			MouseCapture = true;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::WMKillFocus(TWMKillFocus &Message)
{
    if(!m_IsMouseOver)
    	ModalResult = mrCancel;
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::OnMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
		  int X, int Y)
{
	if(X < 0 || Y < 0 || X > Width || Y > Height)
	{
		ModalResult = mrCancel;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::MouseMove(TShiftState Shift, int X, int Y)
{
	if(MouseCapture && X > 0 && X < Width && Y > 0 && Y < Height)
    {
		m_IsMouseOver = true;
        if(MouseCapture)
			MouseCapture = false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
	switch( Key ){
	case VK_RETURN:
		ModalResult = mrOk;
		break;

	case VK_ESCAPE:
		ModalResult = mrCancel;
		break;

	case 'Z':
		if( !m_bRecording && Shift.Contains( ssCtrl ) && !m_pTimer ){
			int iType = -1;
			if( Shift.Contains( ssShift ) ){
				iType = g_Undo.GetRedoType();

				if( iType==UNDO_VOLUME )
					Undo( false );
			}
			else{
				iType = g_Undo.GetUndoType();

				if( iType==UNDO_VOLUME )
					Undo( true );
			}

			if( iType>UNDO_VOLUME )
				ModalResult = mrCancel;
		}

		break;
	}
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::WMEraseBkgnd(Winapi::Messages::TWMEraseBkgnd &Message)
{
	TRect rect = GetClientRect();
	TRect rectFill = rect;

	TCanvas* tempCanvas = new TCanvas;
	tempCanvas->Handle = Message.DC;

	//»æÖÆµ×É«
	tempCanvas->Brush->Color = TColor(0x004D4641);
	tempCanvas->FillRect( rectFill );

	tempCanvas->Brush->Color = FramColor;
	tempCanvas->FrameRect( rect );

	tempCanvas->Pen->Color = GroupFrame;
	tempCanvas->Brush->Color = BkColor;
	tempCanvas->RoundRect(10, 10, 110, Height - 10, 5, 5);

	tempCanvas->MoveTo(60, 15);
	tempCanvas->LineTo(60, Height - 15);

	int nTB = m_aTracks.size();
	if( nTB>0 ){
		int w = 14*2 + nTB * 20 + (nTB-1)* 32;
		tempCanvas->RoundRect(115, 10, w+115, Height - 10, 5, 5);

		int l = 115 + 14 + 20 + 16;
		for( int i=1; i<nTB; i++ ){
			tempCanvas->MoveTo(l, 15);
			tempCanvas->LineTo(l, Height - 15);
			l += 20 + 32;
		}
    }

	delete tempCanvas;

	Message.Result = true;
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::FormCreate(TObject *Sender)
{
	m_InputTrackBar->Position	= (int)( (double)g_fRecordVolume * 100 + 0.5 );
	m_InputTrackBar->OnChange = DoVolumeChanged;
	m_ShowInput->Caption = IntToStr( m_InputTrackBar->Position );

	m_PlayTrackBar->Position	= (int)( (double)g_fSpeakerVolume * 100 + 0.5 );
	m_PlayTrackBar->OnChange = DoVolumeChanged;
	m_ShowPlay->Caption = IntToStr( m_PlayTrackBar->Position );

	int lPos = 129;
	if( g_lstOpusStages.size()>0 ){
		TSkinTrackBar* pTB = new TSkinTrackBar( this );
		pTB->Orientation = false;
		pTB->Parent = this;
		pTB->Tag = COMPOSE_TYPE;
		pTB->SetBounds( lPos, 34, 20, 150 );
		pTB->Position = (int)( (double)g_fMusicVolume * 100 + 0.5 );
		pTB->Enabled = !g_bComposeMute;
		pTB->OnChange = DoVolumeChanged;
		m_aTracks.push_back( pTB );

		TCKBox* pCB = new TCKBox(this);
		pCB->Parent = this;
		pCB->Caption = "";
		pCB->SetBounds( lPos-2, 184, 24, 16 );
		pCB->Checked = !g_bComposeMute;
//		pCB->Hint = "Õý³£/¾²Òô";
//		pCB->ShowHint = true;
		pCB->OnChange = DoTrackMute;
		m_aChecks.push_back( pCB );

		TLabel* pLB = new TLabel(this);
		pLB->Parent = this;
		pLB->AutoSize = false;
		pLB->Caption = IntToStr( pTB->Position );
		pLB->Alignment = taCenter;
		pLB->SetBounds( lPos-6, 15, 30, 13 );
		m_aLabels.push_back( pLB );

		pLB = new TLabel(this);
		pLB->Parent = this;
		pLB->AutoSize = false;
		pLB->Caption = "°é×à";
		pLB->Alignment = taCenter;
		pLB->SetBounds( lPos-1, 209, 24, 14 );
		m_aLabels.push_back( pLB );

		lPos += 20 + 32;
	}

	if( g_aAudioTracks.size()>1 ){
		for( int i=1; i<g_aAudioTracks.size(); i++ ){
			TSkinTrackBar* pTB = new TSkinTrackBar( this );
			pTB->Orientation = false;
			pTB->Parent = this;
			pTB->Tag = VOICE_TYPE + i;
			pTB->SetBounds( lPos, 34, 20, 150 );
			pTB->Position = (int)( g_aAudioTracks[i]->volume );
			pTB->Enabled = !g_aAudioTracks[i]->IsMute();
			pTB->OnChange = DoVolumeChanged;
			m_aTracks.push_back( pTB );

			TCKBox* pCB = new TCKBox(this);
			pCB->Parent = this;
			pCB->Caption = "";
			pCB->SetBounds( lPos-2, 184, 24, 16 );
			pCB->Checked = !g_aAudioTracks[i]->IsMute();
			pCB->OnChange = DoTrackMute;
			m_aChecks.push_back( pCB );

			TLabel* pLB = new TLabel(this);
			pLB->Parent = this;
			pLB->AutoSize = false;
			pLB->Caption = IntToStr( pTB->Position );
			pLB->Alignment = taCenter;
			pLB->SetBounds( lPos-6, 15, 30, 13 );
			m_aLabels.push_back( pLB );

			pLB = new TLabel(this);
			pLB->Parent = this;
			pLB->AutoSize = false;
			pLB->Caption = "Òô¹ì" + IntToStr( i );
			pLB->Alignment = taCenter;
			pLB->SetBounds( lPos-6, 209, 32, 14 );
			m_aLabels.push_back( pLB );

			lPos += 20 + 32;
		}
	}
	else if( g_aAudioTracks[0]->lstBars.size()>0 ){
		TSkinTrackBar* pTB = new TSkinTrackBar( this );
		pTB->Orientation = false;
		pTB->Parent = this;
		pTB->Tag = VOICE_TYPE;
		pTB->SetBounds( lPos, 34, 20, 150 );
		pTB->Position = (int)( g_aAudioTracks[0]->volume );
		pTB->Enabled = !g_aAudioTracks[0]->IsMute();
		pTB->OnChange = DoVolumeChanged;
		m_aTracks.push_back( pTB );

		TCKBox* pCB = new TCKBox(this);
		pCB->Parent = this;
		pCB->Caption = "";
		pCB->SetBounds( lPos-2, 184, 24, 16 );
		pCB->Checked = !g_aAudioTracks[0]->IsMute();
		pCB->OnChange = DoTrackMute;
		m_aChecks.push_back( pCB );

		TLabel* pLB = new TLabel(this);
		pLB->Parent = this;
		pLB->AutoSize = false;
		pLB->Caption = IntToStr( pTB->Position );
		pLB->Alignment = taCenter;
		pLB->SetBounds( lPos-6, 15, 30, 13 );
		m_aLabels.push_back( pLB );

		pLB = new TLabel(this);
		pLB->Parent = this;
		pLB->AutoSize = false;
		pLB->Caption = "Òô¹ì" + IntToStr( 1 );
		pLB->Alignment = taCenter;
		pLB->SetBounds( lPos-6, 209, 32, 14 );
		m_aLabels.push_back( pLB );
	}

	int nTB = m_aTracks.size();
	if( nTB>0 ){
		Width += 5 + 14*2 + nTB * 20 + (nTB-1)* 32;
	}

	SetTransparent( this );
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::FormDestroy(TObject *Sender)
{
	for( int i=0; i<m_aTracks.size(); i++ ){
		delete m_aTracks[i];
		delete m_aChecks[i];
		delete m_aLabels[i*2];
		delete m_aLabels[i*2+1];
	}

	if( m_pTimer ){
		if( m_pTimer->Enabled ){
			TimerProc( m_pTimer );
		}
		else{
			delete m_pTimer;
			m_pTimer = NULL;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::DoVolumeChanged(TObject *Sender)
{
	TSkinTrackBar* pTB = (TSkinTrackBar*)Sender;
	TLabel* pVLB = NULL;

	float fVol =  pTB->Position / 100.0;

	if( pTB->Tag<VOICE_TYPE )
		f_MM_SetStreamVolume( pTB->Tag, fVol );

	if( pTB->Tag==PLAY_TYPE ){
		g_fSpeakerVolume = fVol;
		pVLB = m_ShowPlay;
	}
	else if( pTB->Tag==INPUT_TYPE ){
		g_fRecordVolume = fVol;
		pVLB = m_ShowInput;
	}
	else{
		int iUndoCode = pTB->Tag;
		int volBefore = 0, volAfter = pTB->Position;

		if( pTB->Tag==COMPOSE_TYPE ){

			volBefore = (int)( (double)g_fMusicVolume * 100 + 0.5 );
			g_fMusicVolume = fVol;

			pVLB = m_aLabels[0];
		}
		else{
			int iTrack = pTB->Tag & 0x0F;

			if( !IsTrackMute( ST_AUDIO, iTrack ) )
				f_MM_SetAudioTrackParam( iTrack, 0, fVol );

			volBefore = g_aAudioTracks[iTrack]->volume;
			g_aAudioTracks[iTrack]->volume = pTB->Position;

			for( int i=0; i<m_aTracks.size(); i++ ){
				if( m_aTracks[i]==pTB ){
					pVLB = m_aLabels[i*2];
					break;
				}
			}

			PostMessage( Application->MainFormHandle, UM_AUDIOVOLCHANGED, iTrack, 0 );
		}

		bool bAddUndo = true;

		TUndoLite* pLite = g_Undo.GetLastLite();
		if( pLite && pLite->iType==UNDO_VOLUME && pLite->iCode==iUndoCode
							&& (int)pLite->pBefore>=0 && (int)pLite->pAfter>=0 ){
			bAddUndo = false;
			if( (int)pLite->pBefore==volAfter ){
				g_Undo.CancelUndo();
			}
			else{
				pLite->pAfter = (void*)volAfter;
			}
		}

		if( bAddUndo ){
			g_Undo.AddUndo( UNDO_VOLUME, iUndoCode, 0, 0,
										(void*)volBefore, (void*)volAfter );
		}
	}

	if( pVLB )
		pVLB->Caption = String((int)(pTB->Position));
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::DoTrackMute(TObject *Sender)
{
	for( int i=0; i<m_aChecks.size(); i++ ){
		if( m_aChecks[i]==Sender ){
			bool bNoMute = m_aChecks[i]->Checked;
			float fVol = bNoMute ?  m_aTracks[i]->Position / 100.0 : 0;
			int volBefore, volAfter;

			m_aTracks[i]->Enabled = bNoMute;

			if( m_aTracks[i]->Tag==COMPOSE_TYPE ){
				g_bComposeMute = !bNoMute;
				f_MM_SetStreamVolume( m_aTracks[i]->Tag, fVol );

				volBefore = bNoMute ? -1 : m_aTracks[i]->Position,
				volAfter = bNoMute ? m_aTracks[i]->Position : -1;
			}
			else{
				int iTrack = m_aTracks[i]->Tag & 0x0F;
				bool bSet = false, bUnset = false;

				ChangeTrackState( ST_AUDIO, iTrack, TRACK_MUTE, bSet, bUnset );
				PostMessage( Application->MainFormHandle, UM_AUDIOVOLCHANGED, iTrack,
														MAKELONG( TRACK_MUTE, bUnset ) );

				volBefore = bNoMute ? -1 : bUnset,
				volAfter = bNoMute ? bUnset : -1;
			}

			bool bAddUndo = true;
			TUndoLite* pLite = g_Undo.GetLastLite();

			if( pLite && pLite->iType==UNDO_VOLUME && pLite->iCode==m_aTracks[i]->Tag
													&& (int)pLite->pBefore==volAfter
													&& (int)pLite->pAfter==volBefore ){
				g_Undo.CancelUndo();
 				bAddUndo = false;
			}

			if( bAddUndo ){
				g_Undo.AddUndo( UNDO_VOLUME, m_aTracks[i]->Tag, 0, 0,
												(void*)volBefore, (void*)volAfter );
			}

			break;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::TimerProc(TObject* Sender)
{
	if( m_pTimer ){
		m_pTimer->Enabled = false;

		Undo( m_pTimer->Tag );

		delete m_pTimer;
		m_pTimer = NULL;
	}
}
//---------------------------------------------------------------------------

int __fastcall TVolumeForm::ShowUndo( bool bUndo )
{
	if( !m_pTimer ){
		m_pTimer = new TTimer(this);
		m_pTimer->OnTimer = TimerProc;
		m_pTimer->Interval = 100;
		m_pTimer->Tag = bUndo ? 1 : 0;
		m_pTimer->Enabled = true;
	}

	return ShowModal();
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::OnRecord( bool bRecord )
{
	m_bRecording = bRecord;

	int nTB = m_aTracks.size();
	if( nTB>0 ){
		for( int i=0; i<nTB; i++ ){
			m_aTracks[i]->Enabled = !bRecord && m_aChecks[i]->Checked;
			m_aChecks[i]->Enabled = !bRecord;
		}
	}
}
//---------------------------------------------------------------------------

void TVolumeForm::Undo( bool bUndo )
{
	TUndoLite* pLite = bUndo ? g_Undo.Undo() : g_Undo.Redo();
	int volSet = (int)( bUndo ? pLite->pBefore : pLite->pAfter );
	bool bMuted = (int)pLite->pBefore < 0 || (int)pLite->pAfter < 0;

	TSkinTrackBar* pTB = NULL;
	TLabel* pVLB = NULL;
	TCKBox* pCB = NULL;

	if( pLite->iCode==COMPOSE_TYPE ){
		pTB = m_aTracks[0];
		pVLB = m_aLabels[0];
		pCB = m_aChecks[0];
	}
	else{
		for( int i=0; i<m_aTracks.size(); i++ ){
			if( m_aTracks[i]->Tag==pLite->iCode ){
				pTB = m_aTracks[i];
				pVLB = m_aLabels[i*2];
				pCB = m_aChecks[i];
				break;
			}
		}
	}

	pTB->Enabled = volSet>=0;
	pCB->OnChange = NULL;
	pCB->Checked = volSet>=0;
	pCB->OnChange = DoTrackMute;

	if( bMuted ){
		if( pLite->iCode==COMPOSE_TYPE ){
			g_bComposeMute = volSet<0;
			f_MM_SetStreamVolume( pLite->iCode, volSet<0 ? 0 : volSet / 100.0 );
		}
		else{
			int iTrack = pLite->iCode & 0x0F;
			bool bSolo = volSet>0;
			int iState = bSolo ? TRACK_SOLO : TRACK_MUTE;
			bool bSet = false, bUnset = false;

			ChangeTrackState( ST_AUDIO, iTrack, iState, bSet, bUnset );
			PostMessage( Application->MainFormHandle, UM_AUDIOVOLCHANGED, iTrack,
													MAKELONG( iState, bUnset ) );
		}
	}
	else if( volSet>=0 ){
		float fVol =  volSet / 100.0;

		if( pLite->iCode==COMPOSE_TYPE ){
			g_fMusicVolume = fVol;
			f_MM_SetStreamVolume( pLite->iCode, fVol );
		}
		else{
			int iTrack = pTB->Tag & 0x0F;
			bool bStateChange = g_aAudioTracks[iTrack]->IsMute();

			if( bStateChange ){
				g_aAudioTracks[iTrack]->Mute(false);
			}
			else{
				if( !IsTrackMute( ST_AUDIO, iTrack ) )
					f_MM_SetAudioTrackParam( iTrack, 0, fVol );

				g_aAudioTracks[iTrack]->volume = volSet;
				PostMessage( Application->MainFormHandle, UM_AUDIOVOLCHANGED, iTrack, 0 );
			}
		}

		pTB->OnChange = NULL;
		pTB->Position = volSet;
		pTB->OnChange = DoVolumeChanged;

		pVLB->Caption = String(IntToStr(volSet));
	}
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::FormClose(TObject *Sender, TCloseAction &Action)
{
	PostMessage( Application->MainForm->Handle, UM_SHOW_VOLSET, 0, 0 );
}
//---------------------------------------------------------------------------

void __fastcall TVolumeForm::ChangeRecordVol()
{
	m_InputTrackBar->OnChange = NULL;
	m_InputTrackBar->Position = (int)( (double)g_fRecordVolume * 100 + 0.5 );
	m_InputTrackBar->OnChange = DoVolumeChanged;
	m_ShowInput->Caption = IntToStr( m_InputTrackBar->Position );
}
//---------------------------------------------------------------------------

