unit FormMemory;

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,
  StdCtrls, MemoryTypes, Generics.Collections, Math;

type
  TReadEvent = function (Address: Word): Byte of object;

  { TFormMemory }

  TFormMemory = class(TForm)
    ComboBoxArea: TComboBox;
    Label1: TLabel;
    ListViewMemory: TListView;
    Timer1: TTimer;
    procedure ComboBoxAreaSelect(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ListViewMemoryData(Sender: TObject; Item: TListItem);
    procedure Timer1Timer(Sender: TObject);
  private
    FReloadPending: Boolean;
    FMemory: TMemory;
    FSize: Integer;
  public
    Areas: TObjectList<TMemory>;
    procedure ReloadAreas;
    procedure Reload;
    procedure ReloadList;
  end;

var
  FormMemory: TFormMemory;

const
  ItemsPerLine = 16;


implementation

{$R *.lfm}

procedure TFormMemory.Reload;
begin
  FReloadPending := True;
end;

procedure TFormMemory.ReloadList;
begin
  ListViewMemory.Items.Count := Ceil(FSize / ItemsPerLine);
  ListViewMemory.Refresh;
end;

procedure TFormMemory.ListViewMemoryData(Sender: TObject; Item: TListItem);
var
  Line: string;
  I: Integer;
  Text: string;
  One: Byte;
  Count: Byte;
  Address: Word;
begin
  Address := Item.Index * ItemsPerLine;
  if Address < FSize then begin
    Count := ItemsPerLine;
    if (Address + Count) >= FSize then
      Count := FSize - Address;
    Line := '';
    Text := '';
    for I := 0 to Count - 1 do begin
      One := FMemory.Read(Address + I);
      Line := Line + IntToHex(One, 2) + ' ';
      if One >= 32 then Text := Text + Char(One)
        else Text := Text + ' ';
    end;
    Item.Caption := IntToHex(Address, 8);
    Item.SubItems.Add(Line);
    Item.SubItems.Add(Text);
  end;
end;

procedure TFormMemory.FormShow(Sender: TObject);
begin
  ReloadAreas;
  ComboBoxAreaSelect(nil);
  Reload;
end;

procedure TFormMemory.FormCreate(Sender: TObject);
begin
  Areas := TObjectList<TMemory>.Create(False);
end;

procedure TFormMemory.ComboBoxAreaSelect(Sender: TObject);
begin
  if ComboBoxArea.ItemIndex >= 0 then begin
    FMemory := TMemory(ComboBoxArea.Items.Objects[ComboBoxArea.ItemIndex]);
    FSize := FMemory.Size;
  end else begin
    FMemory := nil;
    FSize := 0;
  end;
  Reload;
end;

procedure TFormMemory.FormDestroy(Sender: TObject);
begin
  FreeAndNil(Areas);
end;

procedure TFormMemory.Timer1Timer(Sender: TObject);
begin
  if FReloadPending then begin
    FReloadPending := False;
    ReloadList;
  end;
end;

procedure TFormMemory.ReloadAreas;
var
  I: Integer;
begin
  ComboBoxArea.Items.BeginUpdate;
  try
    while ComboBoxArea.Items.Count > Areas.Count do
      ComboBoxArea.Items.Delete(ComboBoxArea.Items.Count - 1);
    while ComboBoxArea.Items.Count < Areas.Count do
      ComboBoxArea.Items.Add('');
    for I := 0 to Areas.Count - 1 do begin
      ComboBoxArea.Items.Strings[I] := Areas[I].Title;
      ComboBoxArea.Items.Objects[I] := Areas[I];
    end;
    if (ComboBoxArea.ItemIndex = -1) and (ComboBoxArea.Items.Count > 0) then
      ComboBoxArea.ItemIndex := 0;
  finally
    ComboBoxArea.Items.EndUpdate;
  end;
end;

end.

