unit PropertiesGrid;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, XStringGrid, RTTIUnit;

type
  TPropertiesGrid = class(TXStringGrid) { TStringGrid }
  private
    { Private declarations }
    FRTI: TRTIObj;
    FObj: TObject;
    FLines: TXStringColumns;
    procedure SetObj(AObj: TObject);
    procedure SetLines(Value: TXStringColumns);
  protected
    { Protected declarations }
    function CanEditShow: Boolean; override;
    procedure SizeChanged(OldColCount, OldRowCount: Longint); override;
    procedure DrawEditor(ACol, ARow: integer); override;
    procedure DestroyWnd; override;
    procedure CellEditorDestroying(AEditor: TCellEditor); override;

  public
    { Public declarations }
    constructor Create(Owner: TComponent); override;
    property Obj: TObject read FObj write SetObj;
    destructor Destroy; override;
  published
    { Published declarations }
    property Lines: TXStringColumns read FLines write SetLines;
  end;

procedure Register;

implementation

{TPropertiesGrid.}
constructor TPropertiesGrid.Create(Owner: TComponent);
var r: integer;
begin
  inherited Create(Owner);
  FRTI := TRTIObj.Create(Self);
  FLines := TXStringColumns.Create(self);
  for r := 0 to RowCount - 1 do
    FLines.Add;

  ColCount := 2;
end;

function TPropertiesGrid.CanEditShow: Boolean;
begin
  {
  Result := ([goRowSelect, goEditing] * Options = [goEditing]) and
    FEditorMode and not (csDesigning in ComponentState) and HandleAllocated and
    ((goAlwaysShowEditor in Options) or IsActiveControl);
  }
{
  Result := Focused or
  (goAlwaysShowEditor in Options);
  if not ([goRowSelect, goEditing] * Options = [goEditing]) then
    Result := false;
  if not HandleAllocated then
    Result := false;
  if not EditorMode then
    Result := false
  else begin
    Result := result;
  end;
}
  if StringGridCanEditShow and Focused then begin
    if FLines[Row].Editor <> nil then begin
      FCellEditor := FLines[Row].Editor;
      FCellEditor.StartEdit;
      FEditCol := Col;
      FEditRow := Row;
      DrawEditor(Col, Row);
    end;
  end;
  Result := false;
end;

procedure TPropertiesGrid.SetLines(Value: TXStringColumns);
begin
  FLines.Assign(Value);
end;

procedure TPropertiesGrid.SizeChanged(OldColCount, OldRowCount: Longint);
var
  r: integer;
begin
  if OldRowCount < RowCount then
    for r := OldRowCount to RowCount - 1 do
      FLines.Add
  else
    for r := OldRowCount - 1 downto RowCount do
      FLines[r].Free;

  inherited SizeChanged(OldColCount, OldRowCount);
end;

procedure TPropertiesGrid.DrawEditor(ACol, ARow: integer);
begin
  if FLines[ACol].Editor = nil then
    exit;

  if Assigned(FOnDrawEditor) then
    OnDrawEditor(self, ACol, ARow, FLines[ACol].Editor)
  else
    FLines[ACol].ShowEditor(ARow);
end;

procedure TPropertiesGrid.DestroyWnd;
var
  c: integer;
begin
  for c := 0 to FLines.count - 1 do begin
    if FLines[c].Editor <> nil then begin
      FLines[c].Editor.GridWndDestroying;
    end;
  end;
  inherited DestroyWnd;
end;

procedure TPropertiesGrid.CellEditorDestroying(AEditor: TCellEditor);
var c: integer;
begin
  if Lines <> nil then
    for c := 0 to Lines.Count - 1 do
      if Lines[c].Editor = AEditor then         // Remove references to this instance
        Lines[c].Editor := nil;
  inherited;
end;

procedure TPropertiesGrid.SetObj(AObj: TObject);
var
  i: integer;
  mnw, nw, mvw, vw: integer;
  marg: integer;
begin
  FRTI.Obj := AObj;
  mnw := 0;
  mvw := 0;
  marg := 4;
  RowCount := FRTI.PropCount;
  for i := 0 to FRTI.PropCount - 1 do begin
    Cells[0, i] := FRTI.Props[i].Name;
    nw := Canvas.TextWidth(FRTI.Props[i].Name) + marg;
    if nw > mnw then
      mnw := nw;
    Cells[1, i] := FRTI.Props[i].Value;
    vw := Canvas.TextWidth(FRTI.Props[i].Value) + marg;
    if vw > mvw then
      mvw := vw;
    Lines[i].Editor := TEditCellEditor.Create(Self);
    Lines[i].Editor.Init;
  end;
  if mnw > ColWidths[0] then
    ColWidths[0] := mnw
  else
    mnw := ColWidths[0];
  if mvw > ColWidths[1] then
    ColWidths[1] := mvw
  else
    mvw := ColWidths[1];
  Width := mvw + mnw;
  if Align = alClient then begin
    if Owner is TForm then begin
      TForm(Owner).ClientWidth := mvw + mnw + 3 * GetSystemMetrics(SM_CXHSCROLL);
    end;
  end;
end;

destructor TPropertiesGrid.Destroy;
begin
  inherited;
end;

procedure Register;
begin
  RegisterComponents('Chromulan', [TPropertiesGrid]);
end;

end.
