File: System\Windows\Forms\Controls\ToolStrips\ToolStripSystemRenderer.cs
Web Access
Project: src\src\System.Windows.Forms\src\System.Windows.Forms.csproj (System.Windows.Forms)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Drawing;
using System.Windows.Forms.VisualStyles;
 
namespace System.Windows.Forms;
 
public class ToolStripSystemRenderer : ToolStripRenderer
{
    [ThreadStatic]
    private static VisualStyleRenderer? t_renderer;
    private ToolStripRenderer? _toolStripHighContrastRenderer;
 
    public ToolStripSystemRenderer()
    {
    }
 
    internal ToolStripSystemRenderer(bool isDefault) : base(isDefault)
    {
    }
 
    internal override ToolStripRenderer? RendererOverride
    {
        get
        {
            if (DisplayInformation.HighContrast)
            {
                return HighContrastRenderer;
            }
 
            return null;
        }
    }
 
    internal ToolStripRenderer HighContrastRenderer
    {
        get
        {
            // If system in high contrast mode 'false' flag should be passed to render filled selected button background.
            // This is in consistence with ToolStripProfessionalRenderer.
            _toolStripHighContrastRenderer ??= new ToolStripHighContrastRenderer(systemRenderMode: false);
 
            return _toolStripHighContrastRenderer;
        }
    }
 
    /// <summary>
    ///  Draw the background color
    /// </summary>
    private static VisualStyleRenderer? VisualStyleRenderer
    {
        get
        {
            if (Application.RenderWithVisualStyles)
            {
                if (t_renderer is null && VisualStyleRenderer.IsElementDefined(VisualStyleElement.ToolBar.Button.Normal))
                {
                    t_renderer = new VisualStyleRenderer(VisualStyleElement.ToolBar.Button.Normal);
                }
            }
            else
            {
                t_renderer = null;
            }
 
            return t_renderer;
        }
    }
 
    /// <summary>
    ///  Fill the item's background as bounded by the rectangle
    /// </summary>
    private static void FillBackground(Graphics g, Rectangle bounds, Color backColor)
    {
        // Fill the background with the item's back color
        using var backBrush = backColor.GetCachedSolidBrushScope();
        g.FillRectangle(backBrush, bounds);
    }
 
    /// <summary>
    ///  translates the ToolStrip item state into a toolbar state, which is something the renderer understands
    /// </summary>
    private static int GetItemState(ToolStripItem item)
    {
        return (int)GetToolBarState(item);
    }
 
    /// <summary>
    ///  translates the ToolStrip item state into a toolbar state, which is something the renderer understands
    /// </summary>
    private static int GetSplitButtonDropDownItemState(ToolStripSplitButton? item)
    {
        return (int)GetSplitButtonToolBarState(item, true);
    }
 
    /// <summary>
    ///  translates the ToolStrip item state into a toolbar state, which is something the renderer understands
    /// </summary>
    private static int GetSplitButtonItemState(ToolStripSplitButton? item)
    {
        return (int)GetSplitButtonToolBarState(item, false);
    }
 
    /// <summary>
    ///  translates the ToolStrip item state into a toolbar state, which is something the renderer understands
    /// </summary>
    private static ToolBarState GetSplitButtonToolBarState(ToolStripSplitButton? button, bool dropDownButton)
    {
        ToolBarState state = ToolBarState.Normal;
 
        if (button is not null)
        {
            if (!button.Enabled)
            {
                state = ToolBarState.Disabled;
            }
            else if (dropDownButton)
            {
                if (button.DropDownButtonPressed || button.ButtonPressed)
                {
                    state = ToolBarState.Pressed;
                }
                else if (button.DropDownButtonSelected || button.ButtonSelected)
                {
                    state = ToolBarState.Hot;
                }
            }
            else
            {
                if (button.ButtonPressed)
                {
                    state = ToolBarState.Pressed;
                }
                else if (button.ButtonSelected)
                {
                    state = ToolBarState.Hot;
                }
            }
        }
 
        return state;
    }
 
