Skip to content

Commit a5c7e24

Browse files
Fix existing bug in GripSize calculation in HighDPI.
1 parent 4ad1d39 commit a5c7e24

File tree

1 file changed

+60
-65
lines changed

1 file changed

+60
-65
lines changed

src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripRenderer.cs

Lines changed: 60 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,95 +1052,90 @@ private protected static void OnRenderStatusStripSizingGrip(
10521052
}
10531053

10541054
Graphics g = eArgs.Graphics;
1055-
ReadOnlySpan<Rectangle> baseRects = s_baseSizeGripRectangles;
1055+
ReadOnlySpan<Rectangle> baseRectangles = s_baseSizeGripRectangles;
10561056

1057-
// Use device DPI for scaling
1058-
float dpiScale = 1.0f;
1057+
// Reference height for sizing grips at 96 DPI (standard sizing)
1058+
const int DefaultGripAreaHeight = 20;
10591059

1060-
if (statusStrip.DeviceDpi > 0 && ScaleHelper.IsThreadPerMonitorV2Aware)
1061-
{
1062-
dpiScale = statusStrip.DeviceDpi / 96f;
1063-
}
1060+
// Calculate scaling based on the almost half of the current height
1061+
// of the status strip's sizing grip area
1062+
float heightScale = 0.6f * ((float)sizeGripBounds.Height / DefaultGripAreaHeight);
10641063

1065-
// Create a buffer on the stack for the scaled rectangles
1066-
Span<Rectangle> scaledRects = stackalloc Rectangle[baseRects.Length];
1064+
// Save the current graphics state before transformations
1065+
GraphicsState originalState = g.Save();
10671066

1068-
// Scale the base rectangles for the grip dots
1069-
for (int i = 0; i < baseRects.Length; i++)
1067+
try
10701068
{
1071-
Rectangle r = baseRects[i];
1072-
1073-
scaledRects[i] = new Rectangle(
1074-
(int)(r.X * dpiScale),
1075-
(int)(r.Y * dpiScale),
1076-
Math.Max((int)(r.Width * dpiScale), 2),
1077-
Math.Max((int)(r.Height * dpiScale), 2));
1078-
}
1069+
// Set anti-aliasing for smoother appearance
1070+
SmoothingMode oldSmoothing = g.SmoothingMode;
1071+
g.SmoothingMode = SmoothingMode.AntiAlias;
10791072

1080-
(int cornerOffset, Rectangle lastRect) = GetCornerOffset(statusStrip);
1081-
scaledRects[^1] = lastRect;
1073+
// Translate to the corner where we'll start drawing
1074+
bool isRtl = statusStrip.RightToLeft == RightToLeft.Yes;
1075+
int cornerOffset = GetCornerOffset(statusStrip);
10821076

1083-
SmoothingMode oldSmoothing = g.SmoothingMode;
1084-
g.SmoothingMode = SmoothingMode.AntiAlias;
1077+
// Set up the transform to scale from the bottom corner
1078+
if (isRtl)
1079+
{
1080+
g.TranslateTransform(sizeGripBounds.Left + cornerOffset, sizeGripBounds.Bottom - cornerOffset);
1081+
}
1082+
else
1083+
{
1084+
g.TranslateTransform(sizeGripBounds.Right - cornerOffset, sizeGripBounds.Bottom - cornerOffset);
1085+
}
10851086

1086-
// Optimize for RTL check by determining the calculation function once
1087-
bool isRtl = statusStrip.RightToLeft == RightToLeft.Yes;
1087+
// Apply scaling
1088+
g.ScaleTransform(heightScale, heightScale);
10881089

