unit BrushForm;
{*******************************************************************************
  ShapesDemo
  Written by David Clegg, davidclegg@optusnet.com.au.

  This unit contains the Brush selection form.
*******************************************************************************}

interface

uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data;

type
  TBrushForm = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    Components: System.ComponentModel.Container;
    gbHatch: System.Windows.Forms.GroupBox;
    btnHBackColour: System.Windows.Forms.Button;
    btnHForeColour: System.Windows.Forms.Button;
    cmbHatchStyles: System.Windows.Forms.ComboBox;
    gbSolid: System.Windows.Forms.GroupBox;
    btnSolidColour: System.Windows.Forms.Button;
    pnSolid: System.Windows.Forms.Panel;
    btnCancel: System.Windows.Forms.Button;
    gbTexture: System.Windows.Forms.GroupBox;
    btnImage: System.Windows.Forms.Button;
    pnTexture: System.Windows.Forms.Panel;
    gbLinearGradient: System.Windows.Forms.GroupBox;
    btnLinearEndColour: System.Windows.Forms.Button;
    btnLinearStartColour: System.Windows.Forms.Button;
    pnLinearGradient: System.Windows.Forms.Panel;
    ofdImage: System.Windows.Forms.OpenFileDialog;
    btnOK: System.Windows.Forms.Button;
    cd: System.Windows.Forms.ColorDialog;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
    procedure cmbHatchStyles_DrawItem(sender: System.Object; e: System.Windows.Forms.DrawItemEventArgs);
    procedure TBrushForm_Load(sender: System.Object; e: System.EventArgs);
    procedure btnHForeColour_Click(sender: System.Object; e: System.EventArgs);
    procedure btnHBackColour_Click(sender: System.Object; e: System.EventArgs);
    procedure pnSolid_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
    procedure btnSolidColour_Click(sender: System.Object; e: System.EventArgs);
    procedure pnTexture_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
    procedure btnImage_Click(sender: System.Object; e: System.EventArgs);
    procedure pnLinearGradient_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
    procedure btnLinearStartColour_Click(sender: System.Object; e: System.EventArgs);
    procedure btnLinearEndColour_Click(sender: System.Object; e: System.EventArgs);
    procedure Panel_Click(sender: System.Object; e: System.EventArgs);
    procedure cmbHatchStyles_SelectionChangeCommitted(sender: System.Object;
        e: System.EventArgs);
    procedure TBrushForm_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  private
    FHForeColour: Color;
    FHBackColour: Color;
    FLGStartColour: Color;
    FLGEndColour: Color;
    FBrush: Brush;
    FFocusRectangle: Rectangle;
    FFocusedParent: Control;
    FFormShowing: boolean;
    procedure PopulateControls;
    procedure PopulateHatchStyles;
    procedure PaintPanel(var pPanel: Panel; pBrush: Brush);
    procedure PaintLinearGradientPanel;
    procedure ClearFocusRectangle;
    procedure DrawFocusRectangle(sender: TObject);
    procedure SetHatchBrush;
    procedure SelectBrush(pPanel: Panel);
    procedure SelectHatchBrush;
    procedure SelectCurrentBrush;
    procedure ChooseHatchColour(var pColour: Color);
  public
    class function ShowBrushForm(var pBrush: Brush): DialogResult;
    constructor Create;
  end;

implementation

uses
  System.Globalization, System.Drawing.Drawing2D;