    /// <summary>
    ///  translates the ToolStrip item state into a toolbar state, which is something the renderer understands
    /// </summary>
    private static ToolBarState GetToolBarState(ToolStripItem item)
    {
        ToolBarState state = ToolBarState.Normal;
 
        if (!item.Enabled)
        {
            state = ToolBarState.Disabled;
        }
 
        if (item is ToolStripButton toolStripButton && toolStripButton.Checked)
        {
            if (toolStripButton.Selected)
            {
                state = ToolBarState.Hot; // we'd prefer HotChecked here, but Color Theme uses the same color as Checked
            }
            else
            {
                state = ToolBarState.Checked;
            }
        }
        else if (item.Pressed)
        {
            state = ToolBarState.Pressed;
        }
        else if (item.Selected)
        {
            state = ToolBarState.Hot;
        }
 
        return state;
    }
 
    /// <summary>
    ///  Draw the ToolStrip background. ToolStrip users should override this if they want to draw differently.
    /// </summary>
    protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
    {
        ToolStrip toolStrip = e.ToolStrip;
        Graphics g = e.Graphics;
        Rectangle bounds = e.AffectedBounds;
 
        if (!ShouldPaintBackground(toolStrip))
        {
            return;
        }
 
        if (toolStrip is StatusStrip)
        {
            RenderStatusStripBackground(e);
        }
        else
        {
            if (DisplayInformation.HighContrast)
            {
                FillBackground(g, bounds, SystemColors.ButtonFace);
            }
            else if (DisplayInformation.LowResolution)
            {
                FillBackground(g, bounds, (toolStrip is ToolStripDropDown) ? SystemColors.ControlLight : e.BackColor);
            }
            else if (toolStrip.IsDropDown)
            {
                FillBackground(g, bounds, (!ToolStripManager.VisualStylesEnabled) ?
                                     e.BackColor : SystemColors.Menu);
            }
            else if (toolStrip is MenuStrip)
            {
                FillBackground(g, bounds, (!ToolStripManager.VisualStylesEnabled) ?
                                           e.BackColor : SystemColors.MenuBar);
            }
            else if (ToolStripManager.VisualStylesEnabled && VisualStyleRenderer.IsElementDefined(VisualStyleElement.Rebar.Band.Normal))
            {
                VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
                vsRenderer.SetParameters(VisualStyleElement.ToolBar.Bar.Normal);
                vsRenderer.DrawBackground(g, bounds);
            }
            else
            {
                FillBackground(g, bounds, (!ToolStripManager.VisualStylesEnabled) ?
                                           e.BackColor : SystemColors.MenuBar);
            }
        }
    }
 
    /// <summary>
    ///  Draw the border around the ToolStrip. This should be done as the last step.
    /// </summary>
    protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
    {
        ToolStrip toolStrip = e.ToolStrip;
        Rectangle bounds = toolStrip.ClientRectangle;
 
        if (toolStrip is StatusStrip)
        {
            RenderStatusStripBorder(e);
        }
        else if (toolStrip is ToolStripDropDown toolStripDropDown)
        {
            // Paint the border for the window depending on whether or not we have a drop shadow effect.
            if (toolStripDropDown.DropShadowEnabled && ToolStripManager.VisualStylesEnabled)
            {
                bounds.Width -= 1;
                bounds.Height -= 1;
                e.Graphics.DrawRectangle(SystemPens.ControlDark, bounds);
            }
            else
            {
                ControlPaint.DrawBorder3D(e.Graphics, bounds, Border3DStyle.Raised);
            }
        }
        else
        {
            if (ToolStripManager.VisualStylesEnabled)
            {
                e.Graphics.DrawLine(SystemPens.ButtonHighlight, 0, bounds.Bottom - 1, bounds.Width, bounds.Bottom - 1);
                e.Graphics.DrawLine(SystemPens.InactiveBorder, 0, bounds.Bottom - 2, bounds.Width, bounds.Bottom - 2);
            }
            else
            {
                e.Graphics.DrawLine(SystemPens.ButtonHighlight, 0, bounds.Bottom - 1, bounds.Width, bounds.Bottom - 1);
                e.Graphics.DrawLine(SystemPens.ButtonShadow, 0, bounds.Bottom - 2, bounds.Width, bounds.Bottom - 2);
            }
        }
    }
 