1089-
// Draw the grip dots, bottom-right aligned (mirrored for RTL)
1090-
Span<Rectangle> workingRects = stackalloc Rectangle[3]; // actualRect, highlightRect, shadowRect
1090+
// Draw the sizing grip dots in the scaled context
1091+
foreach (Rectangle baseRect in baseRectangles)
1092+
{
1093+
Rectangle dotRect = new(
1094+
isRtl ? baseRect.X : -baseRect.X - baseRect.Width,
1095+
-baseRect.Y - baseRect.Height,
1096+
baseRect.Width,
1097+
baseRect.Height);
1098+
1099+
// Highlight dot (top-left)
1100+
Rectangle highlightRect = dotRect;
1101+
highlightRect.Offset(-1, -1);
1102+
g.FillEllipse(highLightBrush, highlightRect);
1103+
1104+
// Shadow dot (bottom-right)
1105+
Rectangle shadowRect = dotRect;
1106+
shadowRect.Offset(1, 1);
1107+
g.FillEllipse(shadowBrush, shadowRect);
1108+
}
10911109

1092-
for (int i = 0; i < scaledRects.Length; i++)
1110+
// Restore the original smoothing mode
1111+
g.SmoothingMode = oldSmoothing;
1112+
}
1113+
finally
10931114
{
1094-
ref Rectangle dotRect = ref scaledRects[i];
1095-
ref Rectangle actualRect = ref workingRects[0];
1096-
ref Rectangle highlightRect = ref workingRects[1];
1097-
ref Rectangle shadowRect = ref workingRects[2];
1098-
1099-
actualRect = isRtl
1100-
? new Rectangle(
1101-
x: sizeGripBounds.Left + cornerOffset + dotRect.X,
1102-
y: sizeGripBounds.Bottom - cornerOffset - dotRect.Y - dotRect.Height,
1103-
width: dotRect.Width,
1104-
height: dotRect.Height)
1105-
: new Rectangle(
1106-
x: sizeGripBounds.Right - cornerOffset - dotRect.X - dotRect.Width,
1107-
y: sizeGripBounds.Bottom - cornerOffset - dotRect.Y - dotRect.Height,
1108-
width: dotRect.Width,
1109-
height: dotRect.Height);
1110-
1111-
// Highlight dot (top-left)
1112-
highlightRect = actualRect;
1113-
highlightRect.Offset(-1, -1);
1114-
g.FillEllipse(highLightBrush, highlightRect);
1115-
1116-
// Shadow dot (bottom-right)
1117-
shadowRect = actualRect;
1118-
shadowRect.Offset(1, 1);
1119-
g.FillEllipse(shadowBrush, shadowRect);
1115+
// Always restore the original graphics state
1116+
g.Restore(originalState);
11201117
}
11211118

1122-
g.SmoothingMode = oldSmoothing;
1123-
1124-
// We need to account for Windows 11+ AND whatever styled corners we have.
1125-
static (int cornerOffset, Rectangle rect) GetCornerOffset(StatusStrip statusStrip)
1119+
// Helper method to determine corner offset based on form corner preference
1120+
static int GetCornerOffset(StatusStrip statusStrip)
11261121
{
1127-
// Default values
1128-
(int offset, Rectangle rect) cornerDef = (2, new(1, 1, 2, 2));
1122+
// Default offset
1123+
int offset = 2;
11291124

11301125
if (Environment.OSVersion.Version >= new Version(10, 0, 22000)
11311126
&& statusStrip.FindForm() is Form f)
11321127
{
11331128
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
1134-
cornerDef = f.FormCornerPreference switch
1129+
offset = f.FormCornerPreference switch
11351130
{
1136-
FormCornerPreference.Round => (4, new(1, 1, 2, 2)),
1137-
FormCornerPreference.RoundSmall => (3, new(1, 1, 2, 2)),
1138-
_ => (2, new(0, 0, 2, 2))
1131+
FormCornerPreference.Round => 4,
1132+
FormCornerPreference.RoundSmall => 3,
1133+
_ => 2
11391134
};
11401135
#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
11411136
}
11421137

1143-
return cornerDef;
1138+
return offset;
11441139
}
11451140
}
11461141

0 commit comments

Comments
 (0)