Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #133: Scintilla misbehaves when it receives transparent colors via APIs that don't support alpha channel #135

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions Scintilla.NET/HelperMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,62 @@ static HelperMethods()
}

/// <summary>
/// Converts a 32-bit WinAPI color to <see cref="Color"/>.
/// Converts an ABGR WinAPI color to <see cref="Color"/>.
/// </summary>
/// <param name="color">The color value to convert.</param>
/// <returns>A <see cref="Color"/> equivalent of the 32-bit WinAPI color.</returns>
/// <returns>A <see cref="Color"/> equivalent of the ABGR WinAPI color.</returns>
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;

return Color.FromArgb((color >> 24) & 0xFF, (color >> 0) & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);
}

/// <summary>
/// Converts a <see cref="Color"/> to 32-bit WinAPI color.
/// Converts a <see cref="Color"/> to ABGR WinAPI color.
/// </summary>
/// <param name="color">The <see cref="Color"/> instance to convert.</param>
/// <returns>32-bit WinAPI color value of the <see cref="Color"/> instance.</returns>
/// <returns>ABGR WinAPI color value of the <see cref="Color"/> instance.</returns>
public static int ToWin32Color(Color color)
{
return (color.A << 24) | (color.R << 0) | (color.G << 8) | (color.B << 16);
}

/// <summary>
/// Converts an ABGR WinAPI color to <see cref="Color"/> while ignoring the alpha channel.
/// </summary>
/// <param name="color">The color value to convert.</param>
/// <returns>A <see cref="Color"/> equivalent of the ABGR WinAPI color with alpha channel value set to max (opaque).</returns>
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);
}

/// <summary>
/// Converts a <see cref="Color"/> to ABGR WinAPI color while ignoring the alpha channel.
/// </summary>
/// <param name="color">The <see cref="Color"/> instance to convert.</param>
/// <returns>ABGR WinAPI color value of the <see cref="Color"/> instance with alpha channel value set to max (opaque).</returns>
public static int ToWin32ColorOpaque(Color color)
{
return (0xFF << 24) | (color.R << 0) | (color.G << 8) | (color.B << 16);
}

/// <summary>
/// Gets the folding state of the control as a delimited string containing line indexes.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions Scintilla.NET/Indicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Expand All @@ -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));
}
}
Expand Down
4 changes: 2 additions & 2 deletions Scintilla.NET/Margin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Expand Down
26 changes: 13 additions & 13 deletions Scintilla.NET/Scintilla.cs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ public void CallTipCancel()
/// <param name="color">The new highlight text Color. The default is dark blue.</param>
public void CallTipSetForeHlt(Color color)
{
int colour = HelperMethods.ToWin32Color(color);
int colour = HelperMethods.ToWin32ColorOpaque(color);
DirectMessage(NativeMethods.SCI_CALLTIPSETFOREHLT, new IntPtr(colour));
}

Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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));
}

Expand All @@ -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));
}

Expand Down Expand Up @@ -2614,7 +2614,7 @@ public void SetFoldFlags(FoldFlags flags)
/// <seealso cref="SetFoldMarginHighlightColor" />
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));
Expand All @@ -2628,7 +2628,7 @@ public void SetFoldMarginColor(bool use, Color color)
/// <seealso cref="SetFoldMarginColor" />
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));
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -4717,19 +4717,19 @@ public Document Document
/// <see cref="ScintillaNET.EdgeMode.Background" />.
/// </summary>
/// <returns>The background Color.</returns>
[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
{
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));
}
}
Expand Down
8 changes: 4 additions & 4 deletions Scintilla.NET/Style.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Expand Down Expand Up @@ -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));
}
}
Expand Down
Loading