    /// <summary>
    ///  Draw the grip. ToolStrip users should override this if they want to draw differently.
    /// </summary>
    protected override void OnRenderGrip(ToolStripGripRenderEventArgs e)
    {
        Graphics g = e.Graphics;
        Rectangle bounds = new(Point.Empty, e.GripBounds.Size);
        bool verticalGrip = e.GripDisplayStyle == ToolStripGripDisplayStyle.Vertical;
 
        if (ToolStripManager.VisualStylesEnabled && VisualStyleRenderer.IsElementDefined(VisualStyleElement.Rebar.Gripper.Normal))
        {
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
 
            if (verticalGrip)
            {
                vsRenderer.SetParameters(VisualStyleElement.Rebar.Gripper.Normal);
 
                bounds.Height = ((bounds.Height - 2/*number of pixels for border*/) / 4) * 4; // make sure height is an even interval of 4.
                bounds.Y = Math.Max(0, (e.GripBounds.Height - bounds.Height - 2/*number of pixels for border*/) / 2);
            }
            else
            {
                vsRenderer.SetParameters(VisualStyleElement.Rebar.GripperVertical.Normal);
            }
 
            vsRenderer.DrawBackground(g, bounds);
        }
        else
        {
            // do some fixup so that we don't paint from end to end.
            Color backColor = e.ToolStrip.BackColor;
            FillBackground(g, bounds, backColor);
 
            if (verticalGrip)
            {
                if (bounds.Height >= 4)
                {
                    bounds.Inflate(0, -2);     // scoot down 2PX and start drawing
                }
 
                bounds.Width = 3;
            }
            else
            {
                if (bounds.Width >= 4)
                {
                    bounds.Inflate(-2, 0);        // scoot over 2PX and start drawing
                }
 
                bounds.Height = 3;
            }
 
            RenderSmall3DBorderInternal(g, bounds, ToolBarState.Hot, e.ToolStrip.RightToLeft == RightToLeft.Yes);
        }
    }
 
    /// <summary>
    ///  Draw the items background
    /// </summary>
    protected override void OnRenderItemBackground(ToolStripItemRenderEventArgs e)
    {
    }
 
    /// <summary>
    ///  Draw the items background
    /// </summary>
    protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
    {
    }
 
    /// <summary>
    ///  Draw the button background
    /// </summary>
    protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
    {
        // If system in high contrast mode and specific renderer override is defined, use that.
        // For ToolStripSystemRenderer in High Contrast mode the RendererOverride property will be ToolStripHighContrastRenderer.
        if (RendererOverride is not null)
        {
            base.OnRenderButtonBackground(e);
            return;
        }
 
        RenderItemInternal(e);
    }
 
    /// <summary>
    ///  Draw the button background
    /// </summary>
    protected override void OnRenderDropDownButtonBackground(ToolStripItemRenderEventArgs e)
    {
        // If system in high contrast mode and specific renderer override is defined, use that.
        // For ToolStripSystemRenderer in High Contrast mode the RendererOverride property will be ToolStripHighContrastRenderer.
        if (RendererOverride is not null)
        {
            base.OnRenderDropDownButtonBackground(e);
            return;
        }
 
        RenderItemInternal(e);
    }
 
    /// <summary>
    ///  Draw the button background
    /// </summary>
    protected override void OnRenderOverflowButtonBackground(ToolStripItemRenderEventArgs e)
    {
        ToolStripItem item = e.Item;
        Graphics g = e.Graphics;
 
        if (ToolStripManager.VisualStylesEnabled && VisualStyleRenderer.IsElementDefined(VisualStyleElement.Rebar.Chevron.Normal))
        {
            VisualStyleElement chevronElement = VisualStyleElement.Rebar.Chevron.Normal;
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
            vsRenderer.SetParameters(chevronElement.ClassName, chevronElement.Part, GetItemState(item));
            vsRenderer.DrawBackground(g, new Rectangle(Point.Empty, item.Size));
        }
        else
        {
            RenderItemInternal(e);
            Color arrowColor = item.Enabled ? SystemColors.ControlText : SystemColors.ControlDark;
            DrawArrow(new ToolStripArrowRenderEventArgs(g, item, new Rectangle(Point.Empty, item.Size), arrowColor, ArrowDirection.Down));
        }
    }
 
