{**************************************************** This file is part of the Eye Candy Controls (EC-C) Copyright (C) 2013 Vojtěch Čihák, Czech Republic This library is free software. See the file COPYING.LGPL.txt, included in this distribution, for details about the license. ****************************************************} unit ECTypes; {$mode objfpc}{$H+} //{$DEFINE DBGLINE} {don't remove, just comment} interface uses Classes, SysUtils, Controls, Graphics, Messages, LMessages, Math, LCLIntf, LCLType, {$IFDEF DBGLINE} LCLProc, {$ENDIF} StdCtrls, StrUtils, Themes, Types; type {$PACKENUM 2} TBasicPos = (ebpTopLeft, ebpBottomRight); TColorLayout = (eclRGBColor, eclBGRColor, eclARGBColor, eclABGRColor, eclCMYColor, eclYMCColor, eclACMYColor, eclAYMCColor, eclSystemBGR); TGlyphDesign = (egdNone, egdArrowDec, egdArrowInc, egdArrowUp, egdArrowRight, egdArrowDown, egdArrowLeft, egdArrowUR, egdArrowDR, egdArrowDL, egdArrowUL, egdArrowsUU, egdArrowsRR, egdArrowsDD, egdArrowsLL, egdArrowsUD, egdArrowsMiddle, egdArrowsLR, egdArrowsHMiddle, egdArrowsMax, egdArrowMax, egdArrowMin, egdArrowsMin, egdArrowsHMax, egdArrowHMax, egdArrowHMin, egdArrowsHMin, egdArrowsUDHor, egdArrowsURDL_S, egdArrowsURDL_M, egdArrowURDL_L, egdArrowURDL_XL, egdArrowsUL_DR, egdArrowsUR_DL, egdArrsB_Min, egdArrB_Min, egdArrsB_DD, egdArrB_Down, egdArrsB_Middle, egdArrsB_UD, egdArrB_Up, egdArrsB_UU, egdArrB_Max, egdArrsB_Max, egdArrsB_HMin, egdArrB_HMin, egdArrsB_LL, egdArrB_Left, egdArrsB_HMiddle, egdArrsB_LR, egdArrB_Right, egdArrsB_RR, egdArrB_HMax, egdArrsB_HMax, egdArrC_Min, egdArrC_DD, egdArrC_Down, egdArrC_Middle, egdArrC_UD, egdArrC_LR, egdArrC_Up, egdArrC_UU, egdArrC_Max, egdArrC_URDL, egdPlayPause, egdPlayUpDown, egdPlayStop, egdPlayEject, egdPlayEjectD, egdMathBigMinus, egdMathMinus, egdMathEqual, egdMathPlusMinus, egdMathPlus, egdMathBigPlus, egdCombo, egdList, egdFramedList, egdGrid, egdSizeArrUp, egdSizeArrRight, egdSizeArrDown, egdSizeArrLeft, egdRectBeveled, egdRectFramed, { coloured with 3D/clBtnText frame } egdWinRectClr, egdWinRoundClr, { for color dialogs } egdWindowRect, egdWindowRound); { Total: egdNone + 84 glyphs } TIncrementalMode = (eimContinuous, eimDiscrete); TItemState = (eisDisabled, eisHighlighted, eisEnabled, eisPushed, eisPushedHihlighted, eisPushedDisabled); TItemStates = set of TItemState; TObjectOrientation = (eooHorizontal, eooVertical); TObjectPos = (eopTop, eopRight, eopBottom, eopLeft); TObjectStyle = (eosButton, eosPanel); TRedrawMode = (ermHoverKnob, ermMoveKnob, ermFreeRedraw, ermRedrawBkgnd, ermRecalcRedraw); TTickDesign = (etdSimple, etdThick, etd3DLowered, etd3DRaised); TTickStyle = (etsSolid, etsDotted); TValuesVisibility = (evvNone, evvBounds, evvValues, evvAll); { Events } TMouseMethod = procedure(Button: TMouseButton; Shift: TShiftState) of object; TObjectMethod = procedure of object; TOnPrepareValue = procedure(Sender: TObject; var AValue: Double) of object; { TCanvasHelper } TCanvasHelper = class helper for TCanvas public procedure DrawButtonBackground(ARect: TRect; AEnabled: Boolean); procedure DrawButtonBackground(ARect: TRect; AItemState: TItemState); overload; procedure DrawGlyph(ARect: TRect; AGlyphDesign: TGlyphDesign); procedure DrawPanelBackground(ARect: TRect; ABevelInner, ABevelOuter: TBevelCut; ABevelWidth: Integer; AColor: TColor); procedure DrawPanelBackground(ARect: TRect; ABevelInner, ABevelOuter: TBevelCut; ABevelSpace, ABevelWidth: Integer; AColor3DDark, AColor3DLight, AColor: TColor); function GlyphExtent(AGlyphDesign: TGlyphDesign): TSize; procedure SetFontParams(AOrientation: Integer; ASize: Integer; AStyle: TFontStyles); procedure SetRealGlyphColor(AGlyphColor: TColor; AState: TItemState); overload; end; { TBitmapHelper } TBitmapHelper = class helper for TBitmap public procedure SetProperties(AWidth, AHeight: Integer); procedure TransparentClear; end; { TFontOptions } TFontOptions = class(TPersistent) private FFontColor: TColor; FFontSize: SmallInt; FFontStyles: TFontStyles; procedure SetFontColor(const AValue: TColor); procedure SetFontSize(const AValue: SmallInt); procedure SetFontStyles(const AValue: TFontStyles); protected procedure RecalcRedraw; procedure Redraw; public OnRecalcRedraw: TObjectMethod; OnRedraw: TObjectMethod; Parent: TControl; constructor Create(AParent: TControl); published property FontColor: TColor read FFontColor write SetFontColor default clDefault; property FontSize: SmallInt read FFontSize write SetFontSize; property FontStyles: TFontStyles read FFontStyles write SetFontStyles; end; { TECBaseControl } TECBaseControl = class(TCustomControl) private procedure SetBevelInner(const AValue: TBevelCut); procedure SetBevelOuter(const AValue: TBevelCut); procedure SetBevelSpace(const AValue: SmallInt); procedure SetBevelWidth(const AValue: SmallInt); procedure SetColor3DDark(const AValue: TColor); procedure SetColor3DLight(const AValue: TColor); procedure SetOrientation(const AValue: TObjectOrientation); procedure SetStyle(AValue: TObjectStyle); protected FBevelInner: TBevelCut; FBevelOuter: TBevelCut; FBevelSpace: SmallInt; FBevelWidth: SmallInt; FColor3DDark: TColor; FColor3DLight: TColor; FInvalidRect: TRect; FOrientation: TObjectOrientation; FStyle: TObjectStyle; RedrawMode: TRedrawMode; function GetBorderWidth: Integer; { Border = BevelInner + BevelOuter + BevelSpace } function HasCaption: Boolean; virtual; procedure InvalidateCustomRect(AMove: Boolean); virtual; abstract; procedure OrientationChanged({%H-}AValue: TObjectOrientation); virtual; procedure RecalcRedraw; virtual; abstract; procedure Redraw3DColorAreas; virtual; abstract; procedure SetAutoSize(Value: Boolean); override; procedure StyleChanged({%H-}AValue: TObjectStyle); virtual; procedure WMPaint(var Message: TLMPaint); message LM_PAINT; { resolves vanishing } public UpdateCount: SmallInt; constructor Create(AOwner: TComponent); override; procedure BeginUpdate; virtual; procedure EndUpdate(Recalculate: Boolean = True); virtual; procedure InvalidateNonUpdated; { Invalidates non-updated component (UpdateCount = 0) } procedure Redraw; virtual; abstract; property BevelInner: TBevelCut read FBevelInner write SetBevelInner default bvNone; property BevelOuter: TBevelCut read FBevelOuter write SetBevelOuter default bvRaised; property BevelSpace: SmallInt read FBevelSpace write SetBevelSpace default 0; property BevelWidth: SmallInt read FBevelWidth write SetBevelWidth default 1; property Color3DDark: TColor read FColor3DDark write SetColor3DDark default clDefault; property Color3DLight: TColor read FColor3DLight write SetColor3DLight default clDefault; property Orientation: TObjectOrientation read FOrientation write SetOrientation; property Style: TObjectStyle read FStyle write SetStyle; end; { TECCustomKnob } TECCustomKnob = class(TPersistent) private FBackgroundColor: TColor; FBevelWidth: SmallInt; FColor: TColor; FCursor: TCursor; FHeight: Integer; FStyle: TObjectStyle; FTickMarkCount: SmallInt; FTickMarkDesign: TTickDesign; FTickMarkSpacing: SmallInt; FTickMarkStyle: TTickStyle; FWidth: Integer; procedure SetBackgroundColor(AValue: TColor); procedure SetBevelWidth(const AValue: SmallInt); procedure SetColor(const AValue: TColor); procedure SetCursor(const AValue: TCursor); procedure SetHeight(const AValue: Integer); procedure SetStyle(const AValue: TObjectStyle); procedure SetTickMarkCount(const AValue: SmallInt); procedure SetTickMarkDesign(const AValue: TTickDesign); procedure SetTickMarkSpacing(const AValue: SmallInt); procedure SetTickMarkStyle(const AValue: TTickStyle); procedure SetWidth(const AValue: Integer); protected const cDefBevelWidth = 2; cDefKnobHeight = 32; cDefKnobWidth = 20; cDefTickDesign = etd3DLowered; cDefTickMarkCount = 5; cDefTickMarkSpacing = 2; protected Parent: TECBaseControl; procedure DrawKnobs; public UpdateCount: SmallInt; KnobDisabled: TBitmap; KnobNormal: TBitmap; KnobHighlighted: TBitmap; Left: Integer; MouseEntered: Boolean; Top: Integer; constructor Create(AParent: TECBaseControl); destructor Destroy; override; procedure BeginUpdate; procedure EndUpdate; procedure RecalcRedraw; procedure SetSize(AWidth, AHeight: Integer); property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor; public property BevelWidth: SmallInt read FBevelWidth write SetBevelWidth default cDefBevelWidth; property Color: TColor read FColor write SetColor default clDefault; property Cursor: TCursor read FCursor write SetCursor default crHandPoint; property Height: Integer read FHeight write SetHeight default cDefKnobHeight; property Style: TObjectStyle read FStyle write SetStyle default eosButton; property TickMarkCount: SmallInt read FTickMarkCount write SetTickMarkCount default cDefTickMarkCount; property TickMarkDesign: TTickDesign read FTickMarkDesign write SetTickMarkDesign default cDefTickDesign; property TickMarkSpacing: SmallInt read FTickMarkSpacing write SetTickMarkSpacing default cDefTickMarkSpacing; property TickMarkStyle: TTickStyle read FTickMarkStyle write SetTickMarkStyle default etsSolid; property Width: Integer read FWidth write SetWidth default cDefKnobWidth; end; { TBaseScrollControl } TBaseScrollControl = class(TCustomControl) private FAreaHeight: Integer; FAreaWidth: Integer; FIncrementX: SmallInt; FIncrementY: SmallInt; function GetFullAreaHeight: Integer; function GetFullAreaWidth: Integer; procedure SetAreaHeight(AValue: Integer); procedure SetAreaWidth(AValue: Integer); procedure SetClientAreaLeft(AValue: Integer); procedure SetClientAreaTop(AValue: Integer); procedure SetScrollBars(AValue: TScrollStyle); protected FClientAreaLeft: Integer; FClientAreaTop: Integer; FRequiredArea: TPoint; { area where all devices can fit } FScrollBars: TScrollStyle; FScrollInfoHor, FScrollInfoVert: TScrollInfo; procedure CreateWnd; override; procedure SetDefaultScrollParams; virtual; procedure UpdateRequiredAreaHeight; virtual; abstract; procedure UpdateRequiredAreaWidth; virtual; abstract; procedure UpdateScrollBars(AValue: TScrollStyle); procedure UpdateScrollInfoHor; procedure UpdateScrollInfoVert; procedure WMHScroll(var Msg: TWMScroll); message WM_HSCROLL; procedure WMSize(var Message: TLMSize); message LM_SIZE; procedure WMVScroll(var Msg: TWMScroll); message WM_VSCROLL; public UpdateCount: SmallInt; constructor Create(AOwner: TComponent); override; procedure BeginUpdate; procedure EndUpdate; procedure InvalidateNonUpdated; property AreaHeight: Integer read FAreaHeight write SetAreaHeight default -1; property AreaWidth: Integer read FAreaWidth write SetAreaWidth default -1; property ClientAreaLeft: Integer read FClientAreaLeft write SetClientAreaLeft; property ClientAreaTop: Integer read FClientAreaTop write SetClientAreaTop; property FullAreaHeight: Integer read GetFullAreaHeight; property FullAreaWidth: Integer read GetFullAreaWidth; property IncrementX: SmallInt read FIncrementX write FIncrementX default 1; property IncrementY: SmallInt read FIncrementY write FIncrementY default 1; property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default ssAutoBoth; end; function ARGBToColor(A, R, G, B: Byte): TColor; inline; procedure ColorToRGBA(AColor: TColor; out R, G, B, A: Integer); function ColorToStrLayouted(AColor: TColor; AColorLayout: TColorLayout): string; function GetColorResolvingDefault(ASourceColor, ADefColor: TColor): TColor; inline; function GetColorResolvingDefAndEnabled(ASourceColor, ADefColor: TColor; AEnabled: Boolean): TColor; inline; function GetMergedColor(AColor, BColor: TColor; AProportion: Single): TColor; function GetMonochromaticColor(AColor: TColor): TColor; procedure IncludeRectangle(var AResultRect: TRect; const AppendRect: TRect); function IsInRange(AValue, ALimit, BLimit: Integer): Boolean; function IsRectIntersect(ARect, BRect: TRect): Boolean; function LinearToLogarithmic(AValue, AMin, AMax, ALogarithmBase: Double): Double; function NormalizeRectangle(PointAX, PointAY, PointBX, PointBY: Integer): TRect; function TrimColorString(AString: string): string; function TryStrToColorLayouted(AString: string; ALayout: TColorLayout; out AColor: TColor): Boolean; operator = (ARect, BRect: TRect): Boolean; const pi_1800: Double = 0.00174532925199432958; { = pi/1800 } caThemedContent: array[low(TItemState)..high(TItemState)] of TThemedButton = (tbPushButtonDisabled, tbPushButtonHot, tbPushButtonNormal, tbPushButtonPressed, tbPushButtonHot, tbPushButtonDisabled); caThemedItems: array[low(TItemState)..high(TItemState)] of TThemedButton = (tbPushButtonDisabled, tbPushButtonHot, tbPushButtonNormal, tbPushButtonPressed, tbPushButtonPressed, tbPushButtonPressed); caItemState: array[False..True] of TItemState = (eisDisabled, eisEnabled); caDisabledStates = [eisDisabled, eisPushedDisabled]; caEnabledStates = [eisHighlighted, eisEnabled, eisPushed, eisPushedHihlighted]; implementation function ARGBToColor(A, R, G, B: Byte): TColor; inline; begin Result := (A shl 24) or (B shl 16) or (G shl 8) or R; end; procedure ColorToRGBA(AColor: TColor; out R, G, B, A: Integer); begin R := AColor and $000000FF; G := (AColor shr 8) and $000000FF; B := (AColor shr 16) and $000000FF; A := (AColor shr 24) and $000000FF; end; function ColorToStrLayouted(AColor: TColor; AColorLayout: TColorLayout): string; var R, G, B, A: Integer; begin ColorToRGBA(AColor, R, G, B, A); case AColorLayout of eclRGBColor: Result := inttohex(R, 2) + inttohex(G, 2) + inttohex(B, 2); eclBGRColor: Result := inttohex(B, 2) + inttohex(G, 2) + inttohex(R, 2); eclARGBColor: Result := inttohex(A, 2) + inttohex(R, 2) + inttohex(G, 2) + inttohex(B, 2); eclABGRColor: Result := inttohex(A, 2) + inttohex(B, 2) + inttohex(G, 2) + inttohex(R, 2); eclCMYColor: Result := inttohex(255 - R, 2) + inttohex(255 - G, 2) + inttohex(255 - B, 2); eclYMCColor: Result := inttohex(255 - B, 2) + inttohex(255 - G, 2) + inttohex(255 - R, 2); eclACMYColor: Result := inttohex(A, 2) + inttohex(255 - R, 2) + inttohex(255 - G, 2) + inttohex(255 - B, 2); eclAYMCColor: Result := inttohex(A, 2) + inttohex(255 - B, 2) + inttohex(255 - G, 2) + inttohex(255 - R, 2); eclSystemBGR: Result := ColorToString(AColor); end; end; function GetColorResolvingDefault(ASourceColor, ADefColor: TColor): TColor; begin Result := ASourceColor; if Result = clDefault then Result := ADefColor; end; function GetColorResolvingDefAndEnabled(ASourceColor, ADefColor: TColor; AEnabled: Boolean): TColor; begin Result := ASourceColor; if Result = clDefault then Result := ADefColor; if not AEnabled then Result := GetMonochromaticColor(Result); end; function GetMergedColor(AColor, BColor: TColor; AProportion: Single): TColor; var aR, bR, aG, bG, aB, bB: Integer; begin GetRGBIntValues(ColorToRGB(AColor), aR, aG, aB); GetRGBIntValues(ColorToRGB(BColor), bR, bG, bB); aR := bR + trunc((aR - bR)*AProportion); aG := bG + trunc((aG - bG)*AProportion); aB := bB + trunc((aB - bB)*AProportion); Result := RGBToColor(aR, aG, aB); end; function GetMonochromaticColor(AColor: TColor): TColor; var r, g, b: Integer; begin GetRGBIntValues(ColorToRGB(AColor), r, g, b); r := 341*(r + g + b) shr 10; Result := RGBToColor(r, r, r); end; procedure IncludeRectangle(var AResultRect: TRect; const AppendRect: TRect); begin AResultRect.Left := Math.min(AResultRect.Left, AppendRect.Left); AResultRect.Top := Math.min(AResultRect.Top, AppendRect.Top); AResultRect.Right := Math.max(AResultRect.Right, AppendRect.Right); AResultRect.Bottom := Math.max(AResultRect.Bottom, AppendRect.Bottom); end; function IsInRange(AValue, ALimit, BLimit: Integer): Boolean; begin Result := ((ALimit <= AValue) and (AValue <= BLimit)) or ((BLimit <= AValue) and (AValue <= ALimit)); end; function IsRectIntersect(ARect, BRect: TRect): Boolean; var aTL, aBR: TPoint; begin aTL.X := Math.max(ARect.Left, BRect.Left); aTL.Y := Math.max(ARect.Top, BRect.Top); aBR.X := Math.min(ARect.Right, BRect.Right); aBR.Y := Math.min(ARect.Bottom, BRect.Bottom); Result := (aTL.X < aBR.X) and (aTL.Y < aBR.Y); end; function LinearToLogarithmic(AValue, AMin, AMax, ALogarithmBase: Double): Double; var aProportion: Double; begin aProportion := (AValue - AMin)/(AMax - AMin); if AMin > 0 then AMin := logn(ALogarithmBase, AMin) else AMin := 0; if AMax > 0 then AMax := logn(ALogarithmBase, AMax) else AMax := 0; Result := power(ALogarithmBase, AMin + (AMax - AMin)*aProportion); end; function NormalizeRectangle(PointAX, PointAY, PointBX, PointBY: Integer): TRect; var i: Integer; begin if PointAX > PointBX then begin i := PointAX; PointAX := PointBX; PointBX := i; end; if PointAY > PointBY then begin i := PointAY; PointAY := PointBY; PointBY := i; end; Result := Rect(PointAX, PointAY, PointBX, PointBY); end; function TrimColorString(AString: string): string; var aChar: Char; i: SmallInt; begin Result := ''; for i := 1 to length(AString) do begin {$IFDEF DBGLINE} DebugLn('Character '+ AString[i]); {$ENDIF} aChar := aString[i]; if (aChar in ['0'..'9']) or (aChar in ['A'..'F']) or (aChar in ['a'..'f']) then Result:=Result + aChar; end; {$IFDEF DBGLINE} DebugLn('Result: '+ Result); {$ENDIF} end; function TryStrToColorLayouted(AString: string; ALayout: TColorLayout; out AColor: TColor): Boolean; var i, aLength: SmallInt; A, R, G, B: Byte; begin if ALayout <> eclSystemBGR then begin if ALayout in [eclARGBColor, eclABGRColor, eclACMYColor, eclAYMCColor] then aLength := 8 else aLength := 6; AString := TrimColorString(AString); {$IFDEF DBGLINE} DebugLn('AColorString ' + AString); {$ENDIF} AString:= RightStr(AString, aLength); i := length(AString); if i < aLength then for i := 0 to aLength - 1 - i do AString := '0' + AString; {$IFDEF DBGLINE} DebugLn('AColorString ' + AString); {$ENDIF} try B := Hex2Dec(RightStr(AString, 2)); if aLength = 6 then begin G := Hex2Dec(MidStr(AString, 3, 2)); R := Hex2Dec(LeftStr(AString, 2)); A := 0; end else begin G := Hex2Dec(MidStr(AString, 5, 2)); R := Hex2Dec(MidStr(AString, 3, 2)); A := Hex2Dec(LeftStr(AString, 2)); end; case ALayout of eclRGBColor, eclARGBColor: AColor := ARGBToColor(A, R, G, B); eclBGRColor, eclABGRColor: AColor := ARGBToColor(A, B, G, R); eclCMYColor, eclACMYColor: AColor := ARGBToColor(A, 255 - R, 255 - G, 255 - B); eclYMCColor, eclAYMCColor: AColor := ARGBToColor(A, 255 - B, 255 - G, 255 - R); end; Result := True; except Result := False; end; end else begin try AString := trim(AString); if not IdentToColor(AString, AColor) then begin AString := TrimColorString(AString); if AString <> '' then AColor := TColor(Hex2Dec(AString)) else AColor := clBlack; end; Result := True; except Result := False; end; end; end; operator = (ARect, BRect: TRect): Boolean; begin Result := (ARect.Left = BRect.Left) and (ARect.Right = BRect.Right) and (ARect.Top = BRect.Top) and (ARect.Bottom = BRect.Bottom); end; { TCanvasHelper } procedure TCanvasHelper.DrawButtonBackground(ARect: TRect; AEnabled: Boolean); begin if AEnabled then DrawButtonBackground(ARect, eisEnabled) else DrawButtonBackground(ARect, eisDisabled); end; procedure TCanvasHelper.DrawButtonBackground(ARect: TRect; AItemState: TItemState); begin ThemeServices.DrawElement(Handle, ThemeServices.GetElementDetails(caThemedItems[AItemState]), ARect, nil); end; {$I ecdrawglyph.inc} procedure TCanvasHelper.DrawPanelBackground(ARect: TRect; ABevelInner, ABevelOuter: TBevelCut; ABevelWidth: Integer; AColor: TColor); begin DrawPanelBackground(ARect, ABevelInner, ABevelOuter, 0, ABevelWidth, clDefault, clDefault, AColor); end; procedure TCanvasHelper.DrawPanelBackground(ARect: TRect; ABevelInner, ABevelOuter: TBevelCut; ABevelSpace, ABevelWidth: Integer; AColor3DDark, AColor3DLight, AColor: TColor); var bDefault3D: Boolean; begin { both Canvas.Frame3D methods deflate Rectangle } { bvSpace draw the frame using Canvas.Brush.Color } bDefault3D := ((AColor3DDark = clDefault) and (AColor3DLight = clDefault)); if not bDefault3D then begin AColor3DDark := GetColorResolvingDefault(AColor3DDark, clBtnShadow); AColor3DLight := GetColorResolvingDefault(AColor3DLight, clBtnHilight); end; Brush.Color := AColor; if bDefault3D then begin if ABevelOuter <> bvNone then Frame3D(ARect, ABevelWidth, ABevelOuter) end else case ABevelOuter of bvLowered: Frame3D(ARect, AColor3DDark, AColor3DLight, ABevelWidth); bvRaised: Frame3D(ARect, AColor3DLight, AColor3DDark, ABevelWidth); bvSpace: Frame3D(ARect, ABevelWidth, bvSpace); end; Frame3D(ARect, ABevelSpace, bvSpace); if bDefault3D then begin if ABevelInner <> bvNone then Frame3D(ARect, ABevelWidth, ABevelInner); end else case ABevelInner of bvLowered: Frame3D(ARect, AColor3DDark, AColor3DLight, ABevelWidth); bvRaised: Frame3D(ARect, AColor3DLight, AColor3DDark, ABevelWidth); bvSpace: Frame3D(ARect, ABevelWidth, bvSpace); end; FillRect(ARect); end; function TCanvasHelper.GlyphExtent(AGlyphDesign: TGlyphDesign): TSize; const cLargeGlyph: SmallInt = 16; cSmallGlyph: SmallInt = 8; begin case AGlyphDesign of egdNone: Result := Size(0, 0); egdArrowDec .. egdArrowsUDHor: Result := Size(cSmallGlyph, cSmallGlyph); egdArrowsURDL_S: Result := Size(10, 10); egdArrowsURDL_M: Result := Size(10, 10); egdArrowURDL_L: Result := Size(11, 11); egdArrowURDL_XL: Result := Size(12, 12); egdArrowsUL_DR .. egdArrC_Max: Result := Size(cSmallGlyph, cSmallGlyph); egdArrC_URDL: Result := Size(cLargeGlyph, cLargeGlyph); egdPlayPause .. egdFramedList: Result := Size(cSmallGlyph, cSmallGlyph); egdGrid .. egdWindowRound: Result := Size(cLargeGlyph, cLargeGlyph); end; end; procedure TCanvasHelper.SetFontParams(AOrientation: Integer; ASize: Integer; AStyle: TFontStyles); begin with Font do begin Orientation:=AOrientation; Size:=ASize; Style:=AStyle; end; end; procedure TCanvasHelper.SetRealGlyphColor(AGlyphColor: TColor; AState: TItemState); begin AGlyphColor := GetColorResolvingDefault(AGlyphColor, clBtnText); if AState in [eisHighlighted, eisPushedHihlighted] then AGlyphColor := GetMergedColor(clWhite, AGlyphColor, 0.27) else if AState in [eisDisabled, eisPushedDisabled] then AGlyphColor := GetMergedColor(Pixels[Width div 2, Height div 2], AGlyphColor, 0.67); Brush.Color := AGlyphColor; Pen.Color := AGlyphColor; end; { TBitmapHelper } procedure TBitmapHelper.SetProperties(AWidth, AHeight: Integer); begin Canvas.Brush.Style := bsSolid; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Style := psSolid; Transparent := True; TransparentMode := tmFixed; SetSize(AWidth, AHeight); end; procedure TBitmapHelper.TransparentClear; var aTransparentColor: TColor; begin aTransparentColor := TransparentColor; TransparentColor := clSilver; Canvas.Brush.Color := aTransparentColor; Canvas.FillRect(0, 0, Width, Height); TransparentColor := aTransparentColor; end; { TFontOptions } constructor TFontOptions.Create(AParent: TControl); begin Parent := AParent; FFontColor := clDefault; if assigned(AParent) then with AParent do begin FFontStyles := Font.Style; FFontSize := Font.Size; end end; procedure TFontOptions.RecalcRedraw; begin if assigned(OnRecalcRedraw) then OnRecalcRedraw; end; procedure TFontOptions.Redraw; begin if assigned(OnRedraw) then OnRedraw; end; procedure TFontOptions.SetFontColor(const AValue: TColor); begin if FFontColor = AValue then exit; FFontColor := AValue; Redraw; end; procedure TFontOptions.SetFontSize(const AValue: SmallInt); begin if FFontSize = AValue then exit; FFontSize := AValue; RecalcRedraw; end; procedure TFontOptions.SetFontStyles(const AValue: TFontStyles); begin if FFontStyles = AValue then exit; FFontStyles := AValue; RecalcRedraw; end; { TECBaseControl } constructor TECBaseControl.Create(AOwner: TComponent); begin inherited Create(AOwner); ControlStyle := ControlStyle + [csParentBackground, csReplicatable] - [csOpaque]; FBevelInner := bvNone; FBevelOuter := bvRaised; FBevelWidth := 1; Color := clDefault; FColor3DDark:=clDefault; FColor3DLight:=clDefault; end; procedure TECBaseControl.BeginUpdate; begin inc(UpdateCount); end; procedure TECBaseControl.EndUpdate(Recalculate: Boolean = True); begin dec(UpdateCount); if UpdateCount <= 0 then begin UpdateCount := 0; if Recalculate then RecalcRedraw else Redraw; end; end; function TECBaseControl.GetBorderWidth: Integer; var i: Integer; begin i := 0; if BevelOuter <> bvNone then inc(i); if BevelInner <> bvNone then inc(i); Result := BevelSpace + i*BevelWidth; end; function TECBaseControl.HasCaption: Boolean; begin Result := (Caption <> ''); end; procedure TECBaseControl.InvalidateNonUpdated; begin if UpdateCount = 0 then Invalidate; end; procedure TECBaseControl.OrientationChanged(AValue: TObjectOrientation); begin RecalcRedraw; end; procedure TECBaseControl.SetAutoSize(Value: Boolean); begin inherited SetAutoSize(Value); if Value then begin InvalidatePreferredSize; AdjustSize; end; end; procedure TECBaseControl.StyleChanged(AValue: TObjectStyle); begin Redraw; end; procedure TECBaseControl.WMPaint(var Message: TLMPaint); begin if (RedrawMode < ermFreeRedraw) and ((Message.PaintStruct^.rcPaint.Left < FInvalidRect.Left) or (Message.PaintStruct^.rcPaint.Top < FInvalidRect.Top) or (Message.PaintStruct^.rcPaint.Right > FInvalidRect.Right) or (Message.PaintStruct^.rcPaint.Bottom > FInvalidRect.Bottom)) then RedrawMode := ermFreeRedraw; inherited WMPaint(Message); end; { TECBaseControl.Setters } procedure TECBaseControl.SetBevelInner(const AValue: TBevelCut); begin if FBevelInner = AValue then exit; FBevelInner := AValue; RecalcRedraw; end; procedure TECBaseControl.SetBevelOuter(const AValue: TBevelCut); begin if FBevelOuter = AValue then exit; FBevelOuter := AValue; RecalcRedraw; end; procedure TECBaseControl.SetBevelSpace(const AValue: SmallInt); begin if FBevelSpace = AValue then exit; FBevelSpace := AValue; RecalcRedraw; end; procedure TECBaseControl.SetBevelWidth(const AValue: SmallInt); begin if FBevelWidth = AValue then exit; FBevelWidth := AValue; RecalcRedraw; end; procedure TECBaseControl.SetColor3DDark(const AValue: TColor); begin if FColor3DDark = AValue then exit; FColor3DDark := AValue; Redraw3DColorAreas; end; procedure TECBaseControl.SetColor3DLight(const AValue: TColor); begin if FColor3DLight = AValue then exit; FColor3DLight := AValue; Redraw3DColorAreas; end; procedure TECBaseControl.SetOrientation(const AValue: TObjectOrientation); begin if FOrientation = AValue then exit; FOrientation := AValue; OrientationChanged(AValue); end; procedure TECBaseControl.SetStyle(AValue: TObjectStyle); begin if FStyle = AValue then exit; FStyle := AValue; StyleChanged(AValue); end; { TECCustomKnob } constructor TECCustomKnob.Create(AParent: TECBaseControl); begin inherited Create; Parent := AParent; { don't change order ! } FBevelWidth := cDefBevelWidth; FColor := clDefault; FCursor := crHandPoint; FHeight := cDefKnobHeight; FTickMarkCount := cDefTickMarkCount; FTickMarkDesign := cDefTickDesign; FTickMarkSpacing := cDefTickMarkSpacing; FWidth := cDefKnobWidth; KnobDisabled := TBitmap.Create; KnobDisabled.SetProperties(self.FWidth, self.FHeight); KnobNormal := TBitmap.Create; KnobNormal.SetProperties(self.FWidth, self.FHeight); KnobHighlighted := TBitmap.Create; KnobHighlighted.SetProperties(self.FWidth, self.FHeight); end; destructor TECCustomKnob.Destroy; begin FreeAndNil(KnobDisabled); FreeAndNil(KnobNormal); FreeAndNil(KnobHighlighted); inherited Destroy; end; procedure TECCustomKnob.BeginUpdate; begin inc(UpdateCount); end; procedure TECCustomKnob.DrawKnobs; var aColor: TColor; aHeight, aWidth, h, i, j, k: Integer; aLight, aVert: Boolean; aRect: TRect; procedure DrawPanelBevel(AKnob: TBitmap); var aColor3DDark, aColor3DLight: TColor; begin with AKnob.Canvas do begin aColor3DDark := Parent.FColor3DDark; aColor3DLight := Parent.FColor3DLight; if (aColor3DDark = clDefault) and (aColor3DLight = clDefault) then begin Frame3D(aRect, BevelWidth, bvRaised); end else begin aColor3DDark := GetColorResolvingDefault(aColor3DDark, clBtnShadow); aColor3DLight := GetColorResolvingDefault(aColor3DLight, clBtnHilight); Frame3D(aRect, aColor3DLight, aColor3DDark, BevelWidth); end; end; end; function ModifyBrightness(AColor: TColor; ABrighness: Single): TColor; var r, g, b: Integer; begin GetRGBIntValues(AColor, r, g, b); b := round(b*ABrighness); if b > 255 then b := 255; g := round(g*ABrighness); if g > 255 then g := 255; r:=round(r*ABrighness); if r > 255 then r := 255; Result:=RGBToColor(r, g, b); end; procedure DrawTick(AKnob: TBitmap; AEnabled: Boolean = True); var { aLight scheme, aEnabled, Normal Line=0, or Lowered=1, Raised=2 } aBrightness: array [False..True, False..True, 0..2] of Single = (((2, 0.8, 1.2), (3, 0.67, 1.4)), ((0.67, 0.8, 1.2), (0.4, 0.67, 1.4))); { Dark Disabled, Dark Enabled, Light Disabled, Light Enabled } procedure DrawLine(x1, y1, x2: Integer; ABrightness: Single); var l: Integer; begin with AKnob.Canvas do begin if TickMarkStyle = etsSolid then begin { etsSolid } if aVert then { Horizontal tick (vertical slider) } for l := x1 to x2 - 1 do Pixels[l, y1] := ModifyBrightness(Pixels[l, y1], ABrightness) else { Vertical tick (horizontal slider) } for l := x1 to x2 - 1 do Pixels[y1, l] := ModifyBrightness(Pixels[y1, l], ABrightness); end else begin { etsDotted } if aVert then { Horizontal tick (vertical slider) } for l := x1 to x2 - 1 do begin if ((l - x1) mod 3) = 0 then Pixels[l, y1] := ModifyBrightness(Pixels[l, y1], ABrightness); end else { Vertical tick (horizontal slider) } for l := x1 to x2 - 1 do if ((l - x1) mod 3) = 0 then Pixels[y1, l] := ModifyBrightness(Pixels[y1, l], ABrightness); end; end; end; begin with AKnob.Canvas do begin case FTickMarkDesign of etdSimple: DrawLine(i, h, j, aBrightness[aLight, AEnabled, 0]); etdThick: begin if TickMarkStyle = etsSolid then begin DrawLine(i, h-1, j, aBrightness[aLight, AEnabled, 0]); DrawLine(i, h, j, aBrightness[aLight, AEnabled, 0]); end else begin DrawLine(i, h, j, aBrightness[aLight, AEnabled, 1]); DrawLine(i + 1, h, j + 1, aBrightness[aLight, AEnabled, 1]); DrawLine(i, h + 1, j, aBrightness[aLight, AEnabled, 1]); end; end; etd3DLowered: begin if TickMarkStyle = etsSolid then begin DrawLine(i, h, j, aBrightness[aLight, AEnabled, 1]); DrawLine(i, h + 1, j, aBrightness[aLight, AEnabled, 2]); end else begin DrawLine(i, h, j, aBrightness[aLight, AEnabled, 1]); DrawLine(i + 1, h + 1, j + 1, aBrightness[aLight, AEnabled, 2]); end; end; etd3DRaised: begin if TickMarkStyle = etsSolid then begin DrawLine(i, h, j, aBrightness[aLight, AEnabled, 1]); DrawLine(i, h - 1, j, aBrightness[aLight, AEnabled, 2]); end else begin DrawLine(i, h, j, aBrightness[aLight, AEnabled, 1]); DrawLine(i - 1, h - 1, j - 1, aBrightness[aLight, AEnabled, 2]); end; end; end; end; end; begin {$IFDEF DBGLINE} DebugLn('DrawKnobs'); {$ENDIF} if (UpdateCount = 0) and assigned(Parent) and assigned(Parent.Parent) then begin KnobHighlighted.BeginUpdate(True); KnobNormal.BeginUpdate(True); aRect := Rect(0, 0, Width, Height); case FStyle of eosButton: begin KnobDisabled.TransparentClear; KnobDisabled.Canvas.DrawButtonBackground(aRect, eisDisabled); KnobNormal.TransparentClear; KnobNormal.Canvas.DrawButtonBackground(aRect, eisEnabled); KnobHighlighted.TransparentClear; KnobHighlighted.Canvas.DrawButtonBackground(aRect, eisHighlighted); end; eosPanel: begin DrawPanelBevel(KnobDisabled); aRect := Rect(0, 0, Width, Height); DrawPanelBevel(KnobNormal); aRect := Rect(0, 0, Width, Height); DrawPanelBevel(KnobHighlighted); i := BevelWidth; aRect := Rect(i, i, Width - i, Height - i); KnobNormal.Canvas.Brush.Color := GetColorResolvingDefault(Color, BackgroundColor); KnobNormal.Canvas.FillRect(aRect); KnobDisabled.Canvas.Brush.Color := ModifyBrightness(ColorToRGB(KnobNormal.Canvas.Brush.Color), 0.97); KnobDisabled.Canvas.FillRect(aRect); KnobHighlighted.Canvas.Brush.Color := ModifyBrightness(ColorToRGB(KnobNormal.Canvas.Brush.Color), 1.07); KnobHighlighted.Canvas.FillRect(aRect); end; end; aVert := (Parent.FOrientation = eooVertical); if aVert then { Parent is Vertical } begin aHeight := FHeight; aWidth := FWidth; end else begin aWidth := FHeight; aHeight := FWidth; end; if (TickMarkCount > 0) and (aWidth >= 10) then begin aColor := ColorToRGB(clBtnText); { detect Light or Dark scheme } aLight := ((aColor and $FF) + ((aColor shr 8) and $FF) + ((aColor shr 16) and $FF)) < 384; i := BevelWidth + TickMarkSpacing; j := aWidth - i; if TickMarkStyle = etsDotted then begin k := (aWidth - 2*i) mod 3; if k < 2 then i := i + 1; if k = 0 then j := j + 1; end; if (TickMarkCount mod 2) = 0 then for k := 1 to (TickMarkCount div 2) do begin h := (aHeight div 2) - 2 + 3*k; DrawTick(KnobDisabled, False); DrawTick(KnobNormal); DrawTick(KnobHighlighted); h := (aHeight div 2) + 1 - 3*k; DrawTick(KnobDisabled, False); DrawTick(KnobNormal); DrawTick(KnobHighlighted); end else begin h := aHeight div 2; DrawTick(KnobDisabled, False); DrawTick(KnobNormal); DrawTick(KnobHighlighted); for k := 1 to (FTickMarkCount div 2) do begin h := (aHeight div 2) + 3*k; DrawTick(KnobDisabled, False); DrawTick(KnobNormal); DrawTick(KnobHighlighted); h := (aHeight div 2) - 3*k; DrawTick(KnobDisabled, False); DrawTick(KnobNormal); DrawTick(KnobHighlighted); end; end; end; KnobDisabled.Mask(KnobDisabled.TransparentColor); KnobHighlighted.Mask(KnobHighlighted.TransparentColor); KnobNormal.Mask(KnobNormal.TransparentColor); KnobHighlighted.EndUpdate(False); KnobNormal.EndUpdate(False); end; end; procedure TECCustomKnob.EndUpdate; begin dec(UpdateCount); if UpdateCount = 0 then DrawKnobs; end; procedure TECCustomKnob.RecalcRedraw; begin if assigned(Parent) then Parent.RecalcRedraw; end; procedure TECCustomKnob.SetSize(AWidth, AHeight: Integer); begin if Height <> AHeight then begin FWidth := AWidth; Height := AHeight; end else Width := AWidth; if AWidth = AHeight then DrawKnobs; end; { TECCustomKnob.Setters } procedure TECCustomKnob.SetBackgroundColor(AValue: TColor); var aTransColor: TColor; begin if FBackgroundColor = AValue then exit; FBackgroundColor := AValue; aTransColor := ColorToRGB(AValue) and $FAFCFE + $020301; KnobDisabled.TransparentColor := aTransColor; KnobHighlighted.TransparentColor := aTransColor; KnobNormal.TransparentColor := aTransColor; DrawKnobs; end; procedure TECCustomKnob.SetBevelWidth(const AValue: SmallInt); begin if FBevelWidth = AValue then exit; FBevelWidth := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetColor(const AValue: TColor); begin if FColor = AValue then exit; FColor := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetCursor(const AValue: TCursor); begin if FCursor = AValue then exit; FCursor := AValue; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetHeight(const AValue: Integer); var aWidth: Integer; begin if (AValue < 1) or (FHeight = AValue) then exit; FHeight := AValue; aWidth := FWidth; KnobDisabled.SetSize(aWidth, AValue); KnobNormal.SetSize(aWidth, AValue); KnobHighlighted.SetSize(aWidth, AValue); DrawKnobs; RecalcRedraw; end; procedure TECCustomKnob.SetStyle(const AValue: TObjectStyle); begin if FStyle = AValue then exit; FStyle := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetTickMarkCount(const AValue: SmallInt); begin if FTickMarkCount = AValue then exit; FTickMarkCount := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetTickMarkDesign(const AValue: TTickDesign); begin if FTickMarkDesign = AValue then exit; FTickMarkDesign := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetTickMarkSpacing(const AValue: SmallInt); begin if FTickMarkSpacing = AValue then exit; FTickMarkSpacing := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetTickMarkStyle(const AValue: TTickStyle); begin if FTickMarkStyle = AValue then exit; FTickMarkStyle := AValue; DrawKnobs; if assigned(Parent) then Parent.InvalidateCustomRect(False); end; procedure TECCustomKnob.SetWidth(const AValue: Integer); var aHeight: Integer; begin if (AValue < 1) or (FWidth = AValue) then exit; FWidth := AValue; aHeight := FHeight; KnobDisabled.SetSize(AValue, aHeight); KnobNormal.SetSize(AValue, aHeight); KnobHighlighted.SetSize(AValue, aHeight); DrawKnobs; RecalcRedraw; end; { TBaseScrollControl } constructor TBaseScrollControl.Create(AOwner: TComponent); begin inherited Create(AOwner); FAreaHeight:=-1; FAreaWidth:=-1; { scrollbars } SetDefaultScrollParams; end; procedure TBaseScrollControl.BeginUpdate; begin inc(UpdateCount); end; procedure TBaseScrollControl.CreateWnd; begin inherited CreateWnd; FClientAreaLeft:=ClientRect.Left; FClientAreaTop:=ClientRect.Top; FScrollInfoHor.fMask:=SIF_RANGE or SIF_PAGE or SIF_POS or SIF_DISABLENOSCROLL; FScrollInfoHor.nMax:=0; FScrollInfoHor.nMin:=0; FScrollInfoHor.nPos:=0; FScrollInfoVert:=FScrollInfoHor; FScrollInfoHor.nPage:=ClientWidth; FScrollInfoVert.nPage:=ClientHeight; end; procedure TBaseScrollControl.EndUpdate; begin dec(UpdateCount); if UpdateCount=0 then Invalidate; end; procedure TBaseScrollControl.InvalidateNonUpdated; begin if UpdateCount=0 then Invalidate; end; procedure TBaseScrollControl.SetDefaultScrollParams; begin FIncrementX:=1; FIncrementY:=1; FScrollBars:=ssAutoBoth; end; procedure TBaseScrollControl.UpdateScrollBars(AValue: TScrollStyle); begin case AValue of ssNone: begin ShowScrollBar(Handle, SB_HORZ, False); ShowScrollBar(Handle, SB_VERT, False); end; ssHorizontal: begin ShowScrollBar(Handle, SB_HORZ, True); ShowScrollBar(Handle, SB_VERT, False); end; ssVertical: begin ShowScrollBar(Handle, SB_HORZ, False); ShowScrollBar(Handle, SB_VERT, True); end; ssBoth: begin ShowScrollBar(Handle, SB_HORZ, True); ShowScrollBar(Handle, SB_VERT, True); end; ssAutoHorizontal: begin ShowScrollBar(Handle, SB_HORZ, FRequiredArea.X>ClientWidth); ShowScrollBar(Handle, SB_VERT, False); end; ssAutoVertical: begin ShowScrollBar(Handle, SB_HORZ, False); ShowScrollBar(Handle, SB_VERT, FRequiredArea.Y>ClientHeight); end; ssAutoBoth: begin ShowScrollBar(Handle, SB_HORZ, FRequiredArea.X>ClientWidth); ShowScrollBar(Handle, SB_VERT, FRequiredArea.Y>ClientHeight); end; end; UpdateScrollInfoHor; UpdateScrollInfoVert; end; procedure TBaseScrollControl.UpdateScrollInfoHor; begin FScrollInfoHor.nPos:=ClientAreaLeft; FScrollInfoHor.nMax:=FullAreaWidth; SetScrollInfo(Handle, SB_Horz, FScrollInfoHor, False); end; procedure TBaseScrollControl.UpdateScrollInfoVert; begin FScrollInfoVert.nPos:=ClientAreaTop; FScrollInfoVert.nMax:=FullAreaHeight; SetScrollInfo(Handle, SB_Vert, FScrollInfoVert, False); end; procedure TBaseScrollControl.WMHScroll(var Msg: TWMScroll); begin { modify ClientArea and its setter will adjust scrollbar } {$IFDEF DEBUG} DebugLn('TBaseECScheme.WMHScroll'); {$ENDIF} case Msg.ScrollCode of SB_LINELEFT: ClientAreaLeft:=ClientAreaLeft-IncrementX; SB_LINERIGHT: ClientAreaLeft:=ClientAreaLeft+IncrementX; SB_PAGELEFT: ClientAreaLeft:=ClientAreaLeft-ClientWidth; SB_PAGERIGHT: ClientAreaLeft:=ClientAreaLeft+ClientWidth; SB_THUMBPOSITION, SB_THUMBTRACK: ClientAreaLeft:=Msg.Pos; SB_LEFT: ClientAreaLeft:=0; SB_RIGHT: ClientAreaLeft:=FullAreaWidth; end; end; procedure TBaseScrollControl.WMSize(var Message: TLMSize); var aCW, aCH: Integer; begin {$IFDEF DEBUG} DebugLn('WMSize W: ', inttostr(Width), ', H: ', inttostr(Height)); {$ENDIF} inherited WMSize(Message); aCW:=ClientWidth; aCH:=ClientHeight; FScrollInfoHor.nPage:=aCW; FScrollInfoVert.nPage:=aCH; if (AreaWidth>-1) and (AreaWidth-1) and (AreaHeight=0 then AValue:=Math.max(AValue, ClientHeight); if (FAreaHeight=AValue) or ((AValue<0) and (FAreaHeight<0)) then exit; FAreaHeight:=AValue; UpdateRequiredAreaHeight; UpdateScrollBars(ScrollBars); Invalidate; end; procedure TBaseScrollControl.SetAreaWidth(AValue: Integer); begin if AValue>=0 then AValue:=Math.max(AValue, ClientWidth); if (FAreaWidth=AValue) or ((AValue<0) and (FAreaWidth<0)) then exit; FAreaWidth:=AValue; UpdateRequiredAreaWidth; UpdateScrollBars(ScrollBars); Invalidate; end; procedure TBaseScrollControl.SetClientAreaLeft(AValue: Integer); begin if AValue<0 then AValue:=0 else if AValue>(FullAreaWidth-ClientWidth) then AValue:=FullAreaWidth-ClientWidth; if FClientAreaLeft=AValue then exit; FClientAreaLeft:=AValue; UpdateScrollBars(ScrollBars); InvalidateNonUpdated; end; procedure TBaseScrollControl.SetClientAreaTop(AValue: Integer); begin if AValue<0 then AValue:=0 else if AValue>(FullAreaHeight-ClientHeight) then AValue:=FullAreaHeight-ClientHeight; if FClientAreaTop=AValue then exit; FClientAreaTop:=AValue; UpdateScrollBars(ScrollBars); InvalidateNonUpdated; end; procedure TBaseScrollControl.SetScrollBars(AValue: TScrollStyle); begin if FScrollBars=AValue then exit; FScrollBars:=AValue; UpdateScrollBars(AValue); end; end.