/*
 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 <Clipbrd.hpp>
#pragma hdrstop

#include "TFormDSKViewer.h"
#include "TFormMain.h"
#include "..\..\Common\ASCII.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"


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

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


static const AnsiString cTitle = "Disk viewer";
static const AnsiString cTitleMonitoring = " - [Monitoring]";

static const AnsiString cDriveALabel = "Drive A";
static const AnsiString cDriveBLabel = "Drive B";

static const AnsiString cStartMonitoringLabel = "Start";
static const AnsiString cStopMonitoringLabel = "Stop";


#define COLOR_TRACK_OK          clBlack
#define COLOR_TRACK_OVERSIZE    clRed

#define COLOR_GAPS              clLime
#define COLOR_WEAK              clYellow
#define COLOR_ERROR             TColor(RGB(255,70,70))   // Pastel Red
#define COLOR_SIZE_0            TColor(RGB(255,128,240)) // Pastel Pink
#define COLOR_SIZE_1            TColor(RGB(255,128,240)) // Pastel Pink
#define COLOR_SIZE_3            TColor(RGB(255,170,35))  // Pastel Orange
#define COLOR_SIZE_4            TColor(RGB(255,170,35))  // Pastel Orange
#define COLOR_SIZE_5            TColor(RGB(255,170,35))  // Pastel Orange
#define COLOR_SIZE_6            TColor(RGB(255,170,35))  // Pastel Orange
#define COLOR_SIZE_7            TColor(RGB(255,170,35))  // Pastel Orange
#define COLOR_INCOMPLETE        clAqua
#define COLOR_COMMON            clWhite
#define COLOR_EMPTY             clLtGray

const AnsiString GAPSSectorLabel = "GAPS";
const AnsiString WEAKSectorLabel = "WEAK";
const AnsiString ERRORSectorLabel = "ERROR";
const AnsiString SIZE0SectorLabel = "SIZE 0";
const AnsiString SIZE1SectorLabel = "SIZE 1";
const AnsiString SIZE3SectorLabel = "SIZE 3";
const AnsiString SIZE4SectorLabel = "SIZE 4";
const AnsiString SIZE5SectorLabel = "SIZE 5";
const AnsiString INCOMPLETESectorLabel = "INCOMPLETE";
const AnsiString COMMONSectorLabel = "COMMON";
const AnsiString EMPTYSectorLabel = "EMPTY";


TFormDSKViewer *FormDSKViewer;
//---------------------------------------------------------------------------
__fastcall TFormDSKViewer::TFormDSKViewer(TComponent* Owner)
	: TForm(Owner)
{
	mEmulatorP = NULL;
	mSettingsP = NULL;
	mStartDriveP = NULL;

	for (int Loop=0; Loop < ComponentCount; Loop++)
	{
		if (Components[Loop]->Name.Pos("RichEdit") == 1)
		{
			((TRichEdit*)Components[Loop])->ParentFont = true;
		}
	}

	// Apply Theme
	Font->Name = "Amstrad CPC464 Regular";
	Font->Size = 6;
}
//---------------------------------------------------------------------------

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

	FormMain->OnDSKViewerFormShow();

	Caption = Title;

	mDataASCII7Bits = false;
	ASCII7bitsMenu->Checked = mDataASCII7Bits;

	mMonitoringInProgress = false;
	PanelCheckMonitoring->Color = mSettingsP->ThemeButtonColor;
	PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonTextColor;

  // Force linespacing
  PARAFORMAT2 ParaFormat;
  memset((void*)&ParaFormat, 0, sizeof(PARAFORMAT2));
  ParaFormat.cbSize = sizeof(PARAFORMAT2);
  ParaFormat.dwMask = PFM_LINESPACING;
  ParaFormat.dyLineSpacing = 25;
  ParaFormat.bLineSpacingRule = 5;
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name.Pos("RichEdit") == 1)
    {
      ((TRichEdit*)Components[Loop])->Clear();
      ((TRichEdit*)Components[Loop])->Perform(EM_SETPARAFORMAT, 0, (LPARAM)&ParaFormat);
    }
  }

  // Force display update
  FormMain->NativeCPC->FDC->DriveA->signal_content_change++;
  OnDiskEvent(FormMain->NativeCPC->FDC->DriveA);

  if (mStartDriveP != NULL)
  {
    if (mStartDriveP == FormMain->NativeCPC->FDC->DriveA)
    {
      ComboBoxDrive->ItemIndex = ComboBoxDrive->Items->IndexOf(cDriveALabel);
    }
    else if (mStartDriveP == FormMain->NativeCPC->FDC->DriveB)
    {
      ComboBoxDrive->ItemIndex = ComboBoxDrive->Items->IndexOf(cDriveBLabel);
    }

    mStartDriveP = NULL;

    if (ComboBoxDrive->ItemIndex != -1)
    {
      ShowDriveContent(0, 0);
    }
  }

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

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

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


void __fastcall TFormDSKViewer::FormHide(TObject *Sender)
{
  mMonitoringInProgress = false;

  // Unsubscribe to events
  if (FormMain != NULL)
  {
		FormMain->UnsubscribeToDiskEvents(OnDiskEvent);
		FormMain->OnDSKViewerFormHide();
	}

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

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


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

  tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ? FormMain->NativeCPC->FDC->DriveA : FormMain->NativeCPC->FDC->DriveB;
  if (DriveP)
  {
    if (DriveP->tracks)
    {
      if (ComboBoxDrive->Text == cDriveALabel)
      {
        Title += " - " + ExtractFileName(mEmulatorP->DiskAFilename);
      }
      else
      {
        Title += " - " + ExtractFileName(mEmulatorP->DiskBFilename);
      }
    }
  }

  if (mMonitoringInProgress)
  {
    Title += cTitleMonitoring;
  }

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


void __fastcall TFormDSKViewer::SetSettings(TSettings* Value)
{
  mSettingsP = Value;

  if (    (mSettingsP->DSKViewerFormLeft != 0)
       || (mSettingsP->DSKViewerFormTop != 0)
       || (mSettingsP->DSKViewerFormWidth != 0)
       || (mSettingsP->DSKViewerFormHeight != 0) )
  {
    Position = poDesigned;
    Left = mSettingsP->DSKViewerFormLeft;
    Top = mSettingsP->DSKViewerFormTop;
    Width = mSettingsP->DSKViewerFormWidth;
    Height = mSettingsP->DSKViewerFormHeight;
  }

  Color = mSettingsP->ThemeBackgroundColor;
  Font->Color = mSettingsP->ThemeText1Color;
  StringGridSectors->Color = Color;
  GroupBoxDisk->Font->Color = mSettingsP->ThemeText2Color;
  GroupBoxTrack->Font->Color = mSettingsP->ThemeText2Color;
  GroupBoxSector->Font->Color = mSettingsP->ThemeText2Color;
  tULong Threshold = (((Color & 0xff0000) >> 16) + ((Color & 0xff00) >> 8) + (Color & 0xff)) / 3;
  if (Threshold >= 0x80)
  {
    Threshold = 0x40;
  }
  else
  {
    Threshold = 0xC0;
  }
  mCellFrameColor = TColor((Threshold << 16) | (Threshold << 8) | Threshold);

  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("PanelCheck") == 1)
		{
			((TPanel*)Components[Loop])->Color = mSettingsP->ThemeButtonColor;
			((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeButtonTextColor;
		}
		else if (Components[Loop]->Name.Pos("RichEdit") == 1)
    {
      ((TRichEdit*)Components[Loop])->Color = Color;
      ((TRichEdit*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
    }

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

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


void __fastcall TFormDSKViewer::FormResize(TObject *Sender)
{
  if ( (Visible == true) && (mSettingsP) )
  {
    mSettingsP->DSKViewerFormWidth = Width;
    mSettingsP->DSKViewerFormHeight = Height;
  }

  // Fix vertical scroll issue
  for (int Loop=0; Loop < ComponentCount; Loop++)
  {
    if (Components[Loop]->Name.Pos("RichEdit") == 1)
    {
      ((TRichEdit*)Components[Loop])->Refresh();
    }
  }

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


void __fastcall TFormDSKViewer::WMMove(TMessage &Message)
{
  if ( (Visible == true) && (mSettingsP) )
  {
    mSettingsP->DSKViewerFormLeft = Left;
    mSettingsP->DSKViewerFormTop = Top;
  }

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


void __fastcall TFormDSKViewer::OnDiskEvent(tDrive* DriveP)
{
tDrive* DisplayedDrive = (ComboBoxDrive->Text == cDriveALabel) ?
        FormMain->NativeCPC->FDC->DriveA :
        FormMain->NativeCPC->FDC->DriveB;

  if (DriveP->signal_track_format)
  {
    if (DisplayedDrive == DriveP)
    {
      // Update graphic
      ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);
    }
  }

  if (DriveP->signal_sector_write)
  {
    if (DisplayedDrive == DriveP)
    {
      // Update graphic
      ShowSideContent(StringGridSectors->Col, StringGridSectors->Row - 1);
    }
  }

  if (DriveP->signal_content_change)
  {
    int LastIndex = ComboBoxDrive->ItemIndex;

    ComboBoxDrive->Visible = true;
    ComboBoxSides->Visible = true;

    // Check available DSK
    ComboBoxDrive->Clear();
    ComboBoxSides->Clear();
    if (FormMain->NativeCPC->FDC->DriveA->dataP != NULL) ComboBoxDrive->Items->Add(cDriveALabel);
    if (FormMain->NativeCPC->FDC->DriveB->dataP != NULL) ComboBoxDrive->Items->Add(cDriveBLabel);

    StringGridSectors->Visible = false;
    GroupBoxTrack->Visible = false;
    PanelSectorState->Visible = false;
    PanelButtonSectorViewExtent->Visible = false;
    PageControlData->Visible = false;
    CheckBox7BitsData->Visible = false;
    GroupBoxSector->Visible = false;
    TabSheetDataSector->TabVisible = false;
    TabSheetDataGAP3->TabVisible = false;
    TabSheetDataDeclared->TabVisible = false;
    TabSheetFileHeader->TabVisible = false;
    PanelCheckMonitoring->Visible = ComboBoxDrive->Items->Count ? true : false;
    ComboBoxSides->Enabled = false;

    if (ComboBoxDrive->Items->Count == 2)
    {
      if (LastIndex == -1)
      {
        ComboBoxDrive->ItemIndex = 0;
        LastIndex = 0;
      }
      ComboBoxDrive->ItemIndex = LastIndex;
      ComboBoxDrive->Enabled = true;
      //ShowDriveContent(LastIndex, 0);
      ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);
    }
    else if (ComboBoxDrive->Items->Count == 1)
    {
      ComboBoxDrive->ItemIndex = 0;
      ComboBoxDrive->Enabled = false;
      //ShowDriveContent(0, 0);
      ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);
    }
    else
    {
      Caption = Title;

      ComboBoxDrive->Visible = false;
      ComboBoxSides->Visible = false;
      GroupBoxDisk->Visible = true;

      RichEditDiskInfo->Clear();
      RichEditDiskInfo->Lines->Append("No disk");
    }
  }

  if ( (mMonitoringInProgress == true) && DriveP->signal_new_position )
  {
    // Display active drive
    if (DisplayedDrive != DriveP)
    {
      if (DriveP == mEmulatorP->NativeCPC->FDC->DriveA)
      {
        ComboBoxDrive->ItemIndex = ComboBoxDrive->Items->IndexOf(cDriveALabel);
      }
      else
      {
        ComboBoxDrive->ItemIndex = ComboBoxDrive->Items->IndexOf(cDriveBLabel);
      }
      //ShowDriveContent(0, 0);
      ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);
    }
    else
    {
      ShowSideContent(DriveP->current_track, DriveP->current_sector);
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::ComboBoxDriveChange(TObject *Sender)
{
  ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);

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

void __fastcall TFormDSKViewer::ComboBoxDriveDrawItem(TWinControl *Control, int Index,
          TRect &Rect, TOwnerDrawState State)
{
  TCanvas* Canvas = ComboBoxDrive->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 = ComboBoxDrive->Items->Strings[Index];
  int TextHeight = Canvas->TextHeight(Text);
  int TextPos = (ComboBoxDrive->ItemHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+5, Rect.Top+TextPos, Text);
  if (State.Contains(odFocused))
  {
    Canvas->DrawFocusRect(Rect);
  }

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


void __fastcall TFormDSKViewer::ComboBoxSidesChange(TObject *Sender)
{
  mCurrentSide = ComboBoxSides->ItemIndex;

  tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
          FormMain->NativeCPC->FDC->DriveA :
          FormMain->NativeCPC->FDC->DriveB;

  if (DriveP->sides && DriveP->flipped)
  {
    mCurrentSide ^= 1;
  }

  ShowSideContent(StringGridSectors->Col, StringGridSectors->Row - 1);

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

void __fastcall TFormDSKViewer::ComboBoxSidesDrawItem(TWinControl *Control, int Index,
          TRect &Rect, TOwnerDrawState State)
{
  TCanvas* Canvas = ComboBoxSides->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 = ComboBoxSides->Items->Strings[Index];
  int TextHeight = Canvas->TextHeight(Text);
  int TextPos = (ComboBoxSides->ItemHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+5, Rect.Top+TextPos, Text);
  if (State.Contains(odFocused))
  {
    Canvas->DrawFocusRect(Rect);
  }

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


void __fastcall TFormDSKViewer::ShowDriveContent(int TrackSelected, int SectorNumber)
{
tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
          FormMain->NativeCPC->FDC->DriveA :
          FormMain->NativeCPC->FDC->DriveB;

  if (DriveP->tracks)
  {
    Caption = Title;

    // Update sides
    if ( ((int)(DriveP->sides+1) != ComboBoxSides->Items->Count)
         || (TrackSelected == 0) )
    {
      ComboBoxSides->Clear();
      for (int Loop=0; Loop < (int)(DriveP->sides+1); Loop++)
      {
        AnsiString SideTitle = "Side " + AnsiString(Loop+1);
        ComboBoxSides->Items->Add(SideTitle);
      }
      mCurrentSide = 0;
    }
    ComboBoxSides->ItemIndex = mCurrentSide;
    if (ComboBoxSides->Items->Count > 1) ComboBoxSides->Enabled = true;

    if (DriveP->sides && DriveP->flipped)
    {
      mCurrentSide ^= 1;
    }

    ShowSideContent(TrackSelected, SectorNumber);

    //
    // Show disk info
    //
    RichEditDiskInfo->Clear();
    RichEditDiskInfo->Lines->BeginUpdate();

    AnsiString Info = "Tracks=" + AnsiString(DriveP->tracks) + " (&" + AnsiString::IntToHex(DriveP->tracks, 2) + ")";
    RichEditDiskInfo->Lines->Append(Info);
    Info = "Sides=" + AnsiString(DriveP->sides + 1);
    RichEditDiskInfo->Lines->Append(Info);
    Info = "Write Protected=";
    if (DriveP->write_protected)
    {
      Info += "Yes";
    }
    else
    {
      Info += "No";
    }
    RichEditDiskInfo->Lines->Append(Info);
    Info = "Header=" + AnsiString((char*)DriveP->dataP).SubString(1, 34);
    RichEditDiskInfo->Lines->Append(Info);

    RichEditDiskInfo->Lines->EndUpdate();
  }
  else
  {
    StringGridSectors->Visible = false;
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::ShowSideContent(int TrackSelected, int SectorNumber)
{
tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
            FormMain->NativeCPC->FDC->DriveA :
            FormMain->NativeCPC->FDC->DriveB;

  StringGridSectors->Visible = true;

  StringGridSectors->ColCount = DriveP->tracks;

  // Get max number of sectors
  tULong NbMaxSectors = 0;
  for (tULong Loop=0; Loop < DriveP->tracks; Loop++)
  {
    // Set Col Header
    StringGridSectors->Cells[Loop][0] = AnsiString(Loop);
    // Number of sectors is greater ?
    if (DriveP->track[Loop]->sectors > NbMaxSectors)
    {
      NbMaxSectors = DriveP->track[Loop][mCurrentSide].sectors;
    }
  }

  StringGridSectors->RowCount = NbMaxSectors + 1; // Add header row

  // Track saturation
  if (TrackSelected > (int)(DriveP->tracks-1)) TrackSelected = DriveP->tracks - 1;
  StringGridSectors->Col = TrackSelected;

  // Any sectors ?
  if (StringGridSectors->RowCount > 1)
  {
    // Sector saturation
    if (SectorNumber < 0) SectorNumber = 0;
    if (SectorNumber > (StringGridSectors->RowCount - 2)) SectorNumber = StringGridSectors->RowCount - 2;
    StringGridSectors->Row = SectorNumber + 1;

    ShowTrackInfo(TrackSelected);
    ShowSectorInfo(TrackSelected, SectorNumber);
    ShowData(TrackSelected, SectorNumber);

    if (StringGridSectors->Enabled == true)
    {
      ActiveControl = StringGridSectors;
      StringGridSectors->Invalidate();
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall TFormDSKViewer::StringGridSectorsDrawCell(TObject *Sender,
    int ACol, int ARow, TRect &Rect, TGridDrawState State) 
{
  TRect CellRect;
#if (__BORLANDC__ == 0x651)
  CellRect.Left = Rect.Left + 1 - 4; // Fix Left issue with RADStudio XE3
#else /* __BORLANDC__ */
  CellRect.Left = Rect.Left + 1;