    /// <summary>
    ///  Draw the button background
    /// </summary>
    protected override void OnRenderLabelBackground(ToolStripItemRenderEventArgs e)
    {
        RenderLabelInternal(e);
    }
 
    /// <summary>
    ///  Draw the items background
    /// </summary>
    protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
    {
        ToolStripMenuItem? item = e.Item as ToolStripMenuItem;
        Graphics g = e.Graphics;
 
        if (item is MdiControlStrip.SystemMenuItem)
        {
            return; // no highlights are painted behind a system menu item
        }
 
        if (item is not null)
        {
            Rectangle bounds = new(Point.Empty, item.Size);
            if (item.IsTopLevel && !ToolStripManager.VisualStylesEnabled)
            {
                // Classic Mode (3D edges)
                // Draw box highlight for toplevel items in downlevel platforms
                if (item.BackgroundImage is not null)
                {
                    ControlPaint.DrawBackgroundImage(g, item.BackgroundImage, item.BackColor, item.BackgroundImageLayout, item.ContentRectangle, item.ContentRectangle);
                }
                else if (item.RawBackColor != Color.Empty)
                {
                    FillBackground(g, item.ContentRectangle, item.BackColor);
                }
 
                // Toplevel menu items do 3D borders.
                ToolBarState state = GetToolBarState(item);
                RenderSmall3DBorderInternal(g, bounds, state, (item.RightToLeft == RightToLeft.Yes));
            }
            else
            {
                // Modern MODE (no 3D edges)
                // Draw blue filled highlight for toplevel items in themed platforms
                // or items parented to a drop down
                Rectangle fillRect = new(Point.Empty, item.Size);
                if (item.IsOnDropDown)
                {
                    // Scoot in by 2 pixels when selected
                    fillRect.X += 2;
                    fillRect.Width -= 3; // its already 1 away from the right edge
                }
 
                if (item.Selected || item.Pressed)
                {
                    // Legacy behavior is to always paint the menu item background. The correct behavior is to only
                    // paint the background if the menu item is enabled.
                    if (item.Enabled)
                    {
                        g.FillRectangle(SystemBrushes.Highlight, fillRect);
                    }
 
                    Color borderColor = ToolStripManager.VisualStylesEnabled
                        ? SystemColors.Highlight
                        : ProfessionalColors.MenuItemBorder;
 
                    // Draw selection border - always drawn regardless of Enabled.
                    using var pen = borderColor.GetCachedPenScope();
                    g.DrawRectangle(pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1);
                }
                else
                {
                    if (item.BackgroundImage is not null)
                    {
                        ControlPaint.DrawBackgroundImage(g, item.BackgroundImage, item.BackColor, item.BackgroundImageLayout, item.ContentRectangle, fillRect);
                    }
                    else if (!ToolStripManager.VisualStylesEnabled && (item.RawBackColor != Color.Empty))
                    {
                        FillBackground(g, fillRect, item.BackColor);
                    }
                }
            }
        }
    }
 
    /// <summary>
    ///  Draws a toolbar separator. ToolStrip users should override this function to change the
    ///  drawing of all separators.
    /// </summary>
    protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
    {
        RenderSeparatorInternal(e.Graphics, e.Item, new Rectangle(Point.Empty, e.Item.Size), e.Vertical);
    }
 
    protected override void OnRenderToolStripStatusLabelBackground(ToolStripItemRenderEventArgs e)
    {
        RenderLabelInternal(e);
        ToolStripStatusLabel? item = e.Item as ToolStripStatusLabel;
        if (item is not null)
        {
            ControlPaint.DrawBorder3D(e.Graphics, new Rectangle(0, 0, item.Width - 1, item.Height - 1), item.BorderStyle, (Border3DSide)item.BorderSides);
        }
    }
 
