/*
    CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
    Copyright (C) 2014-2016 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>
#include <tchar.h>
#pragma hdrstop
#include "TFormMemoryEditor.h"
#include "TFormEditValue.h"
#include "TFormMain.h"
#include "TFormDebugger.h"
#include "TFormZ80Editor.h"
#include "..\..\Common\ASCII.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"


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

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


//===================
// PATCH begin
#ifdef _PATCH_ENABLE

#endif /* _PATCH_ENABLE */
// PATCH end
//===================



#define TEXT_DUMP_FILTER            "Simple text dump (.txt)|*.txt|"\
                                    "All files|*.*"
#define BINARY_DUMP_FILTER          "Binary dump (.bin)|*.bin|"\
                                    "All files|*.*"

#define TAB_BANKED_READ             0
#define TAB_BANKED_WRITE            1
#define TAB_RAM                     2
#define TAB_LOWER_ROM               3
#define TAB_UPPER_ROM               4

static const AnsiString cTitle = "Memory editor";
static const AnsiString cTitlePaused  = " - [PAUSED]";
static const AnsiString cTitleMonitoring  = " - [Monitoring]";


TFormMemoryEditor *FormMemoryEditor;
//---------------------------------------------------------------------------
__fastcall TFormMemoryEditor::TFormMemoryEditor(TComponent* Owner)
  : TForm(Owner)
{
  mSettingsP = NULL;
  mSearchBytes = NULL;

  mChangeValueIncrement = 1;
  mChangeValueNextRequested = false;
	mChangeValueHexa = true;

	mShowASCII7Bits = false;
	mShowDiffHighlight = false;

	PanelEditValue->Visible = false;

	mFormEditValue = new TFormEditValue(this);

	StringGridDump->ColCount = 34;
	StringGridDump->RowCount = 8;
	StringGridDump->ColWidths[0] = 70;
	StringGridDump->ColWidths[17] = 10;
	for (int Loop=18; Loop < 34; Loop++)
	{
		StringGridDump->ColWidths[Loop] = 10;
	}

	SaveDialog->InitialDir = ExtractFilePath(Application->ExeName);
	OpenDialog->InitialDir = ExtractFilePath(Application->ExeName);

	// Select Banked memory
	TabControlMemoryContent->TabIndex = TAB_BANKED_READ;
	mMemoryStartAddress = 0x0000;
	mMemorySize = 0x10000;
	mShowMemoryDumpRoutine = ShowBankedREADDump;
	mWriteDataRoutine = WriteDataBankedREAD;
	mSearchASCIIRoutine = SearchASCIIBankedREAD;
	mSearchHexRoutine = SearchHexBankedREAD;
	mMemoryDiffRoutine = PerformBankedREADDiff;
	mPreviousMemory = new tUChar[mMemorySize];
	mMemoryDiff = new tUChar[mMemorySize];

  mCurrentAddress = 0;
  mTopAddress = 0;

  PageControlOperations->ActivePage = TabSheetBanks;

  PanelCurrentAddress->Caption = AnsiString::IntToHex(mCurrentAddress, 6);

  mFillFromAddress = 0;
  mFillToAddress = 0;
  mFillData = 0;

  PanelFormatFillFrom->Caption = "&&";
  PanelFillFrom->Caption = AnsiString::IntToHex(mFillFromAddress, 6);
  PanelFormatFillTo->Caption = "&&";
  PanelFillTo->Caption = AnsiString::IntToHex(mFillToAddress, 6);
  PanelFormatFillData->Caption = "&&";
  PanelFillData->Caption = AnsiString::IntToHex(mFillData, 2);

  mExportFromAddress = 0;
  mExportToAddress = 0;

  PanelFormatExportFrom->Caption = "&&";
  PanelExportFrom->Caption = AnsiString::IntToHex(mExportFromAddress, 6);
  PanelFormatExportTo->Caption = "&&";
  PanelExportTo->Caption = AnsiString::IntToHex(mExportToAddress, 6);

  StringGridDump->RowCount = StringGridDump->Height / StringGridDump->DefaultRowHeight;
	ScrollBarDump->LargeChange = StringGridDump->RowCount * 16;
  mMaxTopAddress = mMemorySize - ScrollBarDump->LargeChange;

  ScrollBarDump->Position = mTopAddress;
  ScrollBarDump->Min = mMemoryStartAddress;
  ScrollBarDump->Max = mMaxTopAddress;

  // Force client area to keep form size under Windows 10.
  int BorderWidth = Width - ClientWidth;
  int BorderHeight = Height - ClientHeight;
  ClientWidth = 609;
	ClientHeight = 341;
  Constraints->MinWidth = ClientWidth + BorderWidth;
  Constraints->MinHeight = ClientHeight + BorderHeight;

	// Apply theme
	Font->Name = "Amstrad CPC464 Regular";
	Font->Size = 6;
	for (int Loop=0; Loop < ComponentCount; Loop++)
	{
		if (Components[Loop]->Name.Pos("Panel") == 1)
		{
			((TPanel*)Components[Loop])->Font->Color = clBlack;
		}
	}
	EditSearch->Font->Color = clBlack;
	EditSearch->Font->Size = 12;
	PanelFormatSearch->Height = EditSearch->Height;
	LabelSearch->Height = EditSearch->Height;

	StringGridDump->DefaultDrawing = false;
	StringGridDump->Canvas->Font = Font;
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::FormDestroy(TObject *Sender)
{
  delete [] mSearchBytes;
  delete mFormEditValue;

	delete [] mPreviousMemory;
	delete [] mMemoryDiff;

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


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

	FormMain->OnMemoryEditorFormShow();

	mMonitoring = false;
	mPaused = FormMain->NativeCPC->paused;
	Caption = Title;

	// Update GUI linked to Pause modification
	//PanelButtonShowInstruction->Visible = mPaused;
	//SetZ80InstructionsTopAddressMenu->Visible = mPaused;

	FormMain->SubscribeToCPCEvents(OnCPCEvent);

	// Update display
	mMemoryDiffRoutine(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	UpdateBanks(FormMain->NativeCPC);
	PanelCheckMonitoring->Color = mSettingsP->ThemeButtonColor;
	PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonTextColor;

  mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
	ActiveControl = StringGridDump;

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

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

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

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

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


AnsiString __fastcall TFormMemoryEditor::GetTitle(void)
{
  AnsiString Title = cTitle;

  if (mMonitoring == true) Title += cTitleMonitoring;
  if (mPaused == true) Title += cTitlePaused;

 return Title;
}
//---------------------------------------------------------------------------


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

	if (    (mSettingsP->MemoryFormLeft != 0)
       || (mSettingsP->MemoryFormTop != 0)
       || (mSettingsP->MemoryFormWidth != 0)
       || (mSettingsP->MemoryFormHeight != 0) )
  {
    Position = poDesigned;
    Left = mSettingsP->MemoryFormLeft;
    Top = mSettingsP->MemoryFormTop;
    Width = mSettingsP->MemoryFormWidth;
    Height = mSettingsP->MemoryFormHeight;
  }

  ShowHint = mSettingsP->ShowHints;

  // Apply theme
  Color = mSettingsP->ThemeBackgroundColor;
  Font->Color = mSettingsP->ThemeText1Color;
  EditValue->Font->Color = mSettingsP->ThemeText2Color;
	LabelCurrentAddress->Font->Color = mSettingsP->ThemeText1Color;
	LabelRAMSettings->Font->Color = mSettingsP->ThemeText2Color;
	for (int Loop=0; Loop < ComponentCount; Loop++)
	{
		if (Components[Loop]->Name.Pos("LabelBanksRange") == 1)
		{
			((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
		}
		else if (Components[Loop]->Name.Pos("LabelBanks") == 1)
		{
			((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText2Color;
		}
		else if (Components[Loop]->Name.Pos("LabelHelp") == 1)
		{
			((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText2Color;
		}
		else 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("PanelCheck") == 1)
    {
      ((TPanel*)Components[Loop])->Color = mSettingsP->ThemeButtonColor;
      ((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeButtonTextColor;
    }

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

	// Get work data
	for (int Loop=0; Loop < ComponentCount; Loop++)
	{
		AnsiString PanelMarkerName("PanelAddress");
		if (Components[Loop]->Name.Pos(PanelMarkerName) == 1)
		{
			TPanel* MarkerPanel = (TPanel*)Components[Loop];
			int Index = MarkerPanel->Name.SubString(PanelMarkerName.Length()+1,
									MarkerPanel->Name.Length() - PanelMarkerName.Length()).ToInt();
			// Set last marker
			MarkerPanel->Caption = mSettingsP->GetMemoryMarker(Index-1);
		}
	}

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


void __fastcall TFormMemoryEditor::SetDisplayRows(int Value)
{
  // Adjust selected row
  if (StringGridDump->Row >= Value)
  {
    StringGridDump->Row = Value - 1;
  }

  StringGridDump->RowCount = Value;
  ScrollBarDump->LargeChange = StringGridDump->RowCount * 16;
  mMaxTopAddress = mMemoryStartAddress + mMemorySize - ScrollBarDump->LargeChange;
  if (mTopAddress > mMaxTopAddress) mTopAddress = mMaxTopAddress;
  ScrollBarDump->Max = mMaxTopAddress;
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::SetCurrentAddress(tULong Value)
{
	Visible = true;

  mCurrentAddress = Value;

  if (mCurrentAddress < mMemoryStartAddress)
  {
    mCurrentAddress = mMemoryStartAddress;
  }
  else if (mCurrentAddress >= (mMemoryStartAddress + mMemorySize))
  {
    mCurrentAddress = mMemoryStartAddress + mMemorySize - 1;
  }

	PanelCurrentAddress->Caption = AnsiString::IntToHex(mCurrentAddress, 6);

	// Refresh dump display
	StringGridDump->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SetMemorySize(tULong Value)
{
  mMemorySize = Value;
  mMaxTopAddress = mMemoryStartAddress + mMemorySize - ScrollBarDump->LargeChange;

  // Adjust current address
  if (mCurrentAddress < mMemoryStartAddress)
  {
		TopAddress = mMemoryStartAddress;
    CurrentAddress = mMemoryStartAddress;
	}
	else if (mCurrentAddress >= (mMemoryStartAddress + mMemorySize))
	{
    TopAddress = mMemoryStartAddress + mMemorySize - 1;
    CurrentAddress = mMemoryStartAddress + mMemorySize - 1;
  }

  ScrollBarDump->Max = mMaxTopAddress;
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SetTopAddress(tULong Value)
{
	mTopAddress = Value & 0xFFFFFFF0;

	if (mTopAddress > 0xff000000) mTopAddress = 0;
	else if (mTopAddress < mMemoryStartAddress) mTopAddress = mMemoryStartAddress;
	if (mTopAddress > mMaxTopAddress) mTopAddress = mMaxTopAddress;

	ScrollBarDump->Position = mTopAddress;
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SetMemoryStartAddress(tULong Value)
{
  mMemoryStartAddress = Value;
	mMaxTopAddress = mMemoryStartAddress + mMemorySize - ScrollBarDump->LargeChange;

  if (mCurrentAddress < mMemoryStartAddress)
  {
    TopAddress = mMemoryStartAddress;
    CurrentAddress = mMemoryStartAddress;
  }
  if (mCurrentAddress >= (mMemoryStartAddress + mMemorySize))
  {
    TopAddress = mMemoryStartAddress + mMemorySize - 1;
    CurrentAddress = mMemoryStartAddress + mMemorySize - 1;
  }

  ScrollBarDump->Min = mMemoryStartAddress;
  ScrollBarDump->Max = mMaxTopAddress;
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SetMemoryIndex(int Value)
{
  TabControlMemoryContent->TabIndex = Value;

  switch (TabControlMemoryContent->TabIndex)
  {
    case TAB_BANKED_READ:
    {
      mMemoryStartAddress = 0x0000;
      mMemorySize = 0x10000;
      mShowMemoryDumpRoutine = ShowBankedREADDump;
      mWriteDataRoutine = WriteDataBankedREAD;
      mSearchASCIIRoutine = SearchASCIIBankedREAD;
      mSearchHexRoutine = SearchHexBankedREAD;
			mMemoryDiffRoutine = PerformBankedREADDiff;
		}
		break;

		case TAB_BANKED_WRITE:
		{
			mMemoryStartAddress = 0x0000;
			mMemorySize = 0x10000;
			mShowMemoryDumpRoutine = ShowBankedWRITEDump;
			mWriteDataRoutine = WriteDataBankedWRITE;
			mSearchASCIIRoutine = SearchASCIIBankedWRITE;
			mSearchHexRoutine = SearchHexBankedWRITE;
			mMemoryDiffRoutine = PerformBankedWRITEDiff;
		}
		break;

		case TAB_LOWER_ROM:
		{
			mMemoryStartAddress = 0x0000;
			mMemorySize = 16384;
			mShowMemoryDumpRoutine = ShowLowerROMDump;
			mWriteDataRoutine = WriteDataLowerROM;
			mSearchASCIIRoutine = SearchASCIILowerROMMemory;
			mSearchHexRoutine = SearchHexLowerROMMemory;
			mMemoryDiffRoutine = PerformLowerROMDiff;
		}
		break;

		case TAB_UPPER_ROM: // Upper ROM
		{
			mMemoryStartAddress = 0xC000;
			mMemorySize = 16384;
			mShowMemoryDumpRoutine = ShowUpperROMDump;
			mWriteDataRoutine = WriteDataUpperROM;
			mSearchASCIIRoutine = SearchASCIIUpperROMMemory;
			mSearchHexRoutine = SearchHexUpperROMMemory;
			mMemoryDiffRoutine = PerformUpperROMDiff;
		}
		break;

		default: // Entire RAM
		{
			mMemoryStartAddress = 0x0000;
			mMemorySize = FormMain->NativeCPC->ram_size * 1024;
			mShowMemoryDumpRoutine = ShowEntireRAMDump;
			mWriteDataRoutine = WriteDataEntireRAM;
			mSearchASCIIRoutine = SearchASCIIEntireRAMMemory;
			mSearchHexRoutine = SearchHexEntireRAMMemory;
			mMemoryDiffRoutine = PerformEntireRAMDiff;
		}
	}

	// Adapt other parameters
	mMaxTopAddress = mMemoryStartAddress + mMemorySize - ScrollBarDump->LargeChange;
	if (mCurrentAddress < mMemoryStartAddress)
	{
		mTopAddress = mMemoryStartAddress;
		mCurrentAddress = mMemoryStartAddress;
	}
	else if (mCurrentAddress >= (mMemoryStartAddress + mMemorySize))
	{
		mTopAddress = mMemoryStartAddress + mMemorySize - 1;
    mCurrentAddress = mMemoryStartAddress + mMemorySize - 1;
  }
  else if (mCurrentAddress < mTopAddress)
  {
    mTopAddress = mCurrentAddress;
  }
  else if (mCurrentAddress >= (mTopAddress+ScrollBarDump->LargeChange))
  {
    mTopAddress = mCurrentAddress;
  }
  mTopAddress = mTopAddress & 0xFFFFFFF0;
  if (mTopAddress > 0xff000000) mTopAddress = 0;
	else if (mTopAddress < mMemoryStartAddress) mTopAddress = mMemoryStartAddress;
  if (mTopAddress > mMaxTopAddress) mTopAddress = mMaxTopAddress;

  // Adapt scrollbar
  tULong OldTopAddress = mTopAddress;
  ScrollBarDump->Min = 0;
  ScrollBarDump->Position = 0;
  ScrollBarDump->Max = mMaxTopAddress;
  ScrollBarDump->Position = OldTopAddress;
  ScrollBarDump->Min = mMemoryStartAddress;

  // Update current address
  PanelCurrentAddress->Caption = AnsiString::IntToHex(mCurrentAddress, 6);
	mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];

	//
	// Update memory differences
	//
	delete [] mPreviousMemory;
	delete [] mMemoryDiff;
	mPreviousMemory = new tUChar[mMemorySize];
	mMemoryDiff = new tUChar[mMemorySize];
	// Perform differences
	mMemoryDiffRoutine(FormMain->NativeCPC);
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::FormResize(TObject *Sender)
{
  if ( (Visible == true) && (mSettingsP) && (!Tag) )
  {
    mSettingsP->MemoryFormWidth = Width;
    mSettingsP->MemoryFormHeight = Height;

    // Refresh display
    DisplayRows = StringGridDump->Height / StringGridDump->DefaultRowHeight;
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::WMMove(TMessage &Message)
{
  if ( (Visible == true) && (mSettingsP) && (!Tag) )
  {
    mSettingsP->MemoryFormLeft = Left;
    mSettingsP->MemoryFormTop = Top;
  }

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


void __fastcall TFormMemoryEditor::PanelButtonSetAddressClick(TObject *Sender)
{
  TPanel* CurrentPanel = (TPanel*)Sender;
  // Get marker number
  AnsiString PanelSetName("PanelButtonSetAddress");
  int Index = CurrentPanel->Name.SubString(PanelSetName.Length()+1, CurrentPanel->Name.Length() - PanelSetName.Length()).ToInt();
  // Fill associated panel
  AnsiString PanelMarkerName = "PanelAddress" + AnsiString(Index);
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name == PanelMarkerName)
    {
      ((TPanel*)Components[Loop])->Caption = AnsiString::IntToHex(CurrentAddress, 6);
      // Keep marker
      mSettingsP->SetMemoryMarker(Index-1, ((TPanel*)Components[Loop])->Caption);
      break;
    }
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PanelMarkerAddressClick(TObject *Sender)
{
  TPanel* Panel = (TPanel*)Sender;

  mFormEditValue->Title = Panel->Hint;
  mFormEditValue->CurrentValue = StrToInt("0x" + Panel->Caption);
  mFormEditValue->Hexadecimal = true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    Panel->Caption = AnsiString::IntToHex(mFormEditValue->NewValue, 6);

    // Get marker number
    AnsiString PanelName("PanelAddress");
    int Index = Panel->Name.SubString(PanelName.Length()+1, Panel->Name.Length() - PanelName.Length()).ToInt();
    // Keep marker
    mSettingsP->SetMemoryMarker(Index-1, Panel->Caption);
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PanelButtonGoToAddressClick(TObject *Sender)
{
  TPanel* CurrentPanel = (TPanel*)Sender;
  // Get marker number
  AnsiString PanelSetName("PanelButtonGoToAddress");
  int Index = CurrentPanel->Name.SubString(PanelSetName.Length()+1, CurrentPanel->Name.Length() - PanelSetName.Length()).ToInt();
  // Go to associated panel
  AnsiString PanelMarkerName = "PanelAddress" + AnsiString(Index);
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name == PanelMarkerName)
    {
			CurrentAddress = StrToInt("0x" + ((TPanel*)Components[Loop])->Caption);
			TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

      // Display refresh
      UpdateBanks(FormMain->NativeCPC);
      mShowMemoryDumpRoutine(FormMain->NativeCPC);
      StringGridDump->SetFocus();

      break;
    }
  }


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


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

  MemoryIndex = 0; // Select banked memory
  CurrentAddress = _BC;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _DE;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _HL;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = Z80->Regs.BCx.UShort.l;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = Z80->Regs.DEx.UShort.l;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = Z80->Regs.HLx.UShort.l;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _SP;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _PC;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _IX;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

	MemoryIndex = 0; // Select banked memory
	CurrentAddress = _IY;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

  // Display refresh
  UpdateBanks(FormMain->NativeCPC);
  mShowMemoryDumpRoutine(FormMain->NativeCPC);
  StringGridDump->SetFocus();

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


void __fastcall TFormMemoryEditor::PanelCurrentAddressClick(
      TObject *Sender)
{
  mFormEditValue->Title = "Current address";
  mFormEditValue->CurrentValue = mCurrentAddress;
  mFormEditValue->Hexadecimal = true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    tULong NewCurrentAddress = mFormEditValue->NewValue;
    if (NewCurrentAddress < mTopAddress)
    {
      TopAddress = NewCurrentAddress;
    }
    else if (NewCurrentAddress >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = NewCurrentAddress;
    }
    CurrentAddress = NewCurrentAddress;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

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


void __fastcall TFormMemoryEditor::ShowCurrentAddress(tULong Address)
{
	CurrentAddress = Address;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::PanelFormatFillFromClick(
      TObject *Sender)
{
  if (PanelFormatFillFrom->Caption.IsEmpty() == true)
  {
    PanelFormatFillFrom->Caption = "&&";
    PanelFillFrom->Caption = AnsiString::IntToHex(mFillFromAddress, 5);
  }
  else
  {
    PanelFormatFillFrom->Caption = "";
    PanelFillFrom->Caption = mFillFromAddress;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PanelFormatFillToClick(
      TObject *Sender)
{
  if (PanelFormatFillTo->Caption.IsEmpty() == true)
  {
    PanelFormatFillTo->Caption = "&&";
    PanelFillTo->Caption = AnsiString::IntToHex(mFillToAddress, 5);
  }
  else
  {
		PanelFormatFillTo->Caption = "";
    PanelFillTo->Caption = mFillToAddress;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PanelFormatFillDataClick(
      TObject *Sender)
{
  if (PanelFormatFillData->Caption.IsEmpty() == true)
  {
    PanelFormatFillData->Caption = "&&";
    PanelFillData->Caption = AnsiString::IntToHex(mFillData, 2);
  }
  else
  {
    PanelFormatFillData->Caption = "";
    PanelFillData->Caption = mFillData;
  }

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


void __fastcall TFormMemoryEditor::PanelFillFromClick(TObject *Sender)
{
  mFormEditValue->Title = "Fill From";
  mFormEditValue->CurrentValue = mFillFromAddress;
  mFormEditValue->Hexadecimal = PanelFormatFillFrom->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    mFillFromAddress = mFormEditValue->NewValue;
    PanelFillFrom->Caption = (PanelFormatFillFrom->Caption.IsEmpty() == false) ?
                             AnsiString::IntToHex(mFillFromAddress, 5) :
                             AnsiString(mFillFromAddress);
  }

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

void __fastcall TFormMemoryEditor::PanelFillToClick(TObject *Sender)
{
  mFormEditValue->Title = "Fill To";
  mFormEditValue->CurrentValue = mFillToAddress;
  mFormEditValue->Hexadecimal = PanelFormatFillTo->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    mFillToAddress = mFormEditValue->NewValue;
    PanelFillTo->Caption = (PanelFormatFillTo->Caption.IsEmpty() == false) ?
                           AnsiString::IntToHex(mFillToAddress, 5) :
                           AnsiString(mFillToAddress);
  }

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

void __fastcall TFormMemoryEditor::PanelFillDataClick(TObject *Sender)
{
  mFormEditValue->Title = "Fill Data";
  mFormEditValue->CurrentValue = mFillData;
  mFormEditValue->Hexadecimal = PanelFormatFillData->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = 255;
  if (mFormEditValue->ShowModal() == mrOk)
  {
    mFillData = mFormEditValue->NewValue;
    PanelFillData->Caption = (PanelFormatFillData->Caption.IsEmpty() == false) ?
                             AnsiString::IntToHex(mFillData, 2) :
                             AnsiString(mFillData);
  }

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


void __fastcall TFormMemoryEditor::PanelFormatExportFromClick(
      TObject *Sender)
{
  if (PanelFormatExportFrom->Caption.IsEmpty() == true)
  {
    PanelFormatExportFrom->Caption = "&&";
    PanelExportFrom->Caption = AnsiString::IntToHex(mExportFromAddress, 5);
  }
  else
  {
    PanelFormatExportFrom->Caption = "";
    PanelExportFrom->Caption = mExportFromAddress;
  }

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

void __fastcall TFormMemoryEditor::PanelFormatExportToClick(
      TObject *Sender)
{
  if (PanelFormatExportTo->Caption.IsEmpty() == true)
  {
    PanelFormatExportTo->Caption = "&&";
    PanelExportTo->Caption = AnsiString::IntToHex(mExportToAddress, 5);
  }
  else
  {
    PanelFormatExportTo->Caption = "";
    PanelExportTo->Caption = mExportToAddress;
  }

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

void __fastcall TFormMemoryEditor::PanelExportFromClick(
      TObject *Sender)
{
  mFormEditValue->Title = "Dump From";
  mFormEditValue->CurrentValue = mExportFromAddress;
  mFormEditValue->Hexadecimal = PanelFormatExportFrom->Caption.IsEmpty() == true ? false : true;
	mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    mExportFromAddress = mFormEditValue->NewValue;
    PanelExportFrom->Caption = (PanelFormatExportFrom->Caption.IsEmpty() == false) ?
                               AnsiString::IntToHex(mExportFromAddress, 5) :
                               AnsiString(mExportFromAddress);
  }

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


void __fastcall TFormMemoryEditor::PanelExportToClick(TObject *Sender)
{
  mFormEditValue->Title = "Dump To";
  mFormEditValue->CurrentValue = mExportToAddress;
  mFormEditValue->Hexadecimal = PanelFormatExportTo->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = ((FormMain->NativeCPC->ram_size * 1024) - 1);
  if (mFormEditValue->ShowModal() == mrOk)
  {
    mExportToAddress = mFormEditValue->NewValue;
    PanelExportTo->Caption = (PanelFormatExportTo->Caption.IsEmpty() == false) ?
                               AnsiString::IntToHex(mExportToAddress, 5) :
                               AnsiString(mExportToAddress);
  }

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


void __fastcall TFormMemoryEditor::PanelButtonFillClick(TObject *Sender)
{
  bool StartOutOfRange = false;
  bool EndOutOfRange = false;

  tULong StartAddress = mFillFromAddress;
  if (StartAddress < mMemoryStartAddress)
	{
    StartAddress = mMemoryStartAddress;
    StartOutOfRange = true;
  }
  else if (StartAddress > (mMemoryStartAddress + mMemorySize - 1) )
  {
    StartAddress = mMemoryStartAddress + mMemorySize - 1;
    StartOutOfRange = true;
  }

  tULong EndAddress = mFillToAddress;
  if (EndAddress < mMemoryStartAddress)
  {
    EndAddress = mMemoryStartAddress;
    EndOutOfRange = true;
  }
  else if (EndAddress > (mMemoryStartAddress + mMemorySize - 1) )
  {
    EndAddress = mMemoryStartAddress + mMemorySize - 1;
    EndOutOfRange = true;
  }

  // Out of range
  if ( (StartOutOfRange == true) && (EndOutOfRange == true) )
  {
		Application->MessageBox(_T("Out of range"), _T("Error"), MB_OK);
  }
  else
  {
    if (StartAddress > EndAddress)
    {
      tULong Temp = StartAddress;
      StartAddress = EndAddress;
      EndAddress = Temp;
    }

    // Add Banked Read Data
    if (TabControlMemoryContent->TabIndex == TAB_BANKED_READ)
    {
      for (tULong Address = StartAddress; Address <= EndAddress; Address++)
      {
        Engine_WriteBankedRead(FormMain->NativeCPC,
															 Address - mMemoryStartAddress,
                               (tUChar)mFillData);
      }
    }
    // Add Banked Write Data
    else if (TabControlMemoryContent->TabIndex == TAB_BANKED_WRITE)
    {
      for (tULong Address = StartAddress; Address <= EndAddress; Address++)
      {
        Engine_WriteBankedWrite(FormMain->NativeCPC,
                                Address - mMemoryStartAddress,
                                (tUChar)mFillData);
      }
    }
    // Add Lower ROM data
    else if (TabControlMemoryContent->TabIndex == TAB_LOWER_ROM)
    {
      for (tULong Address = StartAddress; Address <= EndAddress; Address++)
      {
        Engine_WriteLowerROM(FormMain->NativeCPC,
                             Address - mMemoryStartAddress,
                             (tUChar)mFillData);
      }
    }
    // Add Upper ROM data
    else if (TabControlMemoryContent->TabIndex == TAB_UPPER_ROM)
    {
      for (tULong Address = StartAddress; Address <= EndAddress; Address++)
      {
        Engine_WriteUpperROM(FormMain->NativeCPC,
                             Address - mMemoryStartAddress,
                             (tUChar)mFillData);
      }
    }
    // RAM
    else
    {
      for (tULong Address = StartAddress; Address <= EndAddress; Address++)
      {
        *(FormMain->NativeCPC->pbRAM + Address) = (tUChar)mFillData;
      }
    }

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

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


void __fastcall TFormMemoryEditor::StringGridDumpSelectCell(
			TObject *Sender, int ACol, int ARow, bool &CanSelect)
{
	CanSelect = (ACol == 17) ? false : true;

	// Invalidate ASCII Area
	if (CanSelect == true)
	{
		StringGridDump->Invalidate();
		mCurrentData = StringGridDump->Cells[ACol][ARow];

		// Update Current address
		int Col = (ACol > 17) ? ACol - 17 : ACol;
		CurrentAddress = mTopAddress + (ARow * 16) + (Col - 1);
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpClick(
			TObject *Sender)
{
	// Update current address
	int Col = StringGridDump->Col;
	Col = (Col > 17) ? Col - 17 : Col;
	CurrentAddress = mTopAddress + (StringGridDump->Row * 16) + (Col - 1);

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpDrawCell(TObject *Sender, int ACol,
					int ARow, TRect &Rect, TGridDrawState State)
{
	TStringGrid* StringGrid = (TStringGrid*)Sender;

	bool OutsideSelection = false;
	int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
	if (mCurrentAddress < mTopAddress)
	{
		OutsideSelection = true;
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		OutsideSelection = true;
	}

	tULong MemoryIndex = mTopAddress - mMemoryStartAddress + (ARow * 16) + ACol - 1;
	if (ACol >= 18)
	{
		MemoryIndex -= 17;
	}

	if (ACol == 0)
	{
		if ( (ARow == StringGridDump->Row) && (OutsideSelection == false) )
		{
			StringGrid->Canvas->Brush->Color = mSettingsP->ThemeText2Color;
			StringGrid->Canvas->Font->Color = Color;
		}
		else
		{
			StringGrid->Canvas->Brush->Color = Color;
			StringGrid->Canvas->Font->Color = mSettingsP->ThemeText2Color;
		}
	}
	else if ( (State.Contains(gdSelected)) && (OutsideSelection == false) )
	{
		StringGrid->Canvas->Brush->Color = mSettingsP->ThemeText2Color;
		StringGrid->Canvas->Font->Color = Color;
	}
	else
	{
		StringGrid->Canvas->Brush->Color = Color;
		if (mShowDiffHighlight == true)
		{
			StringGrid->Canvas->Font->Color = mMemoryDiff[MemoryIndex] ?
							mSettingsP->ThemeText2Color : mSettingsP->ThemeText1Color;
		}
		else
		{
			StringGrid->Canvas->Font->Color = StringGrid->Font->Color;
		}
	}

	if (OutsideSelection == false)
	{
		if (ACol < 17)
		{
			// HEXA part of selected byte ?
			if ( (ARow == StringGridDump->Row) && ((ACol+17) == StringGridDump->Col) )
			{
				StringGrid->Canvas->Brush->Color = mSettingsP->ThemeText1Color;
				StringGrid->Canvas->Font->Color = Color;
			}
		}
		else if (ACol >= 18)
		{
			// ASCII part of selected byte ?
			if ( (ARow == StringGridDump->Row) && ((ACol-17) == StringGridDump->Col) )
			{
				StringGrid->Canvas->Brush->Color = mSettingsP->ThemeText1Color;
				StringGrid->Canvas->Font->Color = Color;
			}
		}
	}

	// Draw cell
	StringGrid->Canvas->FillRect(Rect);
	AnsiString CellContent = StringGrid->Cells[ACol][ARow];
	if (CellContent.Length() > 0)
	{
		int TextWidth = StringGrid->Canvas->TextWidth(CellContent);
		int TextHeight = StringGrid->Canvas->TextHeight(CellContent);
		int TextPosX = (StringGrid->ColWidths[ACol] - TextWidth) / 2;
		int TextPosY = (StringGrid->RowHeights[ARow] - TextHeight) / 2;
		StringGrid->Canvas->TextOut(Rect.Left + TextPosX,
																Rect.Top + TextPosY,
																CellContent);
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpMouseDown(
			TObject *Sender, TMouseButton Button, TShiftState Shift, int X,
			int Y)
{
	// Right click button
	if (Button == mbRight)
	{
		int ACol;
		int ARow;

		// Get cell from coordinates
		StringGridDump->MouseToCell(X, Y, ACol, ARow);

		// Select cell
		StringGridDump->Col = ACol;
		StringGridDump->Row = ARow;
	}

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


void __fastcall TFormMemoryEditor::StringGridDumpKeyDown(
			TObject *Sender, WORD &Key, TShiftState Shift)
{
	bool KeyTreated = false;

	if (StringGridDump->Col < 17)
	{
		switch (Key)
		{
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case VK_NUMPAD0:
			case VK_NUMPAD1:
			case VK_NUMPAD2:
			case VK_NUMPAD3:
			case VK_NUMPAD4:
			case VK_NUMPAD5:
			case VK_NUMPAD6:
			case VK_NUMPAD7:
			case VK_NUMPAD8:
			case VK_NUMPAD9:
			case 'A':
			case 'B':
			case 'C':
			case 'D':
			case 'E':
			case 'F':
			{
				// Edit memory
				StringGridDumpDblClick(Sender);
				if ((Key == '0') || (Key == VK_NUMPAD0)) EditValue->Text = "0";
				else if ((Key == '1') || (Key == VK_NUMPAD1)) EditValue->Text = "1";
				else if ((Key == '2') || (Key == VK_NUMPAD2)) EditValue->Text = "2";
				else if ((Key == '3') || (Key == VK_NUMPAD3)) EditValue->Text = "3";
				else if ((Key == '4') || (Key == VK_NUMPAD4)) EditValue->Text = "4";
				else if ((Key == '5') || (Key == VK_NUMPAD5)) EditValue->Text = "5";
				else if ((Key == '6') || (Key == VK_NUMPAD6)) EditValue->Text = "6";
				else if ((Key == '7') || (Key == VK_NUMPAD7)) EditValue->Text = "7";
				else if ((Key == '8') || (Key == VK_NUMPAD8)) EditValue->Text = "8";
				else if ((Key == '9') || (Key == VK_NUMPAD9)) EditValue->Text = "9";
				else if (Key == 'A') EditValue->Text = "A";
				else if (Key == 'B') EditValue->Text = "B";
				else if (Key == 'C') EditValue->Text = "C";
				else if (Key == 'D') EditValue->Text = "D";
				else if (Key == 'E') EditValue->Text = "E";
				else if (Key == 'F') EditValue->Text = "F";
				EditValue->SelStart = 1;
				KeyTreated = true;
			}
			break;
		}
	}

	if (KeyTreated == false)
	{
		switch (Key)
		{
			case VK_UP:
			{
				bool OutsideSelection = false;
				int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
				if (mCurrentAddress < mTopAddress)
				{
					OutsideSelection = true;
				}
				else if (CurrentRow >= StringGridDump->RowCount)
				{
					OutsideSelection = true;
				}
				if (OutsideSelection == true)
				{
					CurrentAddress -= 16;
					TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
				else if (!StringGridDump->Row)
				{
					TopAddress -= 16;
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
				}
			}
			break;

			case VK_PRIOR:
			{
				if (!StringGridDump->Row)
				{
					TopAddress -= StringGridDump->RowCount * 16;
					if ((CurrentAddress - mMemoryStartAddress) < ((tULong)StringGridDump->RowCount * 16))
					{
						CurrentAddress = mMemoryStartAddress;
					}
					else
					{
						CurrentAddress -= StringGridDump->RowCount * 16;
					}

					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
				}
			}
			break;

			case VK_NEXT:
			{
				if (StringGridDump->Row == (StringGridDump->RowCount-1))
				{
					TopAddress += StringGridDump->RowCount * 16;
					if (((mMemoryStartAddress + mMemorySize) - CurrentAddress) < ((tULong)StringGridDump->RowCount*16))
					{
						CurrentAddress = mMemoryStartAddress + mMemorySize - 1;
					}
					else
					{
						CurrentAddress += StringGridDump->RowCount * 16;
					}

					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
				}
			}
			break;

			case VK_DOWN:
			{
				bool OutsideSelection = false;
				int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
				if (mCurrentAddress < mTopAddress)
				{
					OutsideSelection = true;
				}
				else if (CurrentRow >= StringGridDump->RowCount)
				{
					OutsideSelection = true;
				}
				if (OutsideSelection == true)
				{
					CurrentAddress += 16;
					TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
				else if (StringGridDump->Row == (StringGridDump->RowCount-1))
				{
					TopAddress += 16;
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
				}
			}
			break;

			case VK_HOME:
			{
				TopAddress = mMemoryStartAddress;
				CurrentAddress = mMemoryStartAddress;
				// Display refresh
				UpdateBanks(FormMain->NativeCPC);
				mShowMemoryDumpRoutine(FormMain->NativeCPC);
				// Key has been treated
				Key = 0;
			}
			break;

			case VK_END:
			{
				TopAddress = mMemoryStartAddress + mMemorySize;
				CurrentAddress = mMemoryStartAddress + mMemorySize;
				// Display refresh
				UpdateBanks(FormMain->NativeCPC);
				mShowMemoryDumpRoutine(FormMain->NativeCPC);
				// Key has been treated
				Key = 0;
			}
			break;

			case VK_RETURN:
			{
				// Edit memory
				StringGridDumpDblClick(Sender);
			}
			break;

			case VK_LEFT:
			{
				bool OutsideSelection = false;
				int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
				if (mCurrentAddress < mTopAddress)
				{
					OutsideSelection = true;
				}
				else if (CurrentRow >= StringGridDump->RowCount)
				{
					OutsideSelection = true;
				}
				if (OutsideSelection == true)
				{
					CurrentAddress--;
					TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
				else if ( (StringGridDump->Col == 1) || (StringGridDump->Col == 18) )
				{
					if (CurrentAddress > mMemoryStartAddress)
					{
						CurrentAddress--;
						if (!StringGridDump->Row)
						{
							TopAddress -= 16;
						}
					}
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
			}
			break;

			case VK_RIGHT:
			{
				bool OutsideSelection = false;
				int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
				if (mCurrentAddress < mTopAddress)
				{
					OutsideSelection = true;
				}
				else if (CurrentRow >= StringGridDump->RowCount)
				{
					OutsideSelection = true;
				}
				if (OutsideSelection == true)
				{
					CurrentAddress++;
					TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
				else if ( (StringGridDump->Col == 16) || (StringGridDump->Col == 33) )
				{
					if (CurrentAddress < (mMemoryStartAddress+mMemorySize))
					{
						CurrentAddress++;

						if (StringGridDump->Row == (StringGridDump->RowCount-1))
						{
							TopAddress += 16;
						}
					}
					// Display refresh
					UpdateBanks(FormMain->NativeCPC);
					mShowMemoryDumpRoutine(FormMain->NativeCPC);
					// Key has been treated
					Key = 0;
				}
			}
			break;
		}
	}

	NOT_USED(Shift);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpKeyPress(
			TObject *Sender, char &Key)
{
	if (Key == VK_SPACE)
	{
		StringGridDump->Col = (StringGridDump->Col < 17) ? StringGridDump->Col+17 : StringGridDump->Col-17;
	}
	else if (StringGridDump->Col < 17)
	{
		// Allowed keys for hexadecimal edition
		if ((Key >= '0') && (Key <= '9'))
			return;
		if (Key == VK_DELETE)
			return;
		if ( (Key >= 'a') && (Key <= 'f') )
			return;
		if ( (Key >= 'A') && (Key <= 'F') )
			return;

		// All other keys are ignored
		Key = 0;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpMouseWheelUp(
			TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
	Handled = true;
	bool OutsideSelection = false;
	int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
	if (mCurrentAddress < mTopAddress)
	{
		OutsideSelection = true;
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		OutsideSelection = true;
	}
	tULong OldTopAddress = TopAddress;
	TopAddress -= 16;
	if (OldTopAddress != TopAddress)
	{
		CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
		if (mCurrentAddress < mTopAddress)
		{
		}
		else if (CurrentRow >= StringGridDump->RowCount)
		{
		}
		else if (OutsideSelection == false)
		{
			StringGridDump->Row++;
		}
	}

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);

	NOT_USED(Shift);
	NOT_USED(MousePos);
	NOT_USED(Handled);
	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpMouseWheelDown(
			TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
	Handled = true;
	bool OutsideSelection = false;
	int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
	if (mCurrentAddress < mTopAddress)
	{
		OutsideSelection = true;
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		OutsideSelection = true;
	}
	tULong OldTopAddress = TopAddress;
	TopAddress += 16;
	if (OldTopAddress != TopAddress)
	{
		CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
		if (mCurrentAddress < mTopAddress)
		{
		}
		else if (CurrentRow >= StringGridDump->RowCount)
		{
		}
		else if (OutsideSelection == false)
		{
			StringGridDump->Row--;
		}
	}

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);

	NOT_USED(Shift);
	NOT_USED(MousePos);
	NOT_USED(Handled);
	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::StringGridDumpGetEditMask(
			TObject *Sender, int ACol, int ARow, AnsiString &Value)
{
  Value = "Aa";

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


void __fastcall TFormMemoryEditor::ScrollBarDumpChange(
			TObject *Sender)
{
	if (ScrollBarDump->Focused() == true)
	{
		mTopAddress = (tULong)ScrollBarDump->Position;
		mTopAddress &= 0xFFFFFFF0;

		// Display refresh
		UpdateBanks(FormMain->NativeCPC);
		mShowMemoryDumpRoutine(FormMain->NativeCPC);
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::ScrollBarDumpKeyPress(TObject *Sender, System::WideChar &Key)

{
	if (Key == VK_SPACE)
	{
		StringGridDump->Col = (StringGridDump->Col < 17) ? StringGridDump->Col+17 : StringGridDump->Col-17;
	}
	else
	if (Key == VK_RETURN)
	{
		// Edit memory
		StringGridDumpDblClick(Sender);
	}

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


void __fastcall TFormMemoryEditor::PageControlOperationsChange(
      TObject *Sender)
{
  if (PageControlOperations->ActivePage == TabSheetSearch)
  {
    ActiveControl = EditSearch;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PageControlOperationsDrawTab(TCustomTabControl *Control,
          int TabIndex, const TRect &Rect, bool Active)
{
  TCanvas* Canvas = PageControlOperations->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 < PageControlOperations->PageCount; Loop++)
  {
    if (PageControlOperations->Pages[Loop]->TabVisible == true)
    {
      if (TabCount == TabIndex)
      {
        Sheet = PageControlOperations->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 = (PageControlOperations->TabHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+TextPosX, Rect.Top+TextPosY, Text);

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


void __fastcall TFormMemoryEditor::PanelFormatSearchClick(
      TObject *Sender)
{
  if (PanelFormatSearch->Caption == "$")
  {
    PanelFormatSearch->Caption = "&&";
    LabelSearch->Caption = "Hex data";
  }
  else
  {
    PanelFormatSearch->Caption = "$";
    LabelSearch->Caption = "Text";
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::PanelButtonSearchNextClick(TObject *Sender)
{
  if (EditSearch->Text.Length() == 0)
    return;

  if (PanelFormatSearch->Caption == "$")
  {
    // Convert AnsiString to char array
    mSearchLength = EditSearch->Text.Length();
    delete [] mSearchBytes;
    mSearchBytes = new char[mSearchLength+1];
    strcpy(mSearchBytes, AnsiString(EditSearch->Text).c_str() );

    if (mSearchASCIIRoutine)
    {
      mSearchASCIIRoutine(FormMain->NativeCPC);
    }
  }
  else
  {
    // Convert Uppercase AnsiString to char array
    char* UpperSearchString = new char[EditSearch->Text.Length()+1];
    strcpy(UpperSearchString, AnsiString(EditSearch->Text).UpperCase().c_str() );

    char* UpperHexString = new char[EditSearch->Text.Length()+1];
    int UpperHexStringLength = 0;

    // Remove non hexa characters
    for (int CharLoop=0; CharLoop < EditSearch->Text.Length(); CharLoop++)
    {
      if ( (UpperSearchString[CharLoop] >= '0') && (UpperSearchString[CharLoop] <= '9'))
      {
        UpperHexString[UpperHexStringLength++] = UpperSearchString[CharLoop];
      }
      if ( (UpperSearchString[CharLoop] >= 'A') && (UpperSearchString[CharLoop] <= 'F'))
      {
        UpperHexString[UpperHexStringLength++] = UpperSearchString[CharLoop];
      }
    }
    UpperHexString[UpperHexStringLength] = '\0';

    delete [] UpperSearchString;

    delete [] mSearchBytes;
    mSearchLength = UpperHexStringLength / 2;
    mSearchBytes = new char[mSearchLength];

    // Create hex array
    int HexIndex = 0;
    for (int CharLoop=0; CharLoop < UpperHexStringLength; CharLoop+=2)
    {
      // High nibble (First character)
      if ( (UpperHexString[CharLoop] >= '0') && (UpperHexString[CharLoop] <= '9'))
      {
        mSearchBytes[HexIndex] = (UpperHexString[CharLoop] - '0') << 4;
      }
      else if ( (UpperHexString[CharLoop] >= 'A') && (UpperHexString[CharLoop] <= 'F'))
      {
        mSearchBytes[HexIndex] = (UpperHexString[CharLoop] - 'A' + 10) << 4;
      }

      // Low nibble (Second character)
      if ( (UpperHexString[CharLoop+1] >= '0') && (UpperHexString[CharLoop+1] <= '9'))
      {
        mSearchBytes[HexIndex++] += UpperHexString[CharLoop+1] - '0';
      }
      else if ( (UpperHexString[CharLoop+1] >= 'A') && (UpperHexString[CharLoop+1] <= 'F'))
      {
        mSearchBytes[HexIndex++] += UpperHexString[CharLoop+1] - 'A' + 10;
      }
    }

    delete [] UpperHexString;

    if (mSearchHexRoutine)
    {
      mSearchHexRoutine(FormMain->NativeCPC);
    }
  }

	if (Sender != NULL)
	{
		ActiveControl = StringGridDump;
	}

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


void __fastcall TFormMemoryEditor::PanelButtonAddBreakpointClick(TObject *Sender)
{
	TEmulatorBreakpoint Breakpoint;
	Breakpoint.Address = CurrentAddress;
	Breakpoint.MemoryRead = false;
	Breakpoint.MemoryWrite = false;
	Breakpoint.LowerROM = false;
	Breakpoint.UpperROM = false;
	Breakpoint.UpperROMIndex = 0;

	switch (TabControlMemoryContent->TabIndex)
	{
		// Banked Read
		case 0:
		{
			Breakpoint.MemoryRead = true;
		}
		break;

		// Banked Write
		case 1:
		{
			Breakpoint.MemoryWrite = true;
		}
		break;

		// Lower ROM
		case 3:
		{
			Breakpoint.MemoryRead = true;
			Breakpoint.LowerROM = true;
		}
		break;

		// Upper ROM
		case 4:
		{
			Breakpoint.MemoryRead = true;
			Breakpoint.UpperROM = true;
			Breakpoint.UpperROMIndex = FormMain->NativeCPC->GateArray->upper_ROM;
		}
		break;
	}

	FormDebugger->ToggleBreakpointMem(Breakpoint);

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


void __fastcall TFormMemoryEditor::PanelButtonRefreshClick(TObject *Sender)
{
	// Perform differences
	mMemoryDiffRoutine(FormMain->NativeCPC);

  UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	CurrentAddress = mCurrentAddress;

  ActiveControl = StringGridDump;

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


void __fastcall TFormMemoryEditor::PanelCheckMonitoringClick(TObject *Sender)
{
  mMonitoring = mMonitoring == true ? false : true;
  Caption = Title;

	if (mMonitoring == true)
	{
		PanelCheckMonitoring->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonColor;
  }
  else
  {
		PanelCheckMonitoring->Color = mSettingsP->ThemeButtonColor;
		PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonTextColor;
  }

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


void __fastcall TFormMemoryEditor::TabControlMemoryContentChange(
      TObject *Sender)
{
  // Display refresh
	MemoryIndex = TabControlMemoryContent->TabIndex;
  UpdateBanks(FormMain->NativeCPC);
	mMemoryDiffRoutine(FormMain->NativeCPC);
  mShowMemoryDumpRoutine(FormMain->NativeCPC);
  CurrentAddress = mCurrentAddress;

  // Disable Edit Value
  PanelEditValue->Visible = false;
	StringGridDump->SetFocus();

	// "Banked Read"
	if ( (TabControlMemoryContent->TabIndex == 0)
			 || (TabControlMemoryContent->TabIndex == 1))
	{
		PanelButtonAddBreakpoint->Visible = true;
		AddReadWriteMemoryBreakpointMenu->Visible = true;
		PanelButtonShowInstruction->Visible = true;
		SetZ80InstructionsTopAddressMenu->Visible = true;
	}
	// "Banked Write"
	// "Lower ROM"
	// "Upper ROM"
	else if ( (TabControlMemoryContent->TabIndex == 1)
						|| (TabControlMemoryContent->TabIndex == 3)
						|| (TabControlMemoryContent->TabIndex == 4) )
	{
		PanelButtonAddBreakpoint->Visible = true;
		AddReadWriteMemoryBreakpointMenu->Visible = true;
		PanelButtonShowInstruction->Visible = false;
		SetZ80InstructionsTopAddressMenu->Visible = false;
	}
	else
	{
		PanelButtonAddBreakpoint->Visible = false;
		AddReadWriteMemoryBreakpointMenu->Visible = false;
		PanelButtonShowInstruction->Visible = false;
		SetZ80InstructionsTopAddressMenu->Visible = false;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::TabControlMemoryContentDrawTab(TCustomTabControl *Control,
          int TabIndex, const TRect &Rect, bool Active)
{
  TCanvas* Canvas = TabControlMemoryContent->Canvas;

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

  // Draw tab
  Canvas->FillRect(Rect);
  AnsiString Text = TabControlMemoryContent->Tabs->Strings[TabIndex];
  int TextWidth = Canvas->TextWidth(Text);
  int TextHeight = Canvas->TextHeight(Text);
  int TextPosX = (Rect.Width() - TextWidth) / 2;
  int TextPosY = (TabControlMemoryContent->TabHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+TextPosX, Rect.Top+TextPosY, Text);

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


void __fastcall TFormMemoryEditor::ShowBankedREADDump(tNativeCPC* NativeCPC)
{
tULong BaseAddress = mTopAddress;

  // Update Memory Tab
  TabControlMemoryContent->Tabs->Strings[TAB_UPPER_ROM] = "Upper ROM "
      + AnsiString::IntToHex(FormMain->NativeCPC->GateArray->upper_ROM, 2);

	// Select current address cell
	int LastCol = StringGridDump->Col;
	int CurrentRow = ((int)mCurrentAddress - (int)mTopAddress) / 16;
	int CurrentCol = ((mCurrentAddress - mTopAddress) % 16) + 1;
	if (mCurrentAddress < mTopAddress)
	{
		// Nothing to do !!
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		// Nothing to do !!
	}
	else
	{
		StringGridDump->Row = CurrentRow;
		StringGridDump->Col = CurrentCol;

		if (LastCol > 17)
		{
			StringGridDump->Col += 17;
		}
	}

	int MaxRow = StringGridDump->Height / StringGridDump->DefaultRowHeight;
	int RowLoop;
	for (RowLoop=0; RowLoop < MaxRow; RowLoop++)
	{
		if (BaseAddress >= (mMemoryStartAddress + mMemorySize))
			break;

		StringGridDump->Cells[0][RowLoop] = AnsiString::IntToHex(BaseAddress, 4) + ":";

		for (int ByteLoop=0; ByteLoop < 16; ByteLoop++)
		{
			tUChar Data = (tUChar)Engine_ReadBankedRead(NativeCPC, BaseAddress - mMemoryStartAddress + ByteLoop);
			StringGridDump->Cells[ByteLoop+1][RowLoop] = AnsiString::IntToHex(Data, 2);
			StringGridDump->Cells[18+ByteLoop][RowLoop] = (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
		}

		BaseAddress += 16;
	}

	StringGridDump->RowCount = RowLoop;
	mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::ShowBankedWRITEDump(tNativeCPC* NativeCPC)
{
tULong BaseAddress = mTopAddress;

  // Update Memory Tab
  TabControlMemoryContent->Tabs->Strings[TAB_UPPER_ROM] = "Upper ROM "
      + AnsiString::IntToHex(FormMain->NativeCPC->GateArray->upper_ROM, 2);

  // Select current address cell
	int LastCol = StringGridDump->Col;
	int CurrentRow = (mCurrentAddress - mTopAddress) / 16;
	int CurrentCol = ((mCurrentAddress - mTopAddress) % 16) + 1;
	if (mCurrentAddress < mTopAddress)
	{
		// Nothing to do !!
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		// Nothing to do !!
	}
	else
	{
		StringGridDump->Row = CurrentRow;
		StringGridDump->Col = CurrentCol;

		if (LastCol > 17)
		{
			StringGridDump->Col += 17;
		}
	}

	int MaxRow = StringGridDump->Height / StringGridDump->DefaultRowHeight;
  int RowLoop;
  for (RowLoop=0; RowLoop < MaxRow; RowLoop++)
  {
    if (BaseAddress >= (mMemoryStartAddress + mMemorySize))
      break;

    StringGridDump->Cells[0][RowLoop] = AnsiString::IntToHex(BaseAddress, 4) + ":";

    for (int ByteLoop=0; ByteLoop < 16; ByteLoop++)
    {
      tUChar Data = (tUChar)Engine_ReadBankedWrite(NativeCPC, BaseAddress - mMemoryStartAddress + ByteLoop);
      StringGridDump->Cells[ByteLoop+1][RowLoop] = AnsiString::IntToHex(Data, 2);
      StringGridDump->Cells[18+ByteLoop][RowLoop] = (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
    }

    BaseAddress += 16;
  }

  StringGridDump->RowCount = RowLoop;
  mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::ShowEntireRAMDump(tNativeCPC* NativeCPC)
{
tULong BaseAddress = mTopAddress;

  // Update Memory Tab
  TabControlMemoryContent->Tabs->Strings[TAB_UPPER_ROM] = "Upper ROM "
      + AnsiString::IntToHex(FormMain->NativeCPC->GateArray->upper_ROM, 2);

	// Select current address cell
	int LastCol = StringGridDump->Col;
	int CurrentRow = (mCurrentAddress - mTopAddress) / 16;
	int CurrentCol = ((mCurrentAddress - mTopAddress) % 16) + 1;
	if (mCurrentAddress < mTopAddress)
	{
		// Nothing to do !!
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		// Nothing to do !!
	}
	else
	{
		StringGridDump->Row = CurrentRow;
		StringGridDump->Col = CurrentCol;

		if (LastCol > 17)
		{
			StringGridDump->Col += 17;
		}
	}

	int MaxRow = StringGridDump->Height / StringGridDump->DefaultRowHeight;
	int RowLoop;
	for (RowLoop=0; RowLoop < MaxRow; RowLoop++)
  {
    if (BaseAddress >= (mMemoryStartAddress + mMemorySize))
      break;

    StringGridDump->Cells[0][RowLoop] = AnsiString::IntToHex(BaseAddress, 4) + ":";

    for (int ByteLoop=0; ByteLoop < 16; ByteLoop++)
    {
      tUChar Data = (tUChar)Engine_ReadRAM(NativeCPC,
                                           BaseAddress - mMemoryStartAddress + ByteLoop);
      StringGridDump->Cells[ByteLoop+1][RowLoop] = AnsiString::IntToHex(Data, 2);
      StringGridDump->Cells[18+ByteLoop][RowLoop] = (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
    }

    BaseAddress += 16;
  }

  StringGridDump->RowCount = RowLoop;
	mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::ShowLowerROMDump(tNativeCPC* NativeCPC)
{
tULong BaseAddress = mTopAddress;

	// Update Memory Tab
	TabControlMemoryContent->Tabs->Strings[TAB_UPPER_ROM] = "Upper ROM "
      + AnsiString::IntToHex(FormMain->NativeCPC->GateArray->upper_ROM, 2);

	// Select current address cell
	int LastCol = StringGridDump->Col;
	int CurrentRow = (mCurrentAddress - mTopAddress) / 16;
	int CurrentCol = ((mCurrentAddress - mTopAddress) % 16) + 1;
	if (mCurrentAddress < mTopAddress)
	{
		// Nothing to do !!
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		// Nothing to do !!
	}
	else
	{
		StringGridDump->Row = CurrentRow;
		StringGridDump->Col = CurrentCol;

		if (LastCol > 17)
		{
			StringGridDump->Col += 17;
		}
	}

	int MaxRow = StringGridDump->Height / StringGridDump->DefaultRowHeight;
	int RowLoop;
	for (RowLoop=0; RowLoop < MaxRow; RowLoop++)
	{
		if (BaseAddress >= (mMemoryStartAddress + mMemorySize))
			break;

		StringGridDump->Cells[0][RowLoop] = AnsiString::IntToHex(BaseAddress, 4) + ":";

		for (int ByteLoop=0; ByteLoop < 16; ByteLoop++)
		{
			tUChar Data = (tUChar)Engine_ReadLowerROM(NativeCPC,
																								BaseAddress - mMemoryStartAddress + ByteLoop);
			StringGridDump->Cells[ByteLoop+1][RowLoop] = AnsiString::IntToHex(Data, 2);
			StringGridDump->Cells[18+ByteLoop][RowLoop] = (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
		}

		BaseAddress += 16;
	}

	StringGridDump->RowCount = RowLoop;
	mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::ShowUpperROMDump(tNativeCPC* NativeCPC)
{
tULong BaseAddress = mTopAddress;

  // Update Memory Tab
	TabControlMemoryContent->Tabs->Strings[TAB_UPPER_ROM] = "Upper ROM "
      + AnsiString::IntToHex(FormMain->NativeCPC->GateArray->upper_ROM, 2);

	// Select current address cell
	int LastCol = StringGridDump->Col;
	int CurrentRow = (mCurrentAddress - mTopAddress) / 16;
	int CurrentCol = ((mCurrentAddress - mTopAddress) % 16) + 1;
	if (mCurrentAddress < mTopAddress)
	{
		// Nothing to do !!
	}
	else if (CurrentRow >= StringGridDump->RowCount)
	{
		// Nothing to do !!
	}
	else
	{
		StringGridDump->Row = CurrentRow;
		StringGridDump->Col = CurrentCol;

		if (LastCol > 17)
		{
			StringGridDump->Col += 17;
		}
	}

	int MaxRow = StringGridDump->Height / StringGridDump->DefaultRowHeight;
  int RowLoop;
  for (RowLoop=0; RowLoop < MaxRow; RowLoop++)
  {
    if (BaseAddress >= (mMemoryStartAddress + mMemorySize))
      break;

    StringGridDump->Cells[0][RowLoop] = AnsiString::IntToHex(BaseAddress, 4) + ":";

    for (int ByteLoop=0; ByteLoop < 16; ByteLoop++)
    {
      tUChar Data = (tUChar)Engine_ReadUpperROM(NativeCPC,
                                                BaseAddress - mMemoryStartAddress + ByteLoop);
      StringGridDump->Cells[ByteLoop+1][RowLoop] = AnsiString::IntToHex(Data, 2);
      StringGridDump->Cells[18+ByteLoop][RowLoop] = (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
    }

    BaseAddress += 16;
  }

  StringGridDump->RowCount = RowLoop;
	mCurrentData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::WriteDataBankedREAD(tNativeCPC* NativeCPC)
{
  try
	{
    AnsiString NewData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
    AnsiString HexValue = "0x0" + NewData;
    tULong Data = (tULong)StrToInt(HexValue.Trim());
    Engine_WriteBankedRead(NativeCPC, mCurrentAddress-mMemoryStartAddress, Data);
		FormMain->Refresh();
	}
	catch(...)
	{
		StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
	}
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::WriteDataBankedWRITE(tNativeCPC* NativeCPC)
{
	try
	{
		AnsiString NewData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
		AnsiString HexValue = "0x0" + NewData;
		tULong Data = (tULong)StrToInt(HexValue.Trim());
		Engine_WriteBankedWrite(NativeCPC, mCurrentAddress-mMemoryStartAddress, Data);
		FormMain->Refresh();
	}
	catch(...)
	{
		StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
	}
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::WriteDataEntireRAM(tNativeCPC* NativeCPC)
{
	try
	{
		AnsiString NewData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
		AnsiString HexValue = "0x0" + NewData;
		tUChar Data = (tUChar)StrToInt(HexValue.Trim());

		*(NativeCPC->pbRAM + mCurrentAddress - mMemoryStartAddress) = Data;

		FormMain->Refresh();
	}
	catch(...)
	{
		StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
	}
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::WriteDataLowerROM(tNativeCPC* NativeCPC)
{
	try
	{
		AnsiString NewData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
		AnsiString HexValue = "0x0" + NewData;
		tULong Data = (tULong)StrToInt(HexValue.Trim());
		Engine_WriteLowerROM(NativeCPC, mCurrentAddress-mMemoryStartAddress, Data);
		FormMain->Refresh();
	}
	catch(...)
	{
		StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
	}
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::WriteDataUpperROM(tNativeCPC* NativeCPC)
{
	try
	{
		AnsiString NewData = StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row];
		AnsiString HexValue = "0x0" + NewData;
		tULong Data = (tULong)StrToInt(HexValue.Trim());
		Engine_WriteUpperROM(NativeCPC, mCurrentAddress-mMemoryStartAddress, Data);
		FormMain->Refresh();
	}
	catch(...)
	{
		StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::SearchASCIIBankedREAD(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

	do
	{
		// Next data
		Address++;
		if (Address == (mMemoryStartAddress+mMemorySize))
		{
			Address = mMemoryStartAddress;
		}

    tUChar Data = (tUChar)Engine_ReadBankedRead(NativeCPC, Address);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Adjust case sensitive
    if (CheckBoxStringCaseSensitive->Checked == false)
    {
      if ( (Data >= 'a') && (Data <= 'z')) Data -= 'a' - 'A';
      if ( (SearchData >= 'a') && (SearchData <= 'z')) SearchData -= 'a' - 'A';
    }

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchHexBankedREAD(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = (tUChar)Engine_ReadBankedRead(NativeCPC, Address);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::SearchASCIIBankedWRITE(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = (tUChar)Engine_ReadBankedWrite(NativeCPC, Address);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Adjust case sensitive
    if (CheckBoxStringCaseSensitive->Checked == false)
    {
      if ( (Data >= 'a') && (Data <= 'z')) Data -= 'a' - 'A';
      if ( (SearchData >= 'a') && (SearchData <= 'z')) SearchData -= 'a' - 'A';
    }

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchHexBankedWRITE(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = (tUChar)Engine_ReadBankedWrite(NativeCPC, Address);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::SearchASCIIEntireRAMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbRAM + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Adjust case sensitive
    if (CheckBoxStringCaseSensitive->Checked == false)
    {
      if ( (Data >= 'a') && (Data <= 'z')) Data -= 'a' - 'A';
      if ( (SearchData >= 'a') && (SearchData <= 'z')) SearchData -= 'a' - 'A';
    }

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchHexEntireRAMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbRAM + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchASCIILowerROMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbROMlo + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Adjust case sensitive
    if (CheckBoxStringCaseSensitive->Checked == false)
    {
      if ( (Data >= 'a') && (Data <= 'z')) Data -= 'a' - 'A';
      if ( (SearchData >= 'a') && (SearchData <= 'z')) SearchData -= 'a' - 'A';
    }

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchHexLowerROMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbROMlo + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchASCIIUpperROMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbExpansionROM + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Adjust case sensitive
    if (CheckBoxStringCaseSensitive->Checked == false)
    {
      if ( (Data >= 'a') && (Data <= 'z')) Data -= 'a' - 'A';
      if ( (SearchData >= 'a') && (SearchData <= 'z')) SearchData -= 'a' - 'A';
    }

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------
void __fastcall TFormMemoryEditor::SearchHexUpperROMMemory(tNativeCPC* NativeCPC)
{
tULong Address = mCurrentAddress;
tULong FirstAddress = Address;
tULong FirstFound;
int CompIndex = 0;

  do
  {
    // Next data
    Address++;
    if (Address == (mMemoryStartAddress+mMemorySize))
    {
      Address = mMemoryStartAddress;
    }

    tUChar Data = *(FormMain->NativeCPC->pbExpansionROM + Address - mMemoryStartAddress);
    tUChar SearchData = mSearchBytes[CompIndex];

    // Comparaison OK ?
    if (Data == SearchData)
    {
      if (CompIndex == 0)
      {
        FirstFound = Address;
      }

      CompIndex++;
      // String found ?
      if (CompIndex == mSearchLength)
        break;
    }
    else
    {
      CompIndex = 0;
    }
  }
  while (Address != FirstAddress);

  // Occurence found ?
  if (CompIndex == mSearchLength)
  {
    if (FirstFound < mTopAddress)
    {
      TopAddress = FirstFound;
    }
    else if (FirstFound >= (mTopAddress+ScrollBarDump->LargeChange))
    {
      TopAddress = FirstFound;
    }
    CurrentAddress = FirstFound;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);
  }

	NOT_USED(NativeCPC);
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::PerformBankedREADDiff(tNativeCPC* NativeCPC)
{
	for (tULong Index=0; Index < mMemorySize; Index++)
	{
		tUChar CurrentData = (tUChar)Engine_ReadBankedRead(NativeCPC, mMemoryStartAddress + Index);

		mMemoryDiff[Index] = CurrentData ^ mPreviousMemory[Index]; // Keep differences only

		// Update previous
		mPreviousMemory[Index] = CurrentData;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::PerformBankedWRITEDiff(tNativeCPC* NativeCPC)
{
	for (tULong Index=0; Index < mMemorySize; Index++)
	{
		tUChar CurrentData = (tUChar)Engine_ReadBankedWrite(NativeCPC, mMemoryStartAddress + Index);

		mMemoryDiff[Index] = CurrentData ^ mPreviousMemory[Index]; // Keep differences only

		// Update previous
		mPreviousMemory[Index] = CurrentData;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::PerformLowerROMDiff(tNativeCPC* NativeCPC)
{
	for (tULong Index=0; Index < mMemorySize; Index++)
	{
		tUChar CurrentData = (tUChar)Engine_ReadLowerROM(NativeCPC, mMemoryStartAddress + Index);

		mMemoryDiff[Index] = CurrentData ^ mPreviousMemory[Index]; // Keep differences only

		// Update previous
		mPreviousMemory[Index] = CurrentData;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::PerformUpperROMDiff(tNativeCPC* NativeCPC)
{
	for (tULong Index=0; Index < mMemorySize; Index++)
	{
		tUChar CurrentData = (tUChar)Engine_ReadUpperROM(NativeCPC, mMemoryStartAddress + Index);

		mMemoryDiff[Index] = CurrentData ^ mPreviousMemory[Index]; // Keep differences only

		// Update previous
		mPreviousMemory[Index] = CurrentData;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::PerformEntireRAMDiff(tNativeCPC* NativeCPC)
{
	for (tULong Index=0; Index < mMemorySize; Index++)
	{
		tUChar CurrentData = (tUChar)Engine_ReadRAM(NativeCPC, mMemoryStartAddress + Index);

		mMemoryDiff[Index] = CurrentData ^ mPreviousMemory[Index]; // Keep differences only

		// Update previous
		mPreviousMemory[Index] = CurrentData;
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormMemoryEditor::PanelButtonDumpSetFullLimitsClick(TObject *Sender)
{
  mExportFromAddress = mMemoryStartAddress;
  PanelExportFrom->Caption = (PanelFormatExportFrom->Caption.IsEmpty() == false) ?
                             AnsiString::IntToHex(mExportFromAddress, 6) :
                             AnsiString(mExportFromAddress);

  mExportToAddress = mMemoryStartAddress + mMemorySize - 1;
  PanelExportTo->Caption = (PanelFormatExportTo->Caption.IsEmpty() == false) ?
                           AnsiString::IntToHex(mExportToAddress, 6) :
                           AnsiString(mExportToAddress);

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


void __fastcall TFormMemoryEditor::PanelButtonDumpExportTextClick(TObject *Sender)
{
  bool StartOutOfRange = false;
  bool EndOutOfRange = false;

  tULong StartAddress = mExportFromAddress;
  if (StartAddress < mMemoryStartAddress)
  {
    StartAddress = mMemoryStartAddress;
    StartOutOfRange = true;
  }
  else if (StartAddress > (mMemoryStartAddress + mMemorySize - 1))
  {
    StartAddress = mMemoryStartAddress + mMemorySize - 1;
    StartOutOfRange = true;
  }

  tULong EndAddress = mExportToAddress;
  if (EndAddress < mMemoryStartAddress)
  {
    EndAddress = mMemoryStartAddress;
    EndOutOfRange = true;
  }
  else if (EndAddress > (mMemoryStartAddress + mMemorySize - 1))
  {
    EndAddress = mMemoryStartAddress + mMemorySize - 1;
    EndOutOfRange = true;
  }

  // Out of range
  if ( (StartOutOfRange == true) && (EndOutOfRange == true) )
  {
    Application->MessageBox(_T("Out of range"), _T("Error"), MB_OK);
  }
  else
  {
    SaveDialog->Title = "Export Text Dump";
    SaveDialog->Filter = TEXT_DUMP_FILTER;
    SaveDialog->InitialDir = GetCurrentDir();
    switch (TabControlMemoryContent->TabIndex)
    {
      // Banked memory
      case TAB_BANKED_READ: SaveDialog->FileName = "Banked Read dump.txt"; break;
      // Banked memory
      case TAB_BANKED_WRITE: SaveDialog->FileName = "Banked Write dump.txt"; break;
      // Lower ROM
      case TAB_LOWER_ROM: SaveDialog->FileName = "Lower ROM dump.txt"; break;
      // Upper ROM
      case TAB_UPPER_ROM: SaveDialog->FileName = "Upper ROM dump.txt"; break;
      // Entire RAM
      default: SaveDialog->FileName = "RAM dump.txt"; break;
    }

    if (SaveDialog->Execute() == true)
    {
      // Create file strings
      TStringList* FileStrings = new TStringList();

      // Swap addresses
      if (StartAddress > EndAddress)
      {
        tULong Temp = StartAddress;
        StartAddress = EndAddress;
        EndAddress = Temp;
      }

      for (tULong Address = StartAddress; Address <= EndAddress; Address += 16U)
      {
        // Get size of string
        tUChar StringSize;
        if ( (Address+16U) <= EndAddress)
        {
          StringSize = 16;
        }
        else
        {
          StringSize = (tUChar)(EndAddress - Address + 1);
        }

        // Prepare beginning of string
        AnsiString FileString = "";

        // Add address in big endian
        FileString += AnsiString::IntToHex((Address >> 16) & 0xff, 2);
        FileString += AnsiString::IntToHex((Address >> 8) & 0xff, 2);
        FileString += AnsiString::IntToHex(Address & 0xff, 2);
        FileString += "  ";

        AnsiString ASCIIString = "  ";

        // Add Banked Read Data
        if (TabControlMemoryContent->TabIndex == TAB_BANKED_READ)
        {
          for (tUChar DataLoop=0; DataLoop < StringSize; DataLoop++)
          {
            tUChar Data = (tUChar)Engine_ReadBankedRead(FormMain->NativeCPC, Address - mMemoryStartAddress + DataLoop);
            FileString += AnsiString::IntToHex(Data, 2);
            ASCIIString += (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
            // Data separator
            if ((DataLoop & 3) == 3) FileString += " ";
          }
        }
        // Add Banked Read Data
        else if (TabControlMemoryContent->TabIndex == TAB_BANKED_WRITE)
        {
          for (tUChar DataLoop=0; DataLoop < StringSize; DataLoop++)
          {
            tUChar Data = (tUChar)Engine_ReadBankedWrite(FormMain->NativeCPC, Address - mMemoryStartAddress + DataLoop);
            FileString += AnsiString::IntToHex(Data, 2);
            ASCIIString += (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
            // Data separator
            if ((DataLoop & 3) == 3) FileString += " ";
          }
        }
        // Add Lower ROM data
        else if (TabControlMemoryContent->TabIndex == TAB_LOWER_ROM)
        {
          for (tUChar DataLoop=0; DataLoop < StringSize; DataLoop++)
          {
            tUChar Data = *(FormMain->NativeCPC->pbROMlo + Address - mMemoryStartAddress + DataLoop);
            FileString += AnsiString::IntToHex(Data, 2);
            ASCIIString += (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
            // Data separator
            if ((DataLoop & 3) == 3) FileString += " ";
          }
        }
        // Add Upper ROM data
        else if (TabControlMemoryContent->TabIndex == TAB_UPPER_ROM)
        {
          for (tUChar DataLoop=0; DataLoop < StringSize; DataLoop++)
          {
            tUChar Data = *(FormMain->NativeCPC->pbExpansionROM + Address - mMemoryStartAddress + DataLoop);
            FileString += AnsiString::IntToHex(Data, 2);
            ASCIIString += (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
            // Data separator
            if ((DataLoop & 3) == 3) FileString += " ";
          }
        }
        // Entire RAM
        else
        {
          for (tUChar DataLoop=0; DataLoop < StringSize; DataLoop++)
          {
            tUChar Data = *(FormMain->NativeCPC->pbRAM + Address - mMemoryStartAddress + DataLoop);
            FileString += AnsiString::IntToHex(Data, 2);
            ASCIIString += (mShowASCII7Bits == true) ? ASCIIChar[Data & 0x7f] : ASCIIChar[Data];
            // Data separator
            if ((DataLoop & 3) == 3) FileString += " ";
          }
        }

        FileStrings->Add(FileString + ASCIIString);
      }

      // Write file
      FileStrings->SaveToFile(SaveDialog->FileName);

      delete FileStrings;
    }
  }

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


void __fastcall TFormMemoryEditor::PanelButtonDumpExportBinaryClick(TObject *Sender)
{
  bool StartOutOfRange = false;
  bool EndOutOfRange = false;

  tULong StartAddress = mExportFromAddress;
  if (StartAddress < mMemoryStartAddress)
  {
    StartAddress = mMemoryStartAddress;
    StartOutOfRange = true;
  }
  else if (StartAddress > (mMemoryStartAddress + mMemorySize - 1))
  {
    StartAddress = mMemoryStartAddress + mMemorySize - 1;
    StartOutOfRange = true;
  }

  tULong EndAddress = mExportToAddress;
  if (EndAddress < mMemoryStartAddress)
  {
    EndAddress = mMemoryStartAddress;
    EndOutOfRange = true;
  }
  else if (EndAddress > (mMemoryStartAddress + mMemorySize - 1))
  {
    EndAddress = mMemoryStartAddress + mMemorySize - 1;
    EndOutOfRange = true;
  }

  // Out of range
  if ( (StartOutOfRange == true) && (EndOutOfRange == true) )
  {
    Application->MessageBox(_T("Out of range"), _T("Error"), MB_OK);
  }
  else
  {
    SaveDialog->Title = "Export Binary Dump";
    SaveDialog->Filter = BINARY_DUMP_FILTER;
    SaveDialog->InitialDir = GetCurrentDir();
    switch (TabControlMemoryContent->TabIndex)
    {
      // Banked Read
      case TAB_BANKED_READ: SaveDialog->FileName = "Banked Read dump.bin"; break;
      // Banked Write
      case TAB_BANKED_WRITE: SaveDialog->FileName = "Banked Write dump.bin"; break;
      // Lower ROM
      case TAB_LOWER_ROM: SaveDialog->FileName = "Lower ROM dump.bin"; break;
      // Upper ROM
      case TAB_UPPER_ROM: SaveDialog->FileName = "Upper ROM dump.bin"; break;
      // Entire RAM
      default: SaveDialog->FileName = "RAM dump.bin"; break;
    }

    if (SaveDialog->Execute() == true)
    {
      TFileStream* file = new TFileStream(SaveDialog->FileName, fmCreate);

      // Swap addresses
      if (StartAddress > EndAddress)
      {
        tULong Temp = StartAddress;
        StartAddress = EndAddress;
        EndAddress = Temp;
      }

      // Banked Read Data
      if (TabControlMemoryContent->TabIndex == TAB_BANKED_READ)
      {
        for (tULong Address = StartAddress; Address <= EndAddress; Address++)
        {
          tUChar Data = (tUChar)Engine_ReadBankedRead(FormMain->NativeCPC, Address - mMemoryStartAddress);
          file->Write(&Data, 1);
        }
      }
      // Banked Write Data
      else if (TabControlMemoryContent->TabIndex == TAB_BANKED_WRITE)
      {
        for (tULong Address = StartAddress; Address <= EndAddress; Address++)
        {
          tUChar Data = (tUChar)Engine_ReadBankedWrite(FormMain->NativeCPC, Address - mMemoryStartAddress);
          file->Write(&Data, 1);
        }
      }
      // Add Lower ROM data
      else if (TabControlMemoryContent->TabIndex == TAB_LOWER_ROM)
      {
        tUChar* DataP = FormMain->NativeCPC->pbROMlo + StartAddress - mMemoryStartAddress;
        file->Write(DataP, EndAddress - StartAddress + 1);
      }
      // Add Upper ROM data
      else if (TabControlMemoryContent->TabIndex == TAB_UPPER_ROM)
      {
        tUChar* DataP = FormMain->NativeCPC->pbExpansionROM + StartAddress - mMemoryStartAddress;
        file->Write(DataP, EndAddress - StartAddress + 1);
      }
      // Entire RAM
      else
      {
        tUChar* DataP = FormMain->NativeCPC->pbRAM + StartAddress - mMemoryStartAddress;
        file->Write(DataP, EndAddress - StartAddress + 1);
      }

      delete file;
    }
  }

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


void __fastcall TFormMemoryEditor::PanelButtonDumpImportBinaryClick(TObject *Sender)
{
  OpenDialog->Title = "Import Binary Dump";
  OpenDialog->Filter = BINARY_DUMP_FILTER;
  OpenDialog->InitialDir = GetCurrentDir();

  if (OpenDialog->Execute() == true)
  {
    tULong Length = 0;
    tUChar* FileDataP = NULL;

    int Handle = FileOpen(OpenDialog->FileName, fmOpenRead | fmShareDenyNone);
    if (Handle != -1)
    {
      Length = (tULong)FileSeek(Handle, 0, 2);
      FileSeek(Handle, 0, 0);

      FileDataP = (tUChar*)malloc(Length);

      FileRead(Handle, FileDataP, Length);
      FileClose(Handle);
    }

    bool StartOutOfRange = false;
    bool EndOutOfRange = false;

    tULong StartAddress = mExportFromAddress;
    if (StartAddress < mMemoryStartAddress)
    {
      StartOutOfRange = true;
    }
    else if (StartAddress > (mMemoryStartAddress + mMemorySize - 1))
    {
      StartOutOfRange = true;
    }

    tULong EndAddress = StartAddress + Length - 1;
    if (EndAddress < mMemoryStartAddress)
    {
      EndOutOfRange = true;
    }
    else if (EndAddress > (mMemoryStartAddress + mMemorySize - 1))
    {
      EndOutOfRange = true;
    }

    // Out of range
    if ( (StartOutOfRange == true) && (EndOutOfRange == true) )
    {
      Application->MessageBox(_T("Out of range"), _T("Error"), MB_OK);
    }
    else if (Length)
    {
      for (tULong NbData=0; NbData < Length; NbData++)
      {
        tULong Address = StartAddress + NbData;
        tUChar Data = *(FileDataP + NbData);

        if ( (Address >= mMemoryStartAddress)
             && (Address <= (mMemoryStartAddress + mMemorySize - 1)) )
        {
          Address -= mMemoryStartAddress;

          // Banked Read Data
          if (TabControlMemoryContent->TabIndex == TAB_BANKED_READ)
          {
            Engine_WriteBankedRead(FormMain->NativeCPC, Address, Data);
          }
          // Banked Write Data
          else if (TabControlMemoryContent->TabIndex == TAB_BANKED_WRITE)
          {
            Engine_WriteBankedWrite(FormMain->NativeCPC, Address, Data);
          }
          // Lower ROM data
          else if (TabControlMemoryContent->TabIndex == TAB_LOWER_ROM)
          {
            Engine_WriteLowerROM(FormMain->NativeCPC, Address, Data);
          }
          // Upper ROM data
          else if (TabControlMemoryContent->TabIndex == TAB_UPPER_ROM)
          {
            Engine_WriteUpperROM(FormMain->NativeCPC, Address, Data);
          }
          // Entire RAM
          else
          {
            *(FormMain->NativeCPC->pbRAM + Address) = Data;
          }
        }
      }

      // Display refresh
      UpdateBanks(FormMain->NativeCPC);
      mShowMemoryDumpRoutine(FormMain->NativeCPC);
    }

    free(FileDataP);
  }

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


void __fastcall TFormMemoryEditor::UpdateBanks(tNativeCPC* NativeCPC)
{
  //
  // READ
  //
  // Bank 0
  int Address;
  if (NativeCPC->membank_read[0] == NativeCPC->pbROMlo)
  {
    PanelButtonBankRead0000->Caption = "Lower ROM";
  }
#ifdef ENABLE_MULTIFACE2
  // Multiface 2 ?
  else if (NativeCPC->membank_read[0] == NativeCPC->pbMF2ROM)
  {
    PanelButtonBankRead0000->Caption = "Multiface2";
  }
#endif /* ENABLE_MULTIFACE2 */
  else
  {
    Address = NativeCPC->membank_read[0] - NativeCPC->pbRAM;
    PanelButtonBankRead0000->Caption = AnsiString::IntToHex(Address, 4);
  }
  // Bank 1
  Address = NativeCPC->membank_read[1] - NativeCPC->pbRAM;
  PanelButtonBankRead4000->Caption = AnsiString::IntToHex(Address, 4);
  // Bank 2
  Address = NativeCPC->membank_read[2] - NativeCPC->pbRAM;
  PanelButtonBankRead8000->Caption = AnsiString::IntToHex(Address, 4);
  // Bank 3
  Address = NativeCPC->membank_read[3] - NativeCPC->pbRAM;
  if (NativeCPC->membank_read[3] == NativeCPC->pbExpansionROM)
  {
		PanelButtonBankReadC000->Caption = "Upper ROM";
	}
	else
	{
    PanelButtonBankReadC000->Caption = AnsiString::IntToHex(Address, 4);
  }


	//
  // WRITE
  //
  // Bank 0
#ifdef ENABLE_MULTIFACE2
  // Multiface 2 ?
  if (NativeCPC->membank_write[0] == NativeCPC->pbMF2ROM)
  {
    PanelButtonBankWrite0000->Caption = "Multiface2";
  }
  else
#endif /* ENABLE_MULTIFACE2 */
  {
    Address = NativeCPC->membank_write[0] - NativeCPC->pbRAM;
    PanelButtonBankWrite0000->Caption = AnsiString::IntToHex(Address, 4);
  }
  // Bank 1
  Address = NativeCPC->membank_write[1] - NativeCPC->pbRAM;
  PanelButtonBankWrite4000->Caption = AnsiString::IntToHex(Address, 4);
  // Bank 2
  Address = NativeCPC->membank_write[2] - NativeCPC->pbRAM;
	PanelButtonBankWrite8000->Caption = AnsiString::IntToHex(Address, 4);
  // Bank 3
  Address = NativeCPC->membank_write[3] - NativeCPC->pbRAM;
	PanelButtonBankWriteC000->Caption = AnsiString::IntToHex(Address, 4);


	// 64Ko memory ?
	if (NativeCPC->ram_size == 64)
	{
		ComboBoxRAMBanksBaseAddress->Enabled = false;
		ComboBoxRAMBanksMapping->Enabled = false;
		ComboBoxRAMBanksBaseAddress->Clear();
		ComboBoxRAMBanksBaseAddress->Items->Add(AnsiString::IntToHex(0x10000, 4));
		ComboBoxRAMBanksBaseAddress->ItemIndex = 0;
		ComboBoxRAMBanksMapping->ItemIndex = 0;
		LabelRAMBanksBaseAddress->Caption = "64K";
	}
	else
	{
		ComboBoxRAMBanksBaseAddress->Enabled = true;
		ComboBoxRAMBanksMapping->Enabled = true;

		// Update list of available banks
		ComboBoxRAMBanksBaseAddress->Clear();
		for (tULong Address=0x10000; Address < (NativeCPC->ram_size * 1024); Address += 0x10000)
		{
			ComboBoxRAMBanksBaseAddress->Items->Add(AnsiString::IntToHex(Address, 4));
		}

		// Expansion base
		int Address = 65536 /* First 64Ko */
									+ NativeCPC->ram_4mb_offset
									+ (NativeCPC->GateArray->RAM_bank * 65536);
		ComboBoxRAMBanksBaseAddress->ItemIndex = ComboBoxRAMBanksBaseAddress->Items->IndexOf(AnsiString::IntToHex(Address, 4));
		ComboBoxRAMBanksMapping->ItemIndex = NativeCPC->GateArray->RAM_config & 7;
		LabelRAMBanksBaseAddress->Caption = AnsiString(Address >> 10) + "K";
	}
}
//---------------------------------------------------------------------------


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

  if (mPaused != Pause)
  {
    mPaused = Pause;
		Caption = Title;

		// Update GUI linked to Pause modification
		//PanelButtonShowInstruction->Visible = mPaused;
		//SetZ80InstructionsTopAddressMenu->Visible = mPaused;
	}

	if (Condition & EC_REFRESH)
	{
		PanelButtonRefreshClick(NULL);
	}

	if (Condition & EC_END_INSTRUCTION)
	{
		// Reset differences
		mMemoryDiffRoutine(FormMain->NativeCPC);

		// Display refresh
		UpdateBanks(FormMain->NativeCPC);
		mShowMemoryDumpRoutine(FormMain->NativeCPC);
	}
	else if ( (mMonitoring == true) && (Condition & EC_FRAME_COMPLETE) )
	{
		// Display refresh
		UpdateBanks(FormMain->NativeCPC);
		mShowMemoryDumpRoutine(FormMain->NativeCPC);
	}
	else if (Condition & EC_RESET)
	{
		// Display refresh
		MemoryIndex = TabControlMemoryContent->TabIndex;
		UpdateBanks(FormMain->NativeCPC);
		mShowMemoryDumpRoutine(FormMain->NativeCPC);
		mMemoryDiffRoutine(FormMain->NativeCPC);
		CurrentAddress = mCurrentAddress;
		// Entire form display refresh (to update hexa value format)
		Invalidate();
	}

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


void __fastcall TFormMemoryEditor::StringGridDumpDblClick(TObject *Sender)
{
	// Adapt size of custom edit
  TRect CellRect = StringGridDump->CellRect(StringGridDump->Col, StringGridDump->Row);

  // Prepare Edit Panel position and size
	if (StringGridDump->Col < 17)
	{
		PanelEditValue->Left = StringGridDump->Left + CellRect.Left;
		PanelEditValue->Width = CellRect.Right - CellRect.Left;
		PanelEditValue->Top = StringGridDump->Top + CellRect.Top;
		PanelEditValue->Height = CellRect.Bottom - CellRect.Top;
	}
	else
	{
		PanelEditValue->Left = StringGridDump->Left + CellRect.Left - 4;
		PanelEditValue->Width = CellRect.Right - CellRect.Left + 8;
		PanelEditValue->Top = StringGridDump->Top + CellRect.Top;
		PanelEditValue->Height = CellRect.Bottom - CellRect.Top;
	}

	int TextWidth = StringGridDump->Canvas->TextWidth(mCurrentData);
	int TextHeight = StringGridDump->Canvas->TextHeight(mCurrentData);
	EditValue->Left = (PanelEditValue->Width - TextWidth) / 2;
	EditValue->Width = TextWidth + 1;
	EditValue->Top = ((PanelEditValue->Height - TextHeight) / 2);
	EditValue->Height = TextHeight;
	PanelEditValue->Top = StringGridDump->Top + CellRect.Top;
	EditValue->MaxLength = (StringGridDump->Col < 17) ? 2 : 1;
	EditValue->CharCase = (StringGridDump->Col < 17) ? ecUpperCase : ecNormal;

  EditValue->Text = mCurrentData;
  EditValue->SelectAll();

  PanelEditValue->Visible = true;
  EditValue->SetFocus();

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

void __fastcall TFormMemoryEditor::EditValueKeyPress(TObject *Sender, System::WideChar &Key)
{
  if (Key == VK_RETURN)
  {
		if (EditValue->MaxLength == 2)
		{
			// Update content
			mCurrentData = EditValue->Text;
			StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;

			// Update data
			if (mWriteDataRoutine)
			{
				mWriteDataRoutine(FormMain->NativeCPC);
			}
		}

    // Go next byte
    tULong NextAddress = mCurrentAddress + 1;
    if (NextAddress < (mMemoryStartAddress + mMemorySize))
    {
      if (NextAddress >= (mTopAddress+ScrollBarDump->LargeChange))
      {
        TopAddress += 16;
      }
      CurrentAddress = NextAddress;
    }

    StringGridDump->SetFocus();
    PanelEditValue->Visible = false;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
    mShowMemoryDumpRoutine(FormMain->NativeCPC);

		if ( (EditValue->MaxLength == 1) && (StringGridDump->Col < 17) )
		{
			// Select ASCII
			StringGridDump->Col += 17;
		}

    // Edit Next Byte
    StringGridDumpDblClick(Sender);

    // Key has been treated (prevent windows bell sound)
    Key = 0;
  }
  else if (Key == VK_ESCAPE)
  {
    StringGridDump->SetFocus();
    PanelEditValue->Visible = false;

    // Key has been treated (prevent windows bell sound)
    Key = 0;
  }

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

void __fastcall TFormMemoryEditor::EditValueExit(TObject *Sender)
{
  PanelEditValue->Visible = false;

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

void __fastcall TFormMemoryEditor::EditValueChange(TObject *Sender)
{
	if ( (EditValue->Text.Length() == EditValue->MaxLength)
			 && (PanelEditValue->Visible == true) )
	{
		if (EditValue->MaxLength == 2)
		{
			// Update content
			mCurrentData = EditValue->Text;
			StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
		}
		else
		{
			wchar_t* TextArray = EditValue->Text.c_str();
			char ASCIICode = (char)TextArray[0];
			mCurrentData = AnsiString::IntToHex(ASCIICode, 2);
			StringGridDump->Cells[StringGridDump->Col][StringGridDump->Row] = mCurrentData;
		}

    // Update data
    if (mWriteDataRoutine)
    {
      mWriteDataRoutine(FormMain->NativeCPC);
    }

    // Go next byte
    tULong NextAddress = mCurrentAddress + 1;
    if (NextAddress < (mMemoryStartAddress + mMemorySize))
    {
      if (NextAddress >= (mTopAddress+ScrollBarDump->LargeChange))
      {
        TopAddress += 16;
      }
      CurrentAddress = NextAddress;
    }

    StringGridDump->SetFocus();
    PanelEditValue->Visible = false;

    // Display refresh
    UpdateBanks(FormMain->NativeCPC);
		mShowMemoryDumpRoutine(FormMain->NativeCPC);

		if ( (EditValue->MaxLength == 1) && (StringGridDump->Col < 17) )
		{
			// Select ASCII
			StringGridDump->Col += 17;
		}

    // Edit Next Byte
    StringGridDumpDblClick(Sender);
  }
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::PanelButtonSetFillFromClick(TObject *Sender)
{
  mFillFromAddress = CurrentAddress;
  PanelFillFrom->Caption = (PanelFormatFillFrom->Caption.IsEmpty() == false) ?
                           AnsiString::IntToHex(mFillFromAddress, 6) :
                           AnsiString(mFillFromAddress);

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

void __fastcall TFormMemoryEditor::PanelButtonSetFillToClick(TObject *Sender)
{
  mFillToAddress = CurrentAddress;
  PanelFillTo->Caption = (PanelFormatFillTo->Caption.IsEmpty() == false) ?
                         AnsiString::IntToHex(mFillToAddress, 6) :
                         AnsiString(mFillToAddress);

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

void __fastcall TFormMemoryEditor::PanelButtonSetFillDataClick(TObject *Sender)
{
  AnsiString HexValue = "0x0" + mCurrentData;
  mFillData = (tULong)StrToInt(HexValue.Trim());
  PanelFillData->Caption = (PanelFormatFillData->Caption.IsEmpty() == false) ?
                           AnsiString::IntToHex(mFillData, 2) :
                           AnsiString(mFillData);

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

void __fastcall TFormMemoryEditor::PanelButtonSetDumpFromClick(TObject *Sender)
{
  mExportFromAddress = CurrentAddress;
  PanelExportFrom->Caption = (PanelFormatExportFrom->Caption.IsEmpty() == false) ?
                             AnsiString::IntToHex(mExportFromAddress, 6) :
                             AnsiString(mExportFromAddress);

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

void __fastcall TFormMemoryEditor::PanelButtonSetDumpToClick(TObject *Sender)
{
  mExportToAddress = CurrentAddress;
  PanelExportTo->Caption = (PanelFormatExportTo->Caption.IsEmpty() == false) ?
                           AnsiString::IntToHex(mExportToAddress, 6) :
                           AnsiString(mExportToAddress);

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

void __fastcall TFormMemoryEditor::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 TFormMemoryEditor::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 TFormMemoryEditor::PanelButtonBankRead0000Click(TObject *Sender)
{
	MemoryIndex = 0; // Select banked Read memory
	CurrentAddress = 0x0000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankWrite0000Click(TObject *Sender)
{
	MemoryIndex = 1; // Select banked Write memory
	CurrentAddress = 0x0000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankRead4000Click(TObject *Sender)
{
	MemoryIndex = 0; // Select banked Read memory
	CurrentAddress = 0x4000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankWrite4000Click(TObject *Sender)
{
	MemoryIndex = 1; // Select banked Write memory
	CurrentAddress = 0x4000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankRead8000Click(TObject *Sender)
{
	MemoryIndex = 0; // Select banked Read memory
	CurrentAddress = 0x8000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankWrite8000Click(TObject *Sender)
{
	MemoryIndex = 1; // Select banked Write memory
	CurrentAddress = 0x8000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankReadC000Click(TObject *Sender)
{
	MemoryIndex = 0; // Select banked Read memory
	CurrentAddress = 0xC000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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

void __fastcall TFormMemoryEditor::PanelButtonBankWriteC000Click(TObject *Sender)
{
	MemoryIndex = 1; // Select banked Write memory
	CurrentAddress = 0xC000;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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


void __fastcall TFormMemoryEditor::PanelButtonGoCurrentAddressClick(TObject *Sender)
{
	// Go at current address;
	TopAddress = CurrentAddress - (((StringGridDump->RowCount-1) / 2) * 16); // Middle of Window

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);
	StringGridDump->SetFocus();

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


void __fastcall TFormMemoryEditor::PanelCheckShowASCII7BitsClick(TObject *Sender)
{
	// Invert
	mShowASCII7Bits = mShowASCII7Bits == true ? false : true;

	// Display refresh
	UpdateBanks(FormMain->NativeCPC);
	mShowMemoryDumpRoutine(FormMain->NativeCPC);

	if (mShowASCII7Bits == true)
	{
		PanelCheckShowASCII7Bits->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckShowASCII7Bits->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckShowASCII7Bits->Color = mSettingsP->ThemeButtonColor;
		PanelCheckShowASCII7Bits->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

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

void __fastcall TFormMemoryEditor::PanelCheckShowDiffClick(TObject *Sender)
{
	// Invert
	mShowDiffHighlight = mShowDiffHighlight == true ? false : true;

	// Refresh dump display
	StringGridDump->Invalidate();

	if (mShowDiffHighlight == true)
	{
		PanelCheckShowDiff->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckShowDiff->Font->Color = mSettingsP->ThemeButtonColor;
  }
  else
  {
		PanelCheckShowDiff->Color = mSettingsP->ThemeButtonColor;
    PanelCheckShowDiff->Font->Color = mSettingsP->ThemeButtonTextColor;
  }

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

void __fastcall TFormMemoryEditor::SetZ80InstructionsTopAddressMenuClick(TObject *Sender)

{
	FormMain->Pause(true);
	FormZ80Editor->TopAddress = mCurrentAddress;

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


void __fastcall TFormMemoryEditor::EditSearchKeyPress(TObject *Sender, System::WideChar &Key)
{
	if ((Key == VK_RETURN) || (Key == VK_ENTER))
	{
		PanelButtonSearchNextClick(NULL);
		Key = 0;
	}

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


void __fastcall TFormMemoryEditor::ComboBoxDrawItem(TWinControl *Control,
          int Index, TRect &Rect, TOwnerDrawState State)
{
  TComboBox* ComboBox = (TComboBox*)Control;
  TCanvas* Canvas = ComboBox->Canvas;

  if (State.Contains(odSelected))
  {
    Canvas->Brush->Color = clHighlight;
    Canvas->Font->Color = clWhite;
  }
  else
  {
    Canvas->Brush->Color = clWhite;
		Canvas->Font->Color = clBlack;
  }

  // Draw cell
  Canvas->FillRect(Rect);
  AnsiString Text = ComboBox->Items->Strings[Index];
  int TextHeight = Canvas->TextHeight(Text);
  int TextPos = (ComboBox->ItemHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+5, Rect.Top+TextPos, Text);
  if (State.Contains(odFocused))
  {
    Canvas->DrawFocusRect(Rect);
  }

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


void __fastcall TFormMemoryEditor::ComboBoxRAMBanksBaseAddressChange(TObject *Sender)
{
  if (ComboBoxRAMBanksBaseAddress->Focused() == false)
    return;

  tNativeCPC* NativeCPC = FormMain->NativeCPC;

  // Prepare GateArray settings
  int Address = StrToInt("0x" + ComboBoxRAMBanksBaseAddress->Text) - 65536 /* First 64Ko */;
  NativeCPC->ram_4mb_new_offset = Address & 0x00380000;
  NativeCPC->GateArray->RAM_config = (((Address >> 16) & 7) << 3) + ComboBoxRAMBanksMapping->ItemIndex;

  // Update GateArray memory settings
  Engine_GAMemoryManager(NativeCPC);
	FormMain->Refresh();

	// Refresh display
	PanelButtonRefreshClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TFormMemoryEditor::ComboBoxRAMBanksMappingChange(TObject *Sender)
{
  if (ComboBoxRAMBanksMapping->Focused() == false)
    return;

  tNativeCPC* NativeCPC = FormMain->NativeCPC;

  // Prepare GateArray settings
  int Address = StrToInt("0x" + ComboBoxRAMBanksBaseAddress->Text) - 65536 /* First 64Ko */;
  NativeCPC->ram_4mb_new_offset = Address & 0x00380000;
  NativeCPC->GateArray->RAM_config = (((Address >> 16) & 7) << 3) + ComboBoxRAMBanksMapping->ItemIndex;

	// Update GateArray memory settings
	Engine_GAMemoryManager(NativeCPC);
	FormMain->Refresh();

  // Refresh display
  PanelButtonRefreshClick(Sender);
}
//---------------------------------------------------------------------------