{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TBrushForm.InitializeComponent;
begin
  Self.gbHatch := System.Windows.Forms.GroupBox.Create;
  Self.btnHBackColour := System.Windows.Forms.Button.Create;
  Self.btnHForeColour := System.Windows.Forms.Button.Create;
  Self.cmbHatchStyles := System.Windows.Forms.ComboBox.Create;
  Self.gbSolid := System.Windows.Forms.GroupBox.Create;
  Self.btnSolidColour := System.Windows.Forms.Button.Create;
  Self.pnSolid := System.Windows.Forms.Panel.Create;
  Self.btnCancel := System.Windows.Forms.Button.Create;
  Self.gbTexture := System.Windows.Forms.GroupBox.Create;
  Self.btnImage := System.Windows.Forms.Button.Create;
  Self.pnTexture := System.Windows.Forms.Panel.Create;
  Self.gbLinearGradient := System.Windows.Forms.GroupBox.Create;
  Self.btnLinearEndColour := System.Windows.Forms.Button.Create;
  Self.btnLinearStartColour := System.Windows.Forms.Button.Create;
  Self.pnLinearGradient := System.Windows.Forms.Panel.Create;
  Self.ofdImage := System.Windows.Forms.OpenFileDialog.Create;
  Self.btnOK := System.Windows.Forms.Button.Create;
  Self.cd := System.Windows.Forms.ColorDialog.Create;
  Self.gbHatch.SuspendLayout;
  Self.gbSolid.SuspendLayout;
  Self.gbTexture.SuspendLayout;
  Self.gbLinearGradient.SuspendLayout;
  Self.SuspendLayout;
  // 
  // gbHatch
  // 
  Self.gbHatch.BackColor := System.Drawing.SystemColors.Control;
  Self.gbHatch.Controls.Add(Self.btnHBackColour);
  Self.gbHatch.Controls.Add(Self.btnHForeColour);
  Self.gbHatch.Controls.Add(Self.cmbHatchStyles);
  Self.gbHatch.ForeColor := System.Drawing.SystemColors.ControlText;
  Self.gbHatch.Location := System.Drawing.Point.Create(200, 8);
  Self.gbHatch.Name := 'gbHatch';
  Self.gbHatch.Size := System.Drawing.Size.Create(192, 168);
  Self.gbHatch.TabIndex := 14;
  Self.gbHatch.TabStop := False;
  Self.gbHatch.Text := 'HatchBrush';
  Include(Self.gbHatch.Paint, Self.TBrushForm_Paint);
  // 
  // btnHBackColour
  // 
  Self.btnHBackColour.Location := System.Drawing.Point.Create(32, 120);
  Self.btnHBackColour.Name := 'btnHBackColour';
  Self.btnHBackColour.Size := System.Drawing.Size.Create(120, 23);
  Self.btnHBackColour.TabIndex := 9;
  Self.btnHBackColour.Text := 'Background Colour...';
  Include(Self.btnHBackColour.Click, Self.btnHBackColour_Click);
  // 
  // btnHForeColour
  // 
  Self.btnHForeColour.Location := System.Drawing.Point.Create(32, 80);
  Self.btnHForeColour.Name := 'btnHForeColour';
  Self.btnHForeColour.Size := System.Drawing.Size.Create(120, 23);
  Self.btnHForeColour.TabIndex := 8;
  Self.btnHForeColour.Text := 'Foreground Colour...';
  Include(Self.btnHForeColour.Click, Self.btnHForeColour_Click);
  // 
  // cmbHatchStyles
  // 
  Self.cmbHatchStyles.DrawMode := System.Windows.Forms.DrawMode.OwnerDrawFixed;
  Self.cmbHatchStyles.DropDownStyle := System.Windows.Forms.ComboBoxStyle.DropDownList;
  Self.cmbHatchStyles.ItemHeight := 18;
  Self.cmbHatchStyles.Location := System.Drawing.Point.Create(8, 32);
  Self.cmbHatchStyles.Name := 'cmbHatchStyles';
  Self.cmbHatchStyles.Size := System.Drawing.Size.Create(176, 24);
  Self.cmbHatchStyles.Sorted := True;
  Self.cmbHatchStyles.TabIndex := 7;
  Include(Self.cmbHatchStyles.Click, Self.cmbHatchStyles_SelectionChangeCommitted);
  Include(Self.cmbHatchStyles.DrawItem, Self.cmbHatchStyles_DrawItem);
  Include(Self.cmbHatchStyles.SelectionChangeCommitted, Self.cmbHatchStyles_SelectionChangeCommitted);
  // 
  // gbSolid
  // 
  Self.gbSolid.Controls.Add(Self.btnSolidColour);
  Self.gbSolid.Controls.Add(Self.pnSolid);
  Self.gbSolid.Location := System.Drawing.Point.Create(8, 8);
  Self.gbSolid.Name := 'gbSolid';
  Self.gbSolid.Size := System.Drawing.Size.Create(184, 80);
  Self.gbSolid.TabIndex := 13;
  Self.gbSolid.TabStop := False;
  Self.gbSolid.Text := 'SolidBrush';
  Include(Self.gbSolid.Paint, Self.TBrushForm_Paint);
  // 
  // btnSolidColour
  // 
  Self.btnSolidColour.Location := System.Drawing.Point.Create(72, 32);
  Self.btnSolidColour.Name := 'btnSolidColour';
  Self.btnSolidColour.TabIndex := 6;
  Self.btnSolidColour.Text := 'Colour...';
  Include(Self.btnSolidColour.Click, Self.btnSolidColour_Click);
  // 
  // pnSolid
  // 
  Self.pnSolid.BackColor := System.Drawing.SystemColors.Control;
  Self.pnSolid.BorderStyle := System.Windows.Forms.BorderStyle.Fixed3D;
  Self.pnSolid.Location := System.Drawing.Point.Create(16, 24);
  Self.pnSolid.Name := 'pnSolid';
  Self.pnSolid.Size := System.Drawing.Size.Create(40, 40);
  Self.pnSolid.TabIndex := 5;
  Include(Self.pnSolid.Click, Self.Panel_Click);
  Include(Self.pnSolid.Paint, Self.pnSolid_Paint);
  // 
  // btnCancel
  // 
  Self.btnCancel.DialogResult := System.Windows.Forms.DialogResult.Cancel;
  Self.btnCancel.Location := System.Drawing.Point.Create(312, 240);
  Self.btnCancel.Name := 'btnCancel';
  Self.btnCancel.TabIndex := 12;
  Self.btnCancel.Text := 'Cancel';
  // 
  // gbTexture
  // 
  Self.gbTexture.Controls.Add(Self.btnImage);
  Self.gbTexture.Controls.Add(Self.pnTexture);
  Self.gbTexture.Location := System.Drawing.Point.Create(8, 96);
  Self.gbTexture.Name := 'gbTexture';
  Self.gbTexture.Size := System.Drawing.Size.Create(184, 80);
  Self.gbTexture.TabIndex := 16;
  Self.gbTexture.TabStop := False;
  Self.gbTexture.Text := 'TextureBrush';
  Include(Self.gbTexture.Paint, Self.TBrushForm_Paint);
  // 
  // btnImage
  // 
  Self.btnImage.Location := System.Drawing.Point.Create(72, 32);
  Self.btnImage.Name := 'btnImage';
  Self.btnImage.TabIndex := 9;
  Self.btnImage.Text := 'Image...';
  Include(Self.btnImage.Click, Self.btnImage_Click);
  // 
  // pnTexture
  // 
  Self.pnTexture.BorderStyle := System.Windows.Forms.BorderStyle.Fixed3D;
  Self.pnTexture.Location := System.Drawing.Point.Create(16, 24);
  Self.pnTexture.Name := 'pnTexture';
  Self.pnTexture.Size := System.Drawing.Size.Create(40, 40);
  Self.pnTexture.TabIndex := 6;
  Include(Self.pnTexture.Click, Self.Panel_Click);
  Include(Self.pnTexture.Paint, Self.pnTexture_Paint);
  // 
  // gbLinearGradient
  // 
  Self.gbLinearGradient.Controls.Add(Self.btnLinearEndColour);
  Self.gbLinearGradient.Controls.Add(Self.btnLinearStartColour);
  Self.gbLinearGradient.Controls.Add(Self.pnLinearGradient);
  Self.gbLinearGradient.Location := System.Drawing.Point.Create(8, 184);
  Self.gbLinearGradient.Name := 'gbLinearGradient';
  Self.gbLinearGradient.Size := System.Drawing.Size.Create(184, 80);
  Self.gbLinearGradient.TabIndex := 15;
  Self.gbLinearGradient.TabStop := False;
  Self.gbLinearGradient.Text := 'LinearGradiantBrush';
  Include(Self.gbLinearGradient.Paint, Self.TBrushForm_Paint);
  // 
  // btnLinearEndColour
  // 
  Self.btnLinearEndColour.Location := System.Drawing.Point.Create(80, 45);
  Self.btnLinearEndColour.Name := 'btnLinearEndColour';
  Self.btnLinearEndColour.Size := System.Drawing.Size.Create(83, 23);
  Self.btnLinearEndColour.TabIndex := 9;
  Self.btnLinearEndColour.Text := 'End Colour...';
  Include(Self.btnLinearEndColour.Click, Self.btnLinearEndColour_Click);
  // 
  // btnLinearStartColour
  // 
  Self.btnLinearStartColour.Location := System.Drawing.Point.Create(80, 17);
  Self.btnLinearStartColour.Name := 'btnLinearStartColour';
  Self.btnLinearStartColour.Size := System.Drawing.Size.Create(83, 23);
  Self.btnLinearStartColour.TabIndex := 8;
  Self.btnLinearStartColour.Text := 'Start Colour...';
  Include(Self.btnLinearStartColour.Click, Self.btnLinearStartColour_Click);
  // 
  // pnLinearGradient
  // 
  Self.pnLinearGradient.BorderStyle := System.Windows.Forms.BorderStyle.Fixed3D;
  Self.pnLinearGradient.Location := System.Drawing.Point.Create(16, 24);
  Self.pnLinearGradient.Name := 'pnLinearGradient';
  Self.pnLinearGradient.Size := System.Drawing.Size.Create(40, 40);
  Self.pnLinearGradient.TabIndex := 7;
  Include(Self.pnLinearGradient.Click, Self.Panel_Click);
  Include(Self.pnLinearGradient.Paint, Self.pnLinearGradient_Paint);
  // 
  // ofdImage
  // 
  Self.ofdImage.Filter := 'Image files|*.bmp;*.jpg;*.jpeg;';
  // 
  // btnOK
  // 
  Self.btnOK.DialogResult := System.Windows.Forms.DialogResult.OK;
  Self.btnOK.Location := System.Drawing.Point.Create(224, 240);
  Self.btnOK.Name := 'btnOK';
  Self.btnOK.TabIndex := 11;
  Self.btnOK.Text := 'OK';
  // 
  // TBrushForm
  // 
  Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
  Self.ClientSize := System.Drawing.Size.Create(400, 270);
  Self.Controls.Add(Self.btnCancel);
  Self.Controls.Add(Self.gbTexture);
  Self.Controls.Add(Self.gbLinearGradient);
  Self.Controls.Add(Self.btnOK);
  Self.Controls.Add(Self.gbHatch);
  Self.Controls.Add(Self.gbSolid);
  Self.FormBorderStyle := System.Windows.Forms.FormBorderStyle.FixedSingle;
  Self.MaximizeBox := False;
  Self.MinimizeBox := False;
  Self.Name := 'TBrushForm';
  Self.StartPosition := System.Windows.Forms.FormStartPosition.CenterScreen;
  Self.Text := 'Select Brush';
  Include(Self.Load, Self.TBrushForm_Load);
  Include(Self.Paint, Self.TBrushForm_Paint);
  Self.gbHatch.ResumeLayout(False);
  Self.gbSolid.ResumeLayout(False);
  Self.gbTexture.ResumeLayout(False);
  Self.gbLinearGradient.ResumeLayout(False);
  Self.ResumeLayout(False);
end;
{$ENDREGION}

procedure TBrushForm.Dispose(Disposing: Boolean);
begin
  if Disposing then
  begin
    if Components <> nil then
      Components.Dispose();
  end;
  inherited Dispose(Disposing);
end;

constructor TBrushForm.Create;
begin
  inherited Create;
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent;
end;

/// <summary>
/// Ensure the Focus Rectangle is redrawn if the form is repainted.
/// </summary>
/// <param name='sender: System.Object'>
/// Reference to the object that triggered the Paint event.
/// </param>
/// <param name='e: PaintEventArgs'>
/// Contains information relevant to the painting of the form.
/// </param>
procedure TBrushForm.TBrushForm_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
var
  lGraphics: Graphics;
begin
  //Redraw the focus rectangle
  if Assigned(FFocusedParent) then
  begin
    lGraphics := FFocusedParent.CreateGraphics;
    try
      ControlPaint.DrawFocusRectangle(lGraphics, FFocusRectangle);
    finally
      //The Graphics reference must be disposed once we are finished
      //with it
      lGraphics.Dispose;
    end;
  end;
end;

/// <summary>
/// Set the HatchBrush when a new selection is chosen in the Combobox.
/// </summary>
procedure TBrushForm.cmbHatchStyles_SelectionChangeCommitted(sender: System.Object;
    e: System.EventArgs);
begin
  SetHatchBrush;
end;

/// <summary>
/// Create a new HatchBrush, based on the selected HatchStyle, and
/// assign it to fBrush.
/// </summary>
procedure TBrushForm.SetHatchBrush;
var
  lHatchStyle: HatchStyle;
begin
  if not FFormShowing then
  begin
    if (FFocusedParent <> gbHatch) then
      //Redraw the focus rectangle around the Hatch Combobox, if it isn't
      //already
      DrawFocusRectangle(cmbHatchStyles);

    if (cmbHatchStyles.SelectedIndex <> -1) then
    begin
      lHatchStyle := HatchStyle(cmbHatchStyles.Items[cmbHatchStyles.SelectedIndex]);
      FBrush := HatchBrush.Create(lHatchStyle, FHForeColour, FHBackColour);
    end;
  end;
end;

/// <summary>
/// Draw a focus rectangle around the clicked panel, and set the current brush to
/// the one stored in the Panels Tag property.
/// </summary>
procedure TBrushForm.Panel_Click(sender: System.Object; e: System.EventArgs);
begin
  DrawFocusRectangle(Sender);
  FBrush := Brush(Control(Sender).Tag);
end;

/// <summary>
/// Choose a new end colour for the LinearGradientBrush.
/// </summary>
procedure TBrushForm.btnLinearEndColour_Click(sender: System.Object; e: System.EventArgs);
begin
  if cd.ShowDialog = System.Windows.Forms.DialogResult.OK then
  begin
    FLGEndColour := cd.Color;
    PaintLinearGradientPanel;
    Panel_Click(pnLinearGradient, nil);
  end;
end;

/// <summary>
/// Choose a new start colour for the LinearGradientBrush.
/// </summary>
procedure TBrushForm.btnLinearStartColour_Click(sender: System.Object; e: System.EventArgs);
begin
  if cd.ShowDialog = System.Windows.Forms.DialogResult.OK then
  begin
    FLGStartColour := cd.Color;
    PaintLinearGradientPanel;
    Panel_Click(pnLinearGradient, nil);
  end;
end;

/// <summary>
/// Fill pnLinearGradient using a LinearGradientBrush.
/// </summary>
procedure TBrushForm.pnLinearGradient_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
begin
  PaintLinearGradientPanel;
end;

/// <summary>
/// Select a new image for the TextureBrush.
/// </summary>
procedure TBrushForm.btnImage_Click(sender: System.Object; e: System.EventArgs);
begin
  if ofdImage.ShowDialog = System.Windows.Forms.DialogResult.OK then
  begin
    pnTexture.Tag := TextureBrush.Create(Bitmap.Create(ofdImage.FileName));
    pnTexture.Invalidate;
    Panel_Click(pnTexture, nil);
  end;
end;

/// <summary>
/// Fill pnTexture using a TextureBrush.
/// </summary>
procedure TBrushForm.pnTexture_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
begin
  if Assigned(pnTexture.Tag) then
    PaintPanel(pnTexture, Brush(pnTexture.Tag));
end;

/// <summary>
/// Choose a new colour for the SolidBrush.
/// </summary>
procedure TBrushForm.btnSolidColour_Click(sender: System.Object; e: System.EventArgs);
begin
  if cd.ShowDialog = System.Windows.Forms.DialogResult.OK then
  begin
    pnSolid.Tag := SolidBrush.Create(cd.Color);
    pnSolid.Invalidate;
    Panel_Click(pnSolid, nil);
  end;
end;

/// <summary>
/// Fill pnSolid using a SolidBrush.
/// </summary>
procedure TBrushForm.pnSolid_Paint(sender: System.Object; e: System.Windows.Forms.PaintEventArgs);
begin
  if Assigned(pnSolid.Tag) then
    PaintPanel(pnSolid, Brush(pnSolid.Tag))
  else
    PaintPanel(pnSolid, SolidBrush.Create(Color.Red));
end;

/// <summary>
/// Sets pColour to the chosen colour, repaints the hatch combobox with the
/// updated HatchBrush, ensures the selection rectangle is painted and
/// FBrush is updated.
/// </summary>
procedure TBrushForm.ChooseHatchColour(var pColour: Color);
begin
  if cd.ShowDialog = System.Windows.Forms.DialogResult.OK then
  begin
    pColour := cd.Color;
    SetHatchBrush;
    SelectHatchBrush;
  end;
  Invalidate;
end;

/// <summary>
/// Choose a new foreground colour for the HatchBrush.
/// </summary>
procedure TBrushForm.btnHForeColour_Click(sender: System.Object; e: System.EventArgs);
begin
  ChooseHatchColour(FHForeColour);
end;

/// <summary>
/// Choose a new background colour for the HatchBrush.
/// </summary>
procedure TBrushForm.btnHBackColour_Click(sender: System.Object; e: System.EventArgs);
begin
  ChooseHatchColour(FHBackColour);
end;

procedure TBrushForm.TBrushForm_Load(sender: System.Object; e: System.EventArgs);
begin
  FFormShowing := true;
  try
    PopulateControls;
  finally
    FFormShowing := False;
  end;
end;

/// <summary>
/// Provide custom drawing so we can show a graphical representation for each
/// HatchBrush listed in the combobox.
/// </summary>
procedure TBrushForm.cmbHatchStyles_DrawItem(sender: System.Object; e: System.Windows.Forms.DrawItemEventArgs);
var
  lRect: Rectangle;
  lBrush: SolidBrush;
  lHatchStyle: HatchStyle;
  lHatchBrush: HatchBrush;
  lPen: Pen;

begin
  // Draw the background of the ListBox control for each item.
   lRect := System.Drawing.Rectangle.Create(Point.Create(e.Bounds.X + 2, e.Bounds.Y + 2),
                                            System.Drawing.Size.Create(e.Bounds.Height - 4, e.Bounds.Height - 4));

   //If the item being drawn is highlighted, change the font color to make it
   //easier to read
   if (e.State and DrawItemState.Selected) = DrawItemState.Selected then
     lBrush := SolidBrush.Create(BackColor)
   else
     lBrush := SolidBrush.Create(ForeColor);
   lPen := Pen.Create(Color.Black, 1);

   e.DrawBackground;
   if e.Index <> -1 then
   begin
     //Draw a rectangle using the HatchStyle for the current item
     lHatchStyle := HatchStyle(cmbHatchStyles.Items[e.Index]);
     lHatchBrush := HatchBrush.Create(lHatchStyle, FHForeColour, FHBackColour);
     e.Graphics.FillRectangle(lHatchBrush, lRect);
     e.Graphics.DrawRectangle(lPen, lRect);
     e.Graphics.DrawString(TObject(lHatchStyle).ToString, e.Font, lBrush, lRect.X + lRect.Width + 5, lRect.Y + 2);
   end;
   e.DrawFocusRectangle;
end;

/// <summary>
/// Class function to be used to show a modal instance of BrushForm.
/// </summary>
/// <param name="pBrush">
/// Used to pass in the currently selected brush, and return the new selection.
/// </param>
/// <returns>
/// Returns the DialogResult.
/// </returns>
class function TBrushForm.ShowBrushForm(var pBrush: Brush): DialogResult;
begin
  with TBrushForm.Create do
  try
    FBrush := pBrush;
    Result := ShowDialog;
    if Result = System.Windows.Forms.DialogResult.OK then
      pBrush := FBrush;
  finally
    Free;
  end;
end;

/// <summary>
/// Populate the controls and show the currently selected Brush.
/// </summary>
procedure TBrushForm.PopulateControls;
begin
  //Default Colors for LinearGradientBrush and HatchBrush
  FLGStartColour := Color.Blue;
  FLGEndColour := Color.Black;
  FHForeColour := Color.White;
  FHBackColour := Color.Black;

  PopulateHatchStyles;
  SelectCurrentBrush;
end;

/// <summary>
/// Paints a Focus Rectangle around the currently selected brush.
/// </summary>
procedure TBrushForm.SelectCurrentBrush;
begin
  if Assigned(FBrush) then
  begin
    if (FBrush is SolidBrush) then
      SelectBrush(pnSolid)
    else if (FBrush is TextureBrush) then
      SelectBrush(pnTexture)
    else if (FBrush is LinearGradientBrush) then
      SelectBrush(pnLinearGradient)
    else if (FBrush is HatchBrush) then
      SelectHatchBrush
  end
  else
  begin
    //No brush currently selected, so default to a SolidBrush
    //with a colour of red
    FBrush := SolidBrush.Create(Color.Red);
    Panel_Click(pnSolid, nil);
  end;
end;

/// <summary>
/// Paints a Focus Rectangle around the selected panel, and ensures
/// that the correct brush is associated with it.
/// </summary>
procedure TBrushForm.SelectBrush(pPanel: Panel);
begin
  pPanel.Tag := FBrush;
  Panel_Click(pPanel, nil);
end;

/// <summary>
/// Paints a Focus Rectangle around the Hatch Brush Combo Box and sets
/// the item index to the currently selected brush.
/// </summary>
procedure TBrushForm.SelectHatchBrush;
begin
  if FBrush is HatchBrush then
  begin
    FHForeColour := HatchBrush(FBrush).ForegroundColor;
    FHBackColour := HatchBrush(FBrush).BackgroundColor;
    DrawFocusRectangle(cmbHatchStyles);
    cmbHatchStyles.SelectedIndex := cmbHatchStyles.Items.IndexOf(HatchBrush(fBrush).HatchStyle);
  end;
end;

/// <summary>
/// Populate the Hatch Styles combobox with all values from the
/// System.Drawing.Drawing2D.HatchStyle enumeration.
/// </summary>
procedure TBrushForm.PopulateHatchStyles;
var
  lHatchStyle: HatchStyle;
begin
  cmbHatchStyles.Items.Clear;
  for lHatchStyle := Low(HatchStyle) to High(HatchStyle) do
    cmbHatchStyles.Items.Add(lHatchStyle);
  if cmbHatchStyles.Items.Count <> 0 then
    cmbHatchStyles.SelectedIndex := 0;
end;

/// <summary>
/// Fill pPanel using pBrush.
/// </summary>
procedure TBrushForm.PaintPanel(var pPanel: Panel; pBrush: Brush);
var
  lGraphics: Graphics;
begin
  lGraphics := pPanel.CreateGraphics;
  try
    lGraphics.FillRectangle(pBrush, pPanel.ClientRectangle);
    //Save the brush so we can reference it when the panel is clicked
    pPanel.Tag := pBrush;
  finally
    lGraphics.Dispose;
  end;
end;

/// <summary>
/// Fill pnLinearGradient using a LinearGradientBrush
/// </summary>
procedure TBrushForm.PaintLinearGradientPanel;
var
  lBrush: LinearGradientBrush;
begin
  lBrush := LinearGradientBrush.Create(pnLinearGradient.ClientRectangle,
                                       FLGStartColour,
                                       FLGEndColour, LinearGradientMode.Vertical);
  pnLinearGradient.Tag := lBrush;
  PaintPanel(pnLinearGradient, lBrush);
end;

/// <summary>
/// Draw a focus rectangle around the selected control.
/// </summary>
procedure TBrushForm.DrawFocusRectangle(sender: TObject);
var
  lControl: Control;
  lGraphics: Graphics;
begin
  //Clear the previous focus rectangle
  ClearFocusRectangle;

  //Grab a reference to the control
  lControl := Control(sender);

  //Create a rectangle 2 pixels either side of the controls dimensions.
  //Save a reference to the rectangle and the controls parent so
  //we can repaint it if necessary, and so we can clear the old focus
  //rectangle.
  FFocusRectangle :=
    System.Drawing.Rectangle.Create(lControl.Left - 2, lControl.Top - 2,
                   lControl.Width + 4, lControl.Height + 4);
  FFocusedParent := lControl.Parent;

  //Grab a reference to the controls parents graphics area and draw
  //the focus rectangle.
  lGraphics := FFocusedParent.CreateGraphics;
  try
    ControlPaint.DrawFocusRectangle(lGraphics, fFocusRectangle);
  finally
    //The Graphics reference must be disposed once we are finished
    //with it.
    lGraphics.Dispose;
  end;
end;

/// <summary>
/// Clears the previous focus rectangle.
/// </summary>
procedure TBrushForm.ClearFocusRectangle;
var
  lPen: Pen;
  lGraphics: Graphics;
begin
  if Assigned(FFocusedParent) then
  begin
    lPen := Pen.Create(FFocusedParent.BackColor, 2);
    lGraphics := FFocusedParent.CreateGraphics;
    try
      lGraphics.DrawRectangle(lPen, FFocusRectangle);
    finally
      //The Graphics reference must be disposed once we are finished
      //with it
      lGraphics.Dispose;
    end;
  end;
end;

end.
