Skip to content

Commit

Permalink
Merge pull request #135 from ahmetsait/opaque-colors
Browse files Browse the repository at this point in the history
Fix #133: Scintilla misbehaves when it receives transparent colors via APIs that don't support alpha channel
  • Loading branch information
desjarlais authored Jul 29, 2024
2 parents 01e3c49 + 0325b32 commit 0cb6cfb
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 30 deletions.
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

0 comments on commit 0cb6cfb

Please sign in to comment.