-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix issue 14795: ComboBox with DropDownStyle.Simple renders incorrectly and displays an unexpected vertical scrollbar #14827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -165,19 +165,6 @@ private ModernComboTargetState ComputeModernComboTargetState() | |
| { | ||
| int topInset = chromeInsets.Top + Padding.Top; | ||
| int bottomInset = chromeInsets.Bottom + Padding.Bottom; | ||
| editBounds.Y += topInset; | ||
|
|
||
| editBounds.Height = Math.Max( | ||
| 1, | ||
| editBounds.Height - topInset - bottomInset); | ||
|
|
||
| editBounds.Height = Math.Max( | ||
| 1, | ||
| Math.Min( | ||
| editBounds.Height, | ||
| ClientRectangle.Bottom | ||
| - bottomInset | ||
| - editBounds.Top)); | ||
|
|
||
| // Inset the edit window horizontally so its rectangular corners clear the rounded | ||
| // field arcs, and reserve the (now wider) drop-down button on the button side. | ||
|
|
@@ -189,30 +176,91 @@ private ModernComboTargetState ComputeModernComboTargetState() | |
| ModernControlVisualStyles.ComboBoxButtonExtraWidth, | ||
| DeviceDpiInternal); | ||
|
|
||
| if (RightToLeft == RightToLeft.Yes) | ||
| if (DropDownStyle == ComboBoxStyle.Simple) | ||
| { | ||
| // In RTL the drop-down button sits on the left, so its reservation goes there. | ||
| editBounds.X += rightInset + extraButtonWidth; | ||
| int dividerThickness = Math.Max( | ||
| 1, | ||
| ScaleHelper.ScaleToDpi( | ||
| ModernControlVisualStyles.BorderThickness, | ||
| DeviceDpiInternal)); | ||
| const int bottomCropLogicalPixels = 2; | ||
| int simpleBottomShrink = ScaleHelper.ScaleToDpi(bottomCropLogicalPixels, DeviceDpiInternal); | ||
| int simpleListBottom = ClientRectangle.Bottom - simpleBottomShrink - dividerThickness; | ||
| int simpleEditTop = topInset + ScaleHelper.ScaleToDpi(1, DeviceDpiInternal); | ||
| int selectionFieldHeight = Math.Max( | ||
| 1, | ||
| (int)PInvokeCore.SendMessage( | ||
| this, | ||
| PInvoke.CB_GETITEMHEIGHT, | ||
| (WPARAM)(-1))); | ||
| int minimumReadableHeight = Math.Max( | ||
| 1, | ||
| FontHeight + ScaleHelper.ScaleToDpi(2, DeviceDpiInternal)); | ||
| int preferredSimpleEditHeight = Math.Max(selectionFieldHeight, minimumReadableHeight) | ||
| + ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); | ||
| int maxSimpleEditHeight = Math.Max( | ||
| 1, | ||
| simpleListBottom - dividerThickness - simpleEditTop); | ||
|
|
||
| // Keep the editor in the top field lane with enough height for full glyph rendering, | ||
| // draw an accent divider below it, and let the permanent list consume the remaining | ||
| // space down to the rounded field border. | ||
| editBounds.Y = simpleEditTop; | ||
| editBounds.Height = Math.Min(preferredSimpleEditHeight, maxSimpleEditHeight); | ||
| editBounds.X = leftInset; | ||
| editBounds.Width = Math.Max( | ||
| 1, | ||
| ClientRectangle.Width - leftInset - rightInset); | ||
|
|
||
| if (!simpleListBounds.IsEmpty) | ||
| { | ||
| simpleListBounds.X = editBounds.Left; | ||
| simpleListBounds.Width = editBounds.Width; | ||
| simpleListBounds.Y = editBounds.Bottom + dividerThickness; | ||
| simpleListBounds.Height = Math.Max( | ||
| 1, | ||
| simpleListBottom - simpleListBounds.Y); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| editBounds.X += leftInset; | ||
| } | ||
|
|
||
| editBounds.Width = Math.Max( | ||
| 1, | ||
| editBounds.Width - leftInset - rightInset - extraButtonWidth); | ||
|
|
||
| if (!simpleListBounds.IsEmpty) | ||
| { | ||
| int simpleListBottom = GetCurrentSimpleListBottom( | ||
| simpleListBounds.Bottom); | ||
| editBounds.Y += topInset; | ||
|
|
||
| simpleListBounds.Y = editBounds.Bottom + bottomInset; | ||
| editBounds.Height = Math.Max( | ||
| 1, | ||
| editBounds.Height - topInset - bottomInset); | ||
|
|
||
| simpleListBounds.Height = Math.Max( | ||
| editBounds.Height = Math.Max( | ||
| 1, | ||
| Math.Min( | ||
| editBounds.Height, | ||
| ClientRectangle.Bottom | ||
| - bottomInset | ||
| - editBounds.Top)); | ||
|
|
||
| if (RightToLeft == RightToLeft.Yes) | ||
| { | ||
| // In RTL the drop-down button sits on the left, so its reservation goes there. | ||
| editBounds.X += rightInset + extraButtonWidth; | ||
| } | ||
| else | ||
| { | ||
| editBounds.X += leftInset; | ||
| } | ||
|
|
||
| editBounds.Width = Math.Max( | ||
| 1, | ||
| simpleListBottom - simpleListBounds.Y); | ||
| editBounds.Width - leftInset - rightInset - extraButtonWidth); | ||
|
|
||
| if (!simpleListBounds.IsEmpty) | ||
| { | ||
| int simpleListBottom = GetCurrentSimpleListBottom( | ||
| simpleListBounds.Bottom); | ||
| simpleListBounds.Y = editBounds.Bottom + bottomInset; | ||
| simpleListBounds.Height = Math.Max( | ||
| 1, | ||
| simpleListBottom - simpleListBounds.Y); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -281,6 +329,60 @@ private void GetAdjustedNativeChildBounds( | |
| } | ||
| } | ||
|
|
||
| private void ConfigureModernSimpleListSurface(HWND listHandle) | ||
| { | ||
| if (DropDownStyle != ComboBoxStyle.Simple | ||
| || !UsesModernComboAdapter | ||
| || listHandle.IsNull) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| WINDOW_STYLE style = (WINDOW_STYLE)PInvokeCore.GetWindowLong( | ||
| listHandle, | ||
| WINDOW_LONG_PTR_INDEX.GWL_STYLE); | ||
| WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvokeCore.GetWindowLong( | ||
| listHandle, | ||
| WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); | ||
|
|
||
| WINDOW_STYLE updatedStyle = style & ~WINDOW_STYLE.WS_BORDER; | ||
| WINDOW_EX_STYLE updatedExStyle = exStyle & ~WINDOW_EX_STYLE.WS_EX_CLIENTEDGE; | ||
|
|
||
| if (updatedStyle == style && updatedExStyle == exStyle) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if (updatedStyle != style) | ||
| { | ||
| PInvokeCore.SetWindowLong( | ||
| listHandle, | ||
| WINDOW_LONG_PTR_INDEX.GWL_STYLE, | ||
| (nint)updatedStyle); | ||
| } | ||
|
|
||
| if (updatedExStyle != exStyle) | ||
| { | ||
| PInvokeCore.SetWindowLong( | ||
| listHandle, | ||
| WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, | ||
| (nint)updatedExStyle); | ||
| } | ||
|
|
||
| PInvoke.SetWindowPos( | ||
| listHandle, | ||
| HWND.Null, | ||
| 0, | ||
| 0, | ||
| 0, | ||
| 0, | ||
| SET_WINDOW_POS_FLAGS.SWP_NOMOVE | ||
| | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | ||
| | SET_WINDOW_POS_FLAGS.SWP_NOZORDER | ||
| | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | ||
| | SET_WINDOW_POS_FLAGS.SWP_FRAMECHANGED); | ||
| } | ||
|
|
||
| private unsafe int GetCurrentSimpleListBottom( | ||
| int fallback) | ||
| { | ||
|
|
@@ -464,24 +566,63 @@ private void ApplyEditMargins( | |
|
|
||
| private void ApplyChildBounds(HWND childHandle, Rectangle targetBounds) | ||
| { | ||
| bool isModernSimpleList = UsesModernComboAdapter | ||
| && DropDownStyle == ComboBoxStyle.Simple | ||
| && childHandle == _childListBox?.HWND; | ||
|
|
||
| if (childHandle.IsNull | ||
| || targetBounds.IsEmpty | ||
| || GetChildBounds(childHandle) == targetBounds) | ||
| || targetBounds.IsEmpty) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| PInvoke.SetWindowPos( | ||
| childHandle, | ||
| HWND.Null, | ||
| targetBounds.Left, | ||
| targetBounds.Top, | ||
| if (GetChildBounds(childHandle) != targetBounds) | ||
| { | ||
| PInvoke.SetWindowPos( | ||
| childHandle, | ||
| HWND.Null, | ||
| targetBounds.Left, | ||
| targetBounds.Top, | ||
| targetBounds.Width, | ||
| targetBounds.Height, | ||
| SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | ||
| | SET_WINDOW_POS_FLAGS.SWP_NOZORDER); | ||
|
|
||
| _modernComboLayoutWriteCount++; | ||
| } | ||
|
|
||
| if (isModernSimpleList) | ||
| { | ||
| ConfigureModernSimpleListClipRegion( | ||
| childHandle, | ||
| targetBounds); | ||
| } | ||
| } | ||
|
|
||
| private void ConfigureModernSimpleListClipRegion( | ||
| HWND listHandle, | ||
| Rectangle targetBounds) | ||
| { | ||
| if (listHandle.IsNull) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| int bottomShrink = ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); | ||
|
SimonZhao888 marked this conversation as resolved.
Outdated
|
||
| int visibleHeight = Math.Max(1, targetBounds.Height - bottomShrink); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The bottom crop is still applied twice. |
||
| using RegionScope region = new( | ||
| 0, | ||
| 0, | ||
| targetBounds.Width, | ||
| targetBounds.Height, | ||
| SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | ||
| | SET_WINDOW_POS_FLAGS.SWP_NOZORDER); | ||
| visibleHeight); | ||
|
|
||
| _modernComboLayoutWriteCount++; | ||
| if (PInvoke.SetWindowRgn( | ||
| listHandle, | ||
| region, | ||
| fRedraw: true) != 0) | ||
| { | ||
| region.RelinquishOwnership(); | ||
| } | ||
| } | ||
|
|
||
| private Rectangle GetChildBounds(HWND child) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.