|
3 | 3 |
|
4 | 4 | using System.ComponentModel;
|
5 | 5 | using System.Drawing;
|
| 6 | +using System.Drawing.Drawing2D; |
6 | 7 | using System.Drawing.Imaging;
|
7 | 8 | using System.Drawing.Text;
|
8 | 9 | using System.Windows.Forms.Layout;
|
@@ -55,12 +56,16 @@ public abstract class ToolStripRenderer
|
55 | 56 | // status strip sizing grip.
|
56 | 57 | private static readonly Rectangle[] s_baseSizeGripRectangles =
|
57 | 58 | [
|
58 |
| - new(8, 0, 2, 2), |
| 59 | + new(12, 0, 2, 2), |
59 | 60 | new(8, 4, 2, 2),
|
60 |
| - new(8, 8, 2, 2), |
61 |
| - new(4, 4, 2, 2), |
62 | 61 | new(4, 8, 2, 2),
|
63 |
| - new(0, 8, 2, 2) |
| 62 | + new(0, 12, 2, 2), |
| 63 | + new(8, 0, 2, 2), |
| 64 | + new(4, 4, 2, 2), |
| 65 | + new(0, 8, 2, 2), |
| 66 | + new(4, 0, 2, 2), |
| 67 | + new(0, 4, 2, 2), |
| 68 | + new(1, 1, 2, 2), |
64 | 69 | ];
|
65 | 70 |
|
66 | 71 | protected ToolStripRenderer()
|
@@ -1028,78 +1033,94 @@ private protected void OnRenderStatusStripSizingGrip(
|
1028 | 1033 | return;
|
1029 | 1034 | }
|
1030 | 1035 |
|
1031 |
| - Graphics g = eArgs.Graphics; |
1032 |
| - |
1033 |
| - // we have a set of stock rectangles. Translate them over to where the grip is to be drawn |
1034 |
| - // for the white set, then translate them up and right one pixel for the grey. |
1035 |
| - |
1036 | 1036 | if (eArgs.ToolStrip is not StatusStrip statusStrip)
|
1037 | 1037 | {
|
1038 | 1038 | return;
|
1039 | 1039 | }
|
1040 | 1040 |
|
1041 | 1041 | Rectangle sizeGripBounds = statusStrip.SizeGripBounds;
|
1042 |
| - |
1043 | 1042 | if (LayoutUtils.IsZeroWidthOrHeight(sizeGripBounds))
|
1044 | 1043 | {
|
1045 | 1044 | return;
|
1046 | 1045 | }
|
1047 | 1046 |
|
1048 |
| - Rectangle[] whiteRectangles = new Rectangle[s_baseSizeGripRectangles.Length]; |
1049 |
| - Rectangle[] greyRectangles = new Rectangle[s_baseSizeGripRectangles.Length]; |
| 1047 | + Graphics g = eArgs.Graphics; |
| 1048 | + |
| 1049 | + // Use device DPI for scaling |
| 1050 | + float dpiScale = 1.0f; |
1050 | 1051 |
|
1051 |
| - for (int i = 0; i < s_baseSizeGripRectangles.Length; i++) |
| 1052 | + if (statusStrip.DeviceDpi > 0 && ScaleHelper.IsThreadPerMonitorV2Aware) |
1052 | 1053 | {
|
1053 |
| - Rectangle baseRect = s_baseSizeGripRectangles[i]; |
| 1054 | + dpiScale = statusStrip.DeviceDpi / 96f; |
| 1055 | + } |
1054 | 1056 |
|
1055 |
| - if (statusStrip.RightToLeft == RightToLeft.Yes) |
1056 |
| - { |
1057 |
| - baseRect.X = sizeGripBounds.Width - baseRect.X - baseRect.Width; |
1058 |
| - } |
| 1057 | + // Scale the base rectangles for the grip dots |
| 1058 | + Rectangle[] scaledRects = new Rectangle[s_baseSizeGripRectangles.Length]; |
1059 | 1059 |
|
1060 |
| - // Height of pyramid (10px) + 2px padding from bottom. |
1061 |
| - baseRect.Offset( |
1062 |
| - x: sizeGripBounds.X, |
1063 |
| - y: sizeGripBounds.Bottom - 12); |
| 1060 | + for (int i = 0; i < s_baseSizeGripRectangles.Length; i++) |
| 1061 | + { |
| 1062 | + Rectangle r = s_baseSizeGripRectangles[i]; |
1064 | 1063 |
|
1065 |
| - whiteRectangles[i] = baseRect; |
| 1064 | + scaledRects[i] = new Rectangle( |
| 1065 | + (int)(r.X * dpiScale), |
| 1066 | + (int)(r.Y * dpiScale), |
| 1067 | + Math.Max((int)(r.Width * dpiScale), 2), |
| 1068 | + Math.Max((int)(r.Height * dpiScale), 2)); |
| 1069 | + } |
1066 | 1070 |
|
1067 |
| - int offset = -1 + GetCornerOffset(statusStrip); |
| 1071 | + (int cornerOffset, Rectangle lastRect) = GetCornerOffset(statusStrip); |
| 1072 | + scaledRects[^1] = lastRect; |
1068 | 1073 |
|
1069 |
| - if (statusStrip.RightToLeft == RightToLeft.Yes) |
1070 |
| - { |
1071 |
| - baseRect.Offset(1, -1 - offset); |
1072 |
| - } |
1073 |
| - else |
1074 |
| - { |
1075 |
| - baseRect.Offset(-1, -1 - offset); |
1076 |
| - } |
| 1074 | + SmoothingMode oldSmoothing = g.SmoothingMode; |
| 1075 | + g.SmoothingMode = SmoothingMode.AntiAlias; |
1077 | 1076 |
|
1078 |
| - greyRectangles[i] = baseRect; |
| 1077 | + // Draw the grip dots, bottom-right aligned (mirrored for RTL) |
| 1078 | + foreach (Rectangle dotRect in scaledRects) |
| 1079 | + { |
| 1080 | + Rectangle actualRect = statusStrip.RightToLeft == RightToLeft.Yes |
| 1081 | + ? new Rectangle( |
| 1082 | + x: sizeGripBounds.Left + cornerOffset + dotRect.X, |
| 1083 | + y: sizeGripBounds.Bottom - cornerOffset - dotRect.Y - dotRect.Height, |
| 1084 | + width: dotRect.Width, |
| 1085 | + height: dotRect.Height) |
| 1086 | + |
| 1087 | + : new Rectangle( |
| 1088 | + x: sizeGripBounds.Right - cornerOffset - dotRect.X - dotRect.Width, |
| 1089 | + y: sizeGripBounds.Bottom - cornerOffset - dotRect.Y - dotRect.Height, |
| 1090 | + width: dotRect.Width, |
| 1091 | + height: dotRect.Height); |
| 1092 | + |
| 1093 | + // Highlight dot (top-left) |
| 1094 | + Rectangle highlightRect = actualRect; |
| 1095 | + highlightRect.Offset(-1, -1); |
| 1096 | + |
| 1097 | + g.FillEllipse(highLightBrush, highlightRect); |
| 1098 | + |
| 1099 | + // Shadow dot (bottom-right) |
| 1100 | + Rectangle shadowRect = actualRect; |
| 1101 | + shadowRect.Offset(1, 1); |
| 1102 | + |
| 1103 | + g.FillEllipse(shadowBrush, shadowRect); |
1079 | 1104 | }
|
1080 | 1105 |
|
1081 |
| - g.FillRectangles(highLightBrush, whiteRectangles); |
1082 |
| - g.FillRectangles(shadowBrush, greyRectangles); |
| 1106 | + g.SmoothingMode = oldSmoothing; |
1083 | 1107 |
|
1084 |
| - // We need to compensate for the rounded Window corners from Windows 11 on. |
1085 |
| - static int GetCornerOffset(StatusStrip statusStrip) |
| 1108 | + static (int cornerOffset, Rectangle rect) GetCornerOffset(StatusStrip statusStrip) |
1086 | 1109 | {
|
1087 |
| - // If we're on Windows 11, offset slightly to avoid hitting rounded corners, |
1088 |
| - // _if_ we are at all dealing with rounded corners. |
1089 |
| - int cornerOffset = 0; |
| 1110 | + (int, Rectangle) cornerDef = (2, new(1, 1, 2, 2)); |
1090 | 1111 |
|
1091 | 1112 | if (Environment.OSVersion.Version >= new Version(10, 0, 22000)
|
1092 | 1113 | && statusStrip.FindForm() is Form f)
|
1093 | 1114 | {
|
1094 |
| - cornerOffset = f.FormCornerPreference switch |
| 1115 | + cornerDef = f.FormCornerPreference switch |
1095 | 1116 | {
|
1096 |
| - FormCornerPreference.Round => 5, |
1097 |
| - FormCornerPreference.RoundSmall => 3, |
1098 |
| - _ => 3 |
| 1117 | + FormCornerPreference.Round => (4, new(1, 1, 2, 2)), |
| 1118 | + FormCornerPreference.RoundSmall => (3, new(1, 1, 2, 2)), |
| 1119 | + _ => (2, new(0, 0, 2, 2)) |
1099 | 1120 | };
|
1100 | 1121 | }
|
1101 | 1122 |
|
1102 |
| - return cornerOffset; |
| 1123 | + return cornerDef; |
1103 | 1124 | }
|
1104 | 1125 | }
|
1105 | 1126 |
|
|
0 commit comments