@@ -37,7 +37,7 @@ public abstract class ToolStripRenderer
37
37
private static ColorMatrix ? s_disabledImageColorMatrix ;
38
38
39
39
private EventHandlerList ? _events ;
40
- private readonly bool _isAutoGenerated ;
40
+ private readonly bool _isSystemDefaultAlternative ;
41
41
42
42
private static bool s_isScalingInitialized ;
43
43
internal int _previousDeviceDpi = ScaleHelper . InitialSystemDpi ;
@@ -52,28 +52,12 @@ public abstract class ToolStripRenderer
52
52
private static int s_offset4X = OFFSET_4PIXELS ;
53
53
private static int s_offset4Y = OFFSET_4PIXELS ;
54
54
55
- // Used in building up the half pyramid of rectangles that are drawn in a
56
- // status strip sizing grip.
57
- private static readonly Rectangle [ ] s_baseSizeGripRectangles =
58
- [
59
- new ( 12 , 0 , 2 , 2 ) ,
60
- new ( 8 , 4 , 2 , 2 ) ,
61
- new ( 4 , 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 ) ,
69
- ] ;
70
-
71
55
protected ToolStripRenderer ( )
72
56
{
73
57
}
74
58
75
59
internal ToolStripRenderer ( bool isAutoGenerated ) =>
76
- _isAutoGenerated = isAutoGenerated ;
60
+ _isSystemDefaultAlternative = isAutoGenerated ;
77
61
78
62
// Used in building disabled images.
79
63
private static ColorMatrix DisabledImageColorMatrix
@@ -153,7 +137,13 @@ private EventHandlerList Events
153
137
}
154
138
}
155
139
156
- internal bool IsAutoGenerated => _isAutoGenerated ;
140
+ /// <summary>
141
+ /// Defines, if there is a variation of the system default renderer, that is chosen by the system
142
+ /// to address the current environment context. Like DarkMode, HighContrast, LowRes etc.
143
+ /// (Used to be 'AutoGenerated', presuming to indicate, that the renderer was 'generated' (picked) by the system.)
144
+ /// </summary>
145
+ internal bool IsSystemDefaultAlternative
146
+ => _isSystemDefaultAlternative ;
157
147
158
148
// if we're in a low contrast, high resolution situation, use this renderer under the covers instead.
159
149
internal virtual ToolStripRenderer ? RendererOverride => null ;
@@ -1012,39 +1002,57 @@ protected virtual void OnRenderToolStripStatusLabelBackground(ToolStripItemRende
1012
1002
}
1013
1003
}
1014
1004
1005
+ // Used in building up the half pyramid of rectangles that are drawn in a
1006
+ // status strip sizing grip.
1007
+ private static readonly Rectangle [ ] s_baseSizeGripRectangles =
1008
+ [
1009
+ new ( 12 , 0 , 2 , 2 ) ,
1010
+ new ( 8 , 4 , 2 , 2 ) ,
1011
+ new ( 4 , 8 , 2 , 2 ) ,
1012
+ new ( 0 , 12 , 2 , 2 ) ,
1013
+ new ( 8 , 0 , 2 , 2 ) ,
1014
+ new ( 4 , 4 , 2 , 2 ) ,
1015
+ new ( 0 , 8 , 2 , 2 ) ,
1016
+ new ( 4 , 0 , 2 , 2 ) ,
1017
+ new ( 0 , 4 , 2 , 2 ) ,
1018
+ new ( 1 , 1 , 2 , 2 ) ,
1019
+ ] ;
1020
+
1015
1021
protected virtual void OnRenderStatusStripSizingGrip ( ToolStripRenderEventArgs e )
1016
1022
{
1017
1023
ArgumentNullException . ThrowIfNull ( e ) ;
1018
1024
1025
+ if ( RendererOverride is not null )
1026
+ {
1027
+ RendererOverride . OnRenderStatusStripSizingGrip ( e ) ;
1028
+ return ;
1029
+ }
1030
+
1019
1031
OnRenderStatusStripSizingGrip (
1020
1032
eArgs : e ,
1021
1033
highLightBrush : SystemBrushes . ButtonHighlight ,
1022
- shadowBrush : SystemBrushes . ButtonShadow ) ;
1034
+ shadowBrush : SystemBrushes . GrayText ) ;
1023
1035
}
1024
1036
1025
- private protected void OnRenderStatusStripSizingGrip (
1037
+ private protected static void OnRenderStatusStripSizingGrip (
1026
1038
ToolStripRenderEventArgs eArgs ,
1027
1039
Brush highLightBrush ,
1028
1040
Brush shadowBrush )
1029
1041
{
1030
- if ( RendererOverride is not null )
1031
- {
1032
- RendererOverride . OnRenderStatusStripSizingGrip ( eArgs ) ;
1033
- return ;
1034
- }
1035
-
1036
1042
if ( eArgs . ToolStrip is not StatusStrip statusStrip )
1037
1043
{
1038
1044
return ;
1039
1045
}
1040
1046
1041
1047
Rectangle sizeGripBounds = statusStrip . SizeGripBounds ;
1048
+
1042
1049
if ( LayoutUtils . IsZeroWidthOrHeight ( sizeGripBounds ) )
1043
1050
{
1044
1051
return ;
1045
1052
}
1046
1053
1047
1054
Graphics g = eArgs . Graphics ;
1055
+ ReadOnlySpan < Rectangle > baseRects = s_baseSizeGripRectangles ;
1048
1056
1049
1057
// Use device DPI for scaling
1050
1058
float dpiScale = 1.0f ;
@@ -1054,12 +1062,13 @@ private protected void OnRenderStatusStripSizingGrip(
1054
1062
dpiScale = statusStrip . DeviceDpi / 96f ;
1055
1063
}
1056
1064
1057
- // Scale the base rectangles for the grip dots
1058
- Rectangle [ ] scaledRects = new Rectangle [ s_baseSizeGripRectangles . Length ] ;
1065
+ // Create a buffer on the stack for the scaled rectangles
1066
+ Span < Rectangle > scaledRects = stackalloc Rectangle [ baseRects . Length ] ;
1059
1067
1060
- for ( int i = 0 ; i < s_baseSizeGripRectangles . Length ; i ++ )
1068
+ // Scale the base rectangles for the grip dots
1069
+ for ( int i = 0 ; i < baseRects . Length ; i ++ )
1061
1070
{
1062
- Rectangle r = s_baseSizeGripRectangles [ i ] ;
1071
+ Rectangle r = baseRects [ i ] ;
1063
1072
1064
1073
scaledRects [ i ] = new Rectangle (
1065
1074
( int ) ( r . X * dpiScale ) ,
@@ -1074,40 +1083,49 @@ private protected void OnRenderStatusStripSizingGrip(
1074
1083
SmoothingMode oldSmoothing = g . SmoothingMode ;
1075
1084
g . SmoothingMode = SmoothingMode . AntiAlias ;
1076
1085
1086
+ // Optimize for RTL check by determining the calculation function once
1087
+ bool isRtl = statusStrip . RightToLeft == RightToLeft . Yes ;
1088
+
1077
1089
// Draw the grip dots, bottom-right aligned (mirrored for RTL)
1078
- foreach ( Rectangle dotRect in scaledRects )
1090
+ Span < Rectangle > workingRects = stackalloc Rectangle [ 3 ] ; // actualRect, highlightRect, shadowRect
1091
+
1092
+ for ( int i = 0 ; i < scaledRects . Length ; i ++ )
1079
1093
{
1080
- Rectangle actualRect = statusStrip . RightToLeft == RightToLeft . Yes
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
1081
1100
? new Rectangle (
1082
1101
x : sizeGripBounds . Left + cornerOffset + dotRect . X ,
1083
1102
y : sizeGripBounds . Bottom - cornerOffset - dotRect . Y - dotRect . Height ,
1084
1103
width : dotRect . Width ,
1085
1104
height : dotRect . Height )
1086
-
1087
1105
: new Rectangle (
1088
1106
x : sizeGripBounds . Right - cornerOffset - dotRect . X - dotRect . Width ,
1089
1107
y : sizeGripBounds . Bottom - cornerOffset - dotRect . Y - dotRect . Height ,
1090
1108
width : dotRect . Width ,
1091
1109
height : dotRect . Height ) ;
1092
1110
1093
1111
// Highlight dot (top-left)
1094
- Rectangle highlightRect = actualRect ;
1112
+ highlightRect = actualRect ;
1095
1113
highlightRect . Offset ( - 1 , - 1 ) ;
1096
-
1097
1114
g . FillEllipse ( highLightBrush , highlightRect ) ;
1098
1115
1099
1116
// Shadow dot (bottom-right)
1100
- Rectangle shadowRect = actualRect ;
1117
+ shadowRect = actualRect ;
1101
1118
shadowRect . Offset ( 1 , 1 ) ;
1102
-
1103
1119
g . FillEllipse ( shadowBrush , shadowRect ) ;
1104
1120
}
1105
1121
1106
1122
g . SmoothingMode = oldSmoothing ;
1107
1123
1124
+ // We need to account for Windows 11+ AND whatever styled corners we have.
1108
1125
static ( int cornerOffset , Rectangle rect ) GetCornerOffset ( StatusStrip statusStrip )
1109
1126
{
1110
- ( int , Rectangle ) cornerDef = ( 2 , new ( 1 , 1 , 2 , 2 ) ) ;
1127
+ // Default values
1128
+ ( int offset , Rectangle rect ) cornerDef = ( 2 , new ( 1 , 1 , 2 , 2 ) ) ;
1111
1129
1112
1130
if ( Environment . OSVersion . Version >= new Version ( 10 , 0 , 22000 )
1113
1131
&& statusStrip . FindForm ( ) is Form f )
0 commit comments