diff --git a/components/exctrls/source/excheckctrls.pas b/components/exctrls/source/excheckctrls.pas index a5b07fe1b..bf18986a3 100644 --- a/components/exctrls/source/excheckctrls.pas +++ b/components/exctrls/source/excheckctrls.pas @@ -72,11 +72,12 @@ type procedure AfterSetState; virtual; procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: Integer; {%H-}WithThemeSpace: Boolean); override; + function CanExecUserChange: Boolean; virtual; + procedure Click; override; procedure CMBiDiModeChanged(var {%H-}Message: TLMessage); message CM_BIDIMODECHANGED; procedure CreateHandle; override; procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; - procedure DoClick; procedure DoEnter; override; procedure DoExit; override; procedure DrawBackground; @@ -99,6 +100,7 @@ type procedure Paint; override; procedure TextChanged; override; procedure UnlockGroup; + procedure UserChange; virtual; procedure WMSize(var Message: TLMSize); message LM_SIZE; property Alignment: TLeftRight read FAlignment write SetAlignment default taRightJustify; @@ -218,6 +220,7 @@ type TCustomRadioButtonEx = class(TCustomCheckControlEx) protected procedure AfterSetState; override; + function CanExecUserChange: Boolean; override; function GetThemedButtonDetails(AHovered, APressed, AEnabled: Boolean; AState: TCheckboxState): TThemedElementDetails; override; public @@ -738,6 +741,12 @@ begin PreferredHeight := Max(btnSize.CY, textSize.CY + 2*FFocusBorder); end; +// Will be overridden by the radio button to prevent unchecking a checked btn. +function TCustomCheckControlEx.CanExecUserChange: Boolean; +begin + Result := true; +end; + procedure TCustomCheckControlEx.CMBiDiModeChanged(var Message: TLMessage); begin Invalidate; @@ -768,19 +777,12 @@ begin end; end; -procedure TCustomCheckControlEx.DoClick; +procedure TCustomCheckControlEx.Click; begin - if FReadOnly then - exit; + if Assigned(OnClick) then + OnClick(Self); - if AllowGrayed then begin - case FState of - cbUnchecked: SetState(cbGrayed); - cbGrayed: SetState(cbChecked); - cbChecked: SetState(cbUnchecked); - end; - end else - Checked := not Checked; + UserChange; end; procedure TCustomCheckControlEx.DoEnter; @@ -1050,7 +1052,7 @@ begin if (Key in [VK_RETURN, VK_SPACE]) and not (ssCtrl in Shift) then begin FPressed := False; - DoClick; + UserChange; end; end; @@ -1090,8 +1092,9 @@ procedure TCustomCheckControlEx.MouseUp(Button: TMouseButton; begin inherited MouseUp(Button, Shift, X, Y); if Button = mbLeft then begin - if PtInRect(ClientRect, Point(X, Y)) then DoClick; + if PtInRect(ClientRect, Point(X, Y)) then Click; FPressed := False; + Invalidate; end; end; @@ -1226,6 +1229,25 @@ begin dec(FGroupLock); end; +// Executes a change triggered by user interaction (not by code) +procedure TCustomCheckControlEx.UserChange; +begin + if FReadOnly then + exit; + + if not CanExecUserChange then + exit; + + if AllowGrayed then begin + case FState of + cbUnchecked: SetState(cbGrayed); + cbGrayed: SetState(cbChecked); + cbChecked: SetState(cbUnchecked); + end; + end else + Checked := not Checked; +end; + procedure TCustomCheckControlEx.WMSize(var Message: TLMSize); begin inherited WMSize(Message); @@ -1269,6 +1291,12 @@ begin // Parent.Invalidate; end; +// Prevents the user from unchecking the btn when the btn is already checked. +function TCustomRadioButtonEx.CanExecUserChange: Boolean; +begin + Result := FState <> cbChecked; +end; + function TCustomRadioButtonEx.GetThemedButtonDetails( AHovered, APressed, AEnabled: Boolean; AState: TCheckboxState): TThemedElementDetails; var