/*
 CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
 Copyright (C) 2014-2018 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 <stdlib.h>
#include <Clipbrd.hpp>
#include <Filectrl.hpp>
#include <tchar.h>
#pragma hdrstop
#include "TFormCodeExplorer.h"
#include "TFormMain.h"
#include "TFormDebugger.h"
#include "..\..\Common\Z80DASM\z80dasm.h"
// Following undef should be done just before inclusing pasmo.h
#undef _SP
#include "..\..\Common\Pasmo\pasmo.h"
#include "..\..\Common\ASCII.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"


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

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


static const AnsiString cTitle = "Code explorer";
static const AnsiString cTitlePaused  = " - [PAUSED]";

static const AnsiString cDefaultAsmFilename = "newfile.asm";
static const AnsiString cDefaultBasicFilename = "newfile.bas";


#define NB_DIGITS_TOP_ADDRESS_HEX         4
#define NB_DIGITS_TOP_ADDRESS_DEC         5
#define NB_DIGITS_CODE_ORIGIN_HEX         4
#define NB_DIGITS_CODE_ORIGIN_DEC         5
#define NB_DIGITS_CODE_SIZE_HEX           4
#define NB_DIGITS_CODE_SIZE_DEC           5


// Code from ManageDsk by Ludovic Deplanque
static const char BasicToken[0x80][15] =
{
	/* 0x80 */ "AFTER", "AUTO", "BORDER", "CALL", "CAT", "CHAIN", "CLEAR", "CLG",
	/* 0x88 */ "CLOSEIN", "CLOSEOUT", "CLS", "CONT", "DATA", "DEF", "DEFINT", "DEFREAL",
	/* 0x90 */ "DEFSTR", "DEG", "DELETE", "DIM", "DRAW", "DRAWR", "EDIT", "ELSE",
	/* 0x98 */ "END", "ENT", "ENV", "ERASE", "ERROR", "EVERY", "FOR", "GOSUB",
	/* 0xA0 */ "GOTO", "IF", "INK", "INPUT", "KEY", "LET", "LINE", "LIST",
	/* 0xA8 */ "LOAD", "LOCATE", "MEMORY", "MERGE", "MID$", "MODE", "MOVE", "MOVER",
	/* 0xB0 */ "NEXT", "NEW", "ON", "ON BREAK", "ON ERROR GOTO", "SQ", "OPENIN", "OPENOUT",
	/* 0xB8 */ "ORIGIN", "OUT", "PAPER", "PEN", "PLOT", "PLOTR", "POKE", "PRINT",
	/* 0xC0 */ "'", "RAD", "RANDOMIZE", "READ", "RELEASE", "REM", "RENUM", "RESTORE",
	/* 0xC8 */ "RESUME", "RETURN", "RUN", "SAVE", "SOUND", "SPEED", "STOP", "SYMBOL",
	/* 0xD0 */ "TAG", "TAGOFF", "TROFF", "TRON", "WAIT", "WEND", "WHILE", "WIDTH",
	/* 0xD8 */ "WINDOW", "WRITE", "ZONE", "DI", "EI", "FILL", "GRAPHICS", "MASK",
	/* 0xE0 */ "FRAME", "CURSOR", "#E2", "ERL", "FN", "SPC", "STEP", "SWAP",
	/* 0xE8 */ "#E8", "#E9", "TAB", "THEN", "TO", "USING", ">", "=",
	/* 0xF0 */ ">=", "<", "<>", "<=", "+", "-", "*", "/",
	/* 0xF8 */ "^", "\\ ", "AND", "MOD", "OR", "XOR", "NOT", "#FF"
};

// Code from ManageDsk by Ludovic Deplanque
static const char BasicFcts[0x80][10] =
{
  /* 0x00 */ "ABS", "ASC", "ATN", "CHR$", "CINT", "COS", "CREAL", "EXP",
  /* 0x08 */ "FIX", "FRE", "INKEY", "INP", "INT", "JOY", "LEN", "LOG",
  /* 0x10 */ "LOG10", "LOWER$", "PEEK", "REMAIN", "SGN", "SIN", "SPACE$", "SQ",
  /* 0x18 */ "SQR", "STR$", "TAN", "UNT", "UPPER$", "VAL", "", "",
  /* 0x20 */ "", "", "", "", "", "", "", "",
  /* 0x28 */ "", "", "", "", "", "", "", "",
  /* 0x30 */ "", "", "", "", "", "", "", "",
  /* 0x38 */ "", "", "", "", "", "", "", "",
  /* 0x40 */ "EOF", "ERR", "HIMEM", "INKEY$", "PI", "RND", "TIME", "XPOS",
  /* 0x48 */ "YPOS", "DERR", "", "", "", "", "", "",
  /* 0x50 */ "", "", "", "", "", "", "", "",
  /* 0x58 */ "", "", "", "", "", "", "", "",
  /* 0x60 */ "", "", "", "", "", "", "", "",
  /* 0x68 */ "", "", "", "", "", "", "", "",
  /* 0x70 */ "", "BIN$", "DEC$", "HEX$", "INSTR", "LEFT$", "MAX", "MIN",
  /* 0x78 */ "POS", "RIGHT$", "ROUND", "STRING$", "TEST", "TESTR", "COPYCHR$", "VPOS"
};

// Code from ManageDsk by Ludovic Deplanque
//
// Tableau de décryptage d'un programme en basic protégé
//
static BYTE BasicDecipher[128] =
{
  0xAB, 0x2C, 0xED, 0xEA, 0x6C, 0x37, 0x3F, 0xEC,
  0x9B, 0xDF, 0x7A, 0x0C, 0x3B, 0xD4, 0x6D, 0xF5,
  0x04, 0x44, 0x03, 0x11, 0xDF, 0x59, 0x8F, 0x21,
  0x73, 0x7A, 0xCC, 0x83, 0xDD, 0x30, 0x6A, 0x30,
  0xD3, 0x8F, 0x02, 0xF0, 0x60, 0x6B, 0x94, 0xE4,
  0xB7, 0xF3, 0x03, 0xA8, 0x60, 0x88, 0xF0, 0x43,
  0xE8, 0x8E, 0x43, 0xA0, 0xCA, 0x84, 0x31, 0x53,
  0xF3, 0x1F, 0xC9, 0xE8, 0xAD, 0xC0, 0xBA, 0x6D,
  0x93, 0x08, 0xD4, 0x6A, 0x2C, 0xB2, 0x07, 0x27,
  0xC0, 0x99, 0xEE, 0x89, 0xAF, 0xC3, 0x53, 0xAB,
  0x2B, 0x34, 0x5C, 0x2F, 0x13, 0xEE, 0xAA, 0x2C,
  0xD9, 0xF4, 0xBC, 0x12, 0xB3, 0xC5, 0x1C, 0x68,
  0x01, 0x20, 0x2C, 0xFA, 0x77, 0xA6, 0xB5, 0xA4,
  0xFC, 0x9B, 0xF1, 0x32, 0x5B, 0xC3, 0x70, 0x77,
  0x85, 0x36, 0xBE, 0x5B, 0x8C, 0xC8, 0xB5, 0xC2,
  0xF0, 0x0B, 0x98, 0x0F, 0x36, 0x9D, 0xD8, 0x96
};


static tUChar ReadFileData(tNativeCPC* NativeCPC,tULong addr)
{
  return (((tUChar*)NativeCPC)[addr]);
}


TFormCodeExplorer *FormCodeExplorer;
//---------------------------------------------------------------------------
__fastcall TFormCodeExplorer::TFormCodeExplorer(TComponent* Owner)
  : TForm(Owner)
{
  mEmulatorP = NULL;
  mSettingsP = NULL;

  mBASICLinesAddress = NULL;
  mBASICLinesAddressCount = 0;

  mTopAddress = 0;
  mCodeOrigin = 0;
  mCodeLast = 0;
  mCodeSize = 1;
  mSelectedAddress = 0;

  mAssemblerFilename = cDefaultAsmFilename;
  ComboBoxAssemblerFilename->Text = "CODE.BIN";

  mBasicFilename = cDefaultBasicFilename;
  //ComboBoxBasicFilename->Text = "CODE.BAS";
  ComboBoxBasicFilename->Enabled = false;
  PanelButtonBasicDriveALoad->Visible = false;

  ShowAssemblerInstructions();

  PageControlFeatures->ActivePage = TabSheetPatch;
  PanelButtonPatchUpdate->Height = EditPatchAssembly->Height;
  ComboBoxRAMBanksMapping->ItemIndex = 0;

  mFormEditValue = new TFormEditValue(this);

  // 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;
    }
    else if (Components[Loop]->Name.Pos("Edit") == 1)
    {
      ((TEdit*)Components[Loop])->Font->Color = clBlack;
    }
    else if (Components[Loop]->Name.Pos("Memo") == 1)
    {
      ((TMemo*)Components[Loop])->Font->Color = clBlack;
    }
    else if (Components[Loop]->Name.Pos("ComboBox") == 1)
    {
      ((TComboBox*)Components[Loop])->Font->Color = clBlack;
    }
  }

	StringGridInstructions->Canvas->Font = Font;
}
//---------------------------------------------------------------------------

