From 14ebc4505300b1fc0d99cf97673c6ca906e3c6bf Mon Sep 17 00:00:00 2001 From: michl Date: Fri, 25 Jan 2019 23:34:24 +0000 Subject: [PATCH] LCL: Win32: Fixed not every TGroupBox child follows parent's Enabled property. Issue #34763. Patch by BrunoK git-svn-id: trunk@60224 - --- lcl/interfaces/win32/win32callback.inc | 32 +--------- lcl/interfaces/win32/win32winapi.inc | 88 +++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/lcl/interfaces/win32/win32callback.inc b/lcl/interfaces/win32/win32callback.inc index 906c145236..c7662fef9e 100644 --- a/lcl/interfaces/win32/win32callback.inc +++ b/lcl/interfaces/win32/win32callback.inc @@ -287,26 +287,6 @@ begin TWin32WSWinControl.SetText(ComboBox, ComboBox.Items[Index]); end; -procedure EnableChildWindows(WinControl: TWinControl; Enable: boolean); -var - i: integer; - ChildControl: TWinControl; -begin - for i := 0 to WinControl.ControlCount-1 do - begin - if WinControl.Controls[i] is TWinControl then - begin - ChildControl := TWinControl(WinControl.Controls[i]); - - if not Enable or ChildControl.Enabled then - begin - EnableWindow(ChildControl.Handle, Enable and ChildControl.Enabled); - EnableChildWindows(ChildControl, Enable and ChildControl.Enabled); // Recursive call - end; - end; - end; -end; - // A helper class for WindowProc to make it easier to split code into smaller pieces. // The original function was about 2400 lines. @@ -1471,8 +1451,7 @@ end; procedure TWindowProcHelper.DoMsgEnable; begin - if WParam <> 0 Then - LMessage.Msg := LM_SETEDITABLE; + LMessage.Msg := LM_ENABLE; if Window = Win32WidgetSet.AppHandle then if WParam = 0 then begin @@ -1484,13 +1463,8 @@ begin Screen.EnableForms(DisabledForms); end; - // disable child windows of for example groupboxes, but not of forms - if Assigned(lWinControl) and not (lWinControl is TCustomForm) then - EnableChildWindows(lWinControl, WParam<>0); - - // ugly hack to give bitbtns a nice look - // When no theming active, the internal image needs to be - // recreated when the enabled state is changed + // When themes are not enabled, it is necessary to redraw the BitMap associated + // with the TCustomBitBtn so Windows will reflect the new UI appearence. if not ThemeServices.ThemesEnabled and (lWinControl is TCustomBitBtn) then DrawBitBtnImage(TCustomBitBtn(lWinControl), TCustomBitBtn(lWinControl).Caption); end; diff --git a/lcl/interfaces/win32/win32winapi.inc b/lcl/interfaces/win32/win32winapi.inc index b2e9740445..60a8af002e 100644 --- a/lcl/interfaces/win32/win32winapi.inc +++ b/lcl/interfaces/win32/win32winapi.inc @@ -1212,23 +1212,91 @@ begin end; {------------------------------------------------------------------------------ - Method: EnableWindow - Params: HWnd - handle to window - BEnable - whether to enable the window - Returns: If the window was previously disabled + Method: EnableWindow Response to bug #0033923 + Params: HWnd - handle to window + BEnable - whether to enable the window + Returns: If the window was previously disabled. Enables or disables mouse and keyboard input to the specified window or - control. + control and updates the graphical appearance of the control + + ------------------------------------------------------------------------------ + Note June 2018: ~bk + In normal lazarus behavior, Enable is called by + 1° - TWinControl.InitializeWnd (wcfInitializing in TWinControl.FWinControlFlags) + 2° - When property TWinControl.Enabled changes : TWinControl.CMENABLEDCHANGED + + To satisfy W10 new behaviour, if the aHWND parameter effectively changes the + Enabled state of its window, except if it is a TCusomForm descendant, + all its direct children will be asked to update their UI state if needed and + recusively propagate down the Controls children tree. ------------------------------------------------------------------------------} function TWin32WidgetSet.EnableWindow(HWnd: HWND; BEnable: Boolean): Boolean; + + procedure EnableChildren(AWinControl: TWinControl; Enable: Boolean); + var + i: Integer; + ChildControl: TControl; + ChildWinControl: TWinControl absolute ChildControl; + RequestedEnable: Boolean; + EnabledOld: Boolean; + EnabledNew: Boolean; + begin + for i := 0 to AWinControl.ControlCount - 1 do begin + ChildControl := AWinControl.Controls[i]; + if ChildControl is TWinControl then begin + if not ChildWinControl.HandleAllocated then Continue; + RequestedEnable := ChildWinControl.Enabled and Enable; + EnabledOld := IsWindowEnabled(ChildWinControl.Handle); + Windows.EnableWindow(ChildWinControl.Handle, RequestedEnable); + EnabledNew := IsWindowEnabled(ChildWinControl.Handle); + if (EnabledOld = EnabledNew) or (ChildWinControl.ControlCount < 1) + or (EnabledNew <> RequestedEnable) + then + Continue; + EnableChildren(ChildWinControl, RequestedEnable); + end + else + ChildControl.Invalidate; + end; + end; + + function GetParentEnabled(AWinControl: TWinControl): Boolean; + var + ParentHandle: HWND; + ParentControl: TWinControl; + begin + ParentControl := AWinControl.Parent; + Result := not Assigned(ParentControl) or ParentControl.InheritsFrom(TCustomForm); + if not Result then begin + ParentHandle := GetParent(HWND); + Result := ParentHandle = 0; + if not Result then + Result := IsWindowEnabled(ParentHandle); + end; + end; + var - OldEnable: Boolean; + lWinControl: TWinControl; + IsForm: Boolean; + RequestedEnable: Boolean; begin - OldEnable := IsWindowEnabled(HWnd); - if OldEnable <> BEnable then - Result := Boolean(Windows.EnableWindow(HWnd, BEnable)) + lWinControl := GetWin32WindowInfo(HWnd)^.WinControl; + if not Assigned(lWinControl) then + Exit; + IsForm := lWinControl.InheritsFrom(TCustomForm); + if IsForm then + RequestedEnable := BEnable else - Result := not OldEnable; + RequestedEnable := BEnable and GetParentEnabled(lWinControl); + + Result := Boolean(Windows.EnableWindow(HWnd, RequestedEnable)); + if (wcfInitializing in TWinControlAccess(lWinControl).FWinControlFlags) or IsForm then + Exit; + // Result contains WS_DISABLED style. True means disabled + if (Result <> RequestedEnable) or (lWinControl.ControlCount < 1) then + Exit; + EnableChildren(lWinControl, RequestedEnable); end; {------------------------------------------------------------------------------