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

  Custom Panels
  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 KsPanels;

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

interface

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

type

  { The following table lists the possible values:
    <TABLE>
    Value                       Meaning
    -----                       -------
    pbkRoll                     The panel button rollup/rolldown panel
    pbkHide                     The panel button hide panel
    </TABLE>
  }
  TKsPanelButtonKind = (pbkRoll, pbkHide);

{ TKsCustomPanel class }

{ TKsCustomPanel implements a advanced panel control with caption and button. }
  TKsCustomPanel = class(TKsCustomControl)
  private
    FCaptionHeight: integer;
    FShowCaption: boolean;
    FBorderWidth: integer;
    FBevelWidth: integer;
    FShowBevel: boolean;
    FShowButton: boolean;
    FMouseOnButton: boolean;
    FButtonPressed: boolean;
    FRolled: boolean;
    FOldHeight: integer;
    FOnButtonClick: TNotifyEvent;
    FButtonKind: TKsPanelButtonKind;
    FOnRollup: TNotifyEvent;
    FOnHide: TNotifyEvent;
    procedure SetCaptionHeight(const Value: integer);
    procedure SetShowCaption(const Value: boolean);
    procedure SetBorderWidth(const Value: integer);
    procedure SetBevelWidth(const Value: integer);
    procedure SetShowBevel(const Value: boolean);
    procedure SetShowButton(const Value: boolean);
    procedure SetRolled(const Value: boolean);
    procedure SetButtonKind(const Value: TKsPanelButtonKind);
  protected
    procedure CMTextChanged(var Msg: TMessage); message CM_TEXTCHANGED;

    procedure PaintBuffer; override;
    { }
    function GetButtonRect: TRect;
    function GetCaptionRect: TRect;
    procedure DrawCaption; virtual;
    procedure DrawFace; virtual;
    { Events }
    procedure DoButtonClick;
    procedure RollUp;
    procedure RollDown;
    { Inherited Events }
    procedure MouseLeave; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    { VCL }
    function GetClientRect: TRect; override;

    property MouseOnButton: boolean read FMouseOnButton;
    property ButtonPressed: boolean read FButtonPressed; 
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;

    { Height of panel caption }
    property CaptionHeight: integer read FCaptionHeight write SetCaptionHeight;
  published
    property Anchors;
    property Align;
    property Blend;
    property BlendValue;
    { Determines the width, in pixels, of both the bevels of a panel. }
    property BevelWidth: integer read FBevelWidth write SetBevelWidth;
    { Specifies the distance, in pixels, between the bevel and client area. }
    property BorderWidth: integer read FBorderWidth write SetBorderWidth;
    { Specifies the panel button kind
      See Also:
        TKsPanelButtonKind
    }
    property ButtonKind: TKsPanelButtonKind read FButtonKind write SetButtonKind;
    property Color;
    property Caption;
    property Font;
    { if panel is rollup then Rolled property set true }
    property Rolled: boolean read FRolled write SetRolled;
    { Determines whether to show bevel }
    property ShowBevel: boolean read FShowBevel write SetShowBevel;
    { Determines whether to show panel button }
    property ShowButton: boolean read FShowButton write SetShowButton;
    { Determines whether to show panel title bar }
    property ShowCaption: boolean read FShowCaption write SetShowCaption;
    property Transparent;
    { Occurs when a panel button clicked }
    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
    { Occurs when a panel rollup/restore }
    property OnRollup: TNotifyEvent read FOnRollup write FOnRollup;
    { Occurs when a panel hide/show }
    property OnHide: TNotifyEvent read FOnHide write FOnHide;
  end;

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

{ TKsCustomPanel }

constructor TKsCustomPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csAcceptsControls];
  Color := clWindow;
  SetBounds(0, 0, 100, 90);

  FButtonKind := pbkRoll;
  FBevelWidth := 1;
  FBorderWidth := 3;
  FCaptionHeight := 20;
  FShowCaption := true;
  FShowBevel := true;
  FShowButton := true;
end;

