lasarus_compotents/bgracontrols/BCExpandPanels.pas

2632 lines
74 KiB
ObjectPascal

{
********************************************************************************
* BGRAExpandPanels Version 1.0 *
* *
* *
* (c) Massimo Magnano, Alexander Roth *
* *
* *
********************************************************************************
See BcExpandPanels.txt for changelog and to-do
}
unit BCExpandPanels;
{$mode objfpc}{$H+}
// for debugging purposes
//{$DEFINE DEBUG_PAINT}
interface
uses
Controls, Classes, ExtCtrls, Graphics, Math, LResources, Dialogs, SysUtils,
Buttons, Themes, Types, Menus, BCPanel;
type
TBCExpandPanelsBehaviour = (EPHotMouse, EPMultipanel, EPSinglePanel);
// TBoundEvent=procedure(sender:TObject; ALeft, ATop, AWidth, AHeight: integer) of object;
TAnimationEvent = procedure(Sender: TObject; deltaLeft, deltaTop, deltaWidth, deltaHeight: integer) of object;
TNormalProcedure = procedure of object;
{ TBCBoundButton }
TGlyphLayout =
(
glLeft,
glRight,
glNone
);
TGlyphKind =
(
gkArrows,
gkClose,
gkMinMax
);
TTextLayout =
(
tlLeft,
tlRight,
tlCenter,
tlNone
);
TBCBoundButtonStyle = (bbsButton, bbsTab, bbsLine, bbsLineDouble,
bbsLineTop, bbsLineBottom, bbsLineDoubleTop, bbsLineDoubleBottom);
TBCBoundButton = class(TCustomSpeedButton)
private
rColorExpanded: TColor;
rColorHighlight: TColor;
rColorShadow: TColor;
rGlyphKind: TGlyphKind;
rGlyphLayout: TGlyphLayout;
rStyle: TBCBoundButtonStyle;
rTabWidth: Integer;
rTextLayout: TTextLayout;
procedure setColorExpanded(AValue: TColor);
procedure SetColorHighlight(AValue: TColor);
procedure SetColorShadow(AValue: TColor);
procedure SetGlyphKind(AValue: TGlyphKind);
procedure SetGlyphLayout(AValue: TGlyphLayout);
procedure SetStyle(AValue: TBCBoundButtonStyle);
procedure SetTabWidth(AValue: Integer);
procedure SetTextLayout(AValue: TTextLayout);
protected
rGlyph :TButtonGlyph;
rUserGlyphExpanded,
rUserGlyphCollapsed,
rGlyphExpanded,
rGlyphCollapsed :TBitmap;
procedure SetGlyphCollapsed(AValue: TBitmap);
procedure SetGlyphExpanded(AValue: TBitmap);
procedure LoadGlyph(GlyphDST :TBitmap; ResName :String);
procedure BuildGlyphs;
procedure Paint; override;
procedure Loaded; override;
(* property AllowAllUp;
property Down;
property Glyph;
property GroupIndex;
property Height; //Don't Decrease visibility :-O
property HelpContext;
property HelpKeyword;
property HelpType;
property Layout;
property Left;
property Margin;
property Name;
property NumGlyphs;
property Spacing;
property ShowCaption;
property Tag;
property Top;
property Width;
property Transparent;
*)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Caption;
property Color nodefault;
property ColorExpanded: TColor read rColorExpanded write setColorExpanded;
property ColorHighlight: TColor read rColorHighlight write SetColorHighlight default clDefault;
property ColorShadow: TColor read rColorShadow write SetColorShadow default clDefault;
property Font;
property Flat;
property GlyphExpanded: TBitmap read rUserGlyphExpanded write SetGlyphExpanded;
property GlyphCollapsed: TBitmap read rUserGlyphCollapsed write SetGlyphCollapsed;
property GlyphLayout: TGlyphLayout read rGlyphLayout write SetGlyphLayout default glNone;
property GlyphKind: TGlyphKind read rGlyphKind write SetGlyphKind default gkArrows;
property ShowAccelChar;
property TextLayout: TTextLayout read rTextLayout write SetTextLayout default tlLeft;
property Style: TBCBoundButtonStyle read rStyle write SetStyle default bbsButton;
//Negative Values is the % of Total Width, Positive is a Fixed Width
property TabWidth: Integer read rTabWidth write SetTabWidth default -50;
end;
{ TBCExpandPanel }
TBCExpandPanel = class(TBCPanel)
private
FEPManagesCollapsing: TNotifyEvent;
FButton: TBCBoundButton;
FButtonSize: integer;
FCollapseKind: TAnchorKind;
FCollapsed: boolean;
FAnimated: boolean;
FOnExpand: TNotifyEvent;
FOnPreExpand: TNotifyEvent;
FOnAnimate: TAnimationEvent;
FOnCollapse: TNotifyEvent;
FOnPreCollapse: TNotifyEvent;
FOnButtonClick: TNotifyEvent;
FInternalOnAnimate: TAnimationEvent;
FButtonPosition: TAnchorKind;
FExpandedButtonColor: TColor;
FCollapsedButtonColor: TColor;
FExpandedSize: integer;
FAnimationSpeed: real;
FTextAlignment: TAlignment;
rBevelColorHighlight: TColor;
rBevelColorShadow: TColor;
rBevelRounded: Boolean;
StopCircleActions: boolean;
FAnimating: boolean;
FVisibleTotal: boolean;
TargetAnimationSize: integer;
EndProcedureOfAnimation: TNormalProcedure;
Timer: TTimer;
function GetEnabled: Boolean;
procedure SetBevelColorHighlight(AValue: TColor);
procedure SetBevelColorShadow(AValue: TColor);
procedure SetBevelRounded(AValue: Boolean);
procedure SetEnabled(AValue: Boolean);
procedure setExpandedSize(Value: integer);
procedure setButtonSize(Value: integer);
procedure setButtonPosition(Value: TAnchorKind);
procedure setCollapseKind(Value: TAnchorKind);
procedure setAnimationSpeed(Value: real);
procedure setCollapsed(Value: boolean);
procedure PositionButton;
procedure SetRelevantSize(comp: TControl; AKind: TAnchorKind; ASize: Integer);
function RelevantSize(comp: TControl; akind: TAnchorKind): integer;
function RelevantOrthogonalSize(comp: TControl; akind: TAnchorKind): integer;
function DeltaCoordinates(deltaMove, deltaSize: integer): TRect; // the outpot (left,top right, bottom) has all the information: left and top encode the movement. rigth and bottom the size changes
procedure Animate(aTargetSize: integer);
procedure SetTextAlignment(AValue: TAlignment);
procedure TimerAnimateSize(Sender: TObject);
procedure EndTimerCollapse;
procedure EndTimerExpand;
procedure UpdateAll;
procedure ButtonClick(Sender: TObject);
procedure DoCollapse;
procedure DoExpand;
procedure AdjustClientRect(var ARect: TRect); override;
property InternalOnAnimate: TAnimationEvent read FInternalOnAnimate write FInternalOnAnimate;
property EPManagesCollapsing: TNotifyEvent read FEPManagesCollapsing write FEPManagesCollapsing;
protected
procedure Loaded; override;
procedure CreateWnd; override;
procedure Paint; override;
public
property Animating: boolean read FAnimating;
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure SetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
published
property TextAlignment: TAlignment read FTextAlignment write SetTextAlignment;
property Enabled: Boolean read GetEnabled write SetEnabled;
property CollapseKind: TAnchorKind read FCollapseKind write setCollapseKind; //To where should it collapse?
property ExpandedSize: integer read FExpandedSize write setExpandedSize;
property ButtonPosition: TAnchorKind read FButtonPosition write setButtonPosition;
property ButtonSize: integer read FButtonSize write setButtonSize;
property Button: TBCBoundButton read FButton;
property AnimationSpeed: real read FAnimationSpeed write setAnimationSpeed;
property Animated: boolean read FAnimated write FAnimated default True;
property Collapsed: boolean read FCollapsed write setCollapsed default False;
property BevelColorHighlight: TColor read rBevelColorHighlight write SetBevelColorHighlight default clBtnHighlight;
property BevelColorShadow: TColor read rBevelColorShadow write SetBevelColorShadow default clBtnShadow;
property BevelRounded: Boolean read rBevelRounded write SetBevelRounded default True;
property OnAnimate: TAnimationEvent read FOnAnimate write FOnAnimate;
property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
property OnPreExpand: TNotifyEvent read FOnPreExpand write FOnPreExpand;
property OnExpand: TNotifyEvent read FOnExpand write FOnExpand;
property OnCollapse: TNotifyEvent read FOnCollapse write FOnCollapse;
property OnPreCollapse: TNotifyEvent read FOnPreCollapse write FOnPreCollapse;
end;
{==============================================================================
Class: TBCExpandPanels
Description:
==============================================================================}
{ TBCExpandPanels }
TBCExpandPanels = class(TComponent)
private
{ Private-Deklarationen }
PanelArray: TList;
// Properties
FArrangeKind: TAnchorKind;
FButtonPosition, FCollapseKind: TAnchorKind;
FButtonGlyphKind: TGlyphKind;
FButtonGlyphLayout: TGlyphLayout;
FButtonStyle: TBCBoundButtonStyle;
FButtonTabWidth: Integer;
FButtonTextLayout: TTextLayout;
FOrthogonalAbove: integer;
FAbove: integer;
FOrthogonalSize: integer;
FBehaviour: TBCExpandPanelsBehaviour;
FOnArrangePanels: TNotifyEvent;
FFixedSize: integer;
FUseFixedSize: boolean;
FAutoCollapseIfTooHigh: boolean;
FUseClientSize: boolean;
function RelevantAbove(comp: TControl): integer;
function RelevantOrthogonalAbove(comp: TControl): integer;
function RelevantSize(comp: TControl): integer;
function RelevantOrthogonalSize(comp: TControl): integer;
procedure setButtonGlyphKind(AValue: TGlyphKind);
procedure setButtonGlyphLayout(AValue: TGlyphLayout);
procedure setButtonStyle(AValue: TBCBoundButtonStyle);
procedure SetButtonTabWidth(AValue: Integer);
procedure setButtonTextLayout(AValue: TTextLayout);
procedure WriteRelevantAbove(comp: TBCExpandPanel; above: integer);
procedure WriteRelevantSize(comp: TBCExpandPanel; size: integer);
procedure WriteRelevantOrthogonalSize(comp: TBCExpandPanel; size: integer);
procedure WriteRelevantOrthogonalAbove(comp: TBCExpandPanel; size: integer);
procedure setArrangeKind(Value: TAnchorKind);
procedure setButtonPosition(Value: TAnchorKind);
procedure setCollapseKind(Value: TAnchorKind);
procedure setUseClientSize(Value: boolean);
procedure setUseFixedSize(Value: boolean);
procedure setAutoCollapseIfTooHigh(Value: boolean);
procedure setFixedSize(Value: integer);
procedure setOrthogonalAbove(Value: integer);
procedure setAbove(Value: integer);
procedure setOrthogonalSize(Value: integer);
procedure setBehaviour(Value: TBCExpandPanelsBehaviour);
procedure MakeCorrectButtonClickPointers;
procedure RollOutOnAnimate(Sender: TObject; deltaLeft, deltaTop, deltaWidth, deltaHeight: integer);
procedure RollOutClick(Sender: TObject);
procedure HotTrackSetActivePanel(Value: integer);
procedure DelLastPanel;
procedure RollOut1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
protected
{ Protected-Deklarationen }
public
{ Public-Deklarationen }
property OrthogonalAbove: integer read FOrthogonalAbove write setOrthogonalAbove;
property Above: integer read FAbove write setAbove;
property OrthogonalSize: integer read FOrthogonalSize write setOrthogonalSize;
function IdxOfPanel(aname: string): integer; overload;
procedure CollapseIfTooHigh;
// procedure SetCorrectSize;
procedure AddPanel(rollout: TBCExpandPanel);
procedure InsertPanel(idx: integer; rollout: TBCExpandPanel);
function DeltePanel(aname: string): boolean; overload;
function DeltePanel(idx: integer): boolean; overload;
procedure DelteLastPanel;
procedure ArrangePanels;
function Count: integer;
function Panel(idx: integer): TBCExpandPanel;
property CollapseKind: TAnchorKind read FCollapseKind write setCollapseKind;
property ButtonPosition: TAnchorKind read FButtonPosition write setButtonPosition;
property ButtonGlyphLayout: TGlyphLayout read FButtonGlyphLayout write setButtonGlyphLayout;
property ButtonGlyphKind: TGlyphKind read FButtonGlyphKind write setButtonGlyphKind;
property ButtonStyle: TBCBoundButtonStyle read FButtonStyle write setButtonStyle;
property ButtonTabWidth: Integer read FButtonTabWidth write SetButtonTabWidth;
property ButtonTextLayout: TTextLayout read FButtonTextLayout write setButtonTextLayout;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published-Deklarationen }
// property FixedHeight:integer read FFixedHeight write setFixedSize;
// property UseFixedHeight:boolean read FUseFixedHeight write setUseFixedSize;
// property UseClientHeight:boolean read FUseClientHeight write setUseClientSize;
// property AutoCollapseIfTooHigh:boolean read FAutoCollapseIfTooHigh write setAutoCollapseIfTooHigh;
property ArrangeKind: TAnchorKind read FArrangeKind write setArrangeKind;
property OnArrangePanels: TNotifyEvent read FOnArrangePanels write FOnArrangePanels;
property Behaviour: TBCExpandPanelsBehaviour read FBehaviour write setBehaviour;
end;
procedure Register;
implementation
uses GraphType, LCLProc;
const
//GrayScale a Color : Taken from BGRABitmap package
redWeightShl10 = 306; // = 0.299
greenWeightShl10 = 601; // = 0.587
blueWeightShl10 = 117; // = 0.114
procedure korrigiere(var w: real; min, max: real);
var
temp: real;
begin
if max < min then
begin
temp := min;
min := max;
max := temp;
end;
if w < min then
w := min;
if w > max then
w := max;
end;
//Function copied from BGRABitmap package may work ;-)
function Grayscale(AColor :TColor):TColor;
Var
rColor, gray :Integer;
begin
rColor :=ColorToRGB(AColor);
gray := (Red(rColor) * redWeightShl10 + Green(rColor) * greenWeightShl10 + Blue(rColor) * blueWeightShl10 + 512) shr 10;
Result :=RGBToColor(gray, gray, gray);
end;
function GetHighlightColor(BaseColor: TColor; Value:Integer): TColor;
Var
rColor :Integer;
begin
rColor :=ColorToRGB(BaseColor);
Result := RGBToColor(
Min(Red(rColor) + Value, $FF),
Min(Green(rColor) + Value, $FF),
Min(Blue(rColor) + Value, $FF));
end;
function GetShadowColor(BaseColor: TColor; Value:Integer): TColor;
Var
rColor :Integer;
begin
rColor :=ColorToRGB(BaseColor);
Result := RGBToColor(
Max(Red(rColor) - Value, $22),
Max(Green(rColor) - Value, $22),
Max(Blue(rColor) - Value, $22));
end;
//Canvas Draw Functions
procedure Frame3d_Rounded(Canvas: TCanvas;
var ARect: TRect; const FrameWidth : integer; RX, RY:Integer;
const Style : TGraphicsBevelCut;
ShadowColor, HighlightColor, InternalColor: TColor);
var
DRect: TRect;
procedure drawUP;
begin
inc(DRect.Left,1); inc(DRect.Top,1);
//is outside the Rect but in this way we don't have a hole of 1 px
inc(DRect.Right,1); inc(DRect.Bottom,1);
Canvas.Brush.Color :=ShadowColor;
Canvas.Brush.Style :=bsSolid;
Canvas.Pen.Color := clNone;
Canvas.Pen.Width := 1; //The Shadow is always 1 Pixel
Canvas.Pen.Style := psClear;
Canvas.RoundRect(DRect, RX,RY);
dec(DRect.Left,1); dec(DRect.Top,1);
dec(DRect.Right,2); dec(DRect.Bottom,2);
Canvas.Brush.Color :=InternalColor;
if (InternalColor = clNone)
then Canvas.Brush.Style :=bsClear
else Canvas.Brush.Style :=bsSolid;
Canvas.Pen.Color :=HighlightColor;
Canvas.Pen.Width := FrameWidth;
Canvas.Pen.Style := psSolid;
Canvas.RoundRect(DRect, RX,RY);
Inc(ARect.Top, FrameWidth);
Inc(ARect.Left, FrameWidth);
Dec(ARect.Right, FrameWidth+1); //+The Shadow (1 Pixel) +1?
Dec(ARect.Bottom, FrameWidth+1);
end;
procedure drawFLAT;
begin
Canvas.Brush.Color := InternalColor;
if (InternalColor = clNone)
then Canvas.Brush.Style :=bsClear
else Canvas.Brush.Style :=bsSolid;
Canvas.Pen.Color := clNone;
Canvas.Pen.Width := FrameWidth;
Canvas.Pen.Style := psClear;
Canvas.RoundRect(DRect, RX,RY);
end;
procedure drawDOWN;
begin
Canvas.Brush.Color :=ShadowColor;
Canvas.Brush.Style :=bsSolid;
Canvas.Pen.Color := clNone;
Canvas.Pen.Width := 1;
Canvas.Pen.Style := psClear;
Canvas.RoundRect(DRect, RX,RY);
inc(DRect.Left,1); inc(DRect.Top,1);
Canvas.Brush.Color :=InternalColor;
if (InternalColor = clNone)
then Canvas.Brush.Style :=bsClear
else Canvas.Brush.Style :=bsSolid;
Canvas.Pen.Color :=HighlightColor;
Canvas.Pen.Width := FrameWidth;
Canvas.Pen.Style := psSolid;
Canvas.RoundRect(DRect, RX,RY);
Inc(ARect.Top, FrameWidth+1); //+The Shadow (1 Pixel)
Inc(ARect.Left, FrameWidth+1);
Dec(ARect.Right, FrameWidth);
Dec(ARect.Bottom, FrameWidth);
end;
begin
DRect :=ARect;
Case Style of
bvNone: drawFLAT;
bvSpace: begin
drawFLAT;
InflateRect(ARect, -FrameWidth, -FrameWidth);
end;
bvRaised: drawUP;
bvLowered: drawDOWN;
end;
end;
procedure TBCBoundButton.SetColorHighlight(AValue: TColor);
begin
if (rColorHighlight <> AValue) then
begin
rColorHighlight := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCBoundButton.setColorExpanded(AValue: TColor);
begin
if (rColorExpanded <> AValue) then
begin
rColorExpanded := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCBoundButton.SetColorShadow(AValue: TColor);
begin
if (rColorShadow <> AValue) then
begin
rColorShadow := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCBoundButton.SetGlyphKind(AValue: TGlyphKind);
begin
if (rGlyphKind <> AValue) then
begin
rGlyphKind:=AValue;
if not(csLoading in ComponentState) then
begin
BuildGlyphs;
Invalidate;
end;
end;
end;
procedure TBCBoundButton.SetGlyphLayout(AValue: TGlyphLayout);
begin
if (rGlyphLayout <> AValue) then
begin
rGlyphLayout := AValue;
if not(csLoading in ComponentState) then
begin
BuildGlyphs;
Invalidate;
end;
end;
end;
procedure TBCBoundButton.SetStyle(AValue: TBCBoundButtonStyle);
begin
if (rStyle <> AValue) then
begin
rStyle:=AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCBoundButton.SetTabWidth(AValue: Integer);
begin
if (rTabWidth <> AValue) then
begin
rTabWidth:=AValue;
if not(csLoading in ComponentState) and (rStyle = bbsTab)
then Invalidate;
end;
end;
procedure TBCBoundButton.SetTextLayout(AValue: TTextLayout);
begin
if (rTextLayout <> AValue) then
begin
rTextLayout := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCBoundButton.SetGlyphCollapsed(AValue: TBitmap);
begin
rUserGlyphCollapsed.Assign(AValue);
if not(csLoading in ComponentState) then
begin
BuildGlyphs;
Invalidate;
end;
end;
procedure TBCBoundButton.SetGlyphExpanded(AValue: TBitmap);
begin
rUserGlyphExpanded.Assign(AValue);
if not(csLoading in ComponentState) then
begin
BuildGlyphs;
Invalidate;
end;
end;
procedure TBCBoundButton.LoadGlyph(GlyphDST: TBitmap; ResName: String);
Var
rGlyphO: TPortableNetworkGraphic;
begin
rGlyphO :=TPortableNetworkGraphic.Create;
rGlyphO.LoadFromLazarusResource(ResName);
GlyphDST.Assign(rGlyphO);
FreeAndNil(rGlyphO);
end;
procedure TBCBoundButton.BuildGlyphs;
begin
if (rGlyphLayout <> glNone) then
begin
if (rUserGlyphCollapsed.Empty)
then Case rGlyphKind of
gkArrows: case TBCExpandPanel(Owner).CollapseKind of
akTop: LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_BOTTOM');
akLeft: LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_RIGHT');
akRight: LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_LEFT');
akBottom: LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_TOP');
end;
gkClose: LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_CLOSE');
gkMinMax: if (TBCExpandPanel(Owner).CollapseKind in [akTop, akBottom])
then LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_MAX_H')
else LoadGlyph(rGlyphCollapsed, 'BCEXP_PANEL_MAX_V');
end
else rGlyphCollapsed.Assign(rUserGlyphCollapsed);
if (rUserGlyphExpanded.Empty)
then Case rGlyphKind of
gkArrows: case TBCExpandPanel(Owner).CollapseKind of
akTop: LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_TOP');
akLeft: LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_LEFT');
akRight: LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_RIGHT');
akBottom: LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_BOTTOM');
end;
gkClose: LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_CLOSE');
gkMinMax: if (TBCExpandPanel(Owner).CollapseKind in [akTop, akBottom])
then LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_MIN_H')
else LoadGlyph(rGlyphExpanded, 'BCEXP_PANEL_MIN_V');
end
else rGlyphExpanded.Assign(rUserGlyphExpanded);
end;
end;
procedure TBCBoundButton.Paint;
var
paintRect, fRect :TRect;
xColor,
xHColor,
xSColor :TColor;
middleX,
middleY,
txtWidth,
txtLeft,
txtTop,
glyphLeft,
glyphTop :Integer;
xCaption :String;
FButtonPosition :TAnchorKind;
FCollapsed, Rounded :Boolean;
procedure drawGlyph(var ATop, ALeft :Integer);
var
AWidth, AHeight :Integer;
begin
AWidth :=paintRect.Right-paintRect.Left-2;
AHeight :=paintRect.Bottom-paintRect.Top-2;
if FCollapsed
then rGlyph.Glyph.Assign(rGlyphCollapsed)
else rGlyph.Glyph.Assign(rGlyphExpanded);
//We must Calculate the Real Position of the Glyph
Case FButtonPosition of
akTop,
akBottom : begin
if (rGlyphLayout = glLeft)
then begin
ALeft :=2;
ATop :=middleY-(rGlyph.Glyph.Height div 2);
end
else begin
ALeft :=AWidth-rGlyph.Glyph.Width;
ATop :=middleY-(rGlyph.Glyph.Height div 2);
end;
end;
akLeft :begin
if (rGlyphLayout = glLeft)
then begin //Really on Bottom of paintRect
ALeft :=middleX-(rGlyph.Glyph.Width div 2);
ATop :=AHeight-rGlyph.Glyph.Height;
end
else begin //Really on Top of paintRect
ALeft :=middleX-(rGlyph.Glyph.Width div 2);
ATop :=2;
end;
end;
akRight :begin
if (rGlyphLayout = glLeft)
then begin //Really on Top of paintRect
ALeft :=middleX-(rGlyph.Glyph.Width div 2);
ATop :=2;
end
else begin //Really on Bottom of paintRect
ALeft :=middleX-(rGlyph.Glyph.Width div 2);
ATop :=AHeight-rGlyph.Glyph.Height;
end;
end;
end;
rGlyph.Draw(Canvas, paintRect, point(ALeft, ATop), FState, true, 0);
end;
procedure drawBtn(const ABorderStyle : TGraphicsBevelCut);
var
xTabWidth,
tY, tX: Integer;
begin
Case rStyle of
bbsButton: Frame3d_Rounded(Canvas, paintRect, 1, 5, 5, ABorderStyle, xSColor, xHColor, xColor);
bbsTab: begin
fRect :=paintRect;
Case FButtonPosition of
akTop : begin
//If rTabWidth is Negative Calculate the Tab Width
if (rTabWidth < 0)
then xTabWidth :=(fRect.Right-fRect.Left)*-rTabWidth div 100
else xTabWidth :=rTabWidth;
inc(paintRect.Left, middleX-(xTabWidth div 2));
paintRect.Right:=paintRect.Left+xTabWidth;
Frame3d_Rounded(Canvas, paintRect, 1, 5, 5, ABorderStyle, xSColor, xHColor, xColor);
tY :=fRect.Bottom-2;
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=1;
Canvas.Pen.Color :=xHColor;
if Rounded
then Canvas.MoveTo(2, tY)
else Canvas.MoveTo(0, tY);
Canvas.LineTo(paintRect.Left-3, tY);
Canvas.LineTo(paintRect.Left, tY-3);
if Rounded
then Canvas.MoveTo(fRect.Right-4, tY)
else Canvas.MoveTo(fRect.Right, tY);
Canvas.LineTo(paintRect.Right+2, tY);
Canvas.LineTo(paintRect.Right-1, tY-3);
Canvas.Pen.Color :=xColor;
Canvas.MoveTo(paintRect.Left-2, tY);
Canvas.LineTo(paintRect.Right+2, tY);
dec(tY);
Canvas.MoveTo(paintRect.Left-1, tY);
Canvas.LineTo(paintRect.Right+1, tY);
tY :=fRect.Bottom-1;
if FCollapsed then Canvas.Pen.Color :=xSColor;
if Rounded
then begin
Canvas.MoveTo(fRect.Left+2, tY);
Canvas.LineTo(fRect.Right-3, tY);
end
else begin
Canvas.MoveTo(fRect.Left, tY);
Canvas.LineTo(fRect.Right, tY);
end;
end;
akBottom : begin
if (rTabWidth < 0)
then xTabWidth :=(fRect.Right-fRect.Left)*-rTabWidth div 100
else xTabWidth :=rTabWidth;
inc(paintRect.Left, middleX-(xTabWidth div 2));
paintRect.Right:=paintRect.Left+xTabWidth;
dec(paintRect.Top);
Frame3d_Rounded(Canvas, paintRect, 1, 5, 5, ABorderStyle, xSColor, xHColor, xColor);
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=1;
Canvas.Pen.Color :=xHColor;
if Rounded
then Canvas.MoveTo(2, 1)
else Canvas.MoveTo(0, 1);
Canvas.LineTo(paintRect.Left-3, 1);
Canvas.LineTo(paintRect.Left, 4);
if Rounded
then Canvas.MoveTo(fRect.Right-4, 1)
else Canvas.MoveTo(fRect.Right, 1);
Canvas.LineTo(paintRect.Right+2, 1);
Canvas.LineTo(paintRect.Right-1, 4);
Canvas.Pen.Color :=xColor;
Canvas.MoveTo(paintRect.Left-2, 1);
Canvas.LineTo(paintRect.Right+2, 1);
Canvas.MoveTo(paintRect.Left-1, 2);
Canvas.LineTo(paintRect.Right+1, 2);
if FCollapsed then Canvas.Pen.Color :=xSColor;
if Rounded
then begin
Canvas.MoveTo(fRect.Left+2, 0);
Canvas.LineTo(fRect.Right-3, 0);
end
else begin
Canvas.MoveTo(fRect.Left, 0);
Canvas.LineTo(fRect.Right, 0);
end;
end;
akLeft : begin
if (rTabWidth < 0)
then xTabWidth :=(fRect.Bottom-fRect.Top)*-rTabWidth div 100
else xTabWidth :=rTabWidth;
inc(paintRect.Top, middleY-(xTabWidth div 2));
paintRect.Bottom:=paintRect.Top+xTabWidth;
Frame3d_Rounded(Canvas, paintRect, 1, 5, 5, ABorderStyle, xSColor, xHColor, xColor);
tX :=fRect.Right-2;
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=1;
Canvas.Pen.Color :=xHColor;
if Rounded
then Canvas.MoveTo(tX, 2)
else Canvas.MoveTo(tX, 0);
Canvas.LineTo(tX, paintRect.Top-3);
Canvas.LineTo(tX-3, paintRect.Top);
if Rounded
then Canvas.MoveTo(tX, fRect.Bottom-4)
else Canvas.MoveTo(tX, fRect.Bottom);
Canvas.LineTo(tX, paintRect.Bottom+2);
Canvas.LineTo(tX-3, paintRect.Bottom-1);
Canvas.Pen.Color :=xColor;
Canvas.MoveTo(tX, paintRect.Top-2);
Canvas.LineTo(tX, paintRect.Bottom+2);
dec(tX);
Canvas.MoveTo(tX, paintRect.Top-1);
Canvas.LineTo(tX, paintRect.Bottom+1);
tX :=fRect.Right-1;
if FCollapsed then Canvas.Pen.Color :=xSColor;
if Rounded
then begin
Canvas.MoveTo(tX, fRect.Top+2);
Canvas.LineTo(tX, fRect.Bottom-3);
end
else begin
Canvas.MoveTo(tX, fRect.Top);
Canvas.LineTo(tX, fRect.Bottom);
end;
end;
akRight : begin
if (rTabWidth < 0)
then xTabWidth :=(fRect.Bottom-fRect.Top)*-rTabWidth div 100
else xTabWidth :=rTabWidth;
inc(paintRect.Top, middleY-(xTabWidth div 2));
paintRect.Bottom:=paintRect.Top+xTabWidth;
dec(paintRect.Left);
Frame3d_Rounded(Canvas, paintRect, 1, 5, 5, ABorderStyle, xSColor, xHColor, xColor);
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=1;
Canvas.Pen.Color :=xHColor;
if Rounded
then Canvas.MoveTo(1, 2)
else Canvas.MoveTo(1, 0);
Canvas.LineTo(1, paintRect.Top-3);
Canvas.LineTo(4, paintRect.Top);
if Rounded
then Canvas.MoveTo(1, fRect.Bottom-4)
else Canvas.MoveTo(1, fRect.Bottom);
Canvas.LineTo(1, paintRect.Bottom+2);
Canvas.LineTo(4, paintRect.Bottom-1);
Canvas.Pen.Color :=xColor;
Canvas.MoveTo(1, paintRect.Top-2);
Canvas.LineTo(1, paintRect.Bottom+2);
Canvas.MoveTo(2, paintRect.Top-1);
Canvas.LineTo(2, paintRect.Bottom+1);
if FCollapsed then Canvas.Pen.Color :=xSColor;
if Rounded
then begin
Canvas.MoveTo(0, fRect.Top+2);
Canvas.LineTo(0, fRect.Bottom-3);
end
else begin
Canvas.MoveTo(0, fRect.Top);
Canvas.LineTo(0, fRect.Bottom);
end;
end;
end;
end;
end;
end;
procedure drawText;
Var
DTop, DLeft,
AWidth, AHeight,
txtH :Integer;
procedure CalcCuttedCaption(MaxWidth :Integer);
Var
txtMaxChars :Integer;
begin
txtWidth :=0;
if (MaxWidth < Canvas.TextWidth('...'))
then xCaption :=''
else begin
txtMaxChars :=Canvas.TextFitInfo(xCaption, MaxWidth);
txtWidth :=Canvas.TextWidth(xCaption);
while (txtWidth > MaxWidth) do
begin
dec(txtMaxChars, 3); //-1 Chars fit better, -3 Chars for more speed
xCaption :=Copy(xCaption, 0, txtMaxChars)+'...';
txtWidth :=Canvas.TextWidth(xCaption);
end;
end;
(* Original Code, Test Speed
if (txtW > AWidth)
then begin
txtMaxChars :=Canvas.TextFitInfo(xCaption, AWidth);
xCaption :=Copy(xCaption, 0, txtMaxChars-3)+'...';
txtW :=Canvas.TextWidth(xCaption);
if (txtW > AWidth)
then xCaption :='';
end;
*)
end;
begin
txtH :=Canvas.TextHeight(xCaption);
AWidth :=paintRect.Right-paintRect.Left-2;
AHeight :=paintRect.Bottom-paintRect.Top-2;
Case FButtonPosition of
akTop,
akBottom : begin
Canvas.Font.Orientation := 0;
txtTop :=middleY-(txtH div 2);
if (rGlyphLayout <> glNone) then
begin
if (rTextLayout = tlCenter)
then dec(AWidth, rGlyph.Glyph.Width*2+4)
else dec(AWidth, rGlyph.Glyph.Width+2)
end;
CalcCuttedCaption(AWidth);
Case rTextLayout of
tlLeft :begin
txtLeft :=paintRect.Left+4;
if (rGlyphLayout = glLeft)
then inc(txtLeft, rGlyph.Glyph.Width+2);
end;
tlRight:begin
txtLeft :=paintRect.Left+AWidth-txtWidth;
if (rGlyphLayout = glLeft)
then inc(txtLeft, rGlyph.Glyph.Width+2);
end;
tlCenter:begin
txtLeft :=middleX-(txtWidth div 2);
end;
end;
//Disabled Position
DTop :=txtTop+1;
DLeft :=txtLeft+1;
end;
akLeft : begin
//Vertically from Bottom to Top
Canvas.Font.Orientation := 900;
txtLeft:=middleX-(txtH div 2);
if (rGlyphLayout <> glNone) then
begin
if (rTextLayout = tlCenter)
then dec(AHeight, rGlyph.Glyph.Height*2+4)
else dec(AHeight, rGlyph.Glyph.Height+2)
end;
//Vertically the Max Width is Height
CalcCuttedCaption(AHeight);
Case rTextLayout of
tlLeft :begin //To Bottom of the ClientRect
txtTop :=paintRect.Top+AHeight-2;
if (rGlyphLayout = glRight)
then inc(txtTop, rGlyph.Glyph.Height+2);
end;
tlRight:begin //To Top of the ClientRect
txtTop :=paintRect.Top+txtWidth+2;
if (rGlyphLayout = glRight)
then inc(txtTop, rGlyph.Glyph.Height+2);
end;
tlCenter:begin
txtTop :=middleY+(txtWidth div 2);
end;
end;
//Disabled Position
DTop :=txtTop-1;
DLeft :=txtLeft+1;
end;
akRight : begin
//Vertically from Top to Bottom
Canvas.Font.Orientation := -900;
txtLeft:=middleX+(txtH div 2)+1; //+1 because is better centered
if (rGlyphLayout <> glNone) then
begin
if (rTextLayout = tlCenter)
then dec(AHeight, rGlyph.Glyph.Height*2+4)
else dec(AHeight, rGlyph.Glyph.Height+2)
end;
CalcCuttedCaption(AHeight);
Case rTextLayout of
tlLeft :begin //To Top of the ClientRect
txtTop :=paintRect.Top+4;
if (rGlyphLayout = glLeft)
then inc(txtTop, rGlyph.Glyph.Height+2);
end;
tlRight:begin //To Bottom of the ClientRect
txtTop :=paintRect.Top+AHeight-txtWidth;
if (rGlyphLayout = glLeft)
then inc(txtTop, rGlyph.Glyph.Height+2);
end;
tlCenter:begin
txtTop :=middleY-(txtWidth div 2);
end;
end;
//Disabled Position
DTop :=txtTop+1;
DLeft :=txtLeft-1;
end;
end;
//Re Test here because we may not have space to draw the text, so now can be empty
if (xCaption <> '') then
begin
if (FState = bsDisabled)
then begin
Canvas.Font.Color := clBtnHighlight;
Canvas.TextOut(DLeft, DTop, xCaption);
Canvas.Font.Color := clBtnShadow;
end
else Canvas.Font.Color := Font.Color;
Canvas.Brush.Style:=bsClear;
Canvas.TextOut(txtLeft, txtTop, xCaption);
end
else txtWidth:=0;
end;
procedure DrawLines;
var
d1, d2, d3, d4, dx :Integer;
isVertical :Boolean;
procedure calc_d(txtL, txtR, glyphL, glyphR :Integer);
begin
if (txtWidth > 0)
then Case rTextLayout of
tlLeft: begin
d1 :=txtR;
if (rGlyphLayout = glRight)
then d2 :=glyphL;
end;
tlCenter:begin
d2 :=txtL;
d3 :=txtR;
if (rGlyphLayout = glLeft)
then d1 :=glyphR
else if (rGlyphLayout = glRight)
then d4 :=glyphL;
end;
tlRight:begin
d2 :=txtL;
if (rGlyphLayout = glLeft)
then d1 :=glyphR;
end;
end
else if (rGlyphLayout = glLeft)
then d1 :=glyphR
else if (rGlyphLayout = glRight)
then d2 :=glyphL;
end;
procedure DrawALine(pCenterX, pCenterY :Integer);
begin
inc(d2); inc(d4); //LineTo don't paint the last Pixel
if isVertical
then begin
//Avoid go outside the Box
pCenterX :=EnsureRange(pCenterX, 0, paintRect.Right-2);
Canvas.Pen.Color := {$ifdef DEBUG_PAINT} clLime {$else} xHColor {$endif};
Canvas.MoveTo(pCenterX, d1);
Canvas.LineTo(pCenterX, d2);
if (d3 > -1) then
begin
Canvas.MoveTo(pCenterX, d3);
Canvas.LineTo(pCenterX, d4);
end;
Canvas.Pen.Color := {$ifdef DEBUG_PAINT} clGreen {$else} xSColor {$endif};
Canvas.MoveTo(pCenterX+1, d1+1);
Canvas.LineTo(pCenterX+1, d2);
if (d3 > -1) then
begin
Canvas.MoveTo(pCenterX+1, d3+1);
Canvas.LineTo(pCenterX+1, d4);
end;
end
else begin
pCenterY :=EnsureRange(pCenterY, 0, paintRect.Bottom-2);
Canvas.Pen.Color :={$ifdef DEBUG_PAINT} clLime {$else} xHColor {$endif};
Canvas.MoveTo(d1, pCenterY);
Canvas.LineTo(d2, pCenterY);
if (d3 > -1) then
begin
Canvas.MoveTo(d3, pCenterY);
Canvas.LineTo(d4, pCenterY);
end;
Canvas.Pen.Color :={$ifdef DEBUG_PAINT} clGreen {$else} xSColor {$endif};
Canvas.MoveTo(d1+1, pCenterY+1);
Canvas.LineTo(d2, pCenterY+1);
if (d3 > -1) then
begin
Canvas.MoveTo(d3+1, pCenterY+1);
Canvas.LineTo(d4, pCenterY+1);
end;
end;
dec(d2); dec(d4); //return to the real Pixels
end;
begin
d3 :=-1;
isVertical :=(FButtonPosition in [akLeft, akRight]);
//Assign to (d1-d2) Line All the space
if isVertical
then begin
d1 :=paintRect.Top;
d2 :=paintRect.Bottom-1;
end
else begin
d1 :=paintRect.Left;
d2 :=paintRect.Right-1;
end;
//Calculate the (d1-d2) (d3-d4) Lines between the Glyph and the Text elements
if (rStyle in [bbsLine, bbsLineDouble]) then
begin
d4 :=d2;
if isVertical
then begin
if (FButtonPosition = akRight)
then calc_d(txtTop-3, txtTop+txtWidth+2, glyphTop-3, glyphTop+rGlyph.Glyph.Height+2)
else begin
//Only in this case (akLeft) the point coordinate is from bottom to top
d1 :=paintRect.Bottom-1;
d2 :=paintRect.Top;
d4 :=d2;
calc_d(txtTop+2, txtTop-txtWidth-3, glyphTop+rGlyph.Glyph.Height+2, glyphTop-3);
//Exchange the values for Shadow coerence
dx :=d1; d1 :=d2; d2 :=dx;
if (d3 > -1) then begin dx :=d3; d3 :=d4; d4 :=dx; end;
end;
end
else calc_d(txtLeft-3, txtLeft+txtWidth+2, glyphLeft-3, glyphLeft+rGlyph.Glyph.Width+2);
end;
//Draw the Lines
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=1;
Case rStyle of
bbsLine: DrawALine(middleX, middleY);
bbsLineDouble: begin
DrawALine(middleX-2, middleY-2);
DrawALine(middleX+2, middleY+2);
end;
bbsLineTop: DrawALine(paintRect.Left, paintRect.Top);
bbsLineBottom: DrawALine(paintRect.Right-2, paintRect.Bottom-2);
bbsLineDoubleTop: begin
DrawALine(paintRect.Left, paintRect.Top);
DrawALine(paintRect.Left+3, paintRect.Top+3);
end;
bbsLineDoubleBottom: begin
DrawALine(paintRect.Right-5, paintRect.Bottom-5);
DrawALine(paintRect.Right-2, paintRect.Bottom-2);
end;
end;
end;
begin
paintRect :=GetClientRect;
{$ifdef DEBUG_PAINT}
Canvas.Brush.Color:=clYellow;
Canvas.Brush.Style:=bsSolid;
Canvas.FillRect(paintRect);
{$endif}
middleY :=paintRect.Top+((paintRect.Bottom-paintRect.Top) div 2);
middleX :=paintRect.Left+((paintRect.Right-paintRect.Left) div 2);
FButtonPosition :=TBCExpandPanel(Owner).FButtonPosition;
FCollapsed :=TBCExpandPanel(Owner).FCollapsed;
Rounded :=not(FCollapsed) and TBCExpandPanel(Owner).rBevelRounded;
if FCollapsed
then xColor :=Self.Color
else xColor :=rColorExpanded;
xCaption :=Caption;
Case FState of
Buttons.bsHot:begin
if (rColorHighlight = clDefault)
then xHColor :=GetHighlightColor(xColor, 120)
else xHColor :=rColorHighlight;
if (rColorShadow = clDefault)
then xSColor :=GetShadowColor(xColor, 40)
else xSColor :=rColorShadow;
xColor :=GetHighlightColor(xColor, 20);
drawBtn(bvRaised);
end;
Buttons.bsDown:begin
if (rColorHighlight = clDefault)
then xHColor :=GetHighlightColor(xColor, 60)
else xHColor :=rColorHighlight;
if (rColorShadow = clDefault)
then xSColor :=GetShadowColor(xColor, 60)
else xSColor :=rColorShadow;
xColor :=GetHighlightColor(xColor, 20);
drawBtn(bvLowered);
end;
else begin
if (FState = bsDisabled)
then xColor :=GrayScale(xColor);
if Flat
then xHColor :=xColor
else if (rColorHighlight = clDefault)
then xHColor :=GetHighlightColor(xColor, 60)
else xHColor :=rColorHighlight;
if (rColorShadow = clDefault)
then xSColor :=GetShadowColor(xColor, 60)
else xSColor :=rColorShadow;
if Flat
then drawBtn(bvSpace)
else drawBtn(bvRaised);
end;
end;
if (rGlyphLayout <> glNone)
then drawGlyph(glyphTop, glyphLeft)
else begin
glyphTop :=0;
glyphLeft:=0;
end;
if (rTextLayout <> tlNone) and (xCaption <> '')
then drawText
else txtWidth:=0;
if (rStyle in [bbsLine..bbsLineDoubleBottom])
then DrawLines;
end;
procedure TBCBoundButton.Loaded;
begin
inherited Loaded;
if not(csDesigning in ComponentState) then
begin
//IF Used Outside TBCExpandPanel
if not(Owner is TBCExpandPanel)
then BuildGlyphs;
end;
end;
constructor TBCBoundButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Color :=clSkyBlue;
rColorExpanded := RGBToColor(23, 136, 248);
rColorHighlight :=clDefault;
rColorShadow :=clDefault;
rGlyphLayout :=glNone;
rGlyphKind :=gkArrows;
rTextLayout :=tlLeft;
Flat :=False;
rStyle :=bbsButton;
rTabWidth :=-50;
//Why FGlyph is Private in ancestor?????
rGlyph := TButtonGlyph.Create;
rGlyph.IsDesigning := csDesigning in ComponentState;
rGlyph.ShowMode := gsmAlways;
rGlyphExpanded :=TBitmap.Create;
rGlyphExpanded.Transparent := True;
rGlyphCollapsed :=TBitmap.Create;
rGlyphCollapsed.Transparent := True;
rUserGlyphExpanded :=TBitmap.Create;
rUserGlyphExpanded.Transparent := True;
rUserGlyphCollapsed :=TBitmap.Create;
rUserGlyphCollapsed.Transparent := True;
SetSubComponent((Owner is TBCExpandPanel));
// ControlStyle := ControlStyle + [csNoFocus, csNoDesignSelectable];
end;
destructor TBCBoundButton.Destroy;
begin
FreeAndNil(rGlyphExpanded);
FreeAndNil(rGlyphCollapsed);
FreeAndNil(rUserGlyphExpanded);
FreeAndNil(rUserGlyphCollapsed);
FreeAndNil(rGlyph);
inherited Destroy;
end;
{TBCExpandPanels}
constructor TBCExpandPanels.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
PanelArray := TList.Create;
FCollapseKind := akTop;
FButtonPosition := akTop;
FButtonGlyphKind :=gkArrows;
FButtonGlyphLayout :=glNone;
FButtonStyle :=bbsButton;
FButtonTabWidth :=-50;
FButtonTextLayout :=tlLeft;
FArrangeKind := akTop;
FUseFixedSize := False;
FUseClientSize := False;
FFixedSize := 400;
FAutoCollapseIfTooHigh := False;
FAbove := 10;
FOrthogonalAbove := 10;
FOrthogonalSize := 200;
end;
destructor TBCExpandPanels.Destroy;
var
i: integer;
begin
for I := PanelArray.Count - 1 downto 0 do
PanelArray.Delete(i);
PanelArray.Free;
PanelArray := nil;
inherited Destroy;
end;
procedure TBCExpandPanels.AddPanel(rollout: TBCExpandPanel);
begin
InsertPanel(PanelArray.Count, rollout);
end;
procedure TBCExpandPanels.InsertPanel(idx: integer; rollout: TBCExpandPanel);
begin
if Count <= 0 then
begin
FAbove := RelevantAbove(rollout);
FOrthogonalAbove := RelevantOrthogonalAbove(rollout);
FOrthogonalSize := RelevantOrthogonalSize(rollout);
end
else
begin
WriteRelevantAbove(rollout, FAbove);
WriteRelevantOrthogonalAbove(rollout, FOrthogonalAbove);
WriteRelevantOrthogonalSize(rollout, FOrthogonalSize);
end;
with rollout do
begin
Tag := Idx;
FButton.Tag := Idx;
FButton.OnMouseMove := @RollOut1MouseMove;
InternalOnAnimate := @RollOutOnAnimate;
end;
PanelArray.Insert(idx, rollout);
if FBehaviour <> EPMultipanel then
HotTrackSetActivePanel(0); //damit das erste ausgeklappt ist
ArrangePanels;
MakeCorrectButtonClickPointers;
end;
function TBCExpandPanels.DeltePanel(aname: string): boolean;
var
i: integer;
begin
Result := False;
for i := 0 to PanelArray.Count - 1 do
if TBCExpandPanel(PanelArray[i]).Name = aname then
begin
PanelArray.Delete(i);
Result := True;
break;
end;
ArrangePanels;
end;
function TBCExpandPanels.DeltePanel(idx: integer): boolean;
begin
Result := False;
if (idx >= 0) and (idx <= PanelArray.Count - 1) then
begin
PanelArray.Delete(idx);
Result := True;
end;
ArrangePanels;
end;
procedure TBCExpandPanels.DelteLastPanel;
begin
if (PanelArray.Count >= 1) then
PanelArray.Delete(PanelArray.Count - 1);
ArrangePanels;
end;
procedure TBCExpandPanels.DelLastPanel;
begin
PanelArray.Delete(PanelArray.Count - 1);
end;
function TBCExpandPanels.RelevantAbove(comp: TControl): integer;
begin
case FArrangeKind of
akLeft: Result := comp.Left;
akTop: Result := comp.Top;
end;
end;
function TBCExpandPanels.RelevantOrthogonalAbove(comp: TControl): integer;
begin
case FArrangeKind of
akTop: Result := comp.Left;
akLeft: Result := comp.Top;
end;
end;
function TBCExpandPanels.RelevantSize(comp: TControl): integer;
begin
case FArrangeKind of
akLeft: Result := comp.Width;
akTop: Result := comp.Height;
end;
end;
function TBCExpandPanels.RelevantOrthogonalSize(comp: TControl): integer;
begin
case FArrangeKind of
akLeft: Result := comp.Height;
akTop: Result := comp.Width;
end;
end;
procedure TBCExpandPanels.setButtonGlyphKind(AValue: TGlyphKind);
var
i: Integer;
begin
if (FButtonGlyphKind <> AValue) then
begin
FButtonGlyphKind:=AValue;
for i := 0 to PanelArray.Count - 1 do
Panel(i).Button.GlyphKind := AValue;
end;
end;
procedure TBCExpandPanels.setButtonGlyphLayout(AValue: TGlyphLayout);
var
i: Integer;
begin
if (FButtonGlyphLayout <> AValue) then
begin
FButtonGlyphLayout:=AValue;
for i := 0 to PanelArray.Count - 1 do
Panel(i).Button.GlyphLayout := AValue;
end;
end;
procedure TBCExpandPanels.setButtonStyle(AValue: TBCBoundButtonStyle);
var
i: Integer;
begin
if (FButtonStyle <> AValue) then
begin
FButtonStyle:=AValue;
for i := 0 to PanelArray.Count - 1 do
Panel(i).Button.Style := AValue;
end;
end;
procedure TBCExpandPanels.SetButtonTabWidth(AValue: Integer);
var
i: Integer;
begin
if (FButtonTabWidth <> AValue) then
begin
FButtonTabWidth:=AValue;
for i := 0 to PanelArray.Count - 1 do
Panel(i).Button.TabWidth := AValue;
end;
end;
procedure TBCExpandPanels.setButtonTextLayout(AValue: TTextLayout);
var
i: Integer;
begin
if (FButtonTextLayout <> AValue) then
begin
FButtonTextLayout:=AValue;
for i := 0 to PanelArray.Count - 1 do
Panel(i).Button.TextLayout := AValue;
end;
end;
procedure TBCExpandPanels.WriteRelevantAbove(comp: TBCExpandPanel; above: integer);
begin
case FArrangeKind of
akLeft: comp.Left := above;
akTop: comp.Top := above;
end;
end;
procedure TBCExpandPanels.WriteRelevantSize(comp: TBCExpandPanel; size: integer);
begin
case FArrangeKind of
akLeft: comp.Width := size;
akTop: comp.Height := size;
end;
end;
procedure TBCExpandPanels.WriteRelevantOrthogonalSize(comp: TBCExpandPanel; size: integer);
begin
case FArrangeKind of
akLeft: comp.Height := size;
akTop: comp.Width := size;
end;
end;
procedure TBCExpandPanels.WriteRelevantOrthogonalAbove(comp: TBCExpandPanel; size: integer);
begin
case FArrangeKind of
akLeft: comp.Top := size;
akTop: comp.Left := size;
end;
end;
procedure TBCExpandPanels.setArrangeKind(Value: TAnchorKind);
begin
case Value of //that is mean, but I haven't implemented the bottom and right yet....
akRight: Value := akLeft;
akBottom: Value := akTop;
end;
if FArrangeKind = Value then
exit;
FArrangeKind := Value;
ArrangePanels;
end;
procedure TBCExpandPanels.setButtonPosition(Value: TAnchorKind);
var
i: integer;
begin
if FButtonPosition = Value then
exit;
FButtonPosition := Value;
for i := 0 to PanelArray.Count - 1 do
Panel(i).ButtonPosition := Value;
end;
procedure TBCExpandPanels.setCollapseKind(Value: TAnchorKind);
var
i: integer;
begin
if FCollapseKind = Value then
exit;
FCollapseKind := Value;
for i := 0 to PanelArray.Count - 1 do
Panel(i).CollapseKind := Value;
end;
procedure TBCExpandPanels.setUseClientSize(Value: boolean);
begin
FUseClientSize := Value;
ArrangePanels;
end;
procedure TBCExpandPanels.setUseFixedSize(Value: boolean);
begin
if FUseFixedSize = Value then
exit;
FUseFixedSize := Value;
ArrangePanels;
end;
procedure TBCExpandPanels.setAutoCollapseIfTooHigh(Value: boolean);
begin
if FAutoCollapseIfTooHigh = Value then
exit;
FAutoCollapseIfTooHigh := Value;
if FAutoCollapseIfTooHigh then
CollapseIfTooHigh;
end;
procedure TBCExpandPanels.setFixedSize(Value: integer);
var
r: real;
begin
if FFixedSize = Value then
exit;
r := Value;
korrigiere(r, 20, 10000);
FFixedSize := round(r);
ArrangePanels;
end;
procedure TBCExpandPanels.setOrthogonalAbove(Value: integer);
begin
if FOrthogonalAbove = Value then
exit;
FOrthogonalAbove := Value;
ArrangePanels;
end;
procedure TBCExpandPanels.setAbove(Value: integer);
begin
if FAbove = Value then
exit;
FAbove := Value;
ArrangePanels;
end;
procedure TBCExpandPanels.setOrthogonalSize(Value: integer);
var
i: integer;
begin
FOrthogonalSize := Value;
for I := 0 to PanelArray.Count - 1 do
WriteRelevantOrthogonalSize(TBCExpandPanel(PanelArray[i]), FOrthogonalSize);
end;
procedure TBCExpandPanels.setBehaviour(Value: TBCExpandPanelsBehaviour);
var
i: integer;
isAlreadyOneExpand: boolean;
begin
isAlreadyOneExpand := False;
FBehaviour := Value;
MakeCorrectButtonClickPointers;
// look if more then one is open
for I := 0 to PanelArray.Count - 1 do
with TBCExpandPanel(PanelArray[i]) do
if (Behaviour <> EPMultipanel) and not Collapsed then //leave only the first open, if it is not MultiPanel
if not isAlreadyOneExpand then
isAlreadyOneExpand := True
else
Collapsed := True;
end;
procedure TBCExpandPanels.MakeCorrectButtonClickPointers;
var
i: integer;
begin
// set correct pointers
for I := 0 to PanelArray.Count - 1 do
with TBCExpandPanel(PanelArray[i]) do
if FBehaviour <> EPMultipanel then
EPManagesCollapsing := @RollOutClick
else
EPManagesCollapsing := nil;
end;
procedure TBCExpandPanels.CollapseIfTooHigh;
var
i, h, max: integer;
tempanimated: boolean;
begin
if Count <= 1 then
exit;
h := RelevantAbove(Panel(0));
max := RelevantSize(Panel(0).Parent);
for i := 0 to Count - 1 do
if h + RelevantSize(Panel(i)) > max then
with Panel(i) do
begin
tempanimated := Animated;
Animated := False;
Collapsed := True;
Animated := tempanimated;
h := h + TBCExpandPanel(Panel(i)).ButtonSize;
end
else
h := h + RelevantSize(Panel(i));
end;
procedure TBCExpandPanels.RollOutOnAnimate(Sender: TObject; deltaLeft, deltaTop, deltaWidth, deltaHeight: integer);
var
idx, i, size: integer;
begin
idx := PanelArray.IndexOf(Sender);
for i := idx + 1 to PanelArray.Count - 1 do
begin
size := RelevantAbove(TBCExpandPanel(PanelArray[i]));
case FArrangeKind of
akTop: size := size + deltaTop + deltaHeight;
akLeft: size := size + deltaLeft + deltaWidth;
end;
WriteRelevantAbove(TBCExpandPanel(PanelArray[i]), size);
end;
end;
//procedure TBCExpandPanels.SetCorrectSize;
//const plus=1; //extra Anstand
//var
// i, exSize,
// countexpanded,
// SumSize, closedSize:Integer;
//begin
// if PanelArray.Count<=0 then
// exit;
// SumSize:=FFixedSize;
// if FUseClientSize then
// SumSize:=TBCExpandPanel(PanelArray[0]).Parent.Height;
// countexpanded:=0;
// closedSize:=0;
// for I := 0 to PanelArray.count-1 do
// with TBCExpandPanel(PanelArray[i]) do
// begin
// if not Collapsed and not Animating //error producer!!! animating does not neccessairily mean that it is expanding
// or Collapsed and Animating then
// inc(countexpanded)
// else
// closedSize:=closedSize+Height;
// end;
// exSize:=SumSize- FTop- closedSize;
// case Behaviour of
// EPMultipanel:
// if countexpanded>0 then
// exSize:=trunc(exSize/countexpanded)
// else
// exSize:=400;
// end;
// for I := 0 to PanelArray.count-1 do
// with TBCExpandPanel(PanelArray[i]) do
// begin
// if not FUseFixedSize and not FUseClientSize then
// ExpandedSize:=200
// else
// ExpandedSize:=exSize;
// end;
//end;
{==============================================================================
Procedure: ArrangePanels
Belongs to: TBCExpandPanels
Result: None
Parameters:
Description:
==============================================================================}
procedure TBCExpandPanels.ArrangePanels;
const
plus = 1; //extra Anstand
var
i, t: integer;
begin
if Count <= 0 then
exit;
//left setzen!!!
// SetCorrectSize;
t := FAbove + plus;
for I := 0 to PanelArray.Count - 1 do
begin
if not TBCExpandPanel(PanelArray[i]).Visible then
continue;
WriteRelevantAbove(TBCExpandPanel(PanelArray[i]), t);
WriteRelevantOrthogonalAbove(TBCExpandPanel(PanelArray[i]), OrthogonalAbove);
t := t + plus + self.RelevantSize(TBCExpandPanel(PanelArray[i]));
end;
if FAutoCollapseIfTooHigh then
CollapseIfTooHigh;
if Assigned(FOnArrangePanels) then
FOnArrangePanels(Self);
end;
function TBCExpandPanels.Count: integer;
begin
Result := PanelArray.Count;
end;
function TBCExpandPanels.Panel(idx: integer): TBCExpandPanel;
begin
if idx < Count then
Result := TBCExpandPanel(PanelArray.Items[idx])
else
Result := nil;
end;
{==============================================================================
Procedure: RollOutClick
Belongs to: TBCExpandPanels
Result: None
Parameters:
Sender : TObject =
Description:
==============================================================================}
procedure TBCExpandPanels.RollOutClick(Sender: TObject);
begin
if (Behaviour <> EPMultipanel) then
HotTrackSetActivePanel(TBCBoundButton(Sender).Tag);
end;
procedure TBCExpandPanels.HotTrackSetActivePanel(Value: integer);
var
i: integer;
begin
for I := PanelArray.Count - 1 downto 0 do
TBCExpandPanel(PanelArray[i]).Collapsed := Value <> i;
end;
procedure TBCExpandPanels.RollOut1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
begin
if (Behaviour = EPHotMouse) and (TBCExpandPanel(PanelArray[TBCBoundButton(Sender).Tag]).Collapsed) then
HotTrackSetActivePanel(TBCBoundButton(Sender).Tag);
end;
function TBCExpandPanels.IdxOfPanel(aname: string): integer;
var
i: integer;
begin
Result := -1; // is not here
for i := 0 to PanelArray.Count - 1 do
if TBCExpandPanel(PanelArray[i]).Name = aname then
begin
Result := i;
break;
end;
end;
{ TBCExpandPanel }
procedure TBCExpandPanel.setCollapsed(Value: boolean);
begin
{$ifopt D+}
debugln('TBCExpandPanel.setCollapsed '+BoolToStr(Collapsed, True));
{$endif}
if FCollapsed = Value then
exit;
FCollapsed := Value;
if not(csLoading in ComponentState)
then if Value
then DoCollapse
else DoExpand;
end;
procedure TBCExpandPanel.SetRelevantSize(comp: TControl; AKind: TAnchorKind; ASize: Integer);
begin
case AKind of
akTop, akBottom: comp.Height :=ASize;
akLeft, akRight: comp.Width :=ASize;
end;
end;
function TBCExpandPanel.RelevantSize(comp: TControl; akind: TAnchorKind): integer;
begin
case akind of
akTop, akBottom: Result := comp.Height;
akLeft, akRight: Result := comp.Width;
end;
end;
function TBCExpandPanel.RelevantOrthogonalSize(comp: TControl; akind: TAnchorKind): integer;
begin
case akind of
akTop, akBottom: Result := comp.Width;
akLeft, akRight: Result := comp.Height;
end;
end;
function TBCExpandPanel.DeltaCoordinates(deltaMove, deltaSize: integer): TRect;
begin
Result := Rect(0, 0, 0, 0);
case FCollapseKind of
akTop: Result := Rect(0, 0, 0, deltaSize);
akLeft: Result := Rect(0, 0, deltaSize, 0);
akBottom: Result := Rect(0, deltaMove, 0, deltaSize);
akRight: Result := Rect(deltaMove, 0, deltaSize, 0);
end;
end;
procedure TBCExpandPanel.TimerAnimateSize(Sender: TObject);
var
step: real;
originalsize, size: integer;
deltaMove, deltaSize: integer;
delta: TRect;
vorzeichen: integer;
begin
deltaMove := 0;
deltaSize := 0;
StopCircleActions := False;
FAnimating := True;
step := FAnimationSpeed;
Size := RelevantSize(Self, FCollapseKind);
vorzeichen := Sign(TargetAnimationSize - RelevantSize(self, FCollapseKind)); // muss ich delta addieren oder muss ich delta abziehen
originalsize := ExpandedSize;
//One huge step if not animated
if not FAnimated or not (ComponentState * [csLoading, csDesigning] = []) then
step := abs(Size - TargetAnimationSize);
//small steps if animated
if FAnimated and (ComponentState * [csLoading, csDesigning] = []) then
begin
step := step * originalsize / 200;
if step < 3 then
step := 3;
end;
//now actually do something
if Abs(Size - TargetAnimationSize) > 0 then
begin
if Abs(Size - TargetAnimationSize) < abs(step) then // if there is just a little bit left to go, set delta so it can go directly to the end size
deltaSize := TargetAnimationSize - Size
else
deltaSize := vorzeichen * round(step);
if (CollapseKind = akBottom) or (CollapseKind = akRight) then
deltaMove := -deltaSize;
delta := DeltaCoordinates(deltaMove, deltaSize);
SetBounds(Left + delta.Left, Top + delta.Top, Width + delta.Right, Height + delta.Bottom);
if assigned(FInternalOnAnimate) then
FInternalOnAnimate(self, delta.Left, delta.Top, delta.Right, delta.Bottom);
if assigned(FOnAnimate) then
FOnAnimate(self, delta.Left, delta.Top, delta.Right, delta.Bottom);
end;
if Abs(Size - TargetAnimationSize) = 0 then //it's finished ( executes it NEXT time the timer activates!)
begin
Timer.Enabled := False;
FAnimating := False;
StopCircleActions := False;
if assigned(EndProcedureOfAnimation) then
EndProcedureOfAnimation;
end;
end;
procedure TBCExpandPanel.EndTimerCollapse;
begin
if assigned(OnCollapse) then
OnCollapse(self);
UpdateAll;
end;
procedure TBCExpandPanel.EndTimerExpand;
begin
if assigned(OnExpand) then
OnExpand(self);
UpdateAll;
end;
procedure TBCExpandPanel.UpdateAll;
begin
Update;
//FButton.Update;
end;
procedure TBCExpandPanel.setExpandedSize(Value: integer);
begin
{$ifopt D+}
debugln('TBCExpandPanel.setExpandedSize');
debugln(IntToStr(Value));
{$endif}
if (FExpandedSize = Value) then
exit;
FExpandedSize := Value;
if not(csLoading in ComponentState) and not(FCollapsed)
then Animate(FExpandedSize);
end;
function TBCExpandPanel.GetEnabled: Boolean;
begin
Result :=inherited Enabled;
if (FButton.Enabled <> Result) //Paranoic Think
then FButton.Enabled :=Result;
end;
procedure TBCExpandPanel.SetBevelColorHighlight(AValue: TColor);
begin
if (rBevelColorHighlight <> AValue) then
begin
rBevelColorHighlight := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCExpandPanel.SetBevelColorShadow(AValue: TColor);
begin
if (rBevelColorShadow <> AValue) then
begin
rBevelColorShadow := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCExpandPanel.SetBevelRounded(AValue: Boolean);
begin
if (rBevelRounded <> AValue) then
begin
rBevelRounded := AValue;
if not(csLoading in ComponentState)
then Invalidate;
end;
end;
procedure TBCExpandPanel.SetEnabled(AValue: Boolean);
begin
inherited Enabled :=AValue;
FButton.Enabled :=AValue;
end;
procedure TBCExpandPanel.setButtonSize(Value: integer);
begin
if FButtonSize = Value then
exit;
FButtonSize := Value;
PositionButton;
end;
procedure TBCExpandPanel.SetBounds(ALeft, ATop, AWidth, AHeight: integer);
begin
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
if not Collapsed and not Animating and (ComponentState * [csLoading] = []) then
FExpandedSize := RelevantSize(self, FCollapseKind);
end;
procedure TBCExpandPanel.setButtonPosition(Value: TAnchorKind);
var
wasanimated, wascollpased: boolean;
begin
if FButtonPosition = Value then
exit;
wasanimated := Animated;
wascollpased := Collapsed;
Animated := False;
if Collapsed then
Collapsed := False;
FButtonPosition := Value;
PositionButton;
Collapsed := wascollpased;
Animated := wasanimated;
Invalidate;
end;
procedure TBCExpandPanel.setCollapseKind(Value: TAnchorKind);
var
wasanimated, wascollpased: boolean;
begin
if FCollapseKind = Value then
exit;
wasanimated := Animated;
wascollpased := Collapsed;
Animated := False;
if Collapsed then
Collapsed := False;
FCollapseKind := Value;
//switsch sizes
case FCollapseKind of
akLeft, akRight: FExpandedSize := Width;
akTop, akBottom: FExpandedSize := Height;
end;
if not(csLoading in ComponentState) then
begin
FButton.BuildGlyphs;
FButton.Invalidate;
end;
Collapsed := wascollpased;
Animated := wasanimated;
end;
procedure TBCExpandPanel.setAnimationSpeed(Value: real);
begin
korrigiere(Value, 3, 1000);
FAnimationSpeed := Value;
end;
procedure TBCExpandPanel.PositionButton;
function ButtonRect: TRect;
begin
case FButtonPosition of
akBottom, akTop: Result := Rect(0, 0, RelevantOrthogonalSize(self, FButtonPosition), FButtonSize);
akLeft, akRight: Result := Rect(0, 0, FButtonSize, RelevantOrthogonalSize(self, FButtonPosition));
end;
//this must come after the thing above!!!
// this moves the button to the bottom, or the right
case FButtonPosition of
akBottom: Result.Top := Result.Top + RelevantSize(self, FButtonPosition) - FButtonSize;
akRight: Result.Left := Result.Left + RelevantSize(self, FButtonPosition) - FButtonSize;
end;
end;
var
new: TRect;
begin
if StopCircleActions or not(Assigned(FButton)) or (csLoading in ComponentState)
then exit;
StopCircleActions := True;
new := ButtonRect;
FButton.SetBounds(new.Left, new.Top, new.Right, new.Bottom);
//set anchors
case FButtonPosition of
akBottom: FButton.Anchors := [akTop, akLeft, akBottom, akRight] - [akTop];
akLeft: FButton.Anchors := [akTop, akLeft, akBottom, akRight] - [akRight];
akTop: FButton.Anchors := [akTop, akLeft, akBottom, akRight] - [akBottom];
akRight: FButton.Anchors := [akTop, akLeft, akBottom, akRight] - [akLeft];
end;
Invalidate;
StopCircleActions := False;
end;
procedure TBCExpandPanel.ButtonClick(Sender: TObject);
begin
if Assigned(FEPManagesCollapsing) then
FEPManagesCollapsing(self)
else
Collapsed := not Collapsed;
if Assigned(OnButtonClick) then
OnButtonClick(self);
end;
procedure TBCExpandPanel.Animate(aTargetSize: integer);
var
storAnimated: boolean;
begin
if (FAnimating) then
begin
// FinishLastAnimationFast
storAnimated := FAnimated;
FAnimated := False;
TimerAnimateSize(self);
FAnimated := storAnimated;
end;
// Now do animation
TargetAnimationSize := aTargetSize;
if (ComponentState * [csLoading, csDesigning] = []) and FAnimated then
begin
Timer.Enabled := True;
Timer.OnTimer := @TimerAnimateSize;
//EndProcedureOfAnimation := nil; //On Collapse then EndTimerCollapse never Executed
end
else
begin
TimerAnimateSize(self);
TimerAnimateSize(self);
end;
end;
procedure TBCExpandPanel.SetTextAlignment(AValue: TAlignment);
begin
if FTextAlignment=AValue then Exit;
FTextAlignment:=AValue;
Invalidate;
end;
procedure TBCExpandPanel.DoCollapse;
var
i :Integer;
curControl: TControl;
begin
(* may work but is irrilevant because TSpeedButton is always on Bottom ????why?
i :=0;
while (i < ControlCount) do
begin
curControl :=Controls[i];
if not(curControl is TBCBoundButton) then
begin
Self.SetChildZPosition(curControl, 0);
end;
inc(i)
end;*)
if assigned(OnPreCollapse) then
OnPreCollapse(self);
//FButton.Color := FCollapsedButtonColor;
EndProcedureOfAnimation := @EndTimerCollapse;
Animate(FButtonSize);
{$ifopt D+}
debugln('TBCExpandPanel.DoCollapse');
debugln('FButtonSize ' + IntToStr(FButtonSize));
{$endif}
end;
procedure TBCExpandPanel.DoExpand;
begin
if assigned(OnPreExpand) then
OnPreExpand(self);
// FButton.ControlStyle := FButton.ControlStyle + [csNoFocus, csNoDesignSelectable];
// FButton.Parent:=self;
//FButton.Color := FExpandedButtonColor;
EndProcedureOfAnimation := @EndTimerExpand;
Animate(FExpandedSize);
{$ifopt D+}
debugln('TBCExpandPanel.DoExpand');
debugln('FExpandedSize ' + IntToStr(FExpandedSize));
{$endif}
end;
procedure TBCExpandPanel.AdjustClientRect(var ARect: TRect);
begin
inherited AdjustClientRect(ARect);
if Assigned(FButton) then
case ButtonPosition of
akTop:
ARect.Top := ARect.Top + fButton.Height;
akBottom:
ARect.Bottom := ARect.Bottom - fButton.Height;
akLeft:
ARect.Left := ARect.Left + fButton.Width;
akRight:
ARect.Right := ARect.Right - fButton.Width;
end;
end;
procedure TBCExpandPanel.Loaded;
begin
inherited Loaded;
end;
procedure TBCExpandPanel.CreateWnd;
begin
inherited CreateWnd;
FButton.BuildGlyphs; //Button Loaded is called Before Self.Loaded and cannot Build Glyphs
(* if (FCollapsed)
then SetRelevantSize(Self, FButtonPosition, FButtonSize)
else SetRelevantSize(Self, FButtonPosition, FExpandedSize); *)
PositionButton;
end;
procedure TBCExpandPanel.Paint;
var
ARect: TRect;
TS: TTextStyle;
begin
if not(FCollapsed) then
begin
ARect := GetClientRect;
Case FButtonPosition of
akTop: inc(ARect.Top, FButtonSize);
akBottom: dec(ARect.Bottom, FButtonSize);
akLeft: inc(ARect.Left, FButtonSize);
akRight: dec(ARect.Right, FButtonSize);
end;
{$ifdef DEBUG_PAINT}
Canvas.Brush.Color:=clRed;
Canvas.Brush.Style:=bsSolid;
Canvas.FillRect(ARect);
{$endif}
// if BevelOuter is set then draw a frame with BevelWidth
if (BevelOuter <> bvNone)
then if rBevelRounded
then Frame3d_Rounded(Self.Canvas, ARect, BevelWidth, 5, 5, BevelOuter,
rBevelColorShadow, rBevelColorHighlight, Color)
else Self.Canvas.Frame3d(ARect, BevelWidth, BevelOuter);
InflateRect(ARect, -BorderWidth, -BorderWidth);
// if BevelInner is set then skip the BorderWidth and draw a frame with BevelWidth
if (BevelInner <> bvNone)
then if rBevelRounded
then Frame3d_Rounded(Self.Canvas, ARect, BevelWidth, 5, 5, BevelInner,
rBevelColorShadow, rBevelColorHighlight, Color)
else Self.Canvas.Frame3d(ARect, BevelWidth, BevelInner);
if (Self.Caption <> '') then
begin
TS := Canvas.TextStyle;
TS.Alignment := BidiFlipAlignment(Self.TextAlignment, UseRightToLeftAlignment);
if (BiDiMode <> bdLeftToRight)
then TS.RightToLeft:= True;
TS.Layout:= Graphics.tlCenter;
TS.Opaque:= false;
TS.Clipping:= false;
TS.SystemFont:=Canvas.Font.IsDefault;
if not(Enabled) then
begin
Canvas.Font.Color := clBtnHighlight;
Types.OffsetRect(ARect, 1, 1);
Self.Canvas.TextRect(ARect, ARect.Left, ARect.Top, Self.Caption, TS);
Self.Canvas.Font.Color := clBtnShadow;
Types.OffsetRect(ARect, -1, -1);
end
else Self.Canvas.Font.Color := Font.Color;
Self.Canvas.TextRect(ARect,ARect.Left,ARect.Top, Self.Caption, TS);
end;
end;
end;
constructor TBCExpandPanel.Create(TheOwner: TComponent);
begin
StopCircleActions := True;
inherited;
FButtonSize := 27;
FAnimated := True;
FCollapseKind := akTop;
FVisibleTotal := True;
FCollapsed := False;
FButtonPosition := akTop;
FCollapsedButtonColor := clSkyBlue;
FExpandedButtonColor := RGBToColor(23, 136, 248);
rBevelColorHighlight:=clBtnHighlight;
rBevelColorShadow:=clBtnShadow;
rBevelRounded:=True;
FExpandedSize := 200;
Height := FExpandedSize;
Width := 200;
FAnimationSpeed := 20;
Caption := '';
Timer := TTimer.Create(self);
Timer.Enabled := False;
Timer.Name := 'Animationtimer';
Timer.Interval := 20;
FButton := TBCBoundButton.Create(self);
with FButton do
begin
Parent := self;
Name := 'Button';
Caption := 'Caption';
ControlStyle := ControlStyle + [csNoFocus, csNoDesignSelectable];
FButton.OnClick := @self.ButtonClick;
end;
StopCircleActions := False;
//may be only in CreateWnd but the button is greater by some pixels
PositionButton;
end;
destructor TBCExpandPanel.Destroy;
begin
timer.Enabled := False;
Timer.Free;
if (ComponentState * [csLoading, csDesigning] = []) then
FButton.Free; // bringt einen Fehler in der Designtime wenn ich das hier mache
// FButton.Free; // bringt einen Fehler in der Designtime wenn ich das hier mache
inherited Destroy;
end;
{$IFDEF FPC}
procedure Register;
begin
RegisterComponents('BGRA Controls', [TBCExpandPanel, TBCExpandPanels]);
end;
{$ENDIF}
initialization
{$i BCExpandPanels.lrs}
end.