// SPDX-License-Identifier: LGPL-3.0-linking-exception { Equivalent of standard lazarus TPanel but using BGRA Controls framework for render Functionality: - Customizable background (gradient etc.) - Customizable border (frame 3D or normal border, rounding etc) - FontEx (shadow etc.) originally written in 2011 by Krzysztof Dibowski dibowski at interia.pl } {******************************* CONTRIBUTOR(S) ****************************** - Edivando S. Santos Brasil | mailedivando@gmail.com (Compatibility with delphi VCL 11/2018) ***************************** END CONTRIBUTOR(S) *****************************} unit BCPanel; {$I bgracontrols.inc} interface uses Classes, SysUtils, {$IFDEF FPC}LResources,{$ENDIF} Types, Forms, Controls, Graphics, Dialogs, BGRABitmap, BCBaseCtrls, BGRABitmapTypes, BCTypes, LCLVersion; type TOnAfterRenderBCPanel = procedure(Sender: TObject; const ABGRA: TBGRABitmap; ARect: TRect) of object; TBCPanelBorderStyle = (bpsBorder, bpsFrame3d); { TCustomBCPanel } TCustomBCPanel = class(TBCStyleCustomControl) private { Private declarations } {$IFDEF INDEBUG} FRenderCount: Integer; {$ENDIF} FBackground: TBCBackground; FBevelWidth: Integer; FBGRA: TBGRABitmapEx; FBevelInner, FBevelOuter : TBevelCut; FBorder: TBCBorder; FBorderBCStyle: TBCPanelBorderStyle; FFontEx: TBCFont; FOnAfterRenderBCPanel: TOnAfterRenderBCPanel; FRounding: TBCRounding; procedure SetBackground(AValue: TBCBackground); procedure SetBevelInner(AValue: TBevelCut); procedure SetBevelOuter(AValue: TBevelCut); procedure SetBevelWidth(AValue: Integer); procedure SetBorder(AValue: TBCBorder); procedure SetBorderBCStyle(AValue: TBCPanelBorderStyle); procedure SetFontEx(AValue: TBCFont); procedure SetRounding(AValue: TBCRounding); procedure Render; procedure OnChangeProperty({%H-}Sender: TObject; {%H-}AData: BGRAPtrInt); procedure OnChangeFont({%H-}Sender: TObject; {%H-}AData: BGRAPtrInt); protected { Protected declarations } procedure AdjustClientRect(var aRect: TRect); override; class function GetControlClassDefaultSize: TSize; override; function GetDefaultDockCaption: String; override; procedure SetEnabled(Value: boolean); override; procedure TextChanged; override; protected function GetStyleExtension: String; override; {$IFDEF INDEBUG} function GetDebugText: String; override; {$ENDIF} procedure DrawControl; override; procedure RenderControl; override; protected {$IF LCL_FULLVERSION >= 2080000} procedure SetParentBackground(const AParentBackground: Boolean); override; {$ENDIF} property Background: TBCBackground read FBackground write SetBackground; property BevelInner: TBevelCut read FBevelInner write SetBevelInner; property BevelOuter: TBevelCut read FBevelOuter write SetBevelOuter; property BevelWidth: Integer read FBevelWidth write SetBevelWidth; property Border: TBCBorder read FBorder write SetBorder; property BorderBCStyle: TBCPanelBorderStyle read FBorderBCStyle write SetBorderBCStyle default bpsFrame3d; property FontEx: TBCFont read FFontEx write SetFontEx; property Rounding: TBCRounding read FRounding write SetRounding; protected { Events } property OnAfterRenderBCPanel: TOnAfterRenderBCPanel Read FOnAfterRenderBCPanel Write FOnAfterRenderBCPanel; public { Public declarations } constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure UpdateControl; override; // Called by EndUpdate public { Streaming } {$IFDEF FPC} procedure SaveToFile(AFileName: string); procedure LoadFromFile(AFileName: string); {$ENDIF} procedure OnFindClass({%H-}Reader: TReader; const AClassName: string; var ComponentClass: TComponentClass); end; { TBCPanel } TBCPanel = class(TCustomBCPanel) published property Align; property Anchors; property AssignStyle; property AutoSize; property BorderSpacing; property ChildSizing; {$IFDEF FPC} //# property OnGetDockCaption; {$ENDIF} property Background; property BevelInner; property BevelOuter; property BevelWidth; property Border; property BorderBCStyle; property Caption; property Color; property Constraints; property DockSite; property DragCursor; property DragKind; property DragMode; property Enabled; property FontEx; property ParentBackground; property PopupMenu; property Rounding; property ShowHint; property TabOrder; property TabStop; property UseDockManager default True; property Visible; property OnClick; property OnContextPopup; property OnDockDrop; property OnDockOver; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnGetSiteInfo; property OnMouseDown; property OnMouseEnter; property OnMouseLeave; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnMouseWheelDown; property OnMouseWheelUp; property OnResize; property OnStartDock; property OnStartDrag; property OnUnDock; property OnAfterRenderBCPanel; end; {$IFDEF FPC}procedure Register;{$ENDIF} implementation uses BCTools; {$IFDEF FPC} procedure Register; begin RegisterComponents('BGRA Controls', [TBCPanel]); end; {$ENDIF} { TCustomBCPanel } procedure TCustomBCPanel.DrawControl; begin inherited DrawControl; if FBGRA.NeedRender then Render; if Assigned (FRounding) then begin if (FRounding.RoundX<>0) and (FRounding.RoundY<>0) then FBGRA.Draw(Self.Canvas, 0, 0, False) else FBGRA.Draw(Self.Canvas, 0, 0); end else FBGRA.Draw(Self.Canvas, 0, 0); {$IFNDEF FPC}//# //@ IN DELPHI RenderControl NEDD. IF NO RenderControl BE BLACK AFTER INVALIDATE. FBGRA.NeedRender := True; {$ENDIF} end; procedure TCustomBCPanel.RenderControl; begin inherited RenderControl; if FBGRA<>nil then FBGRA.NeedRender := True; end; {$IF LCL_FULLVERSION >= 2080000} procedure TCustomBCPanel.SetParentBackground(const AParentBackground: Boolean); begin if ParentBackground=AParentBackground then Exit; if AParentBackground then ControlStyle := ControlStyle - [csOpaque] else ControlStyle := ControlStyle + [csOpaque]; inherited; end; {$ENDIF} function TCustomBCPanel.GetStyleExtension: String; begin Result := 'bcpnl'; end; {$IFDEF INDEBUG} function TCustomBCPanel.GetDebugText: String; begin Result := 'R: '+IntToStr(FRenderCount); end; {$ENDIF} procedure TCustomBCPanel.Render; var r: TRect; begin if (csCreating in ControlState) or IsUpdating then Exit; FBGRA.NeedRender := False; FBGRA.SetSize(Width, Height); FBGRA.Fill(BGRAPixelTransparent); r := FBGRA.ClipRect; case FBorderBCStyle of bpsBorder: begin RenderBackgroundAndBorder(FBGRA.ClipRect, FBackground, TBGRABitmap(FBGRA), FRounding, FBorder); CalculateBorderRect(FBorder,r); end; bpsFrame3d: begin // if BevelOuter is set then draw a frame with BevelWidth if (FBevelOuter <> bvNone) and (FBevelWidth > 0) then FBGRA.CanvasBGRA.Frame3d(r, FBevelWidth, FBevelOuter, BGRA(255, 255, 255, 180), BGRA(0, 0, 0, 160)); // Note: Frame3D inflates ARect // if BevelInner is set then skip the BorderWidth and draw a frame with BevelWidth if (FBevelInner <> bvNone) and (FBevelWidth > 0) then begin InflateRect(r, -FBevelWidth, -FBevelWidth); FBGRA.CanvasBGRA.Frame3d(r, FBevelWidth, FBevelInner, BGRA(255, 255, 255, 160), BGRA(0, 0, 0, 160)); // Note: Frame3D inflates ARect end; RenderBackground(r, FBackground, TBGRABitmap(FBGRA), nil, True); end; else RenderBackground(FBGRA.ClipRect, FBackground, TBGRABitmap(FBGRA), FRounding, True); end; if Caption <> '' then RenderText(r,FFontEx,Caption,TBGRABitmap(FBGRA),Enabled); if Assigned(FOnAfterRenderBCPanel) then FOnAfterRenderBCPanel(Self, FBGRA, r); {$IFDEF INDEBUG} FRenderCount := FRenderCount + 1; {$ENDIF} end; procedure TCustomBCPanel.OnChangeProperty(Sender: TObject; AData: BGRAPtrInt); begin RenderControl; Invalidate; end; procedure TCustomBCPanel.OnChangeFont(Sender: TObject; AData: BGRAPtrInt); begin RenderControl; Invalidate; end; procedure TCustomBCPanel.SetRounding(AValue: TBCRounding); begin if FRounding = AValue then Exit; FRounding.Assign(AValue); RenderControl; Invalidate; end; procedure TCustomBCPanel.AdjustClientRect(var aRect: TRect); var BevelSize: Integer; begin inherited AdjustClientRect(aRect); BevelSize := BorderWidth; if (BevelOuter <> bvNone) then inc(BevelSize, BevelWidth); if (BevelInner <> bvNone) then inc(BevelSize, BevelWidth); InflateRect(aRect, -BevelSize, -BevelSize); end; class function TCustomBCPanel.GetControlClassDefaultSize: TSize; begin Result.CX := 170; Result.CY := 50; end; function TCustomBCPanel.GetDefaultDockCaption: String; begin Result := Caption; end; procedure TCustomBCPanel.SetBackground(AValue: TBCBackground); begin if FBackground = AValue then Exit; FBackground.Assign(AValue); RenderControl; Invalidate; end; procedure TCustomBCPanel.SetBevelInner(AValue: TBevelCut); begin if FBevelInner = AValue then Exit; FBevelInner := AValue; RenderControl; Invalidate; end; procedure TCustomBCPanel.SetBevelOuter(AValue: TBevelCut); begin if FBevelOuter = AValue then Exit; FBevelOuter := AValue; RenderControl; Invalidate; end; procedure TCustomBCPanel.SetBevelWidth(AValue: Integer); begin if FBevelWidth = AValue then Exit; FBevelWidth := AValue; RenderControl; Invalidate; end; procedure TCustomBCPanel.SetBorder(AValue: TBCBorder); begin if FBorder = AValue then Exit; FBorder.Assign(AValue); RenderControl; Invalidate; end; procedure TCustomBCPanel.SetBorderBCStyle(AValue: TBCPanelBorderStyle); begin if FBorderBCStyle = AValue then Exit; FBorderBCStyle := AValue; RenderControl; Invalidate; end; procedure TCustomBCPanel.SetFontEx(AValue: TBCFont); begin if FFontEx = AValue then Exit; FFontEx.Assign(AValue); RenderControl; Invalidate; end; procedure TCustomBCPanel.SetEnabled(Value: boolean); begin inherited SetEnabled(Value); RenderControl; Invalidate; end; procedure TCustomBCPanel.TextChanged; begin {$IFDEF FPC} inherited TextChanged; {$ENDIF} RenderControl; Invalidate; end; constructor TCustomBCPanel.Create(TheOwner: TComponent); begin inherited Create(TheOwner); {$IFDEF INDEBUG} FRenderCount := 0; {$ENDIF} {$IFDEF FPC} DisableAutoSizing; Include(FControlState, csCreating); {$ELSE} //# {$ENDIF} BeginUpdate; try ControlStyle := ControlStyle + [csAcceptsControls, csCaptureMouse, csClickEvents, csSetCaption, csDoubleClicks, csReplicatable{$IFDEF FPC}, csNoFocus, csAutoSize0x0{$ENDIF}] + [csOpaque]; // we need the default background //Self.DoubleBuffered := True; with GetControlClassDefaultSize do SetInitialBounds(0, 0, CX, CY); FBGRA := TBGRABitmapEx.Create; FBorderBCStyle := bpsFrame3d; FBackground := TBCBackground.Create(Self); FBorder := TBCBorder.Create(Self); FFontEx := TBCFont.Create(Self); FBevelOuter := bvRaised; FBevelInner := bvNone; FBevelWidth := 1; ParentColor := True; UseDockManager := True; FBackground.OnChange := OnChangeProperty; FBorder.OnChange := OnChangeProperty; FFontEx.OnChange := OnChangeFont; FBackground.Style := bbsColor; FBackground.Color := {$ifdef UseCLDefault}clDefault{$else}clBtnFace{$endif}; FBorder.Style := bboNone; FRounding := TBCRounding.Create(Self); FRounding.OnChange := OnChangeProperty; finally {$IFDEF FPC} EnableAutoSizing; {$ENDIF} EndUpdate; {$IFDEF FPC} Exclude(FControlState, csCreating); {$ELSE} //# {$ENDIF} end; end; destructor TCustomBCPanel.Destroy; begin FBackground.Free; FBorder.Free; FFontEx.Free; FBGRA.Free; FRounding.Free; inherited Destroy; end; procedure TCustomBCPanel.UpdateControl; begin Render; inherited UpdateControl; // invalidate end; {$IFDEF FPC} procedure TCustomBCPanel.SaveToFile(AFileName: string); var AStream: TMemoryStream; begin AStream := TMemoryStream.Create; try WriteComponentAsTextToStream(AStream, Self); AStream.SaveToFile(AFileName); finally AStream.Free; end; end; procedure TCustomBCPanel.LoadFromFile(AFileName: string); var AStream: TMemoryStream; begin AStream := TMemoryStream.Create; try AStream.LoadFromFile(AFileName); ReadComponentFromTextStream(AStream, TComponent(Self), OnFindClass); finally AStream.Free; end; end; {$ENDIF} procedure TCustomBCPanel.OnFindClass(Reader: TReader; const AClassName: string; var ComponentClass: TComponentClass); begin if CompareText(AClassName, 'TBCPanel') = 0 then ComponentClass := TBCPanel; end; end.