destructor TKsCustomPanel.Destroy;
begin
  inherited Destroy;
end;

procedure TKsCustomPanel.Loaded;
begin
  inherited Loaded;
  Invalidate;
end;

function TKsCustomPanel.GetCaptionRect: TRect;
begin
  Result := Rect(0, 0, FWidth, FHeight);

  if FShowBevel then
    InflateRect(Result, -FBevelWidth, -FBevelWidth);

  Result.Bottom := Result.Top + FCaptionHeight;
end;

function TKsCustomPanel.GetButtonRect: TRect;
begin
  if FShowCaption and FShowButton then
  begin
    Result := GetCaptionRect;
    Result.Left := Result.Right - RectHeight(Result);
    InflateRect(Result, -2, -2);
  end
  else
    Result := Rect(0, 0, 0, 0);
end;

procedure TKsCustomPanel.DrawCaption;
var
  R: TRect;
  KindFlags, Flags: integer;
begin
  if not FShowCaption then Exit;

  R := GetCaptionRect;
  { Draw Caption }
  Buffer.FillRect(R, KColor(clBtnFace));
  Buffer.DrawEdge(R, KColor(clBtnHighlight), KColor(clBtnShadow));

  { Draw Text }
  InflateRect(R, -5, 0);
  Buffer.Font.Assign(Font);
  Buffer.DrawText(Caption, R, DrawTextBiDiModeFlags(DT_LEFT or DT_SINGLELINE or DT_VCENTER));

  { Draw Button }
  if not FShowButton then Exit;

  R := GetButtonRect;

  if FButtonKind = pbkHide then
  begin
    KindFlags := DFC_CAPTION;
    Flags := DFCS_CAPTIONCLOSE
  end
  else
  begin
    KindFlags := DFC_SCROLL;
    if FRolled then
      Flags := DFCS_SCROLLDOWN
    else
      Flags := DFCS_SCROLLUP;
  end;

  if ButtonPressed then
    DrawFrameControl(Buffer.DC, R, KindFlags, Flags or DFCS_PUSHED)
  else
    DrawFrameControl(Buffer.DC, R, KindFlags, Flags);

  { Draw Button Bevel }
  if ButtonPressed then
  begin
    { Pressed }
    Buffer.DrawEdge(R, KColor(clBtnShadow), KColor(clBtnHighlight));
    InflateRect(R, -1, -1);
    Buffer.DrawRect(R, KColor(clBtnFace));
  end
  else
    if MouseOnButton then
    begin
      { Rollover }
      Buffer.DrawEdge(R, KColor(clBtnHighlight), KColor(clBtnShadow));
      InflateRect(R, -1, -1);
      Buffer.DrawRect(R, KColor(clBtnFace));
    end
    else
    begin
      { Normal }
      Buffer.DrawRect(R, KColor(clBtnFace));
      InflateRect(R, -1, -1);
      Buffer.DrawRect(R, KColor(clBtnFace));
    end;
end;

procedure TKsCustomPanel.DrawFace;
var
  R: TRect;
begin
  R := Rect(0, 0, FWidth, FHeight);
  { Fill Back  }
  Buffer.FillRect(R, KColor(Color));

  { Draw Bevel }
  if FShowBevel then
  begin
    Buffer.DrawEdge(R, KColor(clBtnShadow), KColor(clBtnHighlight));
    InflateRect(R, -1, -1);
    Buffer.DrawEdge(R, KColor(clBtnHighlight), KColor(clBtnShadow));
  end;
end;

procedure TKsCustomPanel.PaintBuffer;
begin
  inherited ;
  DrawFace;
  DrawCaption;
end;

procedure TKsCustomPanel.DoButtonClick;
begin
  case FButtonKind of
    pbkHide: begin
      if Assigned(FOnHide) then
        FOnHide(Self);
      Hide;
    end;
    pbkRoll: Rolled := not Rolled;
  end;

  if Assigned(FOnButtonClick) then FOnButtonClick(Self);
end;

