//
//  RVColorGrid, v1.3
//  © Dmitry 'Creator' Bobrik, 2003
//  Portions © Sergey Tkachenko & RVActions authors
//

unit RVColorGrid;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  RVGrids;

const
  WM_RVGRIDCOLORCHANGED = WM_USER + $10;

type
  TRVColorGrid = class(TRVCustomGrid)
  private
    { Private declarations }
    FFirstCaption: String;
    FFirstColor: TColor;
    FFlat: Boolean;
    FIndeterminate: Boolean;
    FFirstRowHeight: Integer;
    FOnColorChange: TNotifyEvent;
    function GetChosenColor: TColor;
    procedure SetChosenColor(const Value: TColor);
    procedure SetFirstCaption(const Value: String);
    procedure SetFirstColor(const Value: TColor);
    procedure SetFlat(const Value: Boolean);
    procedure SetIndeterminate(const Value: Boolean);
    function GetFlat: Boolean;
    procedure WMColorChanged(var Msg: TMessage); message WM_RVGRIDCOLORCHANGED;
  protected
    { Protected declarations }
    procedure Initalize; override;
    procedure Resize; override;
    procedure DrawCell(ACol, ARow: Integer; ARect: TRect; ASelected: Boolean); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    property ChosenColor: TColor read GetChosenColor write SetChosenColor;
    function GetColorName: String;
    function SelectCell(ACol, ARow: Longint): Boolean; override;
    function GetRowBegin(ARow: Integer): Integer; override;
  published
    { Published declarations }
    property FirstCaption: String read FFirstCaption write SetFirstCaption;
    property FirstColor: TColor read FFirstColor write SetFirstColor default clNone;
    property Flat: Boolean read GetFlat write SetFlat default False;
    property Indeterminate: Boolean read FIndeterminate write SetIndeterminate;
    property OnColorChange: TNotifyEvent read FOnColorChange write FOnColorChange;

    property Align;
    property Anchors;
    property BiDiMode;
    property Constraints;
    property Ctl3D;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Font;
    property ParentBiDiMode;
    property ParentColor default False;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property Color default clWindow;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnStartDock;
    property OnStartDrag;
    // special
    property BorderStyle;
  end;

implementation
uses ColorRVFrm, RVALocalize, RVXPTheme;

{ TRVColorGrid }

constructor TRVColorGrid.Create(AOwner: TComponent);
begin
  inherited;
  BorderStyle := bsNone;
  FFirstColor := clNone;
end;

procedure TRVColorGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
  ASelected: Boolean);
var TextRect: TRect;
begin
  TextRect := ARect;
  if ARow > 0 then
  begin
    Canvas.Brush.Color := Colors[(ARow - 1) * ColCount + ACol].Color;
    Canvas.Brush.Style := bsSolid;
    InflateRect(TextRect, -2, -2);
    Canvas.FillRect(TextRect);
  end
  else
  begin
    if (ACol <> 0) and not (csDesigning in ComponentState) then
      exit;
    Canvas.Font := Font;
    Canvas.Font.Color := Font.Color;//clWindowText;
    ARect.Left := 0;
    ARect.Right := ClientWidth;
    Canvas.Brush.Color := Color;//clWindow;
    Canvas.Brush.Style := bsSolid;
    Canvas.FillRect(ARect);
    TextRect := ARect;
    if FirstColor <> clNone then
    begin
      Canvas.Brush.Color := FirstColor;
      Canvas.FillRect(Rect(ARect.Left + 3, ARect.Top + 3,
                      ARect.Left + 3 + (ARect.Bottom - ARect.Top - 6),
                      ARect.Bottom - 3));
      Inc(TextRect.Left, 16 + 3);
    end;
    Canvas.Brush.Style := bsClear;
    DrawText(Canvas.Handle, PChar(FirstCaption), Length(FirstCaption), TextRect,
             DT_SINGLELINE or DT_CENTER or DT_VCENTER);
  end;

  if not Indeterminate and (ASelected) then
  begin
    Canvas.Brush.Style := bsClear;
    Canvas.Pen.Color := clHighlight;
    Canvas.Pen.Width := 2;
    Canvas.Pen.Style := psInsideFrame;
    with ARect do
      Canvas.Rectangle(Left,Top,Right,Bottom);
    InflateRect(ARect, -2, -2);
    Canvas.Pen.Width := 1;
    Canvas.Pen.Color := clWindow;
    with ARect do
      Canvas.Rectangle(Left,Top,Right,Bottom);
    end
  else begin
    if FFlat then begin
      Canvas.Brush.Style := bsClear;
      Canvas.Pen.Color := clWindow;
      Canvas.Pen.Width := 2;
      Canvas.Pen.Style := psInsideFrame;
      with ARect do
        Canvas.Rectangle(Left,Top,Right,Bottom);
      end
    else
      DrawEdge(Canvas.Handle, ARect, EDGE_SUNKEN,BF_RECT)
  end;
