{==============================================================================

  Custom Menus      
  Copyright (C) 2000-2001 by Evgeny Kryukov
  All rights reserved

  All contents of this file and all other files included in this archive
  are Copyright (C) 2001 Evgeny Kryukov. Use and/or distribution of
  them requires acceptance of the License Agreement.

  See License.txt for licence information

===============================================================================}

unit KsToolBars;

{$I KsCommonVer.Inc}
{$T-,W-,X+,P+}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  KsBitmap, KsControls;

type

{ TKsCustomToolBar class }

  TKsCustomToolBar = class(TKsCustomControl)
  private
    FBorderWidth: integer;
    FButtonWidth: integer;
    FDividerWidth: integer;
    procedure SetBorderWidth(const Value: integer);
    procedure SetButtonWidth(const Value: integer);
    procedure SetDividerWidth(const Value: integer);
  protected
    procedure AlignControls(AControl: TControl; var Rect: TRect); override;
    function GetClientRect: Trect; override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    procedure PaintBuffer; override;
    { Protected }
    function IsHorizontal: boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Anchors;
    property Align;
    property BorderWidth: integer read FBorderWidth write SetBorderWidth;
    property ButtonWidth: integer read FButtonWidth write SetButtonWidth;
    property DividerWidth: integer read FDividerWidth write SetDividerWidth;
  end;

implementation {===============================================================}

uses KsForms, KsSpeedButtons;

{ TKsCustomToolBar ===============================================================}

constructor TKsCustomToolBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csAcceptsControls];
  Color := clBtnFace;
  Height := 29;
  FBorderWidth := 2;
  FButtonWidth := Height - FBorderWidth * 2;
  FDividerWidth := 8;
end;

destructor TKsCustomToolBar.Destroy;
begin
  inherited Destroy;
end;

function TKsCustomToolBar.IsHorizontal: boolean;
begin
  Result := (FWidth >= FHeight) or (Align in [alTop, alBottom]);
end;

procedure TKsCustomToolBar.PaintBuffer;
begin
  Buffer.FillRect(Rect(0, 0, Fwidth, FHeight), KColor(Color)); 
end;

procedure TKsCustomToolBar.AlignControls(AControl: TControl;
  var Rect: TRect);
var
  AlignList: TList;
  FOriginalParentSize: TPoint;
  FAnchorRules: TPoint;

  function InsertBefore(C1, C2: TControl; AAlign: TAlign): Boolean;
  begin
    Result := False;
    case AAlign of
      alTop: Result := C1.Top < C2.Top;
      alBottom: Result := (C1.Top + C1.Height) >= (C2.Top + C2.Height);
      alLeft: Result := C1.Left < C2.Left;
      alRight: Result := (C1.Left + C1.Width) >= (C2.Left + C2.Width);
    end;
  end;

  procedure DoPosition(Control: TControl; AAlign: TAlign);
  var
    NewLeft, NewTop, NewWidth, NewHeight: Integer;
    ParentSize: TPoint;
  begin
    with Rect do
    begin
      NewWidth := Right - Left;
      if (NewWidth < 0) or (AAlign in [alLeft, alRight]) then
        NewWidth := Control.Width;
      NewHeight := Bottom - Top;
      if (NewHeight < 0) or (AAlign in [alTop, alBottom]) then
        NewHeight := Control.Height;
      NewLeft := Left;
      NewTop := Top;
      case AAlign of
        alTop:
          begin
            Inc(Top, NewHeight);
            NewWidth := Right - Left;
          end;
        alBottom:
          begin
            Dec(Bottom, NewHeight);
            NewTop := Bottom;
          end;
        alLeft:
          begin
            Inc(Left, NewWidth);
            NewHeight := Bottom - Top;
          end;
        alRight:
          begin
            Dec(Right, NewWidth);
            NewLeft := Right;
          end;
      end;
    end;

    Control.SetBounds(NewLeft, NewTop, NewWidth, NewHeight);

    { Adjust client rect if control didn't resize as we expected }
    if (Control.Width <> NewWidth) or (Control.Height <> NewHeight) then
      with Rect do
        case AAlign of
          alTop: Dec(Top, NewHeight - Control.Height);
          alBottom: Inc(Bottom, NewHeight - Control.Height);
          alLeft: Dec(Left, NewWidth - Control.Width);
          alRight: Inc(Right, NewWidth - Control.Width);
          alClient:
            begin
              Inc(Right, NewWidth - Control.Width);
              Inc(Bottom, NewHeight - Control.Height);
            end;
        end;
  end;

  procedure DoAlign(AAlign: TAlign);
  var
    I, J: Integer;
    Control: TControl;
  begin
    AlignList.Clear;
    if (AControl <> nil)  then
      AlignList.Add(AControl);
      
    for I := 0 to ControlCount - 1 do
    begin
      Control := Controls[I];
      if Control = AControl then Continue;

      J := 0;
      while (J < AlignList.Count) and not InsertBefore(Control,
        TControl(AlignList[J]), AAlign) do Inc(J);
      AlignList.Insert(J, Control);
    end;
    
    for I := 0 to AlignList.Count - 1 do
      DoPosition(TControl(AlignList[I]), AAlign);
  end;

  procedure DoSetWidth;
  var
    i: integer;
    Control: TControl;
  begin
    for i := 0 to ControlCount - 1 do
    begin
      Control := Controls[i];

      if Control is TKsCustomSpeedButton then
      begin
        if (Control as TKsCustomSpeedButton).ShowChevron then
          if IsHorizontal then
            Control.Width := FButtonWidth + (Control as TKsCustomSpeedButton).ChevronWidth
          else
            Control.Height := FButtonWidth + (Control as TKsCustomSpeedButton).ChevronWidth
        else
          if IsHorizontal then
            Control.Width := FButtonWidth
          else
            Control.Height := FButtonWidth
      end;

      if Control is TKsSpeedDivider then
        if IsHorizontal then
          Control.Width := FDividerWidth
        else
          Control.Height := FDividerWidth
    end;
  end;

begin
  if Parent <> nil then
    FOriginalParentSize := Point(Parent.Width, Parent.Height)
  else
    FOriginalParentSize := Point(FWidth, FHeight);
  FAnchorRules := Point(0, 0);

  { Set children width }
  DoSetWidth;

  { Aligning }
  AdjustClientRect(Rect);
  AlignList := TList.Create;
  try
    if IsHorizontal then
      DoAlign(alLeft)
    else
      DoAlign(alTop);
  finally
    AlignList.Free;
  end;
end;

function TKsCustomToolBar.GetClientRect: Trect;
begin
  Result := Rect(0, 0, FWidth, FHeight);
  InflateRect(Result, -FBorderWidth, -FBorderWidth);
end;

procedure TKsCustomToolBar.SetBounds(ALeft, ATop, AWidth,
  AHeight: Integer);
begin
  if IsHorizontal then
    FButtonWidth := AHeight - FBorderWidth * 2
  else
    FButtonWidth := AWidth - FBorderWidth * 2;

  Realign;

  inherited;
end;

{ Properties }

procedure TKsCustomToolBar.SetBorderWidth(const Value: integer);
begin
  if FBorderWidth <> Value then
  begin
    FBorderWidth := Value;
    Realign;
  end;
end;

procedure TKsCustomToolBar.SetButtonWidth(const Value: integer);
begin
  if FButtonWidth <> Value then
  begin
    FButtonWidth := Value;
    Realign;
  end;
end;

procedure TKsCustomToolBar.SetDividerWidth(const Value: integer);
begin
  if FDividerWidth <> Value then
  begin
    FDividerWidth := Value;
    Realign;
  end;
end;

end.