procedure TKsCustomPanel.RollDown;
begin
  FRolled := false;
  Height := FOldHeight;
  if Assigned(FOnRollup) then
    FOnRollup(Self);
end;

procedure TKsCustomPanel.RollUp;
begin
  FOldHeight := FHeight;

  Height := RectHeight(GetCaptionRect) + (FBevelWidth) * 2;
  FRolled := true;
  Invalidate;

  if Assigned(FOnRollup) then
    FOnRollup(Self);
end;

{ VCL }

procedure TKsCustomPanel.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  if FRolled then
    AHeight := FHeight;

  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;

function TKsCustomPanel.GetClientRect: TRect;
begin
  Result := Rect(0, 0, FWidth, FHeight);

  InflateRect(Result, -FBorderWidth, -FBorderWidth);

  if FShowBevel then
    InflateRect(Result, -FBevelWidth, -FBevelWidth);

  if FShowCaption then
    Result.Top := Result.Top + RectHeight(GetCaptionRect);
end;

{ Events }

procedure TKsCustomPanel.MouseLeave;
begin
  inherited MouseLeave;

  if FMouseOnButton then
  begin
    FMouseOnButton := false;
    Invalidate;
  end;
end;

procedure TKsCustomPanel.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if (Button = mbLeft) and PtInRect(GetButtonRect, Point(X, Y)) then
  begin
    FButtonPressed := true;
    Invalidate;
  end;
end;

procedure TKsCustomPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;

  { Check MouseOnButton }
  if PtInRect(GetButtonRect, Point(X, Y)) then
  begin
    if not FMouseOnButton then
    begin
      FMouseOnButton := true;
      Invalidate;
    end;
  end
  else
    if FMouseOnButton then
    begin
      FMouseOnButton := false;
      Invalidate;
    end;

  { Check ButtonPressed }
  if (ssLeft in Shift) then
    if MouseOnButton then
    begin
      if FButtonPressed then Exit;
      
      FButtonPressed := true;
      Invalidate;
    end
    else
    begin
      if not FButtonPressed then Exit;

      FButtonPressed := false;
      Invalidate;
    end;
end;

procedure TKsCustomPanel.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited;
  if (Button = mbLeft) and PtInRect(GetButtonRect, Point(X, Y)) then
  begin
    FButtonPressed := false;
    Invalidate;

    DoButtonClick;
  end;
end;

{ Properies }

procedure TKsCustomPanel.SetCaptionHeight(const Value: integer);
begin
  if FCaptionHeight <> Value then
  begin
    FCaptionHeight := Value;
    Invalidate;
    Realign;
  end;
end;

procedure TKsCustomPanel.SetShowCaption(const Value: boolean);
begin
  if FShowCaption <> Value then
  begin
    FShowCaption := Value;
    Realign;
    Invalidate;
  end;
end;

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

procedure TKsCustomPanel.SetBevelWidth(const Value: integer);
begin
  if FBevelWidth <> Value then
  begin
    FBevelWidth := Value;
    Invalidate;
    Realign;
  end;
end;

procedure TKsCustomPanel.SetShowBevel(const Value: boolean);
begin
  if FShowBevel <> Value then
  begin
    FShowBevel := Value;
    Invalidate;
    Realign;
  end;
end;

procedure TKsCustomPanel.SetShowButton(const Value: boolean);
begin
  if FShowButton <> Value then
  begin
    FShowButton := Value;
    Invalidate;
  end;
end;

procedure TKsCustomPanel.SetRolled(const Value: boolean);
begin
  if FRolled <> Value then
  begin
    if not FRolled then
      RollUp
    else
      RollDown;
  end;
end;

procedure TKsCustomPanel.SetButtonKind(const Value: TKsPanelButtonKind);
begin
  if FButtonKind <> Value then
  begin
    FButtonKind := Value;
    Invalidate;
  end;
end;

procedure TKsCustomPanel.CMTextChanged(var Msg: TMessage);
begin
  inherited ;
  Invalidate;
end;

end.