end;

function TRVColorGrid.SelectCell(ACol, ARow: Longint): Boolean;
begin
  FIndeterminate := False;
//  if ARow <= 0 then ACol := 0;
  inherited SelectCell(ACol, ARow);
  Result := False;
  if HandleAllocated then
    SendMessage(Handle, WM_RVGRIDCOLORCHANGED, 0, 0);   // MUST be SendMessage, NOT PostMessage !!!
                                                        // because of using SelectCell in SetChosenColor
end;

function TRVColorGrid.GetRowBegin(ARow: Integer): Integer;
begin
  Result := inherited GetRowBegin(ARow);
  if ARow > 0 then
    Inc(Result, FFirstRowHeight - DefaultRowHeight);
end;

procedure TRVColorGrid.Resize;
begin
  if not HandleAllocated then
    exit;
  ClientHeight := (DefaultRowHeight + GridLineWidth) * RowsVisible - GridLineWidth +
                  (FFirstRowHeight - DefaultRowHeight);
  ClientWidth := (DefaultColWidth + GridLineWidth) * ColCount - GridLineWidth;
  Repaint;
end;

function TRVColorGrid.GetChosenColor: TColor;
begin
  if Indeterminate or (Row = 0) then begin
    Result := FFirstColor;
    exit;
  end;
  Result := Colors[(Row - 1) * ColCount + Col].Color;
end;

function TRVColorGrid.GetColorName: String;
begin
  if Indeterminate or (Row = 0) then begin
    Result := FFirstCaption;
    exit;
  end;
  Result := Colors[(Row - 1) * ColCount + Col].Name;
end;

procedure TRVColorGrid.Initalize;
begin
  inherited;
  FFirstRowHeight := 24;
  FFirstCaption := 'Default';
  DefaultColWidth := 18;
  DefaultRowHeight := 18;
  GridLineWidth := 0;
  ColCount := 8;
  RowCount := 6;
  RowsVisible := 6;
end;

procedure TRVColorGrid.SetChosenColor(const Value: TColor);
var
  i: Integer;
begin
  if Value = FFirstColor then begin
    SelectCell(0, 0);
    Indeterminate := False;
    exit;
  end;
  for i := 0 to ColorCount - 1 do
    if Colors[i].Color = Value then begin
      SelectCell((i mod ColCount), (i div ColCount) + 1);
      Indeterminate := False;
      exit;
  end;
  Indeterminate := True;
end;

procedure TRVColorGrid.SetFirstCaption(const Value: String);
begin
  FFirstCaption := Value;
  Repaint;
end;

procedure TRVColorGrid.SetFirstColor(const Value: TColor);
begin
  FFirstColor := Value;
  Repaint;
end;

procedure TRVColorGrid.SetFlat(const Value: Boolean);
begin
  FFlat := Value;
  Repaint;
end;

procedure TRVColorGrid.SetIndeterminate(const Value: Boolean);
begin
  FIndeterminate := Value;
  Repaint;
end;

procedure TRVColorGrid.WMColorChanged(var Msg: TMessage);
begin
  if Assigned(FOnColorChange) then
    FOnColorChange(Self);
end;

function TRVColorGrid.GetFlat: Boolean;
begin
  Result := FFlat and
    (Assigned(RV_IsAppThemed) and RV_IsAppThemed and RV_IsThemeActive);
end;

end.