#endif /* __BORLANDC__ */
  CellRect.Right = Rect.Right - 1;
  CellRect.Top = Rect.Top + 1;
  CellRect.Bottom = Rect.Bottom - 1;

  // Draw headers ?
  if (ARow == 0)
  {
    tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
              FormMain->NativeCPC->FDC->DriveA :
              FormMain->NativeCPC->FDC->DriveB;
    tTrack* CurrentTrack = &DriveP->track[ACol][mCurrentSide];

    if (CurrentTrack->real_size > FDC_MAX_BYTES_PER_TRACK)
    {
      StringGridSectors->Canvas->Brush->Color = COLOR_TRACK_OVERSIZE;
    }
    else
    {
      StringGridSectors->Canvas->Brush->Color = COLOR_TRACK_OK;
    }

    StringGridSectors->Canvas->Font->Color = clWhite;
    StringGridSectors->Canvas->FillRect(CellRect);
    
    String CellText = StringGridSectors->Cells[ACol][ARow];
    int TextWidth = StringGridSectors->Canvas->TextWidth(CellText);
    int TextPosH = (StringGridSectors->ColWidths[ACol] - TextWidth) / 2;
    int TextHeight = StringGridSectors->Canvas->TextHeight(CellText);
    int TextPosV = (StringGridSectors->RowHeights[ARow] - TextHeight) / 2;
    StringGridSectors->Canvas->TextOut(CellRect.Left + TextPosH - 1,
        CellRect.Top + TextPosV, CellText);
  }
  else
  {
    // Selected cell ?
    if (State.Contains(gdSelected))
    {
      StringGridSectors->Canvas->Brush->Color = clHighlight;
      StringGridSectors->Canvas->FillRect(CellRect);
    }
    else
    {
      tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
                FormMain->NativeCPC->FDC->DriveA :
                FormMain->NativeCPC->FDC->DriveB;
      tTrack* CurrentTrack = &DriveP->track[ACol][mCurrentSide];

      if (ARow <= (int)CurrentTrack->sectors)
      {
        tSector* SectorP = &CurrentTrack->sector[ARow-1];

        if (SectorP->data_gap3_length)
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_GAPS;
        }
        else if (SectorP->weak_count > 1)
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_WEAK;
        }
        else if (SectorP->data_size < SectorP->declared_size)
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_INCOMPLETE;
        }
        else if ((SectorP->declared_size == 128) && (SectorP->empty == cFalse))
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_SIZE_0;
        }
        else if ((SectorP->declared_size == 256) && (SectorP->empty == cFalse))
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_SIZE_1;
        }
        else if ((SectorP->declared_size == 1024) && (SectorP->empty == cFalse))
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_SIZE_3;
        }
        else if ((SectorP->declared_size == 2048) && (SectorP->empty == cFalse))
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_SIZE_4;
        }
        else if ((SectorP->declared_size == 4096) && (SectorP->empty == cFalse))
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_SIZE_5;
        }
        else if ( (SectorP->flags[0] & ST1_DE) && (SectorP->flags[1] & ST2_DD) )
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_ERROR;
        }
        else if (SectorP->empty == cTrue)
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_EMPTY;
        }
        else
        {
          StringGridSectors->Canvas->Brush->Color = COLOR_COMMON;
        }

        StringGridSectors->Canvas->FillRect(CellRect);

        // Draw border
        StringGridSectors->Canvas->Brush->Color = mCellFrameColor;
        StringGridSectors->Canvas->FrameRect(CellRect);
      }
    }
  }

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