void __fastcall TFormCodeExplorer::FormDestroy(TObject *Sender)
{
  delete mFormEditValue;
  delete [] mBASICLinesAddress;

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


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

	FormMain->OnCodeExplorerFormShow();

	// Allow files Drag and Drop
	DragAcceptFiles(Handle, true);

  ShowHint = FormMain->ShowHint;

  WindowState = wsNormal;

  //ComboBoxRAMBanksMapping->Perform(CB_SETDROPPEDWIDTH, 100, 0);
  RichEditAssembler->CaretPos = TPoint(0,0);

  TabControlMemoryContent->TabIndex = 0;
  mMemoryStartAddress = 0x0000;
  mMemorySize = 0x10000;
  mMaxAddress = mMemoryStartAddress + mMemorySize - 1;
  mZ80dasmParam.NativeCPC = FormMain->NativeCPC;
  mZ80dasmParam.ReadFunction = Engine_ReadBankedWrite;
  mZ80dasmParam.DummyZ80 = 0;
  mWriteFunction = Engine_WriteBankedWrite;

  PanelFormatTopAddress->Caption = "&&";
  TopAddress = mTopAddress;
  PanelFormatCodeOrigin->Caption = "&&";
  CodeOrigin = mCodeOrigin;
  PanelFormatCodeLast->Caption = "&&";
  CodeLast = mCodeLast;
  PanelFormatCodeSize->Caption = "&&";
  CodeSize = mCodeSize;

  UpdateCatalogue();
  UpdateBanks();

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

  // Subscribe to events
  FormMain->SubscribeToDiskEvents(OnDiskEvent);
  FormMain->SubscribeToCPCEvents(OnCPCEvent);

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

void __fastcall TFormCodeExplorer::FormHide(TObject *Sender)
{
  // Unsubscribe to events
  if (FormMain != NULL)
  {
    FormMain->UnsubscribeToDiskEvents(OnDiskEvent);
    FormMain->UnsubscribeToCPCEvents(OnCPCEvent);
		FormMain->OnCodeExplorerFormHide();
	}

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

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


AnsiString __fastcall TFormCodeExplorer::GetTitle(void)
{
  AnsiString Title = cTitle;
  if (mPaused == true) Title += cTitlePaused;

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


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

  if (    (mSettingsP->CodeExplorerFormLeft != 0)
       || (mSettingsP->CodeExplorerFormTop != 0)
       || (mSettingsP->CodeExplorerFormWidth != 0)
       || (mSettingsP->CodeExplorerFormHeight != 0) )
  {
    Position = poDesigned;
    Left = mSettingsP->CodeExplorerFormLeft;
    Top = mSettingsP->CodeExplorerFormTop;
    Width = mSettingsP->CodeExplorerFormWidth;
    Height = mSettingsP->CodeExplorerFormHeight;
  }

  // Apply theme
  Color = mSettingsP->ThemeBackgroundColor;
  Font->Color = mSettingsP->ThemeText1Color;
  StringGridInstructions->Font->Color = mSettingsP->ThemeText2Color;
  GroupBoxBanks->Font->Color = mSettingsP->ThemeText2Color;
  PanelPatchMachine->Font->Color = mSettingsP->ThemeText1Color;
  PanelCodeSize->Font->Color = mSettingsP->ThemeText1Color;
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name.Pos("PanelButton") == 1)
    {
      ((TPanel*)Components[Loop])->Color = mSettingsP->ThemeButtonColor;
      ((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeButtonTextColor;
    }
    else if (Components[Loop]->Name.Pos("LabelBankWrite") == 1)
    {
      ((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText2Color;
    }
    else if (Components[Loop]->Name.Pos("PanelBankWrite") == 1)
    {
      ((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
		}
		else if (Components[Loop]->Name.Pos("Label") == 1)
		{
			((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
		}
		else if (Components[Loop]->Name.Pos("EditNoteAddress") == 1)
		{
			((TEdit*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
		}

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

	EditIncludesDirectory->Text = mSettingsP->AsmIncludeDirectory;
	EditPredefines->Text = mSettingsP->AsmPredefines;
	if (mSettingsP->AsmUsePredefines == true)
	{
		PanelCheckUsePredefines->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckUsePredefines->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		PanelCheckUsePredefines->Color = mSettingsP->ThemeButtonColor;
		PanelCheckUsePredefines->Font->Color = mSettingsP->ThemeButtonTextColor;
	}

	// 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->GetCodeExplorerMarker(Index-1);
    }
  }

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


void __fastcall TFormCodeExplorer::FormResize(TObject *Sender)
{
  if ( (Visible == true) && (mSettingsP) && (WindowState != wsMaximized) )
  {
    mSettingsP->CodeExplorerFormWidth = Width;
    mSettingsP->CodeExplorerFormHeight = Height;
  }

  if (Visible == true)
  {
    StringGridInstructions->SetFocus();
  }

  if ( (PageControlFeatures->ActivePage == TabSheetPatch)
       || (PageControlFeatures->ActivePage == TabSheetAssembler) )
  {
    ShowAssemblerInstructions();
  }
  else
  {
    ShowBASICMemory();
  }

  if ( (FormMain->NativeCPC != NULL) && (Visible == true) )
  {
    UpdateInstructions(FormMain->NativeCPC);
    UpdatePatch(FormMain->NativeCPC);
  }

  // Fix display problem with TRichEdit components
  if (RichEditAssembler->Visible == true)
  {
    RichEditAssembler->Refresh();
  }
  if (RichEditBasic->Visible == true)
  {
    RichEditBasic->Refresh();
  }

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


void __fastcall TFormCodeExplorer::WMMove(TMessage &Message)
{
  if ( (Visible == true) && (mSettingsP) && (WindowState != wsMaximized) )
  {
    mSettingsP->CodeExplorerFormLeft = Left;
    mSettingsP->CodeExplorerFormTop = Top;
  }

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


void __fastcall TFormCodeExplorer::ShowAssemblerInstructions(void)
{
  // Update tabs
  TabControlMemoryContent->Tabs->Clear();
  TabControlMemoryContent->Tabs->Add("Banked Write");
  TabControlMemoryContent->Tabs->Add("Lower ROM");
  TabControlMemoryContent->Tabs->Add("Upper ROM");

	// Prepare Grid for Assembler
	StringGridInstructions->RowCount = StringGridInstructions->Height / StringGridInstructions->DefaultRowHeight;
	StringGridInstructions->ColCount = 3;
	StringGridInstructions->ColWidths[0] = 48;
	StringGridInstructions->ColWidths[1] = 100;
	StringGridInstructions->ColWidths[2] = StringGridInstructions->Width -
				(StringGridInstructions->ColWidths[0]+StringGridInstructions->ColWidths[1]);
	ScrollBarAddress->PageSize = StringGridInstructions->RowCount;
	ScrollBarAddress->LargeChange = StringGridInstructions->RowCount;
}
//---------------------------------------------------------------------------

void __fastcall TFormCodeExplorer::ShowBASICMemory(void)
{
	// Update tabs
	TabControlMemoryContent->Tabs->Clear();
	TabControlMemoryContent->Tabs->Add("Banked Write");

  // Prepare Grid for BASIC
  StringGridInstructions->RowCount = StringGridInstructions->Height / StringGridInstructions->DefaultRowHeight;
  StringGridInstructions->ColCount = 2;
  StringGridInstructions->ColWidths[0] = 48;
  StringGridInstructions->ColWidths[1] = StringGridInstructions->Width - StringGridInstructions->ColWidths[0];
  ScrollBarAddress->PageSize = StringGridInstructions->RowCount;
  ScrollBarAddress->LargeChange = StringGridInstructions->RowCount;
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::UpdateInstructions(tNativeCPC* NativeCPC)
{
tULong addr = mTopAddress;

  // Assembler ?
  if ( (PageControlFeatures->ActivePage == TabSheetPatch)
       || (PageControlFeatures->ActivePage == TabSheetAssembler) )
  {
    // Update UpperROM Index
    TabControlMemoryContent->Tabs->Strings[2] = "Upper ROM " + AnsiString(NativeCPC->GateArray->upper_ROM);

    for (int Loop=0; Loop < StringGridInstructions->RowCount; Loop++)
    {
      if (addr <= mMaxAddress)
      {
        StringGridInstructions->Cells[0][Loop] = AnsiString::IntToHex(addr,NB_DIGITS_TOP_ADDRESS_HEX) + ":";
        addr = Z80dasmDecodeInstruction(addr,
                                        &mZ80dasmParam);

        if (addr <= (mMaxAddress+1))
        {
          StringGridInstructions->Cells[1][Loop] = AnsiString(mZ80dasmParam.MachineCode).UpperCase();
          StringGridInstructions->Cells[2][Loop] = AnsiString(mZ80dasmParam.Instruction).UpperCase();
        }
        else
        {
          StringGridInstructions->Cells[1][Loop] = AnsiString(mZ80dasmParam.MachineCode).SubString(0,3).UpperCase();
          StringGridInstructions->Cells[2][Loop] = "ILLEGAL";
        }
      }
      else
      {
        StringGridInstructions->Cells[0][Loop] = "";
        StringGridInstructions->Cells[1][Loop] = "";
        StringGridInstructions->Cells[2][Loop] = "";
      }
    }
  }
  // BASIC
  else
  {
    #define BASIC_NB_BYTES_DISPLAYED    6
    for (int Loop=0; Loop < StringGridInstructions->RowCount; Loop++)
    {
      if (addr <= mMaxAddress)
      {
        StringGridInstructions->Cells[0][Loop] = AnsiString::IntToHex(addr,NB_DIGITS_TOP_ADDRESS_HEX) + ":";

        AnsiString StringData;
        AnsiString StringAscii7Bits = "  ";

        for (int ByteLoop=0; ByteLoop < BASIC_NB_BYTES_DISPLAYED; ByteLoop++)
        {
          if ((addr+ByteLoop) <= mMaxAddress)
          {
            tUChar Data = (tUChar)Engine_ReadBankedWrite(NativeCPC, addr + ByteLoop);
            StringData += AnsiString::IntToHex(Data, 2) + " ";
            StringAscii7Bits += ASCIIChar[Data & 0x7F];
          }
        }

        StringGridInstructions->Cells[1][Loop] = StringData + StringAscii7Bits;
        addr += BASIC_NB_BYTES_DISPLAYED;
      }
      else
      {
        StringGridInstructions->Cells[0][Loop] = "";
        StringGridInstructions->Cells[1][Loop] = "";
      }
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::UpdateCatalogue(void)
{
  // Populate files list
  AnsiString LastAssemblerFilename = ComboBoxAssemblerFilename->Text;
  AnsiString LastBasicFilename = ComboBoxBasicFilename->Text;

  ComboBoxAssemblerFilename->Clear();
  ComboBoxBasicFilename->Clear();

  mEmulatorP->ReadDiskCatalogue(DriveA, (tUChar)0);
  for (int Loop=0; Loop < mEmulatorP->NbCatalogEntries; Loop++)
  {
    ComboBoxAssemblerFilename->Items->Add(mEmulatorP->CatalogEntry[Loop]);
    ComboBoxBasicFilename->Items->Add(mEmulatorP->CatalogEntry[Loop]);
  }

  ComboBoxAssemblerFilename->Text = LastAssemblerFilename;
  ComboBoxBasicFilename->Text = LastBasicFilename;

  if (ComboBoxBasicFilename->Items->Count)
  {
    ComboBoxBasicFilename->Enabled = true;
    PanelButtonBasicDriveALoad->Visible = true;
  }
  else
  {
    ComboBoxBasicFilename->Text = "";
    ComboBoxBasicFilename->Enabled = false;
    PanelButtonBasicDriveALoad->Visible = false;
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::UpdatePatch(tNativeCPC* NativeCPC)
{
tULong addr = mTopAddress;
tULong instr_addr = addr;

  addr = Z80dasmDecodeInstruction(addr,
                                  &mZ80dasmParam);

  int Loop;
  for (Loop=0;
       ((Loop < StringGridInstructions->Row) && (addr <= mMaxAddress));
       Loop++)
  {
    instr_addr = addr;
    addr = Z80dasmDecodeInstruction(addr,
                                    &mZ80dasmParam);
  }

  if ( (Loop == StringGridInstructions->Row)
       && (instr_addr >= mMemoryStartAddress) && (instr_addr <= mMaxAddress) )
  {
    mSelectedAddress = instr_addr;
    EditPatchAssembly->Text = AnsiString(mZ80dasmParam.Instruction).UpperCase();
  }
  else
  {
    EditPatchAssembly->Text = "";
  }

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


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

  if (State.Contains(gdSelected))
  {
    StringGrid->Canvas->Brush->Color = clHighlight;
    StringGrid->Canvas->Font->Color = clWhite;
  }
  else if (ACol == 0)
  {
    StringGrid->Canvas->Brush->Color = Color;
    StringGrid->Canvas->Font->Color = mSettingsP->ThemeText2Color;
  }
  else
  {
    StringGrid->Canvas->Brush->Color = Color;
    StringGrid->Canvas->Font->Color = mSettingsP->ThemeText1Color;
  }

  // Draw cell
  StringGrid->Canvas->FillRect(Rect);
  int TextHeight = StringGrid->Canvas->TextHeight(StringGrid->Cells[ACol][ARow]);
  int TextPos = (StringGrid->RowHeights[ARow] - TextHeight) / 2;
  StringGrid->Canvas->TextOut(Rect.Left+5,
                              Rect.Top+TextPos,
                              StringGrid->Cells[ACol][ARow]);

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


void __fastcall TFormCodeExplorer::PanelFormatTopAddressClick(TObject *Sender)
{
  if (PanelFormatTopAddress->Caption.IsEmpty() == true)
  {
    PanelFormatTopAddress->Caption = "&&";
    PanelTopAddress->Caption = AnsiString::IntToHex(mTopAddress, NB_DIGITS_TOP_ADDRESS_HEX);
  }
  else
  {
    PanelFormatTopAddress->Caption = "";
    PanelTopAddress->Caption = mTopAddress;
  }

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

void __fastcall TFormCodeExplorer::PanelTopAddressClick(TObject *Sender)
{
  mFormEditValue->Title = "Top address";
  mFormEditValue->CurrentValue = mTopAddress;
  mFormEditValue->Hexadecimal = PanelFormatTopAddress->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = mMaxAddress;
  if (mFormEditValue->ShowModal() == mrOk)
  {
    TopAddress = mFormEditValue->NewValue;
    StringGridInstructions->SetFocus();
    StringGridInstructions->Row = 0;
  }

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


void __fastcall TFormCodeExplorer::SetTopAddress(tULong Value)
{
  mTopAddress = Value;
  if (mTopAddress < mMemoryStartAddress)
  {
    mTopAddress = mMemoryStartAddress;
  }
  else if (mTopAddress > mMaxAddress)
  {
    mTopAddress = mMaxAddress;
  }
  ScrollBarAddress->Position = mTopAddress;

  if (PanelFormatTopAddress->Caption.IsEmpty() == true)
  {
    PanelTopAddress->Caption = mTopAddress;
  }
  else
  {
    PanelTopAddress->Caption = AnsiString::IntToHex(mTopAddress, NB_DIGITS_TOP_ADDRESS_HEX);
  }

  UpdateInstructions(FormMain->NativeCPC);
  UpdatePatch(FormMain->NativeCPC);
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::SetCodeOrigin(tLong Value)
{
  mCodeOrigin = Value;

  // Get size of last instruction
  tLong addr = Z80dasmDecodeInstruction(CodeLast, &mZ80dasmParam);
  CodeSize = addr - CodeOrigin;

  if (PanelFormatCodeOrigin->Caption.IsEmpty() == true)
  {
    PanelCodeOrigin->Caption = mCodeOrigin;
  }
  else
  {
    PanelCodeOrigin->Caption = AnsiString::IntToHex(mCodeOrigin, NB_DIGITS_CODE_ORIGIN_HEX);
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelFormatCodeOriginClick(TObject *Sender)
{
  if (PanelFormatCodeOrigin->Caption.IsEmpty() == true)
  {
    PanelFormatCodeOrigin->Caption = "&&";
    PanelCodeOrigin->Caption = AnsiString::IntToHex(mCodeOrigin, NB_DIGITS_CODE_ORIGIN_HEX);
  }
  else
  {
    PanelFormatCodeOrigin->Caption = "";
    PanelCodeOrigin->Caption = mCodeOrigin;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelCodeOriginClick(TObject *Sender)
{
  mFormEditValue->Title = "Code origin";
  mFormEditValue->CurrentValue = mCodeOrigin;
  mFormEditValue->Hexadecimal = PanelFormatCodeOrigin->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = mMaxAddress;
  if (mFormEditValue->ShowModal() == mrOk)
  {
    CodeOrigin = mFormEditValue->NewValue;
  }

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


void __fastcall TFormCodeExplorer::SetCodeLast(tLong Value)
{
  mCodeLast = Value;

  // Get size of last instruction
  tLong addr = Z80dasmDecodeInstruction(CodeLast, &mZ80dasmParam);
  CodeSize = addr - CodeOrigin;

  if (PanelFormatCodeLast->Caption.IsEmpty() == true)
  {
    PanelCodeLast->Caption = mCodeLast;
  }
  else
  {
    PanelCodeLast->Caption = AnsiString::IntToHex(mCodeLast, NB_DIGITS_CODE_ORIGIN_HEX);
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelFormatCodeLastClick(TObject *Sender)
{
  if (PanelFormatCodeLast->Caption.IsEmpty() == true)
  {
    PanelFormatCodeLast->Caption = "&&";
    PanelCodeLast->Caption = AnsiString::IntToHex(mCodeLast, NB_DIGITS_CODE_ORIGIN_HEX);
  }
  else
  {
    PanelFormatCodeLast->Caption = "";
    PanelCodeLast->Caption = mCodeLast;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelCodeLastClick(TObject *Sender)
{
  mFormEditValue->Title = "Last code instruction";
  mFormEditValue->CurrentValue = mCodeLast;
  mFormEditValue->Hexadecimal = PanelFormatCodeLast->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = mMaxAddress;
  if (mFormEditValue->ShowModal() == mrOk)
  {
    CodeLast = mFormEditValue->NewValue;
  }

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


void __fastcall TFormCodeExplorer::SetCodeSize(tLong Value)
{
  mCodeSize = Value;

  if (mCodeSize < 0)
  {
    PanelCodeSize->Caption = "-";
  }
  else
  {
    if (PanelFormatCodeSize->Caption.IsEmpty() == true)
    {
      PanelCodeSize->Caption = mCodeSize;
    }
    else
    {
      PanelCodeSize->Caption = AnsiString::IntToHex(mCodeSize, NB_DIGITS_CODE_SIZE_HEX);
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall TFormCodeExplorer::PanelFormatCodeSizeClick(TObject *Sender)
{
  if (PanelFormatCodeSize->Caption.IsEmpty() == true)
  {
    PanelFormatCodeSize->Caption = "&&";
    PanelCodeSize->Caption = AnsiString::IntToHex(mCodeSize, NB_DIGITS_CODE_SIZE_HEX);
  }
  else
  {
    PanelFormatCodeSize->Caption = "";
    PanelCodeSize->Caption = mCodeSize;
  }

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


void __fastcall TFormCodeExplorer::ScrollBarAddressChange(TObject *Sender)
{
  TopAddress = ScrollBarAddress->Position;

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


void __fastcall TFormCodeExplorer::PanelButtonRefreshClick(TObject *Sender)
{
  // Update banks before updating instructions display
  UpdateBanks();

  // Update instructions display
  if ( (PageControlFeatures->ActivePage == TabSheetPatch)
       || (PageControlFeatures->ActivePage == TabSheetAssembler) )
  {
    ShowAssemblerInstructions();
  }
  else
  {
    ShowBASICMemory();
  }

  UpdateInstructions(FormMain->NativeCPC);
  UpdatePatch(FormMain->NativeCPC);
  UpdateCatalogue();

  // Form is active ?
  if (this->Active == true)
  {
    StringGridInstructions->SetFocus();
  }

  // Refresh code size
  CodeLast = CodeLast;

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


void __fastcall TFormCodeExplorer::PanelButtonRegPCClick(TObject *Sender)
{
tNativeCPC* NativeCPC = FormMain->NativeCPC;
tZ80* Z80 = NativeCPC->Z80;

  // Lower ROM ?
  if ( (_PC < 0x4000) && (NativeCPC->membank_read[0] == NativeCPC->pbROMlo) )
  {
    // Select Lower ROM
    MemoryIndex = 1;
  }
  // Upper ROM ?
  else if ( (_PC >= 0xC000) && (NativeCPC->membank_read[3] == NativeCPC->pbExpansionROM) )
  {
    // Select Upper ROM
    MemoryIndex = 2;
  }
  else
  {
    // Select RAM
    MemoryIndex = 0;
  }


  TopAddress = _PC;
  StringGridInstructions->SetFocus();
  StringGridInstructions->Row = 0;

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


void __fastcall TFormCodeExplorer::StringGridInstructionsMouseWheelUp(TObject *Sender,
          TShiftState Shift, TPoint &MousePos, bool &Handled)
{
  if (!StringGridInstructions->Row)
  {
    if (TopAddress > mMemoryStartAddress)
    {
      TopAddress--;
    }
  }

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

void __fastcall TFormCodeExplorer::StringGridInstructionsMouseWheelDown(TObject *Sender,
          TShiftState Shift, TPoint &MousePos, bool &Handled)
{
  if (StringGridInstructions->Row == StringGridInstructions->RowCount-1)
  {
    if (TopAddress < mMaxAddress)
    {
      TopAddress++;
    }
  }

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


void __fastcall TFormCodeExplorer::StringGridInstructionsDblClick(TObject *Sender)

{
tULong addr = mTopAddress;

  // Assembler ?
  if ( (PageControlFeatures->ActivePage == TabSheetPatch)
       || (PageControlFeatures->ActivePage == TabSheetAssembler) )
  {
    for (int Loop=0;
         ((Loop < StringGridInstructions->Row) && (addr <= mMaxAddress));
         Loop++)
    {
      addr = Z80dasmDecodeInstruction(addr,
                                      &mZ80dasmParam);
    }

    if (addr <= mMaxAddress)
    {
      TopAddress = addr;
      StringGridInstructions->SetFocus();
      StringGridInstructions->Row = 0;
    }
  }
  // BASIC
  else
  {
    // Nothing to do
  }


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


void __fastcall TFormCodeExplorer::PanelButtonSetCodeOriginClick(TObject *Sender)
{
tULong addr = mTopAddress;

  for (int Loop=0;
       ((Loop < StringGridInstructions->Row) && (addr < mMaxAddress));
       Loop++)
  {
    addr = Z80dasmDecodeInstruction(addr,
                                    &mZ80dasmParam);
  }

  if (addr <= mMaxAddress)
  {
    CodeOrigin = addr;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelButtonGoToCodeOriginClick(TObject *Sender)
{
  TopAddress = CodeOrigin;
  StringGridInstructions->SetFocus();
  StringGridInstructions->Row = 0;

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


void __fastcall TFormCodeExplorer::PanelButtonSetCodeLastClick(TObject *Sender)
{
tULong addr = mTopAddress;

  for (int Loop=0;
       ((Loop < StringGridInstructions->Row) && (addr < mMaxAddress));
       Loop++)
  {
    addr = Z80dasmDecodeInstruction(addr, &mZ80dasmParam);
  }

  if (addr <= mMaxAddress)
  {
    CodeLast = addr;
  }

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::PanelButtonGoToCodeLastClick(TObject *Sender)
{
  TopAddress = CodeLast;
  StringGridInstructions->SetFocus();
  StringGridInstructions->Row = 0;

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


void __fastcall TFormCodeExplorer::StringGridInstructionsClick(TObject *Sender)
{
  UpdatePatch(FormMain->NativeCPC);

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

void __fastcall TFormCodeExplorer::EditPatchAssemblyChange(TObject *Sender)
{
  // Get whole assembler code as long char string.
  int linesize = EditPatchAssembly->Text.Length();
  char* line = new char [linesize+1];
  size_t size = wcstombs(line, EditPatchAssembly->Text.c_str(), linesize);
  line[size] = '\0';

  unsigned char * code = NULL;

  try
  {
    if (size > 0)
    {
      unsigned short origin = mSelectedAddress;
      int codesize = pasmo_assemble_lines(line, &origin, &code, NULL);
      if (codesize > 0)
      {
        AnsiString Message = "Machine Code: ";
        for (int loop=0; loop < codesize; loop++)
        {
          Message += AnsiString::IntToHex(code[loop], 2) + " ";
        }
        PanelPatchMachine->Caption = Message;
        PanelButtonPatchUpdate->Visible = true;
      }
      else
      {
        PanelPatchMachine->Caption = "";
        PanelButtonPatchUpdate->Visible = false;
      }
    }
    else
    {
      PanelPatchMachine->Caption = "";
      PanelButtonPatchUpdate->Visible = false;
    }
  }
  catch(Exception &E)
  {
  }

  delete [] code;

  delete [] line;

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


void __fastcall TFormCodeExplorer::PanelButtonPatchUpdateClick(TObject *Sender)
{
  // Get whole assembler code as long char string.
  int linesize = EditPatchAssembly->Text.Length();
  char* line = new char [linesize+1];
  size_t size = wcstombs(line, EditPatchAssembly->Text.c_str(), linesize);
  line[size] = '\0';

  unsigned char * code = NULL;

  try
  {
    unsigned short origin = mSelectedAddress;
    int codesize = pasmo_assemble_lines(line, &origin, &code, NULL);
    if (codesize > 0)
    {
      // Update memory
      for (int loop=0; loop < codesize; loop++)
      {
        mWriteFunction(FormMain->NativeCPC,
                       mSelectedAddress + loop - mMemoryStartAddress,
                       code[loop]);
      }
    }
  }
  catch(Exception &E)
  {
  }

  // Refresh display

  UpdateInstructions(FormMain->NativeCPC);
  StringGridInstructions->SetFocus();

  delete code;

  delete [] line;

	FormMain->Refresh();

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


void __fastcall TFormCodeExplorer::TabControlMemoryContentChange(TObject *Sender)
{
  MemoryIndex = TabControlMemoryContent->TabIndex;

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


void __fastcall TFormCodeExplorer::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 TFormCodeExplorer::SetMemoryIndex(int Value)
{
  TabControlMemoryContent->TabIndex = Value;

	// Banked Write ?
	if (TabControlMemoryContent->Tabs->Strings[Value] == "Banked Write")
	{
		mMemoryStartAddress = 0x0000;
		mMemorySize = 0x10000;
		mZ80dasmParam.ReadFunction = Engine_ReadBankedWrite;
		mWriteFunction = Engine_WriteBankedWrite;
	}
	// Lower ROM ?
	else if (TabControlMemoryContent->Tabs->Strings[Value] == "Lower ROM")
	{
		mMemoryStartAddress = 0x0000;
		mMemorySize = 0x4000;
		mZ80dasmParam.ReadFunction = Engine_ReadLowerROM;
		mWriteFunction = Engine_WriteLowerROM;

	}
	// Upper ROM !!
	else
	{
		mMemoryStartAddress = 0xC000;
		mMemorySize = 0x4000;
		mZ80dasmParam.ReadFunction = Engine_ReadUpperROM;
		mWriteFunction = Engine_WriteUpperROM;
	}

  mZ80dasmParam.StartAddress = mMemoryStartAddress;
  mMaxAddress = mMemoryStartAddress + mMemorySize - 1;

  // Adapt Top Address
  if (TopAddress < mMemoryStartAddress)
  {
    TopAddress = mMemoryStartAddress;
  }
  else if (TopAddress >= (mMemoryStartAddress + mMemorySize))
  {
    TopAddress = mMemoryStartAddress + mMemorySize - 1;
  }
  else
  {
    UpdateInstructions(FormMain->NativeCPC);
  }
  ActiveControl = StringGridInstructions;
  StringGridInstructions->Row = 0;

  // Adapt scrollbar
  tULong OldTopAddress = mTopAddress;
  ScrollBarAddress->Min = 0;
  ScrollBarAddress->Position = 0;
  ScrollBarAddress->Max = mMaxAddress;
  ScrollBarAddress->Position = OldTopAddress;
  ScrollBarAddress->Min = mMemoryStartAddress;
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::PanelButtonAssemblerUpdateClick(TObject *Sender)
{
  TCursor oldCursor = Screen->Cursor;
  Screen->Cursor =  crHourGlass;

  // Get whole assembler code as long char string.
  int linessize = RichEditAssembler->Text.Length();
  char* lines = new char [linessize+1];
	size_t size = wcstombs(lines, RichEditAssembler->Text.c_str(), linessize);
	// Converter success ?
	if ((int)size >= 0)
	{
		lines[size] = '\0';

		tPasmoEnv* env = pasmo_create();

		pasmo_setfilename(env, mAssemblerFilename.c_str());

		// Select current line
		env->selected_line = RichEditAssembler->CaretPos.Y + 1;
		int LineStart = RichEditAssembler->Perform(EM_LINEINDEX,
																							 (TYPE_PERFORM_2ND_PARAM)RichEditAssembler->CaretPos.Y,
																							 (TYPE_PERFORM_3RD_PARAM)0);
		int LineLength = RichEditAssembler->Perform(EM_LINELENGTH,
																								(TYPE_PERFORM_2ND_PARAM)LineStart,
																								(TYPE_PERFORM_3RD_PARAM)0);
		RichEditAssembler->SelStart = LineStart + LineLength;
		RichEditAssembler->SelLength -= LineLength; // Put caret at line begin
		RichEditAssembler->SetFocus();

		// Includes directory
		linessize = EditIncludesDirectory->Text.Length();
		char* includes_folder = new char [linessize+1];
		size = wcstombs(includes_folder, EditIncludesDirectory->Text.c_str(), linessize);
		includes_folder[size] = '\0';
		pasmo_setincludefolder(env, includes_folder);
		delete [] includes_folder;

		// Predefines
		if (mSettingsP->AsmUsePredefines == true)
		{
			linessize = EditPredefines->Text.Length();
			char* predefines = new char [linessize+1];
			size = wcstombs(predefines, EditPredefines->Text.c_str(), linessize);
			predefines[size] = '\0';
			pasmo_setpredefines(env, predefines);
			delete [] predefines;
		}

		unsigned char * code = NULL;

		try
		{
			unsigned short origin = CodeOrigin;
			int codesize = pasmo_assemble_lines(lines, &origin, &code, env);
			if (codesize > 0)
			{
				// Update origin
				CodeOrigin = origin;

				// code size saturation
				if ((tULong)(origin + codesize) > mMaxAddress)
				{
					codesize = mMaxAddress - origin;
				}
				CodeSize = codesize;

				// Update memory
				for (int loop=0; loop < codesize; loop++)
				{
					mWriteFunction(FormMain->NativeCPC,
												 CodeOrigin + loop - mMemoryStartAddress,
												 code[loop]);
				}

				// Get Last instruction address
				tULong addr = CodeOrigin;
				while (addr < (tULong)(origin + codesize))
				{
					tULong nextaddr = Z80dasmDecodeInstruction(addr,
																										 &mZ80dasmParam);
					if (nextaddr == (tULong)(origin + codesize))
					{
						CodeLast = addr;
					}
					addr = nextaddr;
				}

				// Go to selected address
				TopAddress = env->selected_address;
				StringGridInstructions->SetFocus();
				StringGridInstructions->Row = 0;
			}
			else if (codesize < 0)// Error ?
			{
				int errorline = -codesize - 1;

				// Select and display error line
				LineStart = RichEditAssembler->Perform(EM_LINEINDEX, (TYPE_PERFORM_2ND_PARAM)errorline, (TYPE_PERFORM_3RD_PARAM)0);
				LineLength = RichEditAssembler->Perform(EM_LINELENGTH, (TYPE_PERFORM_2ND_PARAM)LineStart, (TYPE_PERFORM_3RD_PARAM)0);
				RichEditAssembler->SelStart = LineStart + LineLength;
				RichEditAssembler->SelLength -= LineLength; // Put caret at line begin
				RichEditAssembler->SetFocus();

				Screen->Cursor = oldCursor;

				MessageBeep(0);

				Application->MessageBox(WideString(pasmo_getcout(env)).c_bstr(), _T("Pasmo assembler"), MB_OK | MB_ICONERROR);
			}
			else
			{
				Screen->Cursor = oldCursor;

				MessageBeep(0);
				Application->MessageBox(_T("No machine code generated."), _T("Pasmo assembler"), MB_OK | MB_ICONEXCLAMATION);
			}
		}
		catch(Exception &E)
		{
			Application->MessageBox(E.Message.c_str(), _T("Pasmo"), MB_OK);
		}

		pasmo_terminate(env);

		delete code;

		// Refresh display
		UpdateInstructions(FormMain->NativeCPC);
	}
	else
	{
		Application->MessageBox(_T("Unable to convert assembler text due to unicode characters.\r\nPlease use ASCII characters only."),
							_T("Pasmo assembler"),
							MB_OK | MB_ICONEXCLAMATION);
	}

	delete [] lines;

  Screen->Cursor = oldCursor;

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


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

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

void __fastcall TFormCodeExplorer::PanelButtonPeekClick(TObject *Sender)
{
  tULong addr = CodeOrigin;
  tULong endaddr = CodeOrigin + CodeSize;

  TCursor mOldCursor = Screen->Cursor;
  Screen->Cursor = crHourGlass;

  RichEditAssembler->SetFocus();
  RichEditAssembler->Lines->BeginUpdate();
  while (addr < endaddr)
  {
    addr = Z80dasmDecodeInstruction(addr,
                                    &mZ80dasmParam);
    RichEditAssembler->SelText = AnsiString(mZ80dasmParam.Instruction).LowerCase() + "\r\n";
  }
  RichEditAssembler->Lines->EndUpdate();
  Screen->Cursor = mOldCursor;

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


void __fastcall TFormCodeExplorer::PanelButtonClearClick(TObject *Sender)
{
  RichEditAssembler->Clear();
	mAssemblerFilename = cDefaultAsmFilename;

	RichEditAssembler->SetFocus();

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


void __fastcall TFormCodeExplorer::PanelButtonAssemblerLoadClick(TObject *Sender)
{
  OpenDialogAssembler->InitialDir = mSettingsP->AsmDirectory;
  if (OpenDialogAssembler->Execute() == true)
  {
    RichEditAssembler->Clear();
    RichEditAssembler->Lines->LoadFromFile(OpenDialogAssembler->FileName);
    mSettingsP->AsmDirectory = ExtractFilePath(OpenDialogAssembler->FileName);
    mAssemblerFilename = ExtractFileName(OpenDialogAssembler->FileName);
  }

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

void __fastcall TFormCodeExplorer::PanelButtonAssemblerSaveClick(TObject *Sender)
{
  if (OpenDialogAssembler->FileName.IsEmpty() == false)
  {
    SaveDialogAssembler->FileName = OpenDialogAssembler->FileName;
  }
  else
  {
    SaveDialogAssembler->FileName = mAssemblerFilename;
  }
	SaveDialogAssembler->InitialDir = mSettingsP->AsmDirectory;
  if (SaveDialogAssembler->Execute() == true)
  {
    RichEditAssembler->Lines->SaveToFile(SaveDialogAssembler->FileName);
    mSettingsP->AsmDirectory = ExtractFilePath(SaveDialogAssembler->FileName);
    mAssemblerFilename = ExtractFileName(SaveDialogAssembler->FileName);
  }

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


void __fastcall TFormCodeExplorer::RichEditAssemblerKeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
{
  if (Shift.Contains(ssCtrl))
  {
    switch (Key)
    {
      case 'A':
      {
        AssemblerSelectAllMenuClick(Sender);
        Key = 0;
      }
      break;

      case 'C':
      {
        AssemblerCopyMenuClick(Sender);
        Key = 0;
      }
      break;

      case 'V':
      {
        AssemblerPasteMenuClick(Sender);
        Key = 0;
      }
      break;
    }
  }

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


void __fastcall TFormCodeExplorer::AssemblerClearMenuClick(TObject *Sender)
{
  bool ClearOK = true;
  if (RichEditAssembler->Text.Length() > 0)
  {
    if (Application->MessageBox(_T("Are you sure to erase your code ?"),
                                _T("Clear code"),
                                MB_YESNO | MB_ICONQUESTION) == IDNO)
    {
       ClearOK = false;
    }
  }

  if (ClearOK == true)
  {
    RichEditAssembler->Clear();
  }

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

void __fastcall TFormCodeExplorer::AssemblerSelectAllMenuClick(TObject *Sender)
{
  RichEditAssembler->SelectAll();

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

void __fastcall TFormCodeExplorer::AssemblerCopyMenuClick(TObject *Sender)
{
  Clipboard()->AsText = RichEditAssembler->SelText;

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

void __fastcall TFormCodeExplorer::AssemblerPasteMenuClick(TObject *Sender)
{
  RichEditAssembler->SelText = Clipboard()->AsText;

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

void __fastcall TFormCodeExplorer::PageControlFeaturesChange(TObject *Sender)
{
	if (PageControlFeatures->ActivePage == TabSheetPatch)
  {
		ShowAssemblerInstructions();
		EditPatchAssembly->SetFocus();
		EditPatchAssembly->SelStart = EditPatchAssembly->Text.Length();
	}
	else if (PageControlFeatures->ActivePage == TabSheetAssembler)
	{
		ShowAssemblerInstructions();
		RichEditAssembler->SetFocus();
	}
	else if (PageControlFeatures->ActivePage == TabSheetBASIC)
	{
		ShowBASICMemory();
		MemoryIndex = 0;
		TopAddress = 0x0170;
		mSelectedAddress = mTopAddress;
		RichEditBasic->SetFocus();
  }

  // Refresh display
  PanelButtonRefreshClick(Sender);

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

void __fastcall TFormCodeExplorer::StringGridInstructionsKeyDown(TObject *Sender,
          WORD &Key, TShiftState Shift)
{
  switch (Key)
  {
    case VK_UP:
    {
      if (!StringGridInstructions->Row)
      {
        if (TopAddress > mMemoryStartAddress)
        {
          TopAddress--;
        }
      }
    }
    break;

    case VK_DOWN:
    {
      if (StringGridInstructions->Row == StringGridInstructions->RowCount-1)
      {
        if (TopAddress < mMaxAddress)
        {
          TopAddress++;
        }
      }
    }
    break;

    case VK_PRIOR:
    {
      if (!StringGridInstructions->Row)
      {
        if ((TopAddress-mMemoryStartAddress) > (tULong)StringGridInstructions->RowCount)
        {
          TopAddress = TopAddress - StringGridInstructions->RowCount;
        }
        else
        {
          TopAddress = mMemoryStartAddress;
        }
      }
    }
    break;

    case VK_NEXT:
    {
      if (StringGridInstructions->Row == StringGridInstructions->RowCount-1)
      {
        if ((mMaxAddress-TopAddress) > (tULong)StringGridInstructions->RowCount)
        {
          TopAddress = TopAddress + StringGridInstructions->RowCount;
        }
        else
        {
          TopAddress = mMaxAddress;
        }
      }
    }
    break;

    case VK_HOME:
    {
      if (Shift.Contains(ssCtrl) == true)
      {
        TopAddress = mMemoryStartAddress;
      }
    }
    break;

    case VK_END:
    {
      if (Shift.Contains(ssCtrl) == true)
      {
        TopAddress = mMaxAddress;
      }
    }
    break;
  }

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


void __fastcall TFormCodeExplorer::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 TFormCodeExplorer::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 TFormCodeExplorer::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(mSelectedAddress, 4);
      // Keep marker
      mSettingsP->SetCodeExplorerMarker(Index-1, ((TPanel*)Components[Loop])->Caption);
      break;
    }
  }

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

  mFormEditValue->Title = Panel->Hint;
  mFormEditValue->CurrentValue = StrToInt("0x" + Panel->Caption);
  mFormEditValue->Hexadecimal = PanelFormatTopAddress->Caption.IsEmpty() == true ? false : true;
  mFormEditValue->MinValue = 0;
  mFormEditValue->MaxValue = mMaxAddress;
  if (mFormEditValue->ShowModal() == mrOk)
  {
    Panel->Caption = AnsiString::IntToHex(mFormEditValue->NewValue, 4);

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

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::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)
    {
      TopAddress = StrToInt("0x" + ((TPanel*)Components[Loop])->Caption);
      mSelectedAddress = mTopAddress;
      StringGridInstructions->SetFocus();
      StringGridInstructions->Row = 0;

      break;
    }
  }

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


void __fastcall TFormCodeExplorer::PanelButtonAssemblerDriveALoadClick(TObject *Sender)
{
  tDiskOperation* DiskOperationP = new tDiskOperation();
  memset(DiskOperationP, 0, sizeof(tDiskOperation));

  // Prepare File Data
  DiskOperationP->NativeCPC = FormMain->NativeCPC;
  DiskOperationP->Drive = FormMain->NativeCPC->FDC->DriveA;

  // Read catalogue
  mEmulatorP->ReadDiskCatalogue(DiskOperationP);
  mEmulatorP->ConvertFilenameToCatalogueEntry(ComboBoxAssemblerFilename->Text.UpperCase(), DiskOperationP);
  // Select filename
  if (mEmulatorP->SelectCatalogueEntry(DiskOperationP) == true)
  {
    // Read file header
    tFileHeader FileHeader;
    tULong FileSize = DiskOperationP->CatalogueEntrySize[DiskOperationP->CatalogueEntryIndex];
    bool FileHeaderPresent = false;
    if (mEmulatorP->ReadFileHeader(DiskOperationP, &FileHeader) == true)
    {
      FileSize = FileHeader.Length + AMSDOS_HEADER_SIZE;
      FileHeaderPresent = true;
    }

    if (FileSize > 0)
    {
	    TCursor mOldCursor = Screen->Cursor;
	    Screen->Cursor = crHourGlass;

      // Load File
      tUChar* FileDataP = new tUChar[FileSize];
      DiskOperationP->FileContentP = FileDataP;
      DiskOperationP->FileSize = FileSize;
      if (mEmulatorP->LoadDriveFile(DiskOperationP) == true)
      {
        CodeOrigin = FileHeader.DataLocation;
		    CodeSize = FileHeader.Length;

		    // Write file in RAM
		    tUChar* DataP = FileDataP;
		    if (FileHeaderPresent == true) DataP += AMSDOS_HEADER_SIZE;
		    for (int loop=0; loop < CodeSize; loop++)
		    {
		      mWriteFunction(FormMain->NativeCPC,
						             CodeOrigin + loop - mMemoryStartAddress,
                         *DataP++);
        }

        // Disassemble
		    tULong addr = CodeOrigin;
		    tULong endaddr = CodeOrigin + CodeSize;

		    RichEditAssembler->SetFocus();
        RichEditAssembler->Clear();
		    RichEditAssembler->Lines->BeginUpdate();
		    while (addr < endaddr)
		    {
          CodeLast = addr;
			    addr = Z80dasmDecodeInstruction(addr,
					                    						&mZ80dasmParam);
			    RichEditAssembler->SelText = AnsiString(mZ80dasmParam.Instruction).LowerCase() + "\r\n";
		    }
		    RichEditAssembler->Lines->EndUpdate();
        RichEditAssembler->CaretPos = TPoint(0,0);

        mAssemblerFilename = ComboBoxAssemblerFilename->Text.UpperCase();
      }

      delete [] FileDataP;

	    Screen->Cursor = mOldCursor;
    }
  }

  delete DiskOperationP;

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

void __fastcall TFormCodeExplorer::PanelButtonAssemblerDriveASaveClick(TObject *Sender)
{
  // Invalid code size ?
  if (mCodeSize <= 0)
  {
    Application->MessageBox(_T("Invalid size."), _T("Error"), MB_OK | MB_ICONERROR);
  }
  else
  {
    tDiskOperation* DiskOperationP = new tDiskOperation();
    memset(DiskOperationP, 0, sizeof(tDiskOperation));

    // Prepare File Data
    DiskOperationP->NativeCPC = FormMain->NativeCPC;
    DiskOperationP->Drive = FormMain->NativeCPC->FDC->DriveA;
    mEmulatorP->ConvertFilenameToCatalogueEntry(ComboBoxAssemblerFilename->Text.UpperCase(), DiskOperationP);
    DiskOperationP->FileStartAddress = (tULong)mCodeOrigin;
    DiskOperationP->FileSize = (tULong)(mCodeSize + AMSDOS_HEADER_SIZE);

    // Prepare file content with header
    tUChar* FileDataP = new tUChar[DiskOperationP->FileSize + AMSDOS_HEADER_SIZE];
    DiskOperationP->FileContentP = FileDataP;
    tFileHeader FileHeader;
    FileHeader.Type = AMSDOS_FILE_TYPE_BINARY;
    FileHeader.DataLength = mCodeSize;
    FileHeader.DataLocation = mCodeOrigin;
    FileHeader.Length = mCodeSize;
    tUChar* DataP = mEmulatorP->CreateFileHeader(DiskOperationP, &FileHeader);
    if (DataP)
    {
      memcpy(DataP, FormMain->NativeCPC->pbRAM + mCodeOrigin, mCodeSize);
    }

    if (mEmulatorP->AddDriveFile(DiskOperationP) == false)
    {
      Application->MessageBox(_T("Not enought free space into drive A disk."),
                              _T("Disk full"),
                              MB_OK | MB_ICONEXCLAMATION);
    }

    delete [] FileDataP;
    delete DiskOperationP;
  }

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


void __fastcall TFormCodeExplorer::OnDiskEvent(tDrive* DriveP)
{
  if (DriveP->signal_content_change)
  {
    UpdateCatalogue();
  }
}
//---------------------------------------------------------------------------


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

	if (Condition & (EC_REFRESH | EC_RESET))
	{
		// Display refresh
		PanelButtonRefreshClick(NULL);
	}

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


void __fastcall TFormCodeExplorer::PanelCheckUsePredefinesClick(TObject *Sender)

{
  // Invert
  mSettingsP->AsmUsePredefines = mSettingsP->AsmUsePredefines == true ? false : true;

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

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

void __fastcall TFormCodeExplorer::EditIncludesDirectoryChange(TObject *Sender)
{
  mSettingsP->AsmIncludeDirectory = EditIncludesDirectory->Text;

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::EditIncludesDirectoryDblClick(TObject *Sender)
{
  String Directory = EditIncludesDirectory->Text;
  if (SelectDirectory(Directory, TSelectDirOpts(), 0) == true)
  {
    EditIncludesDirectory->Text = Directory;
  }

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


void __fastcall TFormCodeExplorer::EditPredefinesChange(TObject *Sender)
{
  mSettingsP->AsmPredefines = EditPredefines->Text;

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


void __fastcall TFormCodeExplorer::UpdateBanks(void)
{
  tNativeCPC* NativeCPC = FormMain->NativeCPC;

  // 64Ko memory ?
  if (NativeCPC->ram_size == 64)
  {
    GroupBoxBanks->Visible = false;
    TabControlMemoryContent->Height = PageControlFeatures->Height;
  }
  else
  {
    TabControlMemoryContent->Height = GroupBoxBanks->Top - 8 - TabControlMemoryContent->Top;
    GroupBoxBanks->Visible = 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));
    LabelCommentRAMBaseAddress->Caption = BuildBankComment(Address);
    ComboBoxRAMBanksMapping->ItemIndex = NativeCPC->GateArray->RAM_config & 7;

    // Update BASIC OUT Command
    AnsiString OUTCommand = "OUT &&";
    OUTCommand += AnsiString::IntToHex((0x7f - (NativeCPC->ram_4mb_offset / (512*1024))), 2);
    OUTCommand += "ff,&&";
    OUTCommand += AnsiString::IntToHex((0xC0 | NativeCPC->GateArray->RAM_config), 2);
    LabelCommentOUTCommand->Caption = OUTCommand.UpperCase();

    // Bank 0000
    Address = NativeCPC->membank_write[0] - NativeCPC->pbRAM;
    PanelBankWrite0000->Caption = AnsiString::IntToHex(Address, 4);

    // Bank 4000
    Address = NativeCPC->membank_write[1] - NativeCPC->pbRAM;
    PanelBankWrite4000->Caption = AnsiString::IntToHex(Address, 4);

    // Bank 8000
    Address = NativeCPC->membank_write[2] - NativeCPC->pbRAM;
    PanelBankWrite8000->Caption = AnsiString::IntToHex(Address, 4);

    // Bank C000
    Address = NativeCPC->membank_write[3] - NativeCPC->pbRAM;
    PanelBankWriteC000->Caption = AnsiString::IntToHex(Address, 4);
  }
}
//---------------------------------------------------------------------------


AnsiString __fastcall TFormCodeExplorer::BuildBankComment(tULong Address)
{
  AnsiString Comment = "";
  bool AddSeparator = false;
  
  // Multiple of 512Ko
  tULong Part = (Address >> 19);
  if (Part > 0)
  {
	  Comment += AnsiString(Part * 512);
	  AddSeparator = true;
  }
  
  // Multiple of 64Ko
  Part = (Address >> 16) & 7;
  if (Part > 0)
  {
	  if (AddSeparator == true)
	  {
		  Comment += "+";
	  }
	  Comment += AnsiString(Part * 64);
	  //AddSeparator = true;
  }

  // First bank
  if (Comment.Length() == 0)
  {
     Comment = "0";
  }

  Comment += " Ko";

  return Comment;
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::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 TFormCodeExplorer::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);
}
//---------------------------------------------------------------------------

void __fastcall TFormCodeExplorer::ComboBoxRAMBanksBaseAddressDrawItem(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 TFormCodeExplorer::EditLineClick(TObject *Sender)
{
  EditLine->SelectAll();

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

void __fastcall TFormCodeExplorer::EditLineKeyPress(TObject *Sender, System::WideChar &Key)
{
	if ((Key == VK_RETURN) || (Key == VK_ENTER))
	{
		PanelButtonGoToLineClick(Sender);
		Key = 0;
	}
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::PanelButtonGoToLineClick(TObject *Sender)
{
  int Line = EditLine->Text.ToInt() - 1;
  if (Line < 0) Line = 0;

	// Highlight line
	int LineStart = RichEditAssembler->Perform(EM_LINEINDEX, (TYPE_PERFORM_2ND_PARAM)Line, (TYPE_PERFORM_3RD_PARAM)0);
	int LineLength = RichEditAssembler->Perform(EM_LINELENGTH, (TYPE_PERFORM_2ND_PARAM)LineStart, (TYPE_PERFORM_3RD_PARAM)0);
	RichEditAssembler->SelStart = LineStart + LineLength;
	RichEditAssembler->SelLength -= LineLength; // Put caret at line begin
	RichEditAssembler->SetFocus();

  RichEditAssembler->Update();
  EditLine->Text = (RichEditAssembler->CaretPos.Y + 1);

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

void __fastcall TFormCodeExplorer::RichEditAssemblerClick(TObject *Sender)
{
  EditLine->Text = (RichEditAssembler->CaretPos.Y + 1);

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::RichEditAssemblerKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
{
  EditLine->Text = (RichEditAssembler->CaretPos.Y + 1);

  NOT_USED(Sender);
  NOT_USED(Key);
  NOT_USED(Shift);
}
//---------------------------------------------------------------------------
void __fastcall TFormCodeExplorer::RichEditAssemblerChange(TObject *Sender)
{
  EditLine->Text = (RichEditAssembler->CaretPos.Y + 1);

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

void __fastcall TFormCodeExplorer::PanelButtonGoToBank0Click(TObject *Sender)
{
  MemoryIndex = 0;
  TopAddress = 0x0000;
  mSelectedAddress = mTopAddress;

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

void __fastcall TFormCodeExplorer::PanelButtonGoToBank1Click(TObject *Sender)
{
  MemoryIndex = 0;
  TopAddress = 0x4000;
  mSelectedAddress = mTopAddress;

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

void __fastcall TFormCodeExplorer::PanelButtonGoToBank2Click(TObject *Sender)
{
  MemoryIndex = 0;
  TopAddress = 0x8000;
  mSelectedAddress = mTopAddress;

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

void __fastcall TFormCodeExplorer::PanelButtonGoToBank3Click(TObject *Sender)
{
  MemoryIndex = 0;
  TopAddress = 0xC000;
  mSelectedAddress = mTopAddress;

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


void __fastcall TFormCodeExplorer::PanelButtonBasicReadClick(TObject *Sender)
{
  RichEditBasic->Clear();
  RichEditBasic->Lines->BeginUpdate();

  delete [] mBASICLinesAddress;
  mBASICLinesAddress = NULL;
  mBASICLinesAddressCount = 0;

  // Start at &170
  tNativeCPC* NativeCPC = FormMain->NativeCPC;
  tULong Address = 0x0170;
  tULong LastAddress = Address;
  tULong LineError = 0;
  TopAddress = Address;

  // Read line size
  tULong LineSize = Engine_ReadBankedWrite(NativeCPC, Address++);
  LineSize += (Engine_ReadBankedWrite(NativeCPC, Address++) << 8);
  while ( (LineSize != 0) && (LastAddress <= Address) )
  {
    tULong LineNumber = Engine_ReadBankedWrite(NativeCPC, Address++);
    LineNumber += (Engine_ReadBankedWrite(NativeCPC, Address++) << 8);

    // Decode and Add BASIC Line
    try
    {
      AnsiString BASICLine = AnsiString(LineNumber) + " ";
      LastAddress = Address;
      Address = DecodeBasicLine(NativeCPC, Address, BASICLine);

      #define MAX_BASIC_LINE_LENGTH     256
      if (BASICLine.Length() > MAX_BASIC_LINE_LENGTH)
      {
        // Truncate line
        BASICLine = BASICLine.SubString(1, MAX_BASIC_LINE_LENGTH);
      }
      RichEditBasic->Lines->Add((String)BASICLine);

      // Add line addresse
      tULong* BASICLinesAddress = new tULong[RichEditBasic->Lines->Count];
      for (int Loop=0; Loop < mBASICLinesAddressCount; Loop++)
      {
        BASICLinesAddress[Loop] = mBASICLinesAddress[Loop];
      }
      BASICLinesAddress[RichEditBasic->Lines->Count - 1] = LastAddress - 4; // Begin of BASIC Line
      delete [] mBASICLinesAddress;
      mBASICLinesAddress = BASICLinesAddress;
      mBASICLinesAddressCount = RichEditBasic->Lines->Count;
    }
    catch (...)
    {
      // Do not display incorrect string
    }

    // Error in line ?
    if (!Address)
    {
      if (!LineError)
      {
        LineError = LineNumber;
      }
    }
	  else
    {
      // Read next line size
      LineSize = Engine_ReadBankedWrite(NativeCPC, Address++);
      LineSize += (Engine_ReadBankedWrite(NativeCPC, Address++) << 8);
    }
  }

  if (LineError)
  {
    WideString Message = "Error in line " + WideString(LineError);
    Application->MessageBox(Message.c_bstr(), _T("BASIC"), MB_OK | MB_ICONEXCLAMATION);
  }

	// Select current line
	RichEditBasic->SelStart = RichEditBasic->Perform(EM_LINEINDEX, (TYPE_PERFORM_2ND_PARAM)LineError, (TYPE_PERFORM_3RD_PARAM)0);
  RichEditBasic->SetFocus();

  RichEditBasic->Lines->EndUpdate();

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


tULong __fastcall TFormCodeExplorer::DecodeBasicLine(tNativeCPC* NativeCPC, tULong Address, AnsiString& BasicLine)
{
  tUChar PrevToken = 0;
  tUChar Token = Engine_ReadBankedWrite(NativeCPC, Address++);
  tUChar NextToken = Engine_ReadBankedWrite(NativeCPC, Address);
  tUChar InsideString = 0;

  while (Token && Address)
  {
    // Inside string ?
    if (InsideString)
    {
      // End of string ?
      if (Token == 0x22)
      {
        InsideString = 0;
        BasicLine += "\"";
      }
      // Printable character ?
      else if ( (Token >= 0x20) && (Token <= 0x7b) )
      {
        BasicLine += (char)(Token);
      }
      else
      {
        BasicLine += "\\x" + AnsiString::IntToHex(Token,2);
      }
    }
    // ASCII Code ?
    else if ( (Token >= 0x23) && (Token <= 0x7b) )
    {
       BasicLine += (char)(Token);
    }
    // Additionnal tokens
    else if (Token == 0xff)
    {
      PrevToken = Token;
      Token = Engine_ReadBankedWrite(NativeCPC, Address++);
      NextToken = Engine_ReadBankedWrite(NativeCPC, Address);

      if ( (Token < 0x80) && (strlen(BasicFcts[Token]) > 0) )
      {
        BasicLine += BasicFcts[Token];
      }
      else
      {
        //Address=0;
        //BasicLine += "!! Unknown token &FF+&" + AnsiString::IntToHex(Token, 2) + " !!";
        BasicLine += "\\xFF\\x" + AnsiString::IntToHex(Token,2);
      }
    }
    // Token
    else switch (Token)
    {
      case 0x01: /* ":" statement seperator */
      {
        // Get next token
        tUChar NextToken = Engine_ReadBankedWrite(NativeCPC, Address);
        // Filter ":" before "'" or before "ELSE".
        switch (NextToken)
        {
          case 0xc0: /* '(REM) */
            break;

          case 0x97: /* ELSE */
          {
            BasicLine += " ";
          }
          break;

          default:
          {
            BasicLine += ":";
          }
        }
      }
      break;
      case 0x02: /* integer variable definition (defined with "%" suffix) */
      case 0x03: /* string variable definition (defined with "$" suffix) */
      case 0x04: /* floating point variable definition (defined with "!" suffix) */
      {
        // Pass 16 bits offset
        Address+=2;
        tUChar Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        while ((Identifier & 0x80) == 0)
        {
          // Add ASCII character
          BasicLine += (char)(Identifier & 0x7f);
          Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        }
        // Add last Identifier character
        BasicLine += (char)(Identifier & 0x7f);
        if (Token == 0x02) BasicLine += "%";
        if (Token == 0x03) BasicLine += "$";
        if (Token == 0x04) BasicLine += "!";
      }
      break;
      case 0x0b: /* variable definition (no suffix) */
      case 0x0d: /* variable definition (no suffix) */
      {
        // Pass 16 bits offset
        Address+=2;
        tUChar Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        while ((Identifier & 0x80) == 0)
        {
          // Add ASCII character
          BasicLine += (char)(Identifier & 0x7f);
          Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        }
        // Add last Identifier character
        BasicLine += (char)(Identifier & 0x7f);
      }
      break;
      case 0x0e: /* number constant "0" */ BasicLine += "0"; break;
      case 0x0f: /* number constant "1" */ BasicLine += "1"; break;
      case 0x10: /* number constant "2" */ BasicLine += "2"; break;
      case 0x11: /* number constant "3" */ BasicLine += "3"; break;
      case 0x12: /* number constant "4" */ BasicLine += "4"; break;
      case 0x13: /* number constant "5" */ BasicLine += "5"; break;
      case 0x14: /* number constant "6" */ BasicLine += "6"; break;
      case 0x15: /* number constant "7" */ BasicLine += "7"; break;
      case 0x16: /* number constant "8" */ BasicLine += "8"; break;
      case 0x17: /* number constant "9" */ BasicLine += "9"; break;
      case 0x18: /* number constant "10" */ BasicLine += "10"; break;
      case 0x19: /* 8-bit integer decimal value */
      {
        tUChar Value = Engine_ReadBankedWrite(NativeCPC, Address++);
        BasicLine += Value;
      }
      break;
      case 0x1b: /* 16-bit integer binary value (with "&X" prefix) */
      {
        tULong Value = Engine_ReadBankedWrite(NativeCPC, Address++);
        Value += Engine_ReadBankedWrite(NativeCPC, Address++) << 8;
        BasicLine += "&X";
        bool FirstZeros=true;
        for (int Loop=0; Loop < 16; Loop++)
        {
          if (Value & 0x8000)
          {
            BasicLine += "1";
            FirstZeros = false;
          }
          else if (FirstZeros == false)
          {
            BasicLine += "0";
          }
          Value <<= 1;
        }
      }
      break;
      case 0x1c: /* 16-bit integer hexadecimal value (with "&H" or "&" prefix) */
      {
        tULong Value = Engine_ReadBankedWrite(NativeCPC, Address++);
        Value += Engine_ReadBankedWrite(NativeCPC, Address++) << 8;
        BasicLine += "&" + AnsiString::IntToHex(Value,1);
      }
      break;
      case 0x1a: /* 16-bit integer decimal value */
      case 0x1e: /* 16-bit integer BASIC line number */
      {
        tULong Value = Engine_ReadBankedWrite(NativeCPC, Address++);
        Value += Engine_ReadBankedWrite(NativeCPC, Address++) << 8;
        BasicLine += Value;
      }
      break;
      case 0x1f: /* floating point value */
      {
        char Temp[16];
        tUChar BASICFloat[5];
        for (tUChar Loop=0; Loop < (tUChar)sizeof(BASICFloat); Loop++)
        {
           BASICFloat[Loop] = Engine_ReadBankedWrite(NativeCPC, Address+Loop);
        }
        BASIC_FloatToString(BASICFloat, Temp);
        BasicLine += Temp;

        Address = Address + 5;
      }
      break;
      case 0x20: /* " " (space) symbol */ BasicLine += " "; break;
      case 0x21: /* ASCII "!" symbol */ BasicLine += "!"; break;
      case 0x22: /* quoted string value */
      {
        InsideString = 1;
        BasicLine += "\"";
      }
      break;
      case 0x7c: /* "|" symbol; prefix for RSX commands */
      {
        BasicLine += "|";
        // Pass 8 bits offset
        Address++;
        tUChar Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        while ((Identifier & 0x80) == 0)
        {
          // Add ASCII character
          BasicLine += (char)(Identifier & 0x7f);
          Identifier = Engine_ReadBankedWrite(NativeCPC, Address++);
        }
        // Add last Identifier character
        BasicLine += (char)(Identifier & 0x7f);
      }
      break;
      case 0x84: /* CAT */
      case 0x86: /* CLEAR */
      case 0x87: /* CLG */
      case 0x88: /* CLOSEIN */
      case 0x89: /* CLOSEOUT */
      case 0x8a: /* CLS */
      case 0x8b: /* CONT */
      case 0x91: /* DEG */
      case 0x98: /* END */
      case 0xa8: /* LOAD */
      case 0xab: /* MERGE */
      case 0xac: /* MID$ */
      case 0xb1: /* NEW */
      case 0xb6: /* OPENIN */
      case 0xb7: /* OPENOUT */
      case 0xb8: /* ORIGIN */
      case 0xc0: /* '(REM) */
      case 0xc1: /* RAD */
      case 0xc5: /* REM */
      case 0xc9: /* RETURN */
      case 0xce: /* STOP */
      case 0xd2: /* TROFF */
      case 0xd3: /* TRON */
      case 0xd5: /* WEND */
      case 0xd7: /* WHILE */
      case 0xd8: /* WINDOW */
      case 0xdb: /* DI */
      case 0xdc: /* EI */
      case 0xdd: /* FILL (v1.1) */
      case 0xde: /* GRAPHICS (v1.1) */
      case 0xdf: /* MASK (v1.1) */
      case 0xe0: /* FRAME (v1.1) */
      case 0xe1: /* CURSOR (v1.1) */
      case 0xe3: /* ERL */
      case 0xe4: /* FN */
      case 0xe5: /* SPC */
      case 0xe7: /* SWAP */
      case 0xea: /* TAB */
      case 0xed: /* USING */
      case 0xee: /* > */
      case 0xef: /* = */
      case 0xf0: /* >= */
      case 0xf1: /* < */
      case 0xf2: /* <> */
      case 0xf3: /* =< */
      case 0xf4: /* + (addition) */
      case 0xf5: /* - (subtraction or unary minus) */
      case 0xf6: /* * (multiplication) */
      case 0xf7: /* / (division) */
      case 0xf8: /* ^ (x to the power of y) */
      case 0xf9: /* \ (integer division) */
      {
        BasicLine += BasicToken[Token-0x80];
      }
      break;
      case 0x80: /* AFTER */
      case 0x81: /* AUTO */
      case 0x82: /* BORDER */
      case 0x83: /* CALL */
      case 0x85: /* CHAIN */
      case 0x8c: /* DATA */
      case 0x8d: /* DEF */
      case 0x8e: /* DEFINT */
      case 0x8f: /* DEFREAL */
      case 0x90: /* DEFSTR */
      case 0x92: /* DELETE */
      case 0x93: /* DIM */
      case 0x94: /* DRAW */
      case 0x95: /* DRAWR */
      case 0x96: /* EDIT */
      case 0x99: /* ENT */
      case 0x9a: /* ENV */
      case 0x9b: /* ERASE */
      case 0x9c: /* ERROR */
      case 0x9d: /* EVERY */
      case 0x9e: /* FOR */
      case 0x9f: /* GOSUB */
      case 0xa0: /* GOTO */
      case 0xa1: /* IF */
      case 0xa2: /* INK */
      case 0xa3: /* INPUT */
      case 0xa4: /* KEY */
      case 0xa5: /* LET */
      case 0xa6: /* LINE */
      case 0xa7: /* LIST */
      case 0xa9: /* LOCATE */
      case 0xaa: /* MEMORY */
      case 0xad: /* MODE */
      case 0xae: /* MOVE */
      case 0xaf: /* MOVER */
      case 0xb0: /* NEXT */
      case 0xb2: /* ON */
      case 0xb3: /* ON BREAK */
      case 0xb4: /* ON ERROR GOTO */
      case 0xb5: /* SQ */
      case 0xb9: /* OUT */
      case 0xba: /* PAPER */
      case 0xbb: /* PEN */
      case 0xbc: /* PLOT */
      case 0xbd: /* PLOTR */
      case 0xbe: /* POKE */
      case 0xbf: /* PRINT */
      case 0xc2: /* RANDOMIZE */
      case 0xc3: /* READ */
      case 0xc4: /* RELEASE */
      case 0xc6: /* RENUM */
      case 0xc7: /* RESTORE */
      case 0xc8: /* RESUME */
      case 0xca: /* RUN */
      case 0xcb: /* SAVE */
      case 0xcc: /* SOUND */
      case 0xcd: /* SPEED */
      case 0xcf: /* SYMBOL */
      case 0xd0: /* TAG */
      case 0xd1: /* TAGOFF */
      case 0xd4: /* WAIT */
      case 0xd6: /* WHILE */
      case 0xd9: /* WRITE */
      case 0xda: /* ZONE */
      case 0xfb: /* MOD */
      case 0xfe: /* NOT */
      {
        BasicLine = AddBasicInstruction(BasicLine, BasicToken[Token-0x80], NextToken);
      }
      break;
      case 0x97: /* ELSE */
      case 0xe6: /* STEP */
      case 0xeb: /* THEN */
      case 0xec: /* TO */
      case 0xfa: /* AND */
      case 0xfc: /* OR */
      case 0xfd: /* XOR */
      {
        BasicLine = AddBasicInstructionAddon(BasicLine, BasicToken[Token-0x80], PrevToken, NextToken);
      }
      break;
      default: /* !! UNKNOWN !! */
      {
        //Address=0;
        //BasicLine += "!! Unknown token &" + AnsiString::IntToHex(Token, 2) + " !!";
        BasicLine += "\\x" + AnsiString::IntToHex(Token,2);
      }
    }

    if (Address)
    {
      PrevToken = Token;
      Token = Engine_ReadBankedWrite(NativeCPC, Address++);
      NextToken = Engine_ReadBankedWrite(NativeCPC, Address);
    }
  }

  return (Address);
}
//---------------------------------------------------------------------------

AnsiString& __fastcall TFormCodeExplorer::AddBasicInstruction(AnsiString& BasicLine, AnsiString Instruction, tUChar NextToken)
{
  BasicLine += Instruction;

  switch (NextToken)
  {
    case 0x00: /* End of line */
    case 0x01: /* ":" statement seperator */
    case 0x20: /* Space */
    case 0x22: /* quoted string value */
    case 0xf5: /* - (subtraction or unary minus) */
      break;

    default:
    {
      // Add Space after Instruction
      BasicLine += " ";
    }
  }

  return BasicLine;
}
//---------------------------------------------------------------------------
AnsiString& __fastcall TFormCodeExplorer::AddBasicInstructionAddon(AnsiString& BasicLine, AnsiString Instruction,
        tUChar PrevToken, tUChar NextToken)
{
  switch (PrevToken)
  {
    case 0x01: /* ":" statement seperator */
    case 0x20: /* Space */
    case 0x29: /* ) */
      break;

    default:
    {
      // Add Space before Instruction
      BasicLine += " ";
    }
  }

  BasicLine += Instruction;

  switch (NextToken)
  {
    case 0x00: /* End of line */
    case 0x01: /* ":" statement seperator */
    case 0x20: /* Space */
    case 0xf5: /* - (subtraction or unary minus) */
    case 0x28: /* ( */
      break;

    default:
    {
      // Add Space after Instruction
      BasicLine += " ";
    }
  }

  return BasicLine;
}
//---------------------------------------------------------------------------




void __fastcall TFormCodeExplorer::PanelButtonBasicGoToClick(TObject *Sender)
{
  if (mBASICLinesAddress && (RichEditBasic->CaretPos.Y < mBASICLinesAddressCount) )
  {
    TopAddress = mBASICLinesAddress[RichEditBasic->CaretPos.Y];
	  StringGridInstructions->SetFocus();
	  StringGridInstructions->Row = 0;

		// Select current line
		int LineStart = RichEditBasic->Perform(EM_LINEINDEX,
																					 (TYPE_PERFORM_2ND_PARAM)RichEditBasic->CaretPos.Y,
																					 (TYPE_PERFORM_3RD_PARAM)0);
		int LineLength = RichEditBasic->Perform(EM_LINELENGTH, (TYPE_PERFORM_2ND_PARAM)LineStart, (TYPE_PERFORM_3RD_PARAM)0);
    RichEditBasic->SelStart = LineStart + LineLength;
    RichEditBasic->SelLength -= LineLength; // Put caret at line begin
    RichEditBasic->SetFocus();
  }

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

void __fastcall TFormCodeExplorer::BASICSelectAllMenuClick(TObject *Sender)
{
  RichEditBasic->SelectAll();

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

void __fastcall TFormCodeExplorer::BASICClearMenuClick(TObject *Sender)
{
  if (RichEditBasic->Text.Length() > 0)
  {
    if (Application->MessageBox(_T("Are you sure to erase your code ?"),
                                _T("Clear code"),
                                MB_YESNO | MB_ICONQUESTION) == IDYES)
    {
	  RichEditBasic->Clear();
    }
  }

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

void __fastcall TFormCodeExplorer::BASICCopyMenuClick(TObject *Sender)
{
  Clipboard()->AsText = RichEditBasic->SelText;

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

void __fastcall TFormCodeExplorer::BASICPasteMenuClick(TObject *Sender)
{
  RichEditBasic->SelText = Clipboard()->AsText;

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

void __fastcall TFormCodeExplorer::PanelButtonBasicDriveALoadClick(TObject *Sender)
{
  tDiskOperation* DiskOperationP = new tDiskOperation();
  memset(DiskOperationP, 0, sizeof(tDiskOperation));

  // Prepare File Data
  DiskOperationP->NativeCPC = FormMain->NativeCPC;
	DiskOperationP->Drive = FormMain->NativeCPC->FDC->DriveA;

  // Read catalogue
  mEmulatorP->ReadDiskCatalogue(DiskOperationP);
  mEmulatorP->ConvertFilenameToCatalogueEntry(ComboBoxBasicFilename->Text.UpperCase(), DiskOperationP);
  // Select filename
  if (mEmulatorP->SelectCatalogueEntry(DiskOperationP) == true)
  {
    // Read file header
    tFileHeader FileHeader;
    tULong FileSize = DiskOperationP->CatalogueEntrySize[DiskOperationP->CatalogueEntryIndex];
    bool FileHeaderPresent = false;
    if (mEmulatorP->ReadFileHeader(DiskOperationP, &FileHeader) == true)
    {
      FileSize = FileHeader.Length + AMSDOS_HEADER_SIZE;
      FileHeaderPresent = true;
    }

    if (FileSize > 0)
    {
	    TCursor mOldCursor = Screen->Cursor;
	    Screen->Cursor = crHourGlass;

      // Load File
      tUChar* FileDataP = new tUChar[FileSize];
      DiskOperationP->FileContentP = FileDataP;
      DiskOperationP->FileSize = FileSize;
      if (mEmulatorP->LoadDriveFile(DiskOperationP) == true)
      {
        CodeOrigin = FileHeader.DataLocation;
		    CodeSize = FileHeader.Length;

		    // Write file in RAM
		    tUChar* DataP = FileDataP;
		    if (FileHeaderPresent == true) DataP += AMSDOS_HEADER_SIZE;

        // Protected BASIC ?
        if (FileHeader.Type & 0x01)
        {
          for (int loop=0; loop < CodeSize; loop++)
          {
            mWriteFunction(FormMain->NativeCPC,
                           CodeOrigin + loop - mMemoryStartAddress,
                           *(DataP++) ^ BasicDecipher[loop & 0x7F]);
          }
        }
        else
        {
          for (int loop=0; loop < CodeSize; loop++)
          {
            mWriteFunction(FormMain->NativeCPC,
                           CodeOrigin + loop - mMemoryStartAddress,
													 *DataP++);
          }
        }

        mBasicFilename = ComboBoxBasicFilename->Text.UpperCase();
      }

      delete [] FileDataP;

	    Screen->Cursor = mOldCursor;
    }
  }

  delete DiskOperationP;

  // Read BASIC
  PanelButtonBasicReadClick(Sender);

  // Refresh Display
  PanelButtonRefreshClick(Sender);

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


void __fastcall TFormCodeExplorer::DropFile(TWMDropFiles &Message)
{
  HDROP hDrop = (HDROP)Message.Drop;
  int FileCount = DragQueryFile(hDrop, -1, NULL, 0 );

  // Create file list from Drop message
  for (int file = 0; file < FileCount; file++)
  {
    int CharacterCount = DragQueryFile(hDrop, file, NULL, 0) + 1; // account for NULL terminator

    _TCHAR* FileName = new _TCHAR[CharacterCount];
		DragQueryFile(hDrop, file, FileName, CharacterCount);

		if (PageControlFeatures->ActivePage == TabSheetAssembler)
		{
			RichEditAssembler->Clear();
			RichEditAssembler->Lines->LoadFromFile(FileName);
			mSettingsP->AsmDirectory = ExtractFilePath(FileName);
			mAssemblerFilename = ExtractFileName(FileName);
		}

    delete [] FileName;
  }

  DragFinish(hDrop);
}
//---------------------------------------------------------------------------


void __fastcall TFormCodeExplorer::PanelButtonAddBreakpointClick(TObject *Sender)

{
	FormDebugger->ToggleBreakpointPC(mSelectedAddress);

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


