/*
    CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
    Copyright (C) 2014-2015 by Frédéric Coste

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <vcl.h>
#pragma hdrstop
#include "TFormDebugger.h"
#include "TFormMain.h"
#include "TFormZ80Editor.h"
#include "TFormMemoryEditor.h"
#include "..\..\Common\Z80DASM\z80dasm.h"


//=================================
// Options

//=================================


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

static const AnsiString cTitle = "Execute";
static const AnsiString cTitlePaused = " - [PAUSED]";
static const AnsiString cTitlePlaying = " - [Playing]";
static const AnsiString cTitleRunning = " - [Running]";

TFormDebugger *FormDebugger;
//---------------------------------------------------------------------------
__fastcall TFormDebugger::TFormDebugger(TComponent* Owner)
				: TForm(Owner)
{
	mSettingsP = NULL;

	mCurrentPC = BREAKPOINT_INVALID;
	mCurrentMemoryRead = BREAKPOINT_INVALID;
	mCurrentMemoryWrite = BREAKPOINT_INVALID;
	mBreakpointsList = new TList;
	mStepOUTbreakpoint.Address = BREAKPOINT_INVALID;

	mFormEditValue = new TFormEditValue(this);

	PageControlData->ActivePage = TabSheetTime;

	// Apply theme
	Font->Name = "Amstrad CPC464 Regular";
	Font->Size = 6;
	PanelBreakpointAddress->Font->Color = clBlack;
	PanelBreakpointUpperROMIndex->Font->Color = clBlack;

	StringGridBreakpoints->Visible = false;
	StringGridBreakpoints->DefaultDrawing = false;
	StringGridBreakpoints->Canvas->Font = Font;
	StringGridBreakpoints->ColCount = 4;
	StringGridBreakpoints->ColWidths[0] = 16;
	StringGridBreakpoints->ColWidths[1] = 50;
	StringGridBreakpoints->ColWidths[2] = 100;
	StringGridBreakpoints->ColWidths[3] = StringGridBreakpoints->Width -
				(StringGridBreakpoints->ColWidths[0]+StringGridBreakpoints->ColWidths[1]+StringGridBreakpoints->ColWidths[2]);

	GroupBoxSelectedBreakpoint->Visible = false;

	PanelButtonShowInstruction->Visible = false;
	PanelButtonShowMemory->Visible = false;
	PanelButtonShowPC->Visible = false;

	PanelButtonBreakpointsUseNone->Visible = false;
	PanelButtonBreakpointsUseAll->Visible = false;
	PanelButtonBreakpointsDel->Visible = false;
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::FormShow(TObject *Sender)
{
  if (FormMain == NULL)
  {
    Close();
    return;
  }

	FormMain->OnDebuggerFormShow();

  mTimerLastPause = 0;
  LabelTimeFromResetS->Caption = "";
  LabelTimeFromResetUS->Caption = "";
  LabelTimeFromLastPauseMS->Caption = "";
  LabelTimeFromLastPauseUS->Caption = "";

  mPaused = false;
  mPauseRequested = false;
  mStepByStep = false;
  mRunTillVBL = false;
	mRunTillHBL = false;
	mPausedByBreakpoint = false;

  FormMain->SubscribeToCPCEvents(OnCPCEvent);

  UpdateControls(FormMain->EmulatorP->Paused,
								 FormMain->EmulatorP->StepByStepActive);
	Caption = Title;

	if (mSettingsP)
	{
		mSettingsP->DebuggerFormVisible = true;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::FormDestroy(TObject *Sender)
{
  delete mFormEditValue;

	if (mBreakpointsList != NULL)
  {
		while (mBreakpointsList->Count)
    {
			delete (TEmulatorBreakpoint*)mBreakpointsList->Items[0];
			mBreakpointsList->Delete(0);
    }

		delete mBreakpointsList;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::FormHide(TObject *Sender)
{
	// Unsubscribe to step by step event
	if (FormMain != NULL)
	{
		FormMain->UnsubscribeToCPCEvents(OnCPCEvent);
		FormMain->OnDebuggerFormHide();
	}

	if (mSettingsP)
	{
		mSettingsP->DebuggerFormVisible = false;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


AnsiString __fastcall TFormDebugger::GetTitle(void)
{
  AnsiString Title = cTitle;
  if (mPaused == true) { Title += cTitlePaused; }
  else if (mStepByStep == true) { Title += cTitlePlaying; }
  else { Title += cTitleRunning; }
  
 return Title;
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::SetSettings(TSettings* Value)
{
  mSettingsP = Value;
  mFormEditValue->Settings = mSettingsP;

  if (    (mSettingsP->DebuggerFormLeft != 0)
       || (mSettingsP->DebuggerFormTop != 0)
			 || (mSettingsP->DebuggerFormWidth != 0)
			 || (mSettingsP->DebuggerFormHeight != 0) )
	{
		Position = poDesigned;
		Left = mSettingsP->DebuggerFormLeft;
		Top = mSettingsP->DebuggerFormTop;
		Width = mSettingsP->DebuggerFormWidth;
    Height = mSettingsP->DebuggerFormHeight;
  }

  // Apply theme
  Color = mSettingsP->ThemeBackgroundColor;
  Font->Color = mSettingsP->ThemeText1Color;
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name.Pos("PanelButton") == 1)
    {
      ((TPanel*)Components[Loop])->Color = mSettingsP->ThemeButtonColor;
      ((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeButtonTextColor;
    }
    else if ( (Components[Loop]->Name.Pos("LabelTitle") == 1)
							|| (Components[Loop]->Name.Pos("LabelTime") == 1) )
    {
      ((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
    }
		else if (Components[Loop]->Name.Pos("GroupBox") == 1)
		{
			((TGroupBox*)Components[Loop])->Font->Color = mSettingsP->ThemeText2Color;
		}

  	// Refresh display
		if ( (Visible == true) && (((TControl*)Components[Loop])->Visible == true) )
		{
			((TControl*)Components[Loop])->Invalidate();
		}
	}

	if (mSettingsP->HideAll == false)
  {
    Visible = mSettingsP->DebuggerFormVisible;
  }
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::FormResize(TObject *Sender)
{
  if ( (Visible == true) && (mSettingsP) )
  {
    mSettingsP->DebuggerFormWidth = Width;
    mSettingsP->DebuggerFormHeight = Height;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormDebugger::WMMove(TMessage &Message)
{
  if ( (Visible == true) && (mSettingsP) )
  {
    mSettingsP->DebuggerFormLeft = Left;
    mSettingsP->DebuggerFormTop = Top;
  }

	NOT_USED(Message);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::Step(void)
{
	if (PanelButtonStep->Visible == true)
	{
		PanelButtonStepClick(NULL);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonStepClick(TObject *Sender)
{
	mRunTillVBL = false;
	mRunTillHBL = false;

	mPauseRequested = true;
	FormMain->ResumeStepByStep(OnCPCEvent);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::Next(void)
{
	if (PanelButtonStepOUT->Visible == true)
	{
		PanelButtonStepOUTClick(NULL);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonStepOUTClick(TObject *Sender)
{
TZ80dasmParam Z80dasmParam;

	memset(&Z80dasmParam, 0, sizeof(TZ80dasmParam));
	Z80dasmParam.NativeCPC = FormMain->NativeCPC;
	Z80dasmParam.ReadFunction = Engine_ReadBankedRead;

	tULong PC = FormMain->NativeCPC->Z80->Regs.PC.ULong;

	mStepOUTbreakpoint.Address = Z80dasmDecodeInstruction(PC, &Z80dasmParam);
	mStepOUTbreakpoint.LowerROM = (FormMain->NativeCPC->GateArray->ROM_config & 0x04) ? false : true;
	mStepOUTbreakpoint.UpperROM = (FormMain->NativeCPC->GateArray->ROM_config & 0x08) ? false : true;
	mStepOUTbreakpoint.UpperROMIndex = FormMain->NativeCPC->GateArray->upper_ROM;

	FillBreakpoints();

	// Simulate click on RUN
	PanelButtonRunClick(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::Play(void)
{
	if (PanelButtonPlay->Visible == true)
	{
		PanelButtonPlayClick(NULL);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonPlayClick(TObject *Sender)
{
	mRunTillVBL = false;
	mRunTillHBL = false;

	if (PanelButtonPlay->Caption == "Play")
	{
		FormMain->ResumeStepByStep(OnCPCEvent);
	}
	else
	{
		FormMain->StopStepByStep(false);
		mPauseRequested = true;
		FormMain->Pause(true);
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::Run(void)
{
	FormMain->StopStepByStep(false);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonRunClick(TObject *Sender)
{
	mRunTillVBL = false;
	mRunTillHBL = false;

	FormMain->StopStepByStep(false);

	if (PanelButtonRun->Caption == "Run")
	{
	}
	else
	{
		mPauseRequested = true;
		FormMain->Pause(true);
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonPlayTillVBLClick(TObject *Sender)
{
  mRunTillVBL = true;
  mRunTillHBL = false;

  mPreviousVBL = Engine_IsVideoVBL(FormMain->EmulatorP->NativeCPC);
  FormMain->ResumeStepByStep(OnCPCEvent);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonPlayTillHBLClick(TObject *Sender)
{
  mRunTillVBL = false;
  mRunTillHBL = true;

  mPreviousHBL = Engine_IsVideoHBL(FormMain->EmulatorP->NativeCPC);
  FormMain->ResumeStepByStep(OnCPCEvent);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::UpdateControls(bool Pause, bool StepByStep)
{
  if (StepByStep == true)
  {
		PanelButtonStep->Visible = Pause;
		PanelButtonStepOUT->Visible = Pause;
		PanelButtonPlay->Visible = true;
		PanelButtonPlay->Caption = (Pause == false) ? "Pause" : "Play";
		PanelButtonRun->Caption = "Run";

	}
	else
	{
		PanelButtonStep->Visible = Pause;
		PanelButtonStepOUT->Visible = Pause;
		PanelButtonPlay->Visible = Pause;
		PanelButtonPlay->Caption = "Play";
		PanelButtonRun->Caption = (Pause == false) ? "Pause" : "Run";
	}

	UpdateBreakpointsGUI(Pause);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::UpdateTimes(void)
{
	// Display times
	tTimer TimerFromReset = FormMain->EmulatorP->NativeCPC->timer_from_reset;

	if (mTimerLastPause != TimerFromReset)
	{
		LabelTimeFromResetS->Caption = ((TimerFromReset / 4) / 1000000);
		LabelTimeFromResetUS->Caption = (TimerFromReset / 4);

		if (mTimerLastPause > TimerFromReset)
		{
			LabelTimeFromLastPauseMS->Caption = "";
			LabelTimeFromLastPauseUS->Caption = "";
			mTimerLastPause = 0;
		}

		if (mTimerLastPause != 0)
		{
      LabelTimeFromLastPauseMS->Caption = (((TimerFromReset - mTimerLastPause) / 4) / 1000);
      LabelTimeFromLastPauseUS->Caption = ((TimerFromReset - mTimerLastPause) / 4);
		}
    mTimerLastPause = TimerFromReset;
  }
}
//---------------------------------------------------------------------------


bool __fastcall TFormDebugger::OnCPCEvent(tULong Condition, tNativeCPC* NativeCPC)
{
  bool Pause = NativeCPC->paused;
  bool StepByStep = NativeCPC->step_by_step;

  if (mPauseRequested == true)
  {
    Pause = true;
		mPauseRequested = false;
	}


	if (Condition & EC_BREAKPOINT)
	{
		// Update breakpoint display
		mCurrentPC = NativeCPC->Z80->Regs.PC.ULong;
		mCurrentPPC = NativeCPC->Z80->Regs.PrevPC.ULong;
		mCurrentMemoryRead = NativeCPC->memread_addr;
		mCurrentMemoryWrite = NativeCPC->memwrite_addr;
		mCurrentLowerROM = (NativeCPC->GateArray->ROM_config & 0x04) ? false : true;
		mCurrentUpperROM = (NativeCPC->GateArray->ROM_config & 0x08) ? false : true;
		mCurrentUpperROMIndex = NativeCPC->GateArray->upper_ROM;

		if ( (mCurrentPC == mStepOUTbreakpoint.Address)
				 && (mCurrentLowerROM == mStepOUTbreakpoint.LowerROM)
				 && (mCurrentUpperROM == mStepOUTbreakpoint.UpperROM)
				 && (mCurrentUpperROMIndex == mStepOUTbreakpoint.UpperROMIndex) )
		{
			mStepOUTbreakpoint.Address = BREAKPOINT_INVALID;
		}

		StringGridBreakpoints->Invalidate();
		SelectActiveBreakpoint();
		UpdateBreakpointPanel();

		mPausedByBreakpoint = true;
		Pause = true;
	}
	else if ( (mCurrentPC != NativeCPC->Z80->Regs.PC.ULong)
						&& (mPausedByBreakpoint == true) )
	{
		mPausedByBreakpoint = false;
		mCurrentPC = BREAKPOINT_INVALID;
		mCurrentMemoryRead = BREAKPOINT_INVALID;
		mCurrentMemoryWrite = BREAKPOINT_INVALID;
		StringGridBreakpoints->Invalidate();
		SelectActiveBreakpoint();
		UpdateBreakpointPanel();
	}

	if ( (Pause != mPaused) || (StepByStep != mStepByStep) )
	{
		UpdateControls(Pause, StepByStep);

		mPaused = Pause;
		mStepByStep = StepByStep;
		Caption = Title;
	}


	if ((Condition & EC_END_INSTRUCTION) == 0)
		return Pause;

  // Check and Update VBL
  if (mRunTillVBL == true)
  {
    bool CurrentVBL = Engine_IsVideoVBL(NativeCPC);
    if (mPreviousVBL != CurrentVBL)
		{
      if (CurrentVBL == true)
      {
        mRunTillVBL = false;
        Pause = true;
      }

      mPreviousVBL = CurrentVBL;
		}
  }

  // Check and Update HBL
  if (mRunTillHBL == true)
  {
    bool CurrentHBL = Engine_IsVideoHBL(NativeCPC);
    if (mPreviousHBL != CurrentHBL)
    {
      if (CurrentHBL == true)
      {
        mRunTillHBL = false;
        Pause = true;
			}

      mPreviousHBL = CurrentHBL;
    }
  }

  if (Pause == true)
  {
    UpdateTimes();
  }

	NOT_USED(Condition);

	return Pause;
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonMouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
  ((TPanel*)Sender)->Color = mSettingsP->ThemeButtonTextColor;
  ((TPanel*)Sender)->Font->Color = mSettingsP->ThemeButtonColor;

  NOT_USED(Button);
  NOT_USED(Shift);
  NOT_USED(X);
  NOT_USED(Y);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonMouseUp(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
  ((TPanel*)Sender)->Color = mSettingsP->ThemeButtonColor;
  ((TPanel*)Sender)->Font->Color = mSettingsP->ThemeButtonTextColor;

  NOT_USED(Button);
  NOT_USED(Shift);
  NOT_USED(X);
  NOT_USED(Y);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PageControlDataDrawTab(TCustomTabControl *Control,
          int TabIndex, const TRect &Rect, bool Active)
{
	TCanvas* Canvas = PageControlData->Canvas;

  if (Active == true)
  {
    Canvas->Font->Color = mSettingsP->ThemeText2Color;
  }

  // Get sheet corresponding to TabIndex
  int TabCount=0;
  TTabSheet* Sheet = NULL;
	for (int Loop=0; Loop < PageControlData->PageCount; Loop++)
  {
		if (PageControlData->Pages[Loop]->TabVisible == true)
		{
      if (TabCount == TabIndex)
      {
        Sheet = PageControlData->Pages[Loop];
        break;
      }

      TabCount++;
    }
  }

  // Draw tab
  Canvas->FillRect(Rect);
  AnsiString Text = Sheet->Caption;
  int TextWidth = Canvas->TextWidth(Text);
  int TextHeight = Canvas->TextHeight(Text);
  int TextPosX = (Rect.Width() - TextWidth) / 2;
  int TextPosY = (PageControlData->TabHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+TextPosX, Rect.Top+TextPosY, Text);

  NOT_USED(Control);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::StringGridBreakpointsDrawCell(TObject *Sender, int ACol,
          int ARow, TRect &Rect, TGridDrawState State)
{
	TStringGrid* StringGrid = (TStringGrid*)Sender;

	TEmulatorBreakpoint* CurrentBreakpointP = NULL;
	if (ARow < mBreakpointsList->Count)
	{
		CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[ARow];
	}

	if ( (ACol == 0) && (CurrentBreakpointP != NULL) )
	{
		if (CurrentBreakpointP->Enable == false)
		{
			StringGrid->Canvas->Brush->Color = Color;
		}
		else if ( (CurrentBreakpointP->Address == mCurrentPC)
							|| (CurrentBreakpointP->Address == mCurrentMemoryRead)
							|| (CurrentBreakpointP->Address == mCurrentMemoryWrite) )
		{
			StringGrid->Canvas->Brush->Color = clRed;
		}
		else if (CurrentBreakpointP->Enable == true)
		{
			StringGrid->Canvas->Brush->Color = mSettingsP->ThemeText2Color;
		}
	}
	else if ( (State.Contains(gdSelected)) && (StringGrid->Enabled == true) )
	{
		StringGrid->Canvas->Brush->Color = clHighlight;
		StringGrid->Canvas->Font->Color = clWhite;
	}
	else if (ACol == 1)
	{
		StringGrid->Canvas->Brush->Color = Color;
		StringGrid->Canvas->Font->Color = mSettingsP->ThemeText2Color;
	}
	else
	{
		StringGrid->Canvas->Brush->Color = Color;
		StringGrid->Canvas->Font->Color = mSettingsP->ThemeText1Color;
	}

  // Draw cell
	StringGrid->Canvas->FillRect(Rect);
	if (ACol == 0)
	{
		StringGrid->Canvas->Brush->Color = Color;
		StringGrid->Canvas->FrameRect(Rect);
	}
	AnsiString Content = StringGrid->Cells[ACol][ARow];
	if (Content.Length() > 0)
	{
		int TextHeight = StringGrid->Canvas->TextHeight(Content);
		int TextPos = (StringGrid->RowHeights[ARow] - TextHeight) / 2;
		StringGrid->Canvas->TextOut(Rect.Left+5,
															Rect.Top+TextPos,
															Content);
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonBreakpointsUseNoneClick(TObject *Sender)
{
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];
		CurrentBreakpointP->Enable = false;
	}

	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
	SelectBreakpoint(StringGridBreakpoints->Row);
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonBreakpointsUseAllClick(TObject *Sender)
{
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];
		CurrentBreakpointP->Enable = true;
	}

	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
	SelectBreakpoint(StringGridBreakpoints->Row);
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::UpdateBreakpointsGUI(bool Pause)
{
	bool GUIVisible = (mBreakpointsList->Count > 0) ? true : false;

	PanelButtonBreakpointsUseNone->Visible = GUIVisible;
	PanelButtonBreakpointsUseAll->Visible = GUIVisible;
	PanelButtonBreakpointsDel->Visible = GUIVisible;

	GroupBoxSelectedBreakpoint->Visible = GUIVisible;

	PanelButtonShowInstruction->Visible = (mBreakpointsList->Count > 0) ? Pause : false;
	PanelButtonShowMemory->Visible = (mBreakpointsList->Count > 0) ? Pause : false;

	bool AllowShowPC = false;
	if ( (mBreakpointsList->Count > 0) && (Pause == true) )
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];
		if ( (CurrentBreakpointP->Address == mCurrentMemoryRead)
				 || (CurrentBreakpointP->Address == mCurrentMemoryWrite) )
		{
			AllowShowPC = true;
		}
	}
	PanelButtonShowPC->Visible = AllowShowPC;
	UpdateBreakpointPanel();
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonBreakpointsAddClick(TObject *Sender)
{
tZ80* Z80 = FormMain->NativeCPC->Z80;

	AddBreakpointPC(_PC, true);
	ActiveControl = StringGridBreakpoints;

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormDebugger::PanelButtonBreakpointsAddPPCClick(TObject *Sender)
{
tZ80* Z80 = FormMain->NativeCPC->Z80;

	AddBreakpointPC(_PrevPC, true);
	ActiveControl = StringGridBreakpoints;

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonBreakpointsDelClick(TObject *Sender)
{
	DeleteBreakpoint((TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row]);

	if (mBreakpointsList->Count)
	{
		ActiveControl = StringGridBreakpoints;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::AddBreakpointPC(tULong Address, bool Use)
{
	tGateArray* GateArray = FormMain->NativeCPC->GateArray;
	TEmulatorBreakpoint Breakpoint;
	Breakpoint.Address = Address;
	Breakpoint.LowerROM = false;
	Breakpoint.UpperROM = false;
	Breakpoint.UpperROMIndex = GateArray->upper_ROM;

	// Lower ROM active
	if ( (Address < 0x4000)
			 && (!(GateArray->ROM_config & 0x04)) )
	{
		Breakpoint.LowerROM = true;
	}
	// Upper ROM Active
	else if ( (Address >= 0xc000) && (Address <= 0xffff)
						&& (!(GateArray->ROM_config & 0x08)) )
	{
		Breakpoint.UpperROM = true;
	}

	AddBreakpointPC(Breakpoint, Use);
}
//---------------------------------------------------------------------------
void __fastcall TFormDebugger::AddBreakpointPC(TEmulatorBreakpoint Breakpoint, bool Use)
{
	Visible = true;
	PageControlData->ActivePage = TabSheetBreakpoints;

	TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
	NewBreakpointP->Enable = Use;
	NewBreakpointP->Address = Breakpoint.Address;
	NewBreakpointP->LowerROM = Breakpoint.LowerROM;
	NewBreakpointP->UpperROM = Breakpoint.UpperROM;
	NewBreakpointP->UpperROMIndex = Breakpoint.UpperROMIndex;
	NewBreakpointP->PC = true;
	NewBreakpointP->MemoryRead = false;
	NewBreakpointP->MemoryWrite = false;

	if (AddBreakpoint(NewBreakpointP) == false)
	{
		delete NewBreakpointP;
	}

	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::AddBreakpointMem(tULong Address, bool Use, bool Read, bool Write)
{
	tGateArray* GateArray = FormMain->NativeCPC->GateArray;
	TEmulatorBreakpoint Breakpoint;
	Breakpoint.Address = Address;
	Breakpoint.LowerROM = false;
	Breakpoint.UpperROM = false;
	Breakpoint.UpperROMIndex = GateArray->upper_ROM;
	Breakpoint.MemoryRead = Read;
	Breakpoint.MemoryWrite = Write;

	// Lower ROM active
	if ( (Address < 0x4000)
			 && (!(GateArray->ROM_config & 0x04)) )
	{
		Breakpoint.LowerROM = true;
	}
	// Upper ROM Active
	else if ( (Address >= 0xc000) && (Address <= 0xffff)
						&& (!(GateArray->ROM_config & 0x08)) )
	{
		Breakpoint.UpperROM = true;
	}

	AddBreakpointMem(Breakpoint, Use);
}
//---------------------------------------------------------------------------
void __fastcall TFormDebugger::AddBreakpointMem(TEmulatorBreakpoint Breakpoint, bool Use)
{
	// Breakpoing valid
	if ( (Breakpoint.MemoryRead == false) && (Breakpoint.MemoryWrite == false) )
		return;

	Visible = true;
	PageControlData->ActivePage = TabSheetBreakpoints;

	TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
	NewBreakpointP->Enable = Use;
	NewBreakpointP->Address = Breakpoint.Address;
	NewBreakpointP->LowerROM = Breakpoint.LowerROM;
	NewBreakpointP->UpperROM = Breakpoint.UpperROM;
	NewBreakpointP->UpperROMIndex = Breakpoint.UpperROMIndex;
	NewBreakpointP->PC = false;
	NewBreakpointP->MemoryRead = Breakpoint.MemoryRead;
	NewBreakpointP->MemoryWrite = Breakpoint.MemoryWrite;

	if (AddBreakpoint(NewBreakpointP) == false)
	{
		delete NewBreakpointP;
	}

	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
}
//---------------------------------------------------------------------------


bool __fastcall TFormDebugger::AddBreakpoint(TEmulatorBreakpoint* NewBreakpointP)
{
	bool Added = false;

	int NewBreakpointIndex = mBreakpointsList->Count;
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];
		if (CurrentBreakpointP->Address >= NewBreakpointP->Address)
		{
			NewBreakpointIndex = Loop;
			break;
		}
	}

	if (NewBreakpointIndex < mBreakpointsList->Count)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[NewBreakpointIndex];
		if ( (CurrentBreakpointP->Address == NewBreakpointP->Address)
				 && (CurrentBreakpointP->LowerROM == NewBreakpointP->LowerROM)
				 && (CurrentBreakpointP->UpperROM == NewBreakpointP->UpperROM)
				 && (CurrentBreakpointP->UpperROMIndex == NewBreakpointP->UpperROMIndex) )
		{
			//
			// Update breakpoint
			//
			if (NewBreakpointP->PC == true)
			{
				CurrentBreakpointP->MemoryRead = false;
				CurrentBreakpointP->MemoryWrite = false;
			}
			else
			{
				CurrentBreakpointP->PC = false;
				if (NewBreakpointP->MemoryRead == true)
				{
					CurrentBreakpointP->MemoryRead = true;
				}
				if (NewBreakpointP->MemoryWrite == true)
				{
					CurrentBreakpointP->MemoryWrite = true;
				}
			}
		}
		else
		{
			// Insert breakpoint
			mBreakpointsList->Insert(NewBreakpointIndex, (void*)NewBreakpointP);
			Added = true;
		}
	}
	else
	{
		// Add new breakpoint at the end of the list
		mBreakpointsList->Add((void*)NewBreakpointP);
		Added = true;
	}

	FillBreakpoints();

	// Select breakpoint
	StringGridBreakpoints->Row = NewBreakpointIndex;
	SelectBreakpoint(NewBreakpointIndex);

	return (Added);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::DeleteBreakpoint(TEmulatorBreakpoint* BreakpointP)
{
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];

		if (CurrentBreakpointP == BreakpointP)
		{
			delete CurrentBreakpointP;
			mBreakpointsList->Delete(Loop);
			break;
		}
	}

	// select previous breakpoint
	if (StringGridBreakpoints->Row > 0)
	{
		StringGridBreakpoints->Row--;
	}

	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
	FillBreakpoints();

	if (mBreakpointsList->Count)
	{
		SelectBreakpoint(StringGridBreakpoints->Row);
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::SelectActiveBreakpoint()
{
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];

		if (CurrentBreakpointP->Address == mCurrentPC)
		{
			StringGridBreakpoints->Row = Loop;
			StringGridBreakpoints->Cells[3][Loop] = "";
		}
		else if ( (CurrentBreakpointP->Address == mCurrentMemoryRead)
							|| (CurrentBreakpointP->Address == mCurrentMemoryWrite) )
		{
			StringGridBreakpoints->Row = Loop;
			StringGridBreakpoints->Cells[3][Loop] = "PC=&" +AnsiString::IntToHex(mCurrentPPC, 4);
		}
		else
		{
			StringGridBreakpoints->Cells[3][Loop] = "";
		}
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::FillBreakpoints(void)
{
	if (mBreakpointsList->Count == 0)
	{
		for (int Loop=0; Loop < StringGridBreakpoints->RowCount; Loop++)
		{
			StringGridBreakpoints->Rows[Loop]->Clear();
		}
		StringGridBreakpoints->Visible = false;
	}
	else
	{
		StringGridBreakpoints->Visible = true;

		StringGridBreakpoints->RowCount = mBreakpointsList->Count;
		for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
		{
			TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];

			StringGridBreakpoints->Rows[Loop]->BeginUpdate();
			StringGridBreakpoints->Rows[Loop]->Clear();
			StringGridBreakpoints->Cells[1][Loop] = AnsiString::IntToHex(CurrentBreakpointP->Address, 4) + ":";
			AnsiString Mode;
			if (CurrentBreakpointP->PC == true)
			{
				Mode += "PC";
			}
			else
			{
				if (CurrentBreakpointP->MemoryRead == true)
				{
					Mode += "R";
				}
				if (CurrentBreakpointP->MemoryWrite == true)
				{
					if (Mode.Length() > 0) Mode += "+";
					Mode += "W";
				}
			}
			if (CurrentBreakpointP->LowerROM == true)
			{
				Mode += " LO";
			}
			else if (CurrentBreakpointP->UpperROM == true)
			{
				Mode += " UP" + AnsiString::IntToHex(CurrentBreakpointP->UpperROMIndex, 2);
			}

			StringGridBreakpoints->Cells[2][Loop] = Mode;
			StringGridBreakpoints->Rows[Loop]->EndUpdate();
		}
	}

	StringGridBreakpoints->Invalidate();

	int NbBreakpoints = mBreakpointsList->Count;
	if (mStepOUTbreakpoint.Address != BREAKPOINT_INVALID) NbBreakpoints++;

	TEmulatorBreakpoint* BreakpointsListP = new TEmulatorBreakpoint[NbBreakpoints];

	if (BreakpointsListP)
	{
		for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
		{
			TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];
			BreakpointsListP[Loop].Address = CurrentBreakpointP->Address;
			BreakpointsListP[Loop].Enable = CurrentBreakpointP->Enable;
			BreakpointsListP[Loop].PC = CurrentBreakpointP->PC;
			BreakpointsListP[Loop].MemoryRead = CurrentBreakpointP->MemoryRead;
			BreakpointsListP[Loop].MemoryWrite = CurrentBreakpointP->MemoryWrite;
			BreakpointsListP[Loop].LowerROM = CurrentBreakpointP->LowerROM;
			BreakpointsListP[Loop].UpperROM = CurrentBreakpointP->UpperROM;
			BreakpointsListP[Loop].UpperROMIndex = CurrentBreakpointP->UpperROMIndex;
		}

		// Add STEP OUT
		if (mStepOUTbreakpoint.Address != BREAKPOINT_INVALID)
		{
			BreakpointsListP[NbBreakpoints-1].Address = mStepOUTbreakpoint.Address;
			BreakpointsListP[NbBreakpoints-1].Enable = true;
			BreakpointsListP[NbBreakpoints-1].PC = true;
			BreakpointsListP[NbBreakpoints-1].MemoryRead = false;
			BreakpointsListP[NbBreakpoints-1].MemoryWrite = false;
			BreakpointsListP[NbBreakpoints-1].LowerROM = mStepOUTbreakpoint.LowerROM;
			BreakpointsListP[NbBreakpoints-1].UpperROM = mStepOUTbreakpoint.UpperROM;
			BreakpointsListP[NbBreakpoints-1].UpperROMIndex = mStepOUTbreakpoint.UpperROMIndex;
		}
	}

	// Update emulator breakpoints.
	FormMain->EmulatorP->UseBreakpoints(BreakpointsListP, NbBreakpoints);

	delete [] BreakpointsListP;
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::StringGridBreakpointsSelectCell(TObject *Sender, int ACol,
					int ARow, bool &CanSelect)
{
	if (ARow >= mBreakpointsList->Count)
	{
		CanSelect = false;
	}

	NOT_USED(Sender);
	NOT_USED(ACol);
	NOT_USED(ARow);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::StringGridBreakpointsClick(TObject *Sender)
{
	SelectBreakpoint(StringGridBreakpoints->Row);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelCheckUseBreakpointClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	// Invert breakpoint enable/disable
	CurrentBreakpointP->Enable = (CurrentBreakpointP->Enable == true) ? false : true;

	UpdateBreakpointPanel();
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelBreakpointAddressClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	mFormEditValue->Title = "Breakpoint address";
	mFormEditValue->CurrentValue = CurrentBreakpointP->Address;
	mFormEditValue->Hexadecimal = true;
	mFormEditValue->MinValue = 0;
	mFormEditValue->MaxValue = 65535; // Max Z80 addressing range
	if (mFormEditValue->ShowModal() == mrOk)
	{
		tULong NewAddress = (tULong)mFormEditValue->NewValue;
		if (NewAddress != CurrentBreakpointP->Address)
		{
			TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
			NewBreakpointP->Enable = CurrentBreakpointP->Enable;
			NewBreakpointP->Address = NewAddress;
			NewBreakpointP->PC = CurrentBreakpointP->PC;
			NewBreakpointP->MemoryRead = CurrentBreakpointP->MemoryRead;
			NewBreakpointP->MemoryWrite = CurrentBreakpointP->MemoryWrite;
			NewBreakpointP->LowerROM = CurrentBreakpointP->LowerROM;
			if (NewAddress >= 0x4000) NewBreakpointP->LowerROM = false;
			NewBreakpointP->UpperROM = CurrentBreakpointP->UpperROM;
			if (NewAddress < 0xC000) NewBreakpointP->UpperROM = false;
			NewBreakpointP->UpperROMIndex = CurrentBreakpointP->UpperROMIndex;

			// Delete selected breakpoing
			DeleteBreakpoint(CurrentBreakpointP);
			// Add breakpoint at new address
			if (AddBreakpoint(NewBreakpointP) == false)
			{
				delete NewBreakpointP;
			}

			//SelectBreakpoint(NewAddress);
			UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
		}
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelCheckBreakpointReadClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->MemoryRead == false)
	{
		CurrentBreakpointP->MemoryRead = true;
		CurrentBreakpointP->PC = false;
	}
	else if ( (CurrentBreakpointP->MemoryRead == true) && 	(CurrentBreakpointP->MemoryWrite == true) )
	{
		CurrentBreakpointP->MemoryRead = false;
		CurrentBreakpointP->PC = false;
	}

	UpdateBreakpointPanel();
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelCheckBreakpointWriteClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->MemoryWrite == false)
	{
		if ( (CurrentBreakpointP->LowerROM == false) && (CurrentBreakpointP->UpperROM == false) )
		{
			CurrentBreakpointP->MemoryWrite = true;
			CurrentBreakpointP->PC = false;
		}
	}
	else if ( (CurrentBreakpointP->MemoryWrite == true) && 	(CurrentBreakpointP->MemoryRead == true) )
	{
		CurrentBreakpointP->MemoryWrite = false;
		CurrentBreakpointP->PC = false;
	}

	UpdateBreakpointPanel();
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelCheckBreakpointPCClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->PC == false)
	{
		CurrentBreakpointP->PC = true;
		CurrentBreakpointP->MemoryRead = false;
		CurrentBreakpointP->MemoryWrite = false;
	}

	UpdateBreakpointPanel();
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelCheckLowerROMClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->LowerROM == true)
	{
		CurrentBreakpointP->LowerROM = false;
	}
	else if (CurrentBreakpointP->Address < 0x4000)
	{
		CurrentBreakpointP->LowerROM = true;
	}

	TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
	NewBreakpointP->Enable = CurrentBreakpointP->Enable;
	NewBreakpointP->Address = CurrentBreakpointP->Address;
	NewBreakpointP->PC = CurrentBreakpointP->PC;
	NewBreakpointP->MemoryRead = CurrentBreakpointP->MemoryRead;
	NewBreakpointP->MemoryWrite = CurrentBreakpointP->MemoryWrite;
	NewBreakpointP->LowerROM = CurrentBreakpointP->LowerROM;
	NewBreakpointP->UpperROM = CurrentBreakpointP->UpperROM;
	NewBreakpointP->UpperROMIndex = CurrentBreakpointP->UpperROMIndex;

	// Delete selected breakpoing
	DeleteBreakpoint(CurrentBreakpointP);
	// Add breakpoint at new address
	if (AddBreakpoint(NewBreakpointP) == false)
	{
		delete NewBreakpointP;
	}

	//SelectBreakpoint(NewAddress);
	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelCheckUpperROMClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->UpperROM == true)
	{
		CurrentBreakpointP->UpperROM = false;
		PanelBreakpointUpperROMIndex->Visible = false;
	}
	else if ( (CurrentBreakpointP->Address >= 0xc000) && (CurrentBreakpointP->Address <= 0xffff) )
	{
		CurrentBreakpointP->UpperROM = true;
		PanelBreakpointUpperROMIndex->Visible = true;
		PanelBreakpointUpperROMIndex->Caption = AnsiString::IntToHex(CurrentBreakpointP->UpperROMIndex, 2);
	}

	TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
	NewBreakpointP->Enable = CurrentBreakpointP->Enable;
	NewBreakpointP->Address = CurrentBreakpointP->Address;
	NewBreakpointP->PC = CurrentBreakpointP->PC;
	NewBreakpointP->MemoryRead = CurrentBreakpointP->MemoryRead;
	NewBreakpointP->MemoryWrite = CurrentBreakpointP->MemoryWrite;
	NewBreakpointP->LowerROM = CurrentBreakpointP->LowerROM;
	NewBreakpointP->UpperROM = CurrentBreakpointP->UpperROM;
	NewBreakpointP->UpperROMIndex = CurrentBreakpointP->UpperROMIndex;

	// Delete selected breakpoing
	DeleteBreakpoint(CurrentBreakpointP);
	// Add breakpoint at new address
	if (AddBreakpoint(NewBreakpointP) == false)
	{
		delete NewBreakpointP;
	}

	//SelectBreakpoint(NewAddress);
	UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
	FillBreakpoints();

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelBreakpointUpperROMIndexClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	mFormEditValue->Title = "Upper ROM index";
	mFormEditValue->CurrentValue = CurrentBreakpointP->UpperROMIndex;
	mFormEditValue->Hexadecimal = true;
	mFormEditValue->MinValue = 0;
	mFormEditValue->MaxValue = 255;
	if (mFormEditValue->ShowModal() == mrOk)
	{
		// Update Upper ROM index
		CurrentBreakpointP->UpperROMIndex = mFormEditValue->NewValue;
		PanelBreakpointUpperROMIndex->Caption = AnsiString::IntToHex(CurrentBreakpointP->UpperROMIndex, 2);

		TEmulatorBreakpoint* NewBreakpointP = new TEmulatorBreakpoint;
		NewBreakpointP->Enable = CurrentBreakpointP->Enable;
		NewBreakpointP->Address = CurrentBreakpointP->Address;
		NewBreakpointP->PC = CurrentBreakpointP->PC;
		NewBreakpointP->MemoryRead = CurrentBreakpointP->MemoryRead;
		NewBreakpointP->MemoryWrite = CurrentBreakpointP->MemoryWrite;
		NewBreakpointP->LowerROM = CurrentBreakpointP->LowerROM;
		NewBreakpointP->UpperROM = CurrentBreakpointP->UpperROM;
		NewBreakpointP->UpperROMIndex = CurrentBreakpointP->UpperROMIndex;

		// Delete selected breakpoing
		DeleteBreakpoint(CurrentBreakpointP);
		// Add breakpoint at new address
		if (AddBreakpoint(NewBreakpointP) == false)
		{
			delete NewBreakpointP;
		}

		//SelectBreakpoint(NewAddress);
		UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
		FillBreakpoints();
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::UpdateBreakpointPanel(void)
{
	if (GroupBoxSelectedBreakpoint->Visible == false) return;

	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];

	if (CurrentBreakpointP->Enable == true)
	{
		PanelCheckUseBreakpoint->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckUseBreakpoint->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckUseBreakpoint->Color = mSettingsP->ThemeButtonColor;
		PanelCheckUseBreakpoint->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	PanelBreakpointAddress->Caption = AnsiString::IntToHex(CurrentBreakpointP->Address, 4);

	if (CurrentBreakpointP->MemoryRead == true)
	{
		PanelCheckBreakpointRead->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckBreakpointRead->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckBreakpointRead->Color = mSettingsP->ThemeButtonColor;
		PanelCheckBreakpointRead->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	if (CurrentBreakpointP->MemoryWrite == true)
	{
		PanelCheckBreakpointWrite->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckBreakpointWrite->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckBreakpointWrite->Color = mSettingsP->ThemeButtonColor;
		PanelCheckBreakpointWrite->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	if (CurrentBreakpointP->PC == true)
	{
		PanelCheckBreakpointPC->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckBreakpointPC->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckBreakpointPC->Color = mSettingsP->ThemeButtonColor;
		PanelCheckBreakpointPC->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	if (CurrentBreakpointP->LowerROM == true)
	{
		PanelCheckLowerROM->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckLowerROM->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckLowerROM->Color = mSettingsP->ThemeButtonColor;
		PanelCheckLowerROM->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	if (CurrentBreakpointP->UpperROM == true)
	{
		PanelCheckUpperROM->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckUpperROM->Font->Color = mSettingsP->ThemeButtonColor;
		PanelBreakpointUpperROMIndex->Visible = true;
		PanelBreakpointUpperROMIndex->Caption = AnsiString::IntToHex(CurrentBreakpointP->UpperROMIndex, 2);
	}
	else
	{
		PanelCheckUpperROM->Color = mSettingsP->ThemeButtonColor;
		PanelCheckUpperROM->Font->Color = mSettingsP->ThemeButtonTextColor;
		PanelBreakpointUpperROMIndex->Visible = false;
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::SelectBreakpoint(int Index)
{
	if (Index < mBreakpointsList->Count)
	{
		// Display Breakpoint settings
		UpdateBreakpointPanel();
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::StringGridBreakpointsMouseDown(TObject *Sender, TMouseButton Button,
					TShiftState Shift, int X, int Y)
{
	int Column;
	int Row;
	StringGridBreakpoints->MouseToCell(X, Y, Column, Row);

	// "Use" column selected
	if ( (Column == 0) && (Button == mbLeft) )
	{
		StringGridBreakpoints->Row = Row;
		PanelCheckUseBreakpointClick(Sender);
	}

	NOT_USED(Button);
	NOT_USED(Shift);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::StringGridBreakpointsKeyPress(TObject *Sender, System::WideChar &Key)
{
	if (Key == VK_SPACE)
	{
		PanelCheckUseBreakpointClick(Sender);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::StringGridBreakpointsKeyDown(TObject *Sender, WORD &Key,
					TShiftState Shift)
{
	if (Key == VK_DELETE)
	{
		PanelButtonBreakpointsDelClick(Sender);
	}

	NOT_USED(Shift);
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::ToggleBreakpointPC(tULong Address)
{
	tGateArray* GateArray = FormMain->NativeCPC->GateArray;
	TEmulatorBreakpoint Breakpoint;
	Breakpoint.Address = Address;
	Breakpoint.LowerROM = false;
	Breakpoint.UpperROM = false;
	Breakpoint.UpperROMIndex = GateArray->upper_ROM;

	// Lower ROM active
	if ( (Address < 0x4000)
			 && (!(GateArray->ROM_config & 0x04)) )
	{
		Breakpoint.LowerROM = true;
	}
	// Upper ROM Active
	else if ( (Address >= 0xc000) && (Address <= 0xffff)
						&& (!(GateArray->ROM_config & 0x08)) )
	{
		Breakpoint.UpperROM = true;
	}

	ToggleBreakpointPC(Breakpoint);
}
//---------------------------------------------------------------------------
void __fastcall TFormDebugger::ToggleBreakpointPC(TEmulatorBreakpoint Breakpoint)
{
	bool AlreadyExist = false;
	TEmulatorBreakpoint* SelectedBreakpointP = NULL;
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];

		if ( (CurrentBreakpointP->Address == Breakpoint.Address)
				 && (CurrentBreakpointP->LowerROM == Breakpoint.LowerROM)
				 && (CurrentBreakpointP->UpperROM == Breakpoint.UpperROM)
				 && (CurrentBreakpointP->UpperROMIndex == Breakpoint.UpperROMIndex) )
		{
			SelectedBreakpointP = CurrentBreakpointP;
		}

		if ( (SelectedBreakpointP != NULL)
				 && (CurrentBreakpointP->PC == true) )
		{
			AlreadyExist = true;
			break;
		}
	}

	if (AlreadyExist == true)
	{
		DeleteBreakpoint(SelectedBreakpointP);
	}
	else if (SelectedBreakpointP != NULL)
	{
		// Update current breakpoint
		SelectedBreakpointP->PC = true;
		SelectedBreakpointP->MemoryRead = false;
		SelectedBreakpointP->MemoryWrite = false;

		FillBreakpoints();
		UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
		UpdateBreakpointPanel();
	}
	else
	{
		AddBreakpointPC(Breakpoint, true);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::ToggleBreakpointMem(TEmulatorBreakpoint Breakpoint)
{
	bool AlreadyExist = false;
	TEmulatorBreakpoint* SelectedBreakpointP = NULL;
	for (int Loop=0; Loop < mBreakpointsList->Count; Loop++)
	{
		TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[Loop];

		if ( (CurrentBreakpointP->Address == Breakpoint.Address)
				 && (CurrentBreakpointP->LowerROM == Breakpoint.LowerROM)
				 && (CurrentBreakpointP->UpperROM == Breakpoint.UpperROM)
				 && (CurrentBreakpointP->UpperROMIndex == Breakpoint.UpperROMIndex) )
		{
			SelectedBreakpointP = CurrentBreakpointP;
		}

		if ( (SelectedBreakpointP != NULL)
				 && (CurrentBreakpointP->MemoryRead == Breakpoint.MemoryRead)
				 && (CurrentBreakpointP->MemoryWrite == Breakpoint.MemoryWrite) )
		{
			AlreadyExist = true;
			break;
		}
	}

	if (AlreadyExist == true)
	{
		DeleteBreakpoint(SelectedBreakpointP);
	}
	else if (SelectedBreakpointP != NULL)
	{
		// Update current breakpoint
		if (Breakpoint.MemoryRead == true)
		{
			SelectedBreakpointP->MemoryRead = (SelectedBreakpointP->MemoryRead == true) ? false : true;
		}
		if (Breakpoint.MemoryWrite == true)
		{
			SelectedBreakpointP->MemoryWrite = (SelectedBreakpointP->MemoryWrite == true) ? false : true;
		}

    FillBreakpoints();
		UpdateBreakpointsGUI(FormMain->EmulatorP->Paused);
		UpdateBreakpointPanel();
	}
	else
	{
		AddBreakpointMem(Breakpoint, true);
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormDebugger::PanelButtonShowInstructionClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];
	FormZ80Editor->TopAddress = CurrentBreakpointP->Address;

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonShowMemoryClick(TObject *Sender)
{
	TEmulatorBreakpoint* CurrentBreakpointP = (TEmulatorBreakpoint*)mBreakpointsList->Items[StringGridBreakpoints->Row];
	FormMemoryEditor->ShowCurrentAddress(CurrentBreakpointP->Address);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormDebugger::PanelButtonShowPCClick(TObject *Sender)
{
	FormZ80Editor->TopAddress = mCurrentPPC;

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------