void __fastcall TFormDSKViewer::StringGridSectorsSelectCell(
      TObject *Sender, int ACol, int ARow, bool &CanSelect)
{
  if ( (StringGridSectors->Focused() == true) && (mMonitoringInProgress == false) )
  {
    tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
              FormMain->NativeCPC->FDC->DriveA :
              FormMain->NativeCPC->FDC->DriveB;
    tTrack* TrackP = &DriveP->track[ACol][mCurrentSide];

    // Show track info
    ShowTrackInfo(ACol);

    // Header selected ?
    if (ARow == 0)
    {
      CanSelect = false;
      return;
    }

    // Show Sector info
    if (ARow <= (int)TrackP->sectors)
    {
      PageControlData->Visible = true;
      CheckBox7BitsData->Visible = true;
      GroupBoxSector->Visible = true;
      ShowSectorInfo(ACol, ARow - 1);
      ShowData(ACol, ARow - 1);
    }
    else
    {
      PanelSectorState->Visible = false;
      PanelButtonSectorViewExtent->Visible = false;
      GroupBoxSector->Visible = false;
      PageControlData->Visible = false;
      CheckBox7BitsData->Visible = false;
    }
  }

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


void __fastcall TFormDSKViewer::ShowTrackInfo(int TrackNumber)
{
  tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
            FormMain->NativeCPC->FDC->DriveA :
            FormMain->NativeCPC->FDC->DriveB;
  tTrack* TrackP = &DriveP->track[TrackNumber][mCurrentSide];

  GroupBoxTrack->Visible = true;

  RichEditTrackInfo->Clear();
  RichEditTrackInfo->Lines->BeginUpdate();

  AnsiString Info = "Cylinder=" + AnsiString(TrackNumber) + " (&" + AnsiString::IntToHex(TrackNumber, 2) + ")";
  RichEditTrackInfo->Lines->Append(Info);
  Info = "Sectors=" + AnsiString(TrackP->sectors);
  RichEditTrackInfo->Lines->Append(Info);
  Info = "DSK Size=" + AnsiString(TrackP->size) + " (&" + AnsiString::IntToHex(TrackP->size, 4) + ")";
  RichEditTrackInfo->Lines->Append(Info);
  Info = "Real Size=" + AnsiString(TrackP->real_size) + " (&" + AnsiString::IntToHex(TrackP->real_size, 4) + ")";
  RichEditTrackInfo->Lines->Append(Info);
  Info = "GAP3 Length=" + AnsiString(TrackP->gap3_length) + " (&" + AnsiString::IntToHex(TrackP->gap3_length, 2) + ")";
  RichEditTrackInfo->Lines->Append(Info);
  Info = "Offset-Info=" + AnsiString(TrackP->offset_info_size) + " (&" + AnsiString::IntToHex(TrackP->offset_info_size, 4) + ")";
  RichEditTrackInfo->Lines->Append(Info);
  Info = "Filler=" + AnsiString(TrackP->filler) + " (&" + AnsiString::IntToHex(TrackP->filler, 2) + ")";
  RichEditTrackInfo->Lines->Append(Info);

  RichEditTrackInfo->Lines->EndUpdate();
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::ShowSectorInfo(int TrackNumber, int SectorNumber)
{
  if (StringGridSectors->Visible == true)
  {
    tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
              FormMain->NativeCPC->FDC->DriveA :
              FormMain->NativeCPC->FDC->DriveB;
    tTrack* TrackP = &DriveP->track[TrackNumber][mCurrentSide];
    tSector* SectorP = &TrackP->sector[SectorNumber];

    GroupBoxSector->Visible = true;

    RichEditSectorInfo->Clear();
    RichEditSectorInfo->Lines->BeginUpdate();

    AnsiString Info = "C=&" + AnsiString::IntToHex(SectorP->CHRN[SECTOR_CHRN_C], 2);
    Info += "  H=&" + AnsiString::IntToHex(SectorP->CHRN[SECTOR_CHRN_H], 2);
    Info += "  R=&" + AnsiString::IntToHex(SectorP->CHRN[SECTOR_CHRN_R], 2);
    Info += "  N=&" + AnsiString::IntToHex(SectorP->CHRN[SECTOR_CHRN_N], 2);
    RichEditSectorInfo->Lines->Append(Info);
    Info = "Declared Size=" + AnsiString(SectorP->declared_size) + " (&" + AnsiString::IntToHex(SectorP->declared_size, 4) + ")";
    RichEditSectorInfo->Lines->Append(Info);
    RichEditSectorInfo->Lines->Append("");
    
    Info = "Flag ST1=&" + AnsiString::IntToHex(SectorP->flags[0], 2);
    if (SectorP->flags[0])
    {
      Info += " (";
      if (SectorP->flags[0] & 0x20) Info += " DE";
      if (SectorP->flags[0] & 0x04) Info += " ND";
      if (SectorP->flags[0] & 0x01) Info += " MA";
      Info += " )";
    }
    RichEditSectorInfo->Lines->Append(Info);
    Info = "Flag ST2=&" + AnsiString::IntToHex(SectorP->flags[1], 2);
    if (SectorP->flags[1])
    {
      Info += " (";
      if (SectorP->flags[1] & 0x40) Info += " CM";
      if (SectorP->flags[1] & 0x20) Info += " DD";
      if (SectorP->flags[1] & 0x01) Info += " MD";
      Info += " )";
    }
    RichEditSectorInfo->Lines->Append(Info);
    Info = "DSK Size=" + AnsiString(SectorP->size) + " (&" + AnsiString::IntToHex(SectorP->size, 4) + ")";
    RichEditSectorInfo->Lines->Append(Info);
    Info = "Data Size=" + AnsiString(SectorP->data_size) + " (&" + AnsiString::IntToHex(SectorP->data_size, 4) + ")";
    RichEditSectorInfo->Lines->Append(Info);
    tUShort CRC = (SectorP->data_crc[SECTOR_CRC_MSB] << 8) + SectorP->data_crc[SECTOR_CRC_LSB];
    Info = "Data CRC=&" + AnsiString::IntToHex(CRC, 4);
    RichEditSectorInfo->Lines->Append(Info);
    Info = "Weak Count=" + AnsiString(SectorP->weak_count);
    RichEditSectorInfo->Lines->Append(Info);
    Info = "GAP3 Length=" + AnsiString(SectorP->info_gap3_length) + " (&" + AnsiString::IntToHex(SectorP->info_gap3_length, 4) + ")";
    RichEditSectorInfo->Lines->Append(Info);
    Info = "Data GAP3 Length=" + AnsiString(SectorP->data_gap3_length) + " (&" + AnsiString::IntToHex(SectorP->data_gap3_length, 4) + ")";
    RichEditSectorInfo->Lines->Append(Info);
    Info = "GAP2=&" + AnsiString::IntToHex(SectorP->gap2_value, 2);
    RichEditSectorInfo->Lines->Append(Info);
    Info = "GAP3=&" + AnsiString::IntToHex(SectorP->gap3_value, 2);
    RichEditSectorInfo->Lines->Append(Info);
    CRC = (SectorP->CHRN[SECTOR_CHRN_CRC_MSB] << 8) + SectorP->CHRN[SECTOR_CHRN_CRC_LSB];
    Info = "CHRN CRC=&" + AnsiString::IntToHex(CRC, 4);
		RichEditSectorInfo->Lines->Append(Info);
		Info = "Offset-Info=" + AnsiString(SectorP->offset_info) + " (&" + AnsiString::IntToHex(SectorP->offset_info, 4) + ")";
		RichEditSectorInfo->Lines->Append(Info);

    RichEditSectorInfo->Lines->EndUpdate();

    //
    // Show sector state
    //
    PanelSectorState->Visible = true;
    PanelButtonSectorViewExtent->Visible = true;
    if (SectorP->data_gap3_length)
    {
      PanelSectorState->Color = COLOR_GAPS;
      PanelSectorState->Caption = GAPSSectorLabel;
    }
    else if (SectorP->weak_count > 1)
    {
      PanelSectorState->Color = COLOR_WEAK;
      PanelSectorState->Caption = WEAKSectorLabel;
    }
    else if (SectorP->data_size < SectorP->declared_size)
    {
      PanelSectorState->Color = COLOR_INCOMPLETE;
      PanelSectorState->Caption = INCOMPLETESectorLabel;
    }
    else if ( (SectorP->declared_size == 128)
              && (!SectorP->empty) )
    {
      PanelSectorState->Color = COLOR_SIZE_0;
      PanelSectorState->Caption = SIZE0SectorLabel;
    }
    else if ( (SectorP->declared_size == 256)
              && (!SectorP->empty) )
    {
      PanelSectorState->Color = COLOR_SIZE_1;
      PanelSectorState->Caption = SIZE1SectorLabel;
    }
    else if ( (SectorP->declared_size == 1024)
              && (!SectorP->empty) )
    {
      PanelSectorState->Color = COLOR_SIZE_3;
      PanelSectorState->Caption = SIZE3SectorLabel;
    }
    else if ( (SectorP->declared_size == 2048)
              && (!SectorP->empty) )
    {
      PanelSectorState->Color = COLOR_SIZE_4;
      PanelSectorState->Caption = SIZE4SectorLabel;
    }
    else if ( (SectorP->declared_size == 4096)
              && (!SectorP->empty) )
    {
      PanelSectorState->Color = COLOR_SIZE_5;
      PanelSectorState->Caption = SIZE5SectorLabel;
    }
    else if ( (SectorP->flags[0] & ST1_DE) && (SectorP->flags[1] & ST2_DD) )
    {
      PanelSectorState->Color = COLOR_ERROR;
      PanelSectorState->Caption = ERRORSectorLabel;
    }
    else if (SectorP->empty == cTrue)
    {
      PanelSectorState->Color = COLOR_EMPTY;
      PanelSectorState->Caption = EMPTYSectorLabel;
    }
    else
    {
      PanelSectorState->Color = COLOR_COMMON;
      PanelSectorState->Caption = COMMONSectorLabel;
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::ShowData(int TrackNumber, int SectorNumber)
{
  if (mMonitoringInProgress == false)
  {
    tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
              FormMain->NativeCPC->FDC->DriveA :
              FormMain->NativeCPC->FDC->DriveB;
    tTrack* TrackP = &DriveP->track[TrackNumber][mCurrentSide];
    tSector* SectorP = &TrackP->sector[SectorNumber];

    tUChar* DataP;

    TTabSheet* PreviousSheet = PageControlData->ActivePage;

    PageControlData->Visible = true;
    CheckBox7BitsData->Visible = true;
    TabSheetDataSector->TabVisible = true;
    TabSheetDataGAP3->TabVisible = SectorP->data_gap3_length ? true : false;
#ifndef _DEBUG
    TabSheetDataDeclared->TabVisible = false;
#else /* _DEBUG */
    TabSheetDataDeclared->TabVisible = SectorP->declared_data ? true : false;
#endif /* _DEBUG */
    tFileHeader FileHeader;
    if (mEmulatorP->ReadFileHeader(SectorP->data, SectorP->data_size, &FileHeader) == true)
    {
      TabSheetFileHeader->TabVisible = true;
    }
    else
    {
      TabSheetFileHeader->TabVisible = false;
    }
    if (PreviousSheet)
    {
      if (PreviousSheet->TabVisible == false) PageControlData->ActivePage = TabSheetDataSector;
    }

    RichEditDataSector->Clear();
    RichEditDataSector->Lines->BeginUpdate();

    int TrackOffset = SectorP->track_offset;
    AnsiString TrackOffsetMessage = "Track Offset=" + AnsiString(TrackOffset) + " (&" + AnsiString::IntToHex(TrackOffset, 4) + ")";
    RichEditDataSector->Lines->Append(TrackOffsetMessage);
    AnsiString DataSizeMessage = "Data Size=" + AnsiString(SectorP->data_size) + " (&" + AnsiString::IntToHex(SectorP->data_size, 4) + ")";
    RichEditDataSector->Lines->Append(DataSizeMessage);
    RichEditDataSector->Lines->Append("");

    //
    // Show Sector Data
    //
    // weak sectors ?
    if (SectorP->weak_count > 1)
    {
      for (int WeakLoop=0; WeakLoop < (int)SectorP->weak_count; WeakLoop++)
      {
        if (WeakLoop) RichEditDataSector->Lines->Append("");
        AnsiString Header = "Weak sector " + AnsiString(WeakLoop+1) + " (+&" + AnsiString::IntToHex(SectorP->declared_size * WeakLoop, 4) + ")";
        RichEditDataSector->Lines->Append(Header);

        DataP = SectorP->data;
        DataP += SectorP->declared_size * WeakLoop;
        int DataSize = SectorP->declared_size;

        // Show sector data
        int DataAddress = 0;
        while (DataSize)
				{
					AnsiString DataASCII = "";
					int RemainingBytes = DataSize < 16 ? 16 - DataSize : 0;
					AnsiString DataContent = AnsiString::IntToHex(DataAddress, 4) + ": ";
					for (int Loop=0;
							 (Loop < 16) && (DataSize);
							 Loop++, DataSize--)
					{
						DataContent += AnsiString::IntToHex(*DataP, 2) + " ";
						if (mDataASCII7Bits == true)
						{
							DataASCII += ASCIIChar[(*DataP & 0x7f)];
						}
						else
						{
							DataASCII += ASCIIChar[*DataP];
						}
						DataP++;
					}
					for (int Loop=0; Loop < RemainingBytes; Loop++)
					{
						DataContent += "   "; // Blank byte
					}
					DataContent += " "; // Separator
					DataContent += DataASCII;
					DataAddress += 16;
					RichEditDataSector->Lines->Append(DataContent);
				}
			}
    }
    else
    {
      int DataSize;
      int ExtraDataSize = 0;

      if (SectorP->data_gap3_length)
      {
        DataSize = SectorP->data_size;
      }
      else if (SectorP->data_size < SectorP->size)
      {
        DataSize = SectorP->data_size;
        ExtraDataSize = SectorP->size - SectorP->data_size;
      }
      else
      {
        DataSize = SectorP->size;
      }

      // Show sector data
      DataP = SectorP->data;
      int DataAddress = 0;
      while (DataSize)
			{
				AnsiString DataASCII = "";
				int RemainingBytes = DataSize < 16 ? 16 - DataSize : 0;
				AnsiString DataContent = AnsiString::IntToHex(DataAddress, 4) + ": ";
				for (int Loop=0;
						 (Loop < 16) && (DataSize);
						 Loop++, DataSize--)
				{
					DataContent += AnsiString::IntToHex(*DataP, 2) + " ";
					if (mDataASCII7Bits == true)
					{
						DataASCII += ASCIIChar[(*DataP & 0x7f)];
					}
					else
					{
						DataASCII += ASCIIChar[*DataP];
					}
					DataP++;
				}
				for (int Loop=0; Loop < RemainingBytes; Loop++)
				{
					DataContent += "   "; // Blank byte
				}
				DataContent += " "; // Separator
				DataContent += DataASCII;
				DataAddress += 16;
				RichEditDataSector->Lines->Append(DataContent);
			}

      //
      // Show extra sector data
      //
      if (ExtraDataSize)
      {
        RichEditDataSector->Lines->Append("");
        AnsiString Header = "Extra data";
        RichEditDataSector->Lines->Append(Header);

        DataSize = ExtraDataSize;
        while (DataSize)
				{
					AnsiString DataASCII = "";
					int RemainingBytes = DataSize < 16 ? 16 - DataSize : 0;
					AnsiString DataContent = AnsiString::IntToHex(DataAddress, 4) + ": ";
					for (int Loop=0;
							 (Loop < 16) && (DataSize);
							 Loop++, DataSize--)
					{
						DataContent += AnsiString::IntToHex(*DataP, 2) + " ";
						if (mDataASCII7Bits == true)
						{
							DataASCII += ASCIIChar[(*DataP & 0x7f)];
						}
						else
						{
							DataASCII += ASCIIChar[*DataP];
						}
						DataP++;
					}
					for (int Loop=0; Loop < RemainingBytes; Loop++)
					{
						DataContent += "   "; // Blank byte
					}
					DataContent += " "; // Separator
					DataContent += DataASCII;
					DataAddress += 16;
					RichEditDataSector->Lines->Append(DataContent);
				}
			}
    }

    RichEditDataSector->Lines->EndUpdate();

    //
    // Show GAP3
    //
    if (SectorP->data_gap3_length)
    {
      RichEditDataGAP3->Clear();
      RichEditDataGAP3->Lines->BeginUpdate();

      TrackOffset = SectorP->track_offset + (SectorP->data_size * SectorP->weak_count);
      TrackOffsetMessage = "Track Offset=" + AnsiString(TrackOffset) + " (&" + AnsiString::IntToHex(TrackOffset, 4) + ")";
      RichEditDataGAP3->Lines->Append(TrackOffsetMessage);
      DataSizeMessage = "GAP3 Size=" + AnsiString(SectorP->data_gap3_length) + " (&" + AnsiString::IntToHex(SectorP->data_gap3_length, 4) + ")";
      RichEditDataGAP3->Lines->Append(DataSizeMessage);
      RichEditDataGAP3->Lines->Append("");

      DataP = SectorP->data;
      DataP += SectorP->data_size * SectorP->weak_count;
      int DataSize = SectorP->data_gap3_length;
      int DataAddress = 0;
      while (DataSize)
			{
				AnsiString DataASCII = "";
				int RemainingBytes = DataSize < 16 ? 16 - DataSize : 0;
				AnsiString DataContent = AnsiString::IntToHex(DataAddress, 4) + ": ";
				for (int Loop=0;
						 (Loop < 16) && (DataSize);
						 Loop++, DataSize--)
				{
					DataContent += AnsiString::IntToHex(*DataP, 2) + " ";
					if (mDataASCII7Bits == true)
					{
						DataASCII += ASCIIChar[(*DataP & 0x7f)];
					}
					else
					{
						DataASCII += ASCIIChar[*DataP];
					}
					DataP++;
				}
				for (int Loop=0; Loop < RemainingBytes; Loop++)
				{
					DataContent += "   "; // Blank byte
				}
				DataContent += " "; // Separator
				DataContent += DataASCII;
				DataAddress += 16;
				RichEditDataGAP3->Lines->Append(DataContent);
			}

      RichEditDataGAP3->Lines->EndUpdate();
    }

#ifdef _DEBUG
    //
    // Show Declared data
    //
    if (SectorP->declared_data)
    {
      RichEditDataDeclared->Clear();
      RichEditDataDeclared->Lines->Append("Preparing data...");
      mDeclaredDataPrepared = false;
    }
#endif /* _DEBUG */

    //
    // Show File Header
    //
    if (TabSheetFileHeader->TabVisible == true)
    {
      RichEditFileHeader->Clear();
      //
      // AMSTRAD CPC464/664/6128 FIRMWARE §8.4
      //
      // The file type (byte 18) is split into a number of fields:
      // Bit 0 Protection If this bit is set the file is protected in some way.
      // Bits 1..3 File contents 0 = Internal BASIC.
      //                         1 = Binary.
      //                         2 = Screen image.
      //                         3 = ASCII.
      //                         4..7 are unallocated.
      // Bits 4..7 Version ASCII files should be version 1, all other files
      //           should be version 0.
      //
      AnsiString Message = "Type= " + AnsiString(FileHeader.Type);
      if (FileHeader.Type & 0x01) Message += " (Protected)";
      switch ((FileHeader.Type >> 1) & 0x07)
      {
        case 0x00: Message += " (BASIC)"; break;
        case 0x01: Message += " (Binary)"; break;
        case 0x02: Message += " (Screen Image)"; break;
        case 0x03: Message += " (ASCII)"; break;
        default: Message += " (UNKNOWN)"; break;
      }
      RichEditFileHeader->Lines->Append(Message);
      Message = "Length= " + AnsiString(FileHeader.Length) + " (&" + AnsiString::IntToHex(FileHeader.Length, 1) + ")";
      RichEditFileHeader->Lines->Append(Message);
      Message = "DataLength= " + AnsiString(FileHeader.DataLength) + " (&" + AnsiString::IntToHex(FileHeader.DataLength, 1) + ")";
      RichEditFileHeader->Lines->Append(Message);
      Message = "Location= " + AnsiString(FileHeader.DataLocation) + " (&" + AnsiString::IntToHex(FileHeader.DataLocation, 4) + ")";
      RichEditFileHeader->Lines->Append(Message);
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::ShowDeclaredData(int TrackNumber, int SectorNumber)
{
#ifdef _DEBUG

  tDrive* DriveP = (ComboBoxDrive->Text == cDriveALabel) ?
              FormMain->NativeCPC->FDC->DriveA :
              FormMain->NativeCPC->FDC->DriveB;
  tTrack* TrackP = &DriveP->track[TrackNumber][mCurrentSide];
  tSector* SectorP = &TrackP->sector[SectorNumber];

  // Show declared data
  RichEditDataDeclared->Clear();
  RichEditDataDeclared->Lines->BeginUpdate();

  int TrackOffset = SectorP->track_offset;
  AnsiString TrackMessage = "Track Offset=" + AnsiString(TrackOffset) + " (&" + AnsiString::IntToHex(TrackOffset, 4) + ")";
  RichEditDataDeclared->Lines->Append(TrackMessage);
  TrackMessage = "Declared Size=" + AnsiString(SectorP->declared_size) + " (&" + AnsiString::IntToHex(SectorP->declared_size, 4) + ")";
  RichEditDataDeclared->Lines->Append(TrackMessage);
  RichEditDataDeclared->Lines->Append("");

  tUChar* DataP = SectorP->declared_data;
  int DataSize = SectorP->declared_size;
  int DataAddress = 0;
  do
  {
    AnsiString DataASCII = "";
    int RemainingBytes = DataSize < 16 ? 16 - DataSize : 0;
    AnsiString DataContent = AnsiString::IntToHex(DataAddress, 4) + ": ";
    for (int Loop=0;
         (Loop < 16) && (DataSize);
         Loop++, DataSize--)
    {
      DataContent += AnsiString::IntToHex(*DataP, 2) + " ";
      if (mDataASCII7Bits == true)
      {
        DataASCII += ASCIIChar[(*DataP & 0x7f)];
      }
      else
      {
        DataASCII += ASCIIChar[*DataP];
      }
      DataP++;
    }

    for (int Loop=0; Loop < RemainingBytes; Loop++)
    {
      DataContent += "   "; // Blank byte
    }
    DataContent += " "; // Separator
    DataContent += DataASCII;

    DataAddress += 16;
    RichEditDataDeclared->Lines->Append(DataContent);
  }
  while (DataSize);

  RichEditDataDeclared->Lines->EndUpdate();

#else /* _DEBUG */
  NOT_USED(TrackNumber);
  NOT_USED(SectorNumber);
#endif /* _DEBUG */
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::PanelCheckMonitoringClick(TObject *Sender)
{

	if (mMonitoringInProgress == false)
	{
		mMonitoringInProgress = true;
		GroupBoxTrack->Enabled = false;
		GroupBoxSector->Enabled = false;
		PageControlData->Visible = false;
		CheckBox7BitsData->Visible = false;
		StringGridSectors->Enabled = false;
		ComboBoxDrive->Enabled = false;
		ComboBoxSides->Enabled = false;
		PanelCheckMonitoring->Color = mSettingsP->ThemeButtonTextColor;
		PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonColor;
	}
	else
	{
		mMonitoringInProgress = false;
		GroupBoxTrack->Enabled = true;
		GroupBoxSector->Enabled = true;
		StringGridSectors->Enabled = true;
		ComboBoxDrive->Enabled = true;
		ComboBoxSides->Enabled = true;
		PanelCheckMonitoring->Color = mSettingsP->ThemeButtonColor;
		PanelCheckMonitoring->Font->Color = mSettingsP->ThemeButtonTextColor;

		ShowData(StringGridSectors->Col, StringGridSectors->Row - 1);
	}

  Caption = Title;

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


void __fastcall TFormDSKViewer::CopyToClipboardMenuClick(TObject *Sender)
{
  TMemo* Memo = (TMemo*)PopupMenuData->PopupComponent;

  TStringList* pBuffer = new TStringList();
  for (int Index=0; Index < Memo->Lines->Count; Index++)
  {
    pBuffer->Add(Memo->Lines->Strings[Index]);
  }

  Clipboard()->AsText = pBuffer->Text;

  delete pBuffer;

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


void __fastcall TFormDSKViewer::ASCII7bitsMenuClick(TObject *Sender)
{
  mDataASCII7Bits = mDataASCII7Bits == true ? false : true;
  ASCII7bitsMenu->Checked = mDataASCII7Bits;

  ShowData(StringGridSectors->Col, StringGridSectors->Row - 1);

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


void __fastcall TFormDSKViewer::PageControlDataChange(TObject *Sender)
{
#ifdef _DEBUG

  if (PageControlData->ActivePage == TabSheetDataDeclared)
  {
    if (mDeclaredDataPrepared == false)
    {
      ShowDeclaredData(StringGridSectors->Col,
                       StringGridSectors->Row - 1);

      mDeclaredDataPrepared = true;
    }
  }
  
#endif /* _DEBUG */

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

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

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

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

      TabCount++;
    }
  }

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

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


void __fastcall TFormDSKViewer::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 TFormDSKViewer::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 TFormDSKViewer::SelectSector(tDrive* DriveP, int Side, int Col, int Row)
{
  if (mMonitoringInProgress == false)
  {
    // Update Drive
    tDrive* ActualDriveP = (ComboBoxDrive->Text == cDriveALabel) ?
                           FormMain->NativeCPC->FDC->DriveA :
                           FormMain->NativeCPC->FDC->DriveB;
    if (ActualDriveP != DriveP)
    {
      ComboBoxDrive->ItemIndex = (DriveP == FormMain->NativeCPC->FDC->DriveA) ? 0 : 1;
      ShowDriveContent(StringGridSectors->Col, StringGridSectors->Row-1);
    }

    // Update Side
    if (mCurrentSide != Side)
    {
      mCurrentSide = Side;

      if (DriveP->sides && DriveP->flipped)
      {
        mCurrentSide ^= 1;
      }

      ComboBoxSides->ItemIndex = mCurrentSide;
      ShowSideContent(StringGridSectors->Col, StringGridSectors->Row - 1);
    }

    // Select sector
    StringGridSectors->Col = Col;
    StringGridSectors->Row = Row;

    // Show track info
    ShowTrackInfo(Col);

    // Show Sector info
    tTrack* TrackP = &DriveP->track[Col][mCurrentSide];
    if (Row <= (int)TrackP->sectors)
    {
      PageControlData->Visible = true;
      CheckBox7BitsData->Visible = true;
      GroupBoxSector->Visible = true;
      ShowSectorInfo(Col, Row - 1);
      ShowData(Col, Row - 1);
    }
    else
    {
      PanelSectorState->Visible = false;
      PanelButtonSectorViewExtent->Visible = false;
      GroupBoxSector->Visible = false;
      PageControlData->Visible = false;
      CheckBox7BitsData->Visible = false;
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormDSKViewer::PanelButtonSectorViewExtentClick(TObject *Sender)

{
  // Sector view minimized ?
  if (StringGridSectors->Width == StringGridSectors->Constraints->MinWidth)
  {
    // Get monitor size
    int ScreenWidth = Screen->Width;
    // Max sectorview width
    int MaxSectorViewSize = ScreenWidth - Left - (Width - ClientWidth) - PanelSectorData->Width;
    int MaxTracks = MaxSectorViewSize / StringGridSectors->DefaultColWidth;

		// Expand to max
		if (MaxTracks > StringGridSectors->ColCount)
		{
			ClientWidth = PanelSectorData->Width + (StringGridSectors->ColCount * StringGridSectors->DefaultColWidth);
    }
    else
    {
      ClientWidth = PanelSectorData->Width + MaxSectorViewSize;
    }
  }
  else
  {
    // Reduce to min
    Width = PanelSectorData->Width + StringGridSectors->Constraints->MinWidth;
  }

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

