diff --git a/GitExtUtils/GitUI/IMenuItemBackgroundFilter.cs b/GitExtUtils/GitUI/IMenuItemBackgroundFilter.cs new file mode 100644 index 00000000000..05c71bc5831 --- /dev/null +++ b/GitExtUtils/GitUI/IMenuItemBackgroundFilter.cs @@ -0,0 +1,9 @@ +using System.Windows.Forms; + +namespace GitExtUtils.GitUI +{ + public interface IMenuItemBackgroundFilter + { + bool ShouldRenderMenuItemBackground(ToolStripItemRenderEventArgs e); + } +} diff --git a/GitExtUtils/GitUI/IToolStripEx.cs b/GitExtUtils/GitUI/IToolStripEx.cs new file mode 100644 index 00000000000..d0719925985 --- /dev/null +++ b/GitExtUtils/GitUI/IToolStripEx.cs @@ -0,0 +1,10 @@ +namespace GitUI +{ + public interface IToolStripEx + { + /// + /// Gets or sets whether the toolstrip control has a border drawn around it. + /// + bool DrawBorder { get; set; } + } +} diff --git a/GitExtUtils/GitUI/Theming/ThemeAwareToolStripRenderer.cs b/GitExtUtils/GitUI/Theming/ThemeAwareToolStripRenderer.cs deleted file mode 100644 index 8803b103e84..00000000000 --- a/GitExtUtils/GitUI/Theming/ThemeAwareToolStripRenderer.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Drawing; -using System.Runtime.CompilerServices; -using System.Windows.Forms; - -namespace GitExtUtils.GitUI.Theming -{ - public class ThemeAwareToolStripRenderer : ToolStripProfessionalRenderer - { - private static readonly ConditionalWeakTable AdaptedImagesCache = - new ConditionalWeakTable(); - - protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) - { - var image = (Bitmap)e.Image; - if (!AdaptedImagesCache.TryGetValue(image, out var adapted)) - { - adapted = image.AdaptLightness(); - AdaptedImagesCache.Add(image, adapted); - } - - base.OnRenderItemCheck(new ToolStripItemImageRenderEventArgs( - e.Graphics, e.Item, adapted, e.ImageRectangle)); - } - } -} diff --git a/GitExtUtils/GitUI/Theming/ThemeFix.cs b/GitExtUtils/GitUI/Theming/ThemeFix.cs index 24cd21cc062..4bd505f94e7 100644 --- a/GitExtUtils/GitUI/Theming/ThemeFix.cs +++ b/GitExtUtils/GitUI/Theming/ThemeFix.cs @@ -74,14 +74,15 @@ private static void SetupTextBoxBase(TextBoxBase textBox) private static void SetupToolStrip(ToolStrip strip) { - strip.Renderer = new ThemeAwareToolStripRenderer(); + strip.EnableTheming(enable: true); + strip.Items.OfType() .ForEach(SetupToolStripLabel); } private static void SetupContextMenu(ContextMenuStrip strip) { - strip.Renderer = new ThemeAwareToolStripRenderer(); + strip.EnableTheming(enable: true); } private static void SetupToolStripLabel(ToolStripLabel label) diff --git a/GitExtUtils/GitUI/ToolStripExRenderer.cs b/GitExtUtils/GitUI/ToolStripExRenderer.cs new file mode 100644 index 00000000000..c26fa6636dd --- /dev/null +++ b/GitExtUtils/GitUI/ToolStripExRenderer.cs @@ -0,0 +1,24 @@ +using System.Windows.Forms; + +namespace GitUI +{ + internal sealed class ToolStripExRenderer : ToolStripSystemRenderer + { + protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) + { + if (e.ToolStrip.GetMenuItemBackgroundFilter()?.ShouldRenderMenuItemBackground(e) != false) + { + base.OnRenderMenuItemBackground(e); + } + } + + protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) + { + if (e.ToolStrip is not IToolStripEx { DrawBorder: false }) + { + // render border + base.OnRenderToolStripBorder(e); + } + } + } +} diff --git a/GitExtUtils/GitUI/ToolStripExThemeAwareRenderer.cs b/GitExtUtils/GitUI/ToolStripExThemeAwareRenderer.cs new file mode 100644 index 00000000000..124876d8e89 --- /dev/null +++ b/GitExtUtils/GitUI/ToolStripExThemeAwareRenderer.cs @@ -0,0 +1,47 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using System.Windows.Forms; +using GitExtUtils.GitUI.Theming; + +namespace GitUI +{ + internal sealed class ToolStripExThemeAwareRenderer : ToolStripProfessionalRenderer + { + private static readonly ConditionalWeakTable AdaptedImagesCache = new(); + + public ToolStripExThemeAwareRenderer() + { + RoundedEdges = false; + } + + protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) + { + var image = (Bitmap)e.Image; + if (!AdaptedImagesCache.TryGetValue(image, out var adapted)) + { + adapted = image.AdaptLightness(); + AdaptedImagesCache.Add(image, adapted); + } + + base.OnRenderItemCheck(new ToolStripItemImageRenderEventArgs( + e.Graphics, e.Item, adapted, e.ImageRectangle)); + } + + protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) + { + if (e.ToolStrip.GetMenuItemBackgroundFilter()?.ShouldRenderMenuItemBackground(e) != false) + { + base.OnRenderMenuItemBackground(e); + } + } + + protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) + { + if (e.ToolStrip is not IToolStripEx { DrawBorder: false }) + { + // render border + base.OnRenderToolStripBorder(e); + } + } + } +} diff --git a/GitExtUtils/GitUI/ToolStripExtensions.cs b/GitExtUtils/GitUI/ToolStripExtensions.cs new file mode 100644 index 00000000000..167a5e923d4 --- /dev/null +++ b/GitExtUtils/GitUI/ToolStripExtensions.cs @@ -0,0 +1,61 @@ +using System.Runtime.CompilerServices; +using System.Windows.Forms; +using GitExtUtils.GitUI; + +namespace GitUI +{ + public static class ToolStripExtensions + { + private static ConditionalWeakTable MenuItemBackgroundFilters = new(); + private static ConditionalWeakTable Renderers = new(); + private static ConditionalWeakTable RenderersThemeAware = new(); + + public static void AttachMenuItemBackgroundFilter(this ToolStrip toolStrip, IMenuItemBackgroundFilter? value) + { + toolStrip.UseCustomRenderer(); + MenuItemBackgroundFilters.Remove(toolStrip); + + if (value is not null) + { + MenuItemBackgroundFilters.Add(toolStrip, value); + } + } + + public static void UseCustomRenderer(this ToolStrip toolStrip) + { + // use either ToolStripExRenderer or ToolStripExThemeAwareRenderer + toolStrip.EnableTheming(enable: toolStrip.IsThemingEnabled()); + } + + internal static void EnableTheming(this ToolStrip toolStrip, bool enable) + { + if (enable) + { + if (toolStrip.Renderer is not ToolStripExThemeAwareRenderer) + { + toolStrip.Renderer = RenderersThemeAware.GetOrCreateValue(toolStrip); + } + } + else + { + if (toolStrip.Renderer is not ToolStripExRenderer) + { + toolStrip.Renderer = Renderers.GetOrCreateValue(toolStrip); + } + } + } + + internal static IMenuItemBackgroundFilter? GetMenuItemBackgroundFilter(this ToolStrip toolStrip) + { + if (MenuItemBackgroundFilters.TryGetValue(toolStrip, out var filter)) + { + return filter; + } + + return null; + } + + internal static bool IsThemingEnabled(this ToolStrip toolStrip) => + toolStrip.Renderer is ToolStripExThemeAwareRenderer; + } +} diff --git a/GitUI/BranchTreePanel/RepoObjectsTree.Designer.cs b/GitUI/BranchTreePanel/RepoObjectsTree.Designer.cs index ed51eddcb9d..c24084f4028 100644 --- a/GitUI/BranchTreePanel/RepoObjectsTree.Designer.cs +++ b/GitUI/BranchTreePanel/RepoObjectsTree.Designer.cs @@ -442,6 +442,7 @@ private void InitializeComponent() // this.leftPanelToolStrip.BackColor = System.Drawing.SystemColors.Control; this.leftPanelToolStrip.ClickThrough = true; + this.leftPanelToolStrip.DrawBorder = false; this.leftPanelToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.leftPanelToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.tsbCollapseAll, diff --git a/GitUI/CommandsDialogs/FormBrowse.Designer.cs b/GitUI/CommandsDialogs/FormBrowse.Designer.cs index b05b272329c..1cf9e78bcf8 100644 --- a/GitUI/CommandsDialogs/FormBrowse.Designer.cs +++ b/GitUI/CommandsDialogs/FormBrowse.Designer.cs @@ -245,6 +245,7 @@ private void InitializeComponent() // this.ToolStripMain.ClickThrough = true; this.ToolStripMain.Dock = System.Windows.Forms.DockStyle.None; + this.ToolStripMain.DrawBorder = false; this.ToolStripMain.GripMargin = new System.Windows.Forms.Padding(0); this.ToolStripMain.GripStyle = ToolStripGripStyle.Hidden; this.ToolStripMain.ImeMode = System.Windows.Forms.ImeMode.NoControl; @@ -279,6 +280,7 @@ private void InitializeComponent() // this.ToolStripFilters.ClickThrough = true; this.ToolStripFilters.Dock = System.Windows.Forms.DockStyle.None; + this.ToolStripFilters.DrawBorder = false; this.ToolStripFilters.GripMargin = new System.Windows.Forms.Padding(0); this.ToolStripFilters.GripStyle = ToolStripGripStyle.Hidden; this.ToolStripFilters.ImeMode = System.Windows.Forms.ImeMode.NoControl; @@ -1786,6 +1788,7 @@ private void InitializeComponent() // this.ToolStripScripts.ClickThrough = true; this.ToolStripScripts.Dock = System.Windows.Forms.DockStyle.None; + this.ToolStripScripts.DrawBorder = false; this.ToolStripScripts.GripMargin = new System.Windows.Forms.Padding(0); this.ToolStripScripts.GripStyle = ToolStripGripStyle.Hidden; this.ToolStripScripts.ImeMode = System.Windows.Forms.ImeMode.NoControl; diff --git a/GitUI/CommandsDialogs/FormCommit.Designer.cs b/GitUI/CommandsDialogs/FormCommit.Designer.cs index d43690d044a..97c7d7f5b64 100644 --- a/GitUI/CommandsDialogs/FormCommit.Designer.cs +++ b/GitUI/CommandsDialogs/FormCommit.Designer.cs @@ -698,6 +698,7 @@ private void InitializeComponent() this.toolbarUnstaged.BackColor = System.Drawing.SystemColors.Control; this.toolbarUnstaged.ClickThrough = true; this.toolbarUnstaged.Dock = System.Windows.Forms.DockStyle.None; + this.toolbarUnstaged.DrawBorder = false; this.toolbarUnstaged.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolbarUnstaged.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolRefreshItem, @@ -870,6 +871,7 @@ private void InitializeComponent() // this.toolbarSelectionFilter.ClickThrough = true; this.toolbarSelectionFilter.Dock = System.Windows.Forms.DockStyle.None; + this.toolbarSelectionFilter.DrawBorder = false; this.toolbarSelectionFilter.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripLabel1, this.selectionFilter}); @@ -924,6 +926,7 @@ private void InitializeComponent() this.toolbarStaged.AutoSize = false; this.toolbarStaged.BackColor = System.Drawing.SystemColors.Control; this.toolbarStaged.ClickThrough = true; + this.toolbarStaged.DrawBorder = false; this.toolbarStaged.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolbarStaged.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStageAllItem, @@ -1187,6 +1190,7 @@ private void InitializeComponent() this.toolbarCommit.AutoSize = false; this.toolbarCommit.BackColor = System.Drawing.SystemColors.Control; this.toolbarCommit.ClickThrough = true; + this.toolbarCommit.DrawBorder = false; this.toolbarCommit.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolbarCommit.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.commitMessageToolStripMenuItem, diff --git a/GitUI/CommandsDialogs/FormEditor.Designer.cs b/GitUI/CommandsDialogs/FormEditor.Designer.cs index 9748781e90c..21455cdd611 100644 --- a/GitUI/CommandsDialogs/FormEditor.Designer.cs +++ b/GitUI/CommandsDialogs/FormEditor.Designer.cs @@ -108,6 +108,7 @@ private void InitializeComponent() // toolStrip1 // this.toolStrip1.ClickThrough = true; + this.toolStrip1.DrawBorder = false; this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripSaveButton}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); @@ -165,4 +166,4 @@ private void InitializeComponent() private System.Windows.Forms.Label label1; private System.Windows.Forms.Label labelWarning; } -} \ No newline at end of file +} diff --git a/GitUI/CommandsDialogs/FormFileHistory.Designer.cs b/GitUI/CommandsDialogs/FormFileHistory.Designer.cs index 2ae559ca424..b320d267c71 100644 --- a/GitUI/CommandsDialogs/FormFileHistory.Designer.cs +++ b/GitUI/CommandsDialogs/FormFileHistory.Designer.cs @@ -38,7 +38,7 @@ private void InitializeComponent() this.View = new GitUI.Editor.FileViewer(); this.BlameTab = new System.Windows.Forms.TabPage(); this.Blame = new GitUI.Blame.BlameControl(); - this.ToolStrip = new System.Windows.Forms.ToolStrip(); + this.ToolStrip = new GitUI.ToolStripEx(); this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel(); this.toolStripBranchFilterComboBox = new System.Windows.Forms.ToolStripComboBox(); this.toolStripBranchFilterDropDownButton = new System.Windows.Forms.ToolStripDropDownButton(); @@ -645,7 +645,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem cherryPickThisCommitToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem revertCommitToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStrip ToolStrip; + private GitUI.ToolStripEx ToolStrip; private System.Windows.Forms.ToolStripLabel toolStripLabel1; private System.Windows.Forms.ToolStripComboBox toolStripBranchFilterComboBox; private System.Windows.Forms.ToolStripDropDownButton toolStripBranchFilterDropDownButton; diff --git a/GitUI/CommandsDialogs/FormStash.Designer.cs b/GitUI/CommandsDialogs/FormStash.Designer.cs index 277247a1d9c..251014615b1 100644 --- a/GitUI/CommandsDialogs/FormStash.Designer.cs +++ b/GitUI/CommandsDialogs/FormStash.Designer.cs @@ -295,6 +295,7 @@ private void InitializeComponent() this.toolStrip1.BackColor = System.Drawing.SystemColors.Control; this.toolStrip1.ClickThrough = true; this.toolStrip1.Dock = System.Windows.Forms.DockStyle.Fill; + this.toolStrip1.DrawBorder = false; this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.showToolStripLabel, @@ -432,4 +433,4 @@ private void InitializeComponent() private ContextMenuStrip contextMenuStripStashedFiles; private ToolStripMenuItem cherryPickFileChangesToolStripMenuItem; } -} \ No newline at end of file +} diff --git a/GitUI/CommandsDialogs/SettingsDialog/Pages/RevisionLinksSettingsPage.Designer.cs b/GitUI/CommandsDialogs/SettingsDialog/Pages/RevisionLinksSettingsPage.Designer.cs index 5336de0ee57..5288c6fa440 100644 --- a/GitUI/CommandsDialogs/SettingsDialog/Pages/RevisionLinksSettingsPage.Designer.cs +++ b/GitUI/CommandsDialogs/SettingsDialog/Pages/RevisionLinksSettingsPage.Designer.cs @@ -30,7 +30,7 @@ private void InitializeComponent() { this.splitContainer1 = new System.Windows.Forms.SplitContainer(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.toolStripManageCategories = new System.Windows.Forms.ToolStrip(); + this.toolStripManageCategories = new GitUI.ToolStripEx(); this.Add = new System.Windows.Forms.ToolStripSplitButton(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.Remove = new System.Windows.Forms.ToolStripButton(); @@ -721,7 +721,7 @@ private void InitializeComponent() private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4; private System.Windows.Forms.TextBox _NO_TRANSLATE_UseRemotes; private System.Windows.Forms.CheckBox chkOnlyFirstRemote; - private System.Windows.Forms.ToolStrip toolStripManageCategories; + private GitUI.ToolStripEx toolStripManageCategories; private System.Windows.Forms.ToolStripSplitButton Add; private System.Windows.Forms.ToolStripButton Remove; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; diff --git a/GitUI/Editor/FileViewer.Designer.cs b/GitUI/Editor/FileViewer.Designer.cs index 4f872d496d6..7119102831b 100644 --- a/GitUI/Editor/FileViewer.Designer.cs +++ b/GitUI/Editor/FileViewer.Designer.cs @@ -1,5 +1,4 @@ -using System; -using System.Windows.Forms; +using System.Windows.Forms; namespace GitUI.Editor { @@ -240,6 +239,7 @@ private void InitializeComponent() this.fileviewerToolbar.BackColor = System.Drawing.SystemColors.Control; this.fileviewerToolbar.ClickThrough = true; this.fileviewerToolbar.Dock = System.Windows.Forms.DockStyle.None; + this.fileviewerToolbar.DrawBorder = false; this.fileviewerToolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.nextChangeButton, this.previousChangeButton, diff --git a/GitUI/UserControls/MenuStripEx.cs b/GitUI/UserControls/MenuStripEx.cs index eac5c574a1a..fd9213957bb 100644 --- a/GitUI/UserControls/MenuStripEx.cs +++ b/GitUI/UserControls/MenuStripEx.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Windows.Forms; namespace GitUI @@ -15,7 +16,9 @@ public class MenuStripEx : MenuStrip /// /// Default value is false, which is the same behavior provided by the base ToolStrip class. /// - public bool ClickThrough { get; set; } = true; + [Category("Behavior")] + [DefaultValue(false)] + public bool ClickThrough { get; set; } protected override void WndProc(ref Message m) { diff --git a/GitUI/UserControls/RevisionGrid/MenuUtil.cs b/GitUI/UserControls/RevisionGrid/MenuUtil.cs index 1eba241c33b..31d1c2a003c 100644 --- a/GitUI/UserControls/RevisionGrid/MenuUtil.cs +++ b/GitUI/UserControls/RevisionGrid/MenuUtil.cs @@ -1,12 +1,13 @@ using System.Drawing; using System.Windows.Forms; +using GitExtUtils.GitUI; namespace GitUI.UserControls.RevisionGrid { internal static class MenuUtil { private static readonly object _captionTag = new(); - private static readonly CaptionCustomMenuRenderer _customMenuRenderer = new(); + private static readonly MenuItemBackgroundFilter _menuItemBackgroundFilter = new(); private static Font? _disabledFont; /// @@ -14,7 +15,7 @@ internal static class MenuUtil /// public static void SetAsCaptionMenuItem(ToolStripMenuItem menuItem, ToolStrip menu) { - menu.Renderer = _customMenuRenderer; + menu.AttachMenuItemBackgroundFilter(_menuItemBackgroundFilter); menuItem.Tag = _captionTag; menuItem.Enabled = false; @@ -30,15 +31,12 @@ public static void SetAsCaptionMenuItem(ToolStripMenuItem menuItem, ToolStrip me /// /// no mouse over effect for disabled menu items, if the Tag is "caption" /// - private sealed class CaptionCustomMenuRenderer : ToolStripProfessionalRenderer + private sealed class MenuItemBackgroundFilter : IMenuItemBackgroundFilter { - protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) + public bool ShouldRenderMenuItemBackground(ToolStripItemRenderEventArgs e) { // Only render the background for non-caption menu items - if (!ReferenceEquals(e.Item.Tag, _captionTag)) - { - base.OnRenderMenuItemBackground(e); - } + return !ReferenceEquals(e.Item.Tag, _captionTag); } } } diff --git a/GitUI/UserControls/ToolStripEx.cs b/GitUI/UserControls/ToolStripEx.cs index 4f8450887a5..17d4b34d2d1 100644 --- a/GitUI/UserControls/ToolStripEx.cs +++ b/GitUI/UserControls/ToolStripEx.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Windows.Forms; namespace GitUI @@ -6,7 +7,7 @@ namespace GitUI /// /// This class adds on to the functionality provided in System.Windows.Forms.ToolStrip. /// - public class ToolStripEx : ToolStrip + public class ToolStripEx : ToolStrip, IToolStripEx { /// /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does @@ -15,11 +16,18 @@ public class ToolStripEx : ToolStrip /// /// Default value is false, which is the same behavior provided by the base ToolStrip class. /// - public bool ClickThrough { get; set; } = true; + [Category("Behavior")] + [DefaultValue(false)] + public bool ClickThrough { get; set; } + + /// + [Category("Appearance")] + [DefaultValue(true)] + public bool DrawBorder { get; set; } = true; public ToolStripEx() { - Renderer = new BorderlessToolStripRenderer(); + this.UseCustomRenderer(); } protected override void WndProc(ref Message m) @@ -33,21 +41,5 @@ protected override void WndProc(ref Message m) m.Result = (IntPtr)NativeMethods.MA_ACTIVATE; } } - - private sealed class BorderlessToolStripRenderer : ToolStripSystemRenderer - { - protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) - { - if (e.ToolStrip.GetType() == typeof(ToolStripEx)) - { - // skip border - } - else - { - // render border - base.OnRenderToolStripBorder(e); - } - } - } } }