|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms.Layout;
namespace System.Windows.Forms;
public abstract class ToolStripRenderer
{
private static readonly object s_renderSplitButtonBackgroundEvent = new();
private static readonly object s_renderItemBackgroundEvent = new();
private static readonly object s_renderItemImageEvent = new();
private static readonly object s_renderItemTextEvent = new();
private static readonly object s_renderToolStripBackgroundEvent = new();
private static readonly object s_renderGripEvent = new();
private static readonly object s_renderButtonBackgroundEvent = new();
private static readonly object s_renderLabelBackgroundEvent = new();
private static readonly object s_renderMenuItemBackgroundEvent = new();
private static readonly object s_renderDropDownButtonBackgroundEvent = new();
private static readonly object s_renderOverflowButtonBackgroundEvent = new();
private static readonly object s_renderImageMarginEvent = new();
private static readonly object s_renderBorderEvent = new();
private static readonly object s_renderArrowEvent = new();
private static readonly object s_renderToolStripStatusLabelBackgroundEvent = new();
private static readonly object s_renderSeparatorEvent = new();
private static readonly object s_renderItemCheckEvent = new();
private static readonly object s_renderToolStripPanelBackgroundEvent = new();
private static readonly object s_renderToolStripContentPanelBackgroundEvent = new();
private static readonly object s_renderStatusStripSizingGripEvent = new();
private static ColorMatrix? s_disabledImageColorMatrix;
private EventHandlerList? _events;
private readonly bool _isAutoGenerated;
private static bool s_isScalingInitialized;
internal int _previousDeviceDpi = ScaleHelper.InitialSystemDpi;
// arrows are rendered as isosceles triangles, whose heights are half the base in order to have 45 degree angles
// Offset2X is half of the base
// Offset2Y is height of the isosceles triangle
private const int OFFSET_2PIXELS = 2;
private const int OFFSET_4PIXELS = 4;
protected static int Offset2X = OFFSET_2PIXELS;
protected static int Offset2Y = OFFSET_2PIXELS;
private static int s_offset4X = OFFSET_4PIXELS;
private static int s_offset4Y = OFFSET_4PIXELS;
// Used in building up the half pyramid of rectangles that are drawn in a
// status strip sizing grip.
private static readonly Rectangle[] s_baseSizeGripRectangles = [
new(8, 0, 2, 2),
new(8, 4, 2, 2),
new(8, 8, 2, 2),
new(4, 4, 2, 2),
new(4, 8, 2, 2),
new(0, 8, 2, 2)
];
protected ToolStripRenderer()
{
}
internal ToolStripRenderer(bool isAutoGenerated)
{
_isAutoGenerated = isAutoGenerated;
}
// Used in building disabled images.
private static ColorMatrix DisabledImageColorMatrix
{
get
{
if (s_disabledImageColorMatrix is null)
{
// This is the result of a GreyScale matrix multiplied by a transparency matrix of .5
float[][] greyscale =
[
[0.2125f, 0.2125f, 0.2125f, 0, 0],
[0.2577f, 0.2577f, 0.2577f, 0, 0],
[0.0361f, 0.0361f, 0.0361f, 0, 0],
[0, 0, 0, 1, 0],
[0.38f, 0.38f, 0.38f, 0, 1],
];
float[][] transparency =
[
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, .7F, 0],
[0, 0, 0, 0, 0],
];
s_disabledImageColorMatrix = ControlPaint.MultiplyColorMatrix(transparency, greyscale);
}
return s_disabledImageColorMatrix;
}
}
/// <summary>
/// Gets the list of event handlers that are attached to this component.
/// </summary>
private EventHandlerList Events
{
get
{
_events ??= new EventHandlerList();
return _events;
}
}
internal bool IsAutoGenerated
{
get { return _isAutoGenerated; }
}
// if we're in a low contrast, high resolution situation, use this renderer under the covers instead.
internal virtual ToolStripRenderer? RendererOverride
{
get
{
return null;
}
}
public event ToolStripArrowRenderEventHandler RenderArrow
{
add => AddHandler(s_renderArrowEvent, value);
remove => RemoveHandler(s_renderArrowEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripRenderEventHandler RenderToolStripBackground
{
add => AddHandler(s_renderToolStripBackgroundEvent, value);
remove => RemoveHandler(s_renderToolStripBackgroundEvent, value);
}
public event ToolStripPanelRenderEventHandler RenderToolStripPanelBackground
{
add => AddHandler(s_renderToolStripPanelBackgroundEvent, value);
remove => RemoveHandler(s_renderToolStripPanelBackgroundEvent, value);
}
public event ToolStripContentPanelRenderEventHandler RenderToolStripContentPanelBackground
{
add => AddHandler(s_renderToolStripContentPanelBackgroundEvent, value);
remove => RemoveHandler(s_renderToolStripContentPanelBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripRenderEventHandler RenderToolStripBorder
{
add => AddHandler(s_renderBorderEvent, value);
remove => RemoveHandler(s_renderBorderEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderButtonBackground
{
add => AddHandler(s_renderButtonBackgroundEvent, value);
remove => RemoveHandler(s_renderButtonBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderDropDownButtonBackground
{
add => AddHandler(s_renderDropDownButtonBackgroundEvent, value);
remove => RemoveHandler(s_renderDropDownButtonBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderOverflowButtonBackground
{
add => AddHandler(s_renderOverflowButtonBackgroundEvent, value);
remove => RemoveHandler(s_renderOverflowButtonBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripGripRenderEventHandler RenderGrip
{
add => AddHandler(s_renderGripEvent, value);
remove => RemoveHandler(s_renderGripEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderItemBackground
{
add => AddHandler(s_renderItemBackgroundEvent, value);
remove => RemoveHandler(s_renderItemBackgroundEvent, value);
}
/// <summary>
/// Draws the split button
/// </summary>
public event ToolStripItemImageRenderEventHandler RenderItemImage
{
add => AddHandler(s_renderItemImageEvent, value);
remove => RemoveHandler(s_renderItemImageEvent, value);
}
/// <summary>
/// Draws the checkmark
/// </summary>
public event ToolStripItemImageRenderEventHandler RenderItemCheck
{
add => AddHandler(s_renderItemCheckEvent, value);
remove => RemoveHandler(s_renderItemCheckEvent, value);
}
/// <summary>
/// Draws the split button
/// </summary>
public event ToolStripItemTextRenderEventHandler RenderItemText
{
add => AddHandler(s_renderItemTextEvent, value);
remove => RemoveHandler(s_renderItemTextEvent, value);
}
public event ToolStripRenderEventHandler RenderImageMargin
{
add => AddHandler(s_renderImageMarginEvent, value);
remove => RemoveHandler(s_renderImageMarginEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderLabelBackground
{
add => AddHandler(s_renderLabelBackgroundEvent, value);
remove => RemoveHandler(s_renderLabelBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripItemRenderEventHandler RenderMenuItemBackground
{
add => AddHandler(s_renderMenuItemBackgroundEvent, value);
remove => RemoveHandler(s_renderMenuItemBackgroundEvent, value);
}
/// <summary>
/// Draws the split button
/// </summary>
public event ToolStripItemRenderEventHandler RenderToolStripStatusLabelBackground
{
add => AddHandler(s_renderToolStripStatusLabelBackgroundEvent, value);
remove => RemoveHandler(s_renderToolStripStatusLabelBackgroundEvent, value);
}
/// <summary>
/// Occurs when the display style has changed
/// </summary>
public event ToolStripRenderEventHandler RenderStatusStripSizingGrip
{
add => AddHandler(s_renderStatusStripSizingGripEvent, value);
remove => RemoveHandler(s_renderStatusStripSizingGripEvent, value);
}
/// <summary>
/// Draws the split button
/// </summary>
public event ToolStripItemRenderEventHandler RenderSplitButtonBackground
{
add => AddHandler(s_renderSplitButtonBackgroundEvent, value);
remove => RemoveHandler(s_renderSplitButtonBackgroundEvent, value);
}
public event ToolStripSeparatorRenderEventHandler RenderSeparator
{
add => AddHandler(s_renderSeparatorEvent, value);
remove => RemoveHandler(s_renderSeparatorEvent, value);
}
#region EventHandlerSecurity
/// -----------------------------------------------------------------------------
///
private void AddHandler(object key, Delegate value)
{
Events.AddHandler(key, value);
}
private void RemoveHandler(object key, Delegate value)
{
Events.RemoveHandler(key, value);
}
#endregion
public static Image CreateDisabledImage(Image normalImage)
{
return CreateDisabledImage(normalImage, null);
}
public void DrawArrow(ToolStripArrowRenderEventArgs e)
{
OnRenderArrow(e);
if (Events[s_renderArrowEvent] is ToolStripArrowRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawToolStripBackground(ToolStripRenderEventArgs e)
{
OnRenderToolStripBackground(e);
if (Events[s_renderToolStripBackgroundEvent] is ToolStripRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawGrip(ToolStripGripRenderEventArgs e)
{
OnRenderGrip(e);
if (Events[s_renderGripEvent] is ToolStripGripRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
public void DrawItemBackground(ToolStripItemRenderEventArgs e)
{
OnRenderItemBackground(e);
if (Events[s_renderItemBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawImageMargin(ToolStripRenderEventArgs e)
{
OnRenderImageMargin(e);
if (Events[s_renderImageMarginEvent] is ToolStripRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawLabelBackground(ToolStripItemRenderEventArgs e)
{
OnRenderLabelBackground(e);
if (Events[s_renderLabelBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
public void DrawButtonBackground(ToolStripItemRenderEventArgs e)
{
OnRenderButtonBackground(e);
if (Events[s_renderButtonBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
public void DrawToolStripBorder(ToolStripRenderEventArgs e)
{
OnRenderToolStripBorder(e);
if (Events[s_renderBorderEvent] is ToolStripRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
public void DrawDropDownButtonBackground(ToolStripItemRenderEventArgs e)
{
OnRenderDropDownButtonBackground(e);
if (Events[s_renderDropDownButtonBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
public void DrawOverflowButtonBackground(ToolStripItemRenderEventArgs e)
{
OnRenderOverflowButtonBackground(e);
if (Events[s_renderOverflowButtonBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw image
/// </summary>
public void DrawItemImage(ToolStripItemImageRenderEventArgs e)
{
OnRenderItemImage(e);
if (Events[s_renderItemImageEvent] is ToolStripItemImageRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw image
/// </summary>
public void DrawItemCheck(ToolStripItemImageRenderEventArgs e)
{
OnRenderItemCheck(e);
if (Events[s_renderItemCheckEvent] is ToolStripItemImageRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw text
/// </summary>
public void DrawItemText(ToolStripItemTextRenderEventArgs e)
{
OnRenderItemText(e);
if (Events[s_renderItemTextEvent] is ToolStripItemTextRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
public void DrawMenuItemBackground(ToolStripItemRenderEventArgs e)
{
OnRenderMenuItemBackground(e);
if (Events[s_renderMenuItemBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawSplitButton(ToolStripItemRenderEventArgs e)
{
OnRenderSplitButtonBackground(e);
if (Events[s_renderSplitButtonBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the background color
/// </summary>
public void DrawToolStripStatusLabelBackground(ToolStripItemRenderEventArgs e)
{
OnRenderToolStripStatusLabelBackground(e);
if (Events[s_renderToolStripStatusLabelBackgroundEvent] is ToolStripItemRenderEventHandler eh)
{
eh(this, e);
}
}
//
public void DrawStatusStripSizingGrip(ToolStripRenderEventArgs e)
{
OnRenderStatusStripSizingGrip(e);
if (Events[s_renderStatusStripSizingGripEvent] is ToolStripRenderEventHandler eh)
{
eh(this, e);
}
}
/// <summary>
/// Draw the separator
/// </summary>
public void DrawSeparator(ToolStripSeparatorRenderEventArgs e)
{
OnRenderSeparator(e);
if (Events[s_renderSeparatorEvent] is ToolStripSeparatorRenderEventHandler eh)
{
eh(this, e);
}
}
public void DrawToolStripPanelBackground(ToolStripPanelRenderEventArgs e)
{
OnRenderToolStripPanelBackground(e);
if (Events[s_renderToolStripPanelBackgroundEvent] is ToolStripPanelRenderEventHandler eh)
{
eh(this, e);
}
}
public void DrawToolStripContentPanelBackground(ToolStripContentPanelRenderEventArgs e)
{
OnRenderToolStripContentPanelBackground(e);
if (Events[s_renderToolStripContentPanelBackgroundEvent] is ToolStripContentPanelRenderEventHandler eh)
{
eh(this, e);
}
}
// consider make public
internal virtual Region? GetTransparentRegion(ToolStrip toolStrip)
{
return null;
}
protected internal virtual void Initialize(ToolStrip toolStrip)
{
}
protected internal virtual void InitializePanel(ToolStripPanel toolStripPanel)
{
}
protected internal virtual void InitializeContentPanel(ToolStripContentPanel contentPanel)
{
}
protected internal virtual void InitializeItem(ToolStripItem item)
{
}
protected static void ScaleArrowOffsetsIfNeeded()
{
if (s_isScalingInitialized)
{
return;
}
Offset2X = ScaleHelper.ScaleToInitialSystemDpi(OFFSET_2PIXELS);
Offset2Y = ScaleHelper.ScaleToInitialSystemDpi(OFFSET_2PIXELS);
s_offset4X = ScaleHelper.ScaleToInitialSystemDpi(OFFSET_4PIXELS);
s_offset4Y = ScaleHelper.ScaleToInitialSystemDpi(OFFSET_4PIXELS);
s_isScalingInitialized = true;
}
protected static void ScaleArrowOffsetsIfNeeded(int dpi)
{
Offset2X = ScaleHelper.ScaleToDpi(OFFSET_2PIXELS, dpi);
Offset2Y = ScaleHelper.ScaleToDpi(OFFSET_2PIXELS, dpi);
s_offset4X = ScaleHelper.ScaleToDpi(OFFSET_4PIXELS, dpi);
s_offset4Y = ScaleHelper.ScaleToDpi(OFFSET_4PIXELS, dpi);
}
protected virtual void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
if (RendererOverride is not null)
{
RendererOverride.OnRenderArrow(e);
return;
}
Graphics g = e.Graphics;
Rectangle dropDownRect = e.ArrowRectangle;
using var brush = e.ArrowColor.GetCachedSolidBrushScope();
Point middle = new(dropDownRect.Left + dropDownRect.Width / 2, dropDownRect.Top + dropDownRect.Height / 2);
// if the width is odd - favor pushing it over one pixel right.
// middle.X += (dropDownRect.Width % 2);
Point[]? arrow = null;
// We need to check for null here, since at design time at this point Item can be null.
if (e.Item is not null && e.Item.DeviceDpi != _previousDeviceDpi && ScaleHelper.IsThreadPerMonitorV2Aware)
{
_previousDeviceDpi = e.Item.DeviceDpi;
ScaleArrowOffsetsIfNeeded(e.Item.DeviceDpi);
}
else
{
ScaleArrowOffsetsIfNeeded();
}
// using (offset4X - Offset2X) instead of (Offset2X) to compensate for rounding error in scaling
int horizontalOffset = ScaleHelper.IsScalingRequirementMet ? s_offset4X - Offset2X : Offset2X;
arrow = e.Direction switch
{
ArrowDirection.Up =>
[
new(middle.X - Offset2X, middle.Y + 1),
new(middle.X + Offset2X + 1, middle.Y + 1),
new(middle.X, middle.Y - Offset2Y)
],
ArrowDirection.Left =>
[
new(middle.X + Offset2X, middle.Y - s_offset4Y),
new(middle.X + Offset2X, middle.Y + s_offset4Y),
new(middle.X - horizontalOffset, middle.Y)
],
ArrowDirection.Right =>
[
new(middle.X - Offset2X, middle.Y - s_offset4Y),
new(middle.X - Offset2X, middle.Y + s_offset4Y),
new(middle.X + horizontalOffset, middle.Y)
],
_ =>
[
new(middle.X - Offset2X, middle.Y - 1),
new(middle.X + Offset2X + 1, middle.Y - 1),
new(middle.X, middle.Y + Offset2Y)
],
};
g.FillPolygon(brush, arrow);
}
/// <summary>
/// Draw the ToolStrip background. ToolStrip users should override this if they want to draw differently.
/// </summary>
protected virtual void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderToolStripBackground(e);
return;
}
}
/// <summary>
/// Draw the border around the ToolStrip. This should be done as the last step.
/// </summary>
protected virtual void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderToolStripBorder(e);
return;
}
}
/// <summary>
/// Draw the grip. ToolStrip users should override this if they want to draw differently.
/// </summary>
protected virtual void OnRenderGrip(ToolStripGripRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderGrip(e);
return;
}
}
/// <summary>
/// Draw the items background
/// </summary>
protected virtual void OnRenderItemBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderItemBackground(e);
return;
}
}
/// <summary>
/// Draw the items background
/// </summary>
protected virtual void OnRenderImageMargin(ToolStripRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderImageMargin(e);
return;
}
}
/// <summary>
/// Draw the button background
/// </summary>
protected virtual void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderButtonBackground(e);
return;
}
}
/// <summary>
/// Draw the button background
/// </summary>
protected virtual void OnRenderDropDownButtonBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderDropDownButtonBackground(e);
return;
}
}
/// <summary>
/// Draw the button background
/// </summary>
protected virtual void OnRenderOverflowButtonBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderOverflowButtonBackground(e);
return;
}
}
/// <summary>
/// Draw the item's image. ToolStrip users should override this function to change the
/// drawing of all images.
/// </summary>
protected virtual void OnRenderItemImage(ToolStripItemImageRenderEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
if (RendererOverride is not null)
{
RendererOverride.OnRenderItemImage(e);
return;
}
Rectangle imageRect = e.ImageRectangle;
Image? image = e.Image;
if (imageRect != Rectangle.Empty && image is not null)
{
bool disposeImage = false;
if (e.ShiftOnPress && e.Item is not null && e.Item.Pressed)
{
imageRect.X++;
}
if (e.Item is not null && !e.Item.Enabled)
{
image = CreateDisabledImage(image, e.ImageAttributes);
disposeImage = true;
}
if (e.Item?.ImageScaling == ToolStripItemImageScaling.None)
{
e.Graphics.DrawImage(image, imageRect, new Rectangle(Point.Empty, imageRect.Size), GraphicsUnit.Pixel);
}
else
{
e.Graphics.DrawImage(image, imageRect);
}
if (disposeImage)
{
image.Dispose();
}
}
}
protected virtual void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
if (RendererOverride is not null)
{
RendererOverride.OnRenderItemCheck(e);
return;
}
Rectangle imageRect = e.ImageRectangle;
Image? image = e.Image;
if (imageRect != Rectangle.Empty && image is not null)
{
if (e.Item is not null)
{
if (!e.Item.Enabled)
{
image = CreateDisabledImage(image, e.ImageAttributes);
}
if (SystemInformation.HighContrast && image is Bitmap bitmap)
{
Color backgroundColor = e.Item.Selected ? SystemColors.Highlight : e.Item.BackColor;
if (ControlPaint.IsDark(backgroundColor))
{
Image invertedImage = ControlPaint.CreateBitmapWithInvertedForeColor(bitmap, e.Item.BackColor);
image = invertedImage;
}
}
}
e.Graphics.DrawImage(image, imageRect, 0, 0, imageRect.Width,
imageRect.Height, GraphicsUnit.Pixel, e.ImageAttributes);
}
}
/// <summary>
/// Draw the item's text. ToolStrip users should override this function to change the
/// drawing of all text.
/// </summary>
protected virtual void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
if (RendererOverride is not null)
{
RendererOverride.OnRenderItemText(e);
return;
}
ToolStripItem? item = e.Item;
Graphics g = e.Graphics;
Color textColor = e.TextColor;
Font? textFont = e.TextFont;
string? text = e.Text;
Rectangle textRect = e.TextRectangle;
TextFormatFlags textFormat = e.TextFormat;
// if we're disabled draw in a different color.
textColor = (item is not null && item.Enabled) ? textColor : SystemColors.GrayText;
if (e.TextDirection != ToolStripTextDirection.Horizontal && textRect.Width > 0 && textRect.Height > 0)
{
// Perf: this is a bit heavy handed.. perhaps we can share the bitmap.
Size textSize = LayoutUtils.FlipSize(textRect.Size);
using Bitmap textBmp = new(textSize.Width, textSize.Height, PixelFormat.Format32bppPArgb);
using Graphics textGraphics = Graphics.FromImage(textBmp);
// now draw the text..
textGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
TextRenderer.DrawText(textGraphics, text, textFont, new Rectangle(Point.Empty, textSize), textColor, textFormat);
textBmp.RotateFlip((e.TextDirection == ToolStripTextDirection.Vertical90) ? RotateFlipType.Rotate90FlipNone : RotateFlipType.Rotate270FlipNone);
g.DrawImage(textBmp, textRect);
}
else
{
TextRenderer.DrawText(g, text, textFont, textRect, textColor, textFormat);
}
}
/// <summary>
/// Draw the button background
/// </summary>
protected virtual void OnRenderLabelBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderLabelBackground(e);
return;
}
}
/// <summary>
/// Draw the items background
/// </summary>
protected virtual void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderMenuItemBackground(e);
return;
}
}
/// <summary>
/// Draws a toolbar separator. ToolStrip users should override this function to change the
/// drawing of all separators.
/// </summary>
protected virtual void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderSeparator(e);
return;
}
}
protected virtual void OnRenderToolStripPanelBackground(ToolStripPanelRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderToolStripPanelBackground(e);
return;
}
}
protected virtual void OnRenderToolStripContentPanelBackground(ToolStripContentPanelRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderToolStripContentPanelBackground(e);
return;
}
}
protected virtual void OnRenderToolStripStatusLabelBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderToolStripStatusLabelBackground(e);
return;
}
}
protected virtual void OnRenderStatusStripSizingGrip(ToolStripRenderEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
if (RendererOverride is not null)
{
RendererOverride.OnRenderStatusStripSizingGrip(e);
return;
}
Graphics g = e.Graphics;
// we have a set of stock rectangles. Translate them over to where the grip is to be drawn
// for the white set, then translate them up and right one pixel for the grey.
if (e.ToolStrip is StatusStrip statusStrip)
{
Rectangle sizeGripBounds = statusStrip.SizeGripBounds;
if (!LayoutUtils.IsZeroWidthOrHeight(sizeGripBounds))
{
Rectangle[] whiteRectangles = new Rectangle[s_baseSizeGripRectangles.Length];
Rectangle[] greyRectangles = new Rectangle[s_baseSizeGripRectangles.Length];
for (int i = 0; i < s_baseSizeGripRectangles.Length; i++)
{
Rectangle baseRect = s_baseSizeGripRectangles[i];
if (statusStrip.RightToLeft == RightToLeft.Yes)
{
baseRect.X = sizeGripBounds.Width - baseRect.X - baseRect.Width;
}
baseRect.Offset(sizeGripBounds.X, sizeGripBounds.Bottom - 12 /*height of pyramid (10px) + 2px padding from bottom*/);
whiteRectangles[i] = baseRect;
if (statusStrip.RightToLeft == RightToLeft.Yes)
{
baseRect.Offset(1, -1);
}
else
{
baseRect.Offset(-1, -1);
}
greyRectangles[i] = baseRect;
}
g.FillRectangles(SystemBrushes.ButtonHighlight, whiteRectangles);
g.FillRectangles(SystemBrushes.ButtonShadow, greyRectangles);
}
}
}
/// <summary>
/// Draw the item's background.
/// </summary>
protected virtual void OnRenderSplitButtonBackground(ToolStripItemRenderEventArgs e)
{
if (RendererOverride is not null)
{
RendererOverride.OnRenderSplitButtonBackground(e);
return;
}
}
// Only paint background effects if no BackColor has been set or no background image has been set.
internal static bool ShouldPaintBackground(Control control)
{
return (control.RawBackColor == Color.Empty && control.BackgroundImage is null);
}
private static Bitmap CreateDisabledImage(Image normalImage, ImageAttributes? imgAttrib)
{
ArgumentNullException.ThrowIfNull(normalImage);
imgAttrib ??= new ImageAttributes();
imgAttrib.ClearColorKey();
imgAttrib.SetColorMatrix(DisabledImageColorMatrix);
Size size = normalImage.Size;
Bitmap disabledBitmap = new(size.Width, size.Height);
using (Graphics graphics = Graphics.FromImage(disabledBitmap))
{
graphics.DrawImage(normalImage,
new Rectangle(0, 0, size.Width, size.Height),
0, 0, size.Width, size.Height,
GraphicsUnit.Pixel,
imgAttrib);
}
return disabledBitmap;
}
}
|