From 0325b32beb19735b7ffc4984259848f937b28ed5 Mon Sep 17 00:00:00 2001 From: Ahmet Sait Date: Mon, 29 Jul 2024 16:20:28 +0300 Subject: [PATCH] Fix #133: Scintilla misbehaves when it receives transparent colors via APIs that don't support alpha channel --- Scintilla.NET/HelperMethods.cs | 42 ++++++++++++++++++++++++++++------ Scintilla.NET/Indicator.cs | 8 +++---- Scintilla.NET/Margin.cs | 4 ++-- Scintilla.NET/Scintilla.cs | 26 ++++++++++----------- Scintilla.NET/Style.cs | 8 +++---- 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/Scintilla.NET/HelperMethods.cs b/Scintilla.NET/HelperMethods.cs index 3433d7c..d1d3eb7 100644 --- a/Scintilla.NET/HelperMethods.cs +++ b/Scintilla.NET/HelperMethods.cs @@ -22,18 +22,18 @@ static HelperMethods() } /// - /// Converts a 32-bit WinAPI color to . + /// Converts an ABGR WinAPI color to . /// /// The color value to convert. - /// A equivalent of the 32-bit WinAPI color. + /// A equivalent of the ABGR WinAPI color. public static Color FromWin32Color(int color) { - if (color == 0) + if ((color & 0xFF_00_00_00) == 0) return Color.Transparent; if (knownColorMap.TryGetValue(color, out Color result)) - // We do all this nonsense because because Visual Studio designer - // does not mark raw colors as default if there exists a known color + // We do all this nonsense because Visual Studio designer does not + // mark raw colors as default if there exists a known color // with the same value. return result; @@ -41,15 +41,43 @@ public static Color FromWin32Color(int color) } /// - /// Converts a to 32-bit WinAPI color. + /// Converts a to ABGR WinAPI color. /// /// The instance to convert. - /// 32-bit WinAPI color value of the instance. + /// ABGR WinAPI color value of the instance. public static int ToWin32Color(Color color) { return (color.A << 24) | (color.R << 0) | (color.G << 8) | (color.B << 16); } + /// + /// Converts an ABGR WinAPI color to while ignoring the alpha channel. + /// + /// The color value to convert. + /// A equivalent of the ABGR WinAPI color with alpha channel value set to max (opaque). + public static Color FromWin32ColorOpaque(int color) + { + color |= unchecked((int)0xFF_00_00_00); + + if (knownColorMap.TryGetValue(color, out Color result)) + // We do all this nonsense because Visual Studio designer does not + // mark raw colors as default if there exists a known color + // with the same value. + return result; + + return Color.FromArgb((color >> 0) & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF); + } + + /// + /// Converts a to ABGR WinAPI color while ignoring the alpha channel. + /// + /// The instance to convert. + /// ABGR WinAPI color value of the instance with alpha channel value set to max (opaque). + public static int ToWin32ColorOpaque(Color color) + { + return (0xFF << 24) | (color.R << 0) | (color.G << 8) | (color.B << 16); + } + /// /// Gets the folding state of the control as a delimited string containing line indexes. /// diff --git a/Scintilla.NET/Indicator.cs b/Scintilla.NET/Indicator.cs index d8b1c6f..1dc8857 100644 --- a/Scintilla.NET/Indicator.cs +++ b/Scintilla.NET/Indicator.cs @@ -137,11 +137,11 @@ public Color ForeColor get { int color = this.scintilla.DirectMessage(NativeMethods.SCI_INDICGETFORE, new IntPtr(Index)).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); this.scintilla.DirectMessage(NativeMethods.SCI_INDICSETFORE, new IntPtr(Index), new IntPtr(color)); } } @@ -160,11 +160,11 @@ public Color HoverForeColor get { int color = this.scintilla.DirectMessage(NativeMethods.SCI_INDICGETHOVERFORE, new IntPtr(Index)).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); this.scintilla.DirectMessage(NativeMethods.SCI_INDICSETHOVERFORE, new IntPtr(Index), new IntPtr(color)); } } diff --git a/Scintilla.NET/Margin.cs b/Scintilla.NET/Margin.cs index 4a2067f..1e591f9 100644 --- a/Scintilla.NET/Margin.cs +++ b/Scintilla.NET/Margin.cs @@ -26,14 +26,14 @@ public Color BackColor get { int color = this.scintilla.DirectMessage(NativeMethods.SCI_GETMARGINBACKN, new IntPtr(Index)).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { if (value.IsEmpty) value = Color.Black; - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); this.scintilla.DirectMessage(NativeMethods.SCI_SETMARGINBACKN, new IntPtr(Index), new IntPtr(color)); } } diff --git a/Scintilla.NET/Scintilla.cs b/Scintilla.NET/Scintilla.cs index 73436ec..42982ce 100644 --- a/Scintilla.NET/Scintilla.cs +++ b/Scintilla.NET/Scintilla.cs @@ -487,7 +487,7 @@ public void CallTipCancel() /// The new highlight text Color. The default is dark blue. public void CallTipSetForeHlt(Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); DirectMessage(NativeMethods.SCI_CALLTIPSETFOREHLT, new IntPtr(colour)); } @@ -1774,7 +1774,7 @@ public int MarkerLineFromHandle(MarkerHandle markerHandle) public void MultiEdgeAddLine(int column, Color edgeColor) { column = Helpers.ClampMin(column, 0); - int colour = HelperMethods.ToWin32Color(edgeColor); + int colour = HelperMethods.ToWin32ColorOpaque(edgeColor); DirectMessage(NativeMethods.SCI_MULTIEDGEADDLINE, new IntPtr(column), new IntPtr(colour)); } @@ -2569,7 +2569,7 @@ public void SelectAll() [Obsolete("Superseded by SelectionAdditionalBackColor property.")] public void SetAdditionalSelBack(Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); DirectMessage(NativeMethods.SCI_SETADDITIONALSELBACK, new IntPtr(colour)); } @@ -2581,7 +2581,7 @@ public void SetAdditionalSelBack(Color color) [Obsolete("Superseded by SelectionAdditionalTextColor property.")] public void SetAdditionalSelFore(Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); DirectMessage(NativeMethods.SCI_SETADDITIONALSELFORE, new IntPtr(colour)); } @@ -2614,7 +2614,7 @@ public void SetFoldFlags(FoldFlags flags) /// public void SetFoldMarginColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useFoldMarginColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETFOLDMARGINCOLOUR, useFoldMarginColour, new IntPtr(colour)); @@ -2628,7 +2628,7 @@ public void SetFoldMarginColor(bool use, Color color) /// public void SetFoldMarginHighlightColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useFoldMarginHighlightColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETFOLDMARGINHICOLOUR, useFoldMarginHighlightColour, new IntPtr(colour)); @@ -2799,7 +2799,7 @@ public void SetSelection(int caret, int anchor) [Obsolete("Superseded by SelectionBackColor property.")] public void SetSelectionBackColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useSelectionForeColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETSELBACK, useSelectionForeColour, new IntPtr(colour)); @@ -2814,7 +2814,7 @@ public void SetSelectionBackColor(bool use, Color color) [Obsolete("Superseded by SelectionTextColor property.")] public void SetSelectionForeColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useSelectionForeColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETSELFORE, useSelectionForeColour, new IntPtr(colour)); @@ -2904,7 +2904,7 @@ public void SetTargetRange(int start, int end) [Obsolete("Superseded by WhitespaceBackColor property.")] public void SetWhitespaceBackColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useWhitespaceBackColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETWHITESPACEBACK, useWhitespaceBackColour, new IntPtr(colour)); @@ -2921,7 +2921,7 @@ public void SetWhitespaceBackColor(bool use, Color color) [Obsolete("Superseded by WhitespaceTextColor property.")] public void SetWhitespaceForeColor(bool use, Color color) { - int colour = HelperMethods.ToWin32Color(color); + int colour = HelperMethods.ToWin32ColorOpaque(color); IntPtr useWhitespaceForeColour = use ? new IntPtr(1) : IntPtr.Zero; DirectMessage(NativeMethods.SCI_SETWHITESPACEFORE, useWhitespaceForeColour, new IntPtr(colour)); @@ -4717,7 +4717,7 @@ public Document Document /// . /// /// The background Color. - [DefaultValue(typeof(Color), "0, 192, 192, 192")] + [DefaultValue(typeof(Color), "Silver")] [Category("Long Lines")] [Description("The background color to use when indicating long lines.")] public Color EdgeColor @@ -4725,11 +4725,11 @@ public Color EdgeColor get { int color = DirectMessage(NativeMethods.SCI_GETEDGECOLOUR).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); DirectMessage(NativeMethods.SCI_SETEDGECOLOUR, new IntPtr(color)); } } diff --git a/Scintilla.NET/Style.cs b/Scintilla.NET/Style.cs index 64ad2f3..6f27f8c 100644 --- a/Scintilla.NET/Style.cs +++ b/Scintilla.NET/Style.cs @@ -98,14 +98,14 @@ public Color BackColor get { int color = this.scintilla.DirectMessage(NativeMethods.SCI_STYLEGETBACK, new IntPtr(Index), IntPtr.Zero).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { if (value.IsEmpty) value = Color.White; - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); this.scintilla.DirectMessage(NativeMethods.SCI_STYLESETBACK, new IntPtr(Index), new IntPtr(color)); } } @@ -231,14 +231,14 @@ public Color ForeColor get { int color = this.scintilla.DirectMessage(NativeMethods.SCI_STYLEGETFORE, new IntPtr(Index), IntPtr.Zero).ToInt32(); - return HelperMethods.FromWin32Color(color); + return HelperMethods.FromWin32ColorOpaque(color); } set { if (value.IsEmpty) value = Color.Black; - int color = HelperMethods.ToWin32Color(value); + int color = HelperMethods.ToWin32ColorOpaque(value); this.scintilla.DirectMessage(NativeMethods.SCI_STYLESETFORE, new IntPtr(Index), new IntPtr(color)); } }