    /// <summary>
    ///  Draw the item's background.
    /// </summary>
    protected override void OnRenderSplitButtonBackground(ToolStripItemRenderEventArgs e)
    {
        // If system in high contrast mode and specific renderer override is defined, use that.
        // For ToolStripSystemRenderer in High Contrast mode the RendererOverride property will be ToolStripHighContrastRenderer.
        if (RendererOverride is not null)
        {
            base.OnRenderSplitButtonBackground(e);
            return;
        }
 
        if (e.Item is not ToolStripSplitButton splitButton)
        {
            return;
        }
 
        Graphics g = e.Graphics;
 
        bool rightToLeft = splitButton.RightToLeft == RightToLeft.Yes;
        Color arrowColor = splitButton.Enabled ? SystemColors.ControlText : SystemColors.ControlDark;
 
        // in right to left - we need to swap the parts so we don't draw  v][ toolStripSplitButton
        VisualStyleElement splitButtonDropDownPart = rightToLeft ? VisualStyleElement.ToolBar.SplitButton.Normal : VisualStyleElement.ToolBar.SplitButtonDropDown.Normal;
        VisualStyleElement splitButtonPart = rightToLeft ? VisualStyleElement.ToolBar.DropDownButton.Normal : VisualStyleElement.ToolBar.SplitButton.Normal;
 
        Rectangle bounds = new(Point.Empty, splitButton.Size);
 
        if (ToolStripManager.VisualStylesEnabled
            && VisualStyleRenderer.IsElementDefined(splitButtonDropDownPart)
            && VisualStyleRenderer.IsElementDefined(splitButtonPart))
        {
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
 
            // Draw the SplitButton Button portion of it.
            vsRenderer.SetParameters(splitButtonPart.ClassName, splitButtonPart.Part, GetSplitButtonItemState(splitButton));
 
            // the lovely Windows theming for split button comes in three pieces:
            //  SplitButtonDropDown: [ v |
            //  Separator:                |
            //  SplitButton:               |  ]
            // this is great except if you want to swap the button in RTL. In this case we need
            // to use the DropDownButton instead of the SplitButtonDropDown and paint the arrow ourselves.
            Rectangle splitButtonBounds = splitButton.ButtonBounds;
            if (rightToLeft)
            {
                // scoot to the left so we don't draw double shadow like so: ][
                splitButtonBounds.Inflate(2, 0);
            }
 
            // Draw the button portion of it.
            vsRenderer.DrawBackground(g, splitButtonBounds);
 
            // Draw the SplitButton DropDownButton portion of it.
            vsRenderer.SetParameters(splitButtonDropDownPart.ClassName, splitButtonDropDownPart.Part, GetSplitButtonDropDownItemState(splitButton));
 
            // Draw the drop down button portion
            vsRenderer.DrawBackground(g, splitButton.DropDownButtonBounds);
 
            // fill in the background image
            Rectangle fillRect = splitButton.ContentRectangle;
            if (splitButton.BackgroundImage is not null)
            {
                ControlPaint.DrawBackgroundImage(g, splitButton.BackgroundImage, splitButton.BackColor, splitButton.BackgroundImageLayout, fillRect, fillRect);
            }
 
            // draw the separator over it.
            RenderSeparatorInternal(g, splitButton, splitButton.SplitterBounds, true);
 
            // and of course, now if we're in RTL we now need to paint the arrow
            // because we're no longer using a part that has it built in.
            if (rightToLeft || splitButton.BackgroundImage is not null)
            {
                DrawArrow(new ToolStripArrowRenderEventArgs(g, splitButton, splitButton.DropDownButtonBounds, arrowColor, ArrowDirection.Down));
            }
 
            ToolBarState state = GetToolBarState(e.Item);
            if (e.Item is ToolStripSplitButton item && !SystemInformation.HighContrast &&
                (state == ToolBarState.Hot || state == ToolBarState.Pressed || state == ToolBarState.Checked))
            {
                var clientBounds = item.ClientBounds;
                bounds.Height -= 1;
                ControlPaint.DrawBorderSimple(g, clientBounds, SystemColors.Highlight);
                using var brush = SystemColors.Highlight.GetCachedSolidBrushScope();
                g.FillRectangle(brush, item.SplitterBounds);
            }
        }
        else
        {
            // Draw the split button button
            Rectangle splitButtonButtonRect = splitButton.ButtonBounds;
 
            if (splitButton.BackgroundImage is not null)
            {
                // fill in the background image
                Rectangle fillRect = splitButton.Selected ? splitButton.ContentRectangle : bounds;
                if (splitButton.BackgroundImage is not null)
                {
                    ControlPaint.DrawBackgroundImage(g, splitButton.BackgroundImage, splitButton.BackColor, splitButton.BackgroundImageLayout, bounds, fillRect);
                }
            }
            else
            {
                FillBackground(g, splitButtonButtonRect, splitButton.BackColor);
            }
 
            ToolBarState state = GetSplitButtonToolBarState(splitButton, false);
 
            RenderSmall3DBorderInternal(g, splitButtonButtonRect, state, rightToLeft);
 
            // draw the split button drop down
            Rectangle dropDownRect = splitButton.DropDownButtonBounds;
 
            // fill the color in the dropdown button
            if (splitButton.BackgroundImage is null)
            {
                FillBackground(g, dropDownRect, splitButton.BackColor);
            }
 
            state = GetSplitButtonToolBarState(splitButton, true);
 
            if (state is ToolBarState.Pressed or ToolBarState.Hot)
            {
                RenderSmall3DBorderInternal(g, dropDownRect, state, rightToLeft);
            }
 
            DrawArrow(new ToolStripArrowRenderEventArgs(g, splitButton, dropDownRect, arrowColor, ArrowDirection.Down));
        }
    }
 
    /// <summary>
    ///  This exists mainly so that buttons, labels and items, etc can share the same implementation.
    ///  If OnRenderButton called OnRenderItem we would never be able to change the implementation
    ///  as it would be a breaking change. If in v1, the user overrode OnRenderItem to draw green triangles
    ///  and in v2 we decided to add a feature to button that would require us to no longer call OnRenderItem -
    ///  the user's version of OnRenderItem would not get called when he upgraded his framework. Hence
    ///  everyone should just call this private shared method. Users need to override each item they want
    ///  to change the look and feel of.
    ///  </summary>
    private static void RenderItemInternal(ToolStripItemRenderEventArgs e)
    {
        ToolStripItem item = e.Item;
        Graphics g = e.Graphics;
 
        ToolBarState state = GetToolBarState(item);
        VisualStyleElement toolBarElement = VisualStyleElement.ToolBar.Button.Normal;
 
        if (ToolStripManager.VisualStylesEnabled
            && VisualStyleRenderer.IsElementDefined(toolBarElement))
        {
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
            vsRenderer.SetParameters(toolBarElement.ClassName, toolBarElement.Part, (int)state);
            vsRenderer.DrawBackground(g, new Rectangle(Point.Empty, item.Size));
 
            if (!SystemInformation.HighContrast &&
                (state == ToolBarState.Hot || state == ToolBarState.Pressed || state == ToolBarState.Checked))
            {
                var bounds = item.ClientBounds;
                bounds.Height -= 1;
                ControlPaint.DrawBorderSimple(g, bounds, SystemColors.Highlight);
            }
        }
        else
        {
            RenderSmall3DBorderInternal(g, new Rectangle(Point.Empty, item.Size), state, (item.RightToLeft == RightToLeft.Yes));
        }
 
        Rectangle fillRect = item.ContentRectangle;
 
        if (item.BackgroundImage is not null)
        {
            ControlPaint.DrawBackgroundImage(g, item.BackgroundImage, item.BackColor, item.BackgroundImageLayout, fillRect, fillRect);
        }
        else
        {
            ToolStrip? parent = item.GetCurrentParent();
            if ((parent is not null) && (state != ToolBarState.Checked) && (item.BackColor != parent.BackColor))
            {
                FillBackground(g, fillRect, item.BackColor);
            }
        }
    }
 
    /// <summary>
    ///  </summary>
    private static void RenderSeparatorInternal(Graphics g, ToolStripItem item, Rectangle bounds, bool vertical)
    {
        VisualStyleElement separator = (vertical)
            ? VisualStyleElement.ToolBar.SeparatorHorizontal.Normal
            : VisualStyleElement.ToolBar.SeparatorVertical.Normal;
 
        if (ToolStripManager.VisualStylesEnabled
            && (VisualStyleRenderer.IsElementDefined(separator)))
        {
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
            vsRenderer.SetParameters(separator.ClassName, separator.Part, GetItemState(item));
            vsRenderer.DrawBackground(g, bounds);
        }
        else
        {
            using var foreColorPen = item.ForeColor.GetCachedPenScope();
 
            if (vertical)
            {
                if (bounds.Height >= 4)
                {
                    bounds.Inflate(0, -2);     // scoot down 2PX and start drawing
                }
 
                bool rightToLeft = (item.RightToLeft == RightToLeft.Yes);
                Pen leftPen = (rightToLeft) ? SystemPens.ButtonHighlight : foreColorPen;
                Pen rightPen = (rightToLeft) ? foreColorPen : SystemPens.ButtonHighlight;
 
                // Draw dark line
                int startX = bounds.Width / 2;
                g.DrawLine(leftPen, startX, bounds.Top, startX, bounds.Bottom);
 
                // Draw highlight one pixel to the right
                startX++;
                g.DrawLine(rightPen, startX, bounds.Top, startX, bounds.Bottom);
            }
            else
            {
                // horizontal separator
                if (bounds.Width >= 4)
                {
                    bounds.Inflate(-2, 0);        // scoot over 2PX and start drawing
                }
 
                // Draw dark line
                int startY = bounds.Height / 2;
                g.DrawLine(foreColorPen, bounds.Left, startY, bounds.Right, startY);
 
                // Draw highlight one pixel to the right
                startY++;
                g.DrawLine(SystemPens.ButtonHighlight, bounds.Left, startY, bounds.Right, startY);
            }
        }
    }
 
    private static void RenderSmall3DBorderInternal(Graphics g, Rectangle bounds, ToolBarState state, bool rightToLeft)
    {
        if (state is ToolBarState.Hot or ToolBarState.Pressed or ToolBarState.Checked)
        {
            Pen leftPen, topPen, rightPen, bottomPen;
            topPen = (state == ToolBarState.Hot) ? SystemPens.ButtonHighlight : SystemPens.ButtonShadow;
            bottomPen = (state == ToolBarState.Hot) ? SystemPens.ButtonShadow : SystemPens.ButtonHighlight;
 
            leftPen = (rightToLeft) ? bottomPen : topPen;
            rightPen = (rightToLeft) ? topPen : bottomPen;
 
            g.DrawLine(topPen, bounds.Left, bounds.Top, bounds.Right - 1, bounds.Top);
            g.DrawLine(leftPen, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 1);
            g.DrawLine(rightPen, bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom - 1);
            g.DrawLine(bottomPen, bounds.Left, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1);
        }
    }
 
    private static void RenderStatusStripBorder(ToolStripRenderEventArgs e)
    {
        if (!Application.RenderWithVisualStyles)
        {
            e.Graphics.DrawLine(SystemPens.ButtonHighlight, 0, 0, e.ToolStrip.Width, 0);
        }
    }
 
    private static void RenderStatusStripBackground(ToolStripRenderEventArgs e)
    {
        if (Application.RenderWithVisualStyles)
        {
            VisualStyleRenderer vsRenderer = VisualStyleRenderer!;
            vsRenderer.SetParameters(VisualStyleElement.Status.Bar.Normal);
            vsRenderer.DrawBackground(e.Graphics, new Rectangle(0, 0, e.ToolStrip.Width - 1, e.ToolStrip.Height - 1));
        }
        else
        {
            if (!SystemInformation.InLockedTerminalSession())
            {
                e.Graphics.Clear(e.BackColor);
            }
        }
    }
 
    private static void RenderLabelInternal(ToolStripItemRenderEventArgs e)
    {
        // don't call RenderItemInternal, as we NEVER want to paint hot.
        ToolStripItem item = e.Item;
        Graphics g = e.Graphics;
 
        Rectangle fillRect = item.ContentRectangle;
 
        if (item.BackgroundImage is not null)
        {
            ControlPaint.DrawBackgroundImage(g, item.BackgroundImage, item.BackColor, item.BackgroundImageLayout, fillRect, fillRect);
        }
        else
        {
            VisualStyleRenderer? vsRenderer = VisualStyleRenderer;
 
            if (vsRenderer is null || (item.BackColor != SystemColors.Control))
            {
                FillBackground(g, fillRect, item.BackColor);
            }
        }
    }
}