Skip to content

Commit d0bd680

Browse files
committed
Added color replacement
1 parent 6913438 commit d0bd680

File tree

11 files changed

+226
-73
lines changed

11 files changed

+226
-73
lines changed

src/Colorful.Console.Tests/ColorStoreTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public sealed class ColorStoreTests
1818
public static ColorStore GetColorStore()
1919
{
2020
ColorStore colorStore = new ColorStore(new ConcurrentDictionary<Color, ConsoleColor>(), new ConcurrentDictionary<ConsoleColor, Color>());
21-
colorStore.Update(TEST_COLOR, TEST_CONSOLE_COLOR);
21+
colorStore.Update(TEST_CONSOLE_COLOR, TEST_COLOR);
2222

2323
return colorStore;
2424
}
@@ -27,7 +27,7 @@ public static ColorStore GetColorStore()
2727
public void RequiresUpdate_ReturnsFalse_IfColorStoreContainsColor()
2828
{
2929
ColorStore colorStore = GetColorStore();
30-
30+
3131
bool requiresUpdate = colorStore.RequiresUpdate(TEST_COLOR);
3232

3333
Assert.False(requiresUpdate);

src/Colorful.Console/COLORREF.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using System.Runtime.InteropServices;
6+
using System.Drawing;
7+
8+
namespace Colorful
9+
{
10+
/// <summary>
11+
/// A Win32 COLORREF, used to specify an RGB color. See MSDN for more information:
12+
/// https://msdn.microsoft.com/en-us/library/windows/desktop/dd183449(v=vs.85).aspx
13+
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
15+
public struct COLORREF
16+
{
17+
private uint ColorDWORD;
18+
19+
internal COLORREF(Color color)
20+
{
21+
ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
22+
}
23+
24+
internal COLORREF(uint r, uint g, uint b)
25+
{
26+
ColorDWORD = r + (g << 8) + (b << 16);
27+
}
28+
29+
public override string ToString()
30+
{
31+
return ColorDWORD.ToString();
32+
}
33+
}
34+
}

src/Colorful.Console/ColorExtensions.cs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
namespace Colorful
2-
{
3-
using System;
4-
using System.Drawing;
1+
using System;
2+
using System.Drawing;
53

4+
namespace Colorful
5+
{
66
/// <summary>
77
/// <see cref="Color"/> extension methods.
88
/// </summary>
@@ -20,14 +20,9 @@ public static ConsoleColor ToNearestConsoleColor(this Color color)
2020
foreach (ConsoleColor consoleColor in Enum.GetValues(typeof(ConsoleColor)))
2121
{
2222
string consoleColorName = Enum.GetName(typeof(ConsoleColor), consoleColor);
23-
consoleColorName = string.Equals(consoleColorName, nameof(ConsoleColor.DarkYellow), StringComparison.Ordinal) ?
24-
nameof(Color.Orange) :
25-
consoleColorName;
23+
consoleColorName = string.Equals(consoleColorName, nameof(ConsoleColor.DarkYellow), StringComparison.Ordinal) ? nameof(Color.Orange) : consoleColorName;
2624
Color rgbColor = Color.FromName(consoleColorName);
27-
double sum =
28-
Math.Pow(rgbColor.R - color.R, 2.0) +
29-
Math.Pow(rgbColor.G - color.G, 2.0) +
30-
Math.Pow(rgbColor.B - color.B, 2.0);
25+
double sum = Math.Pow(rgbColor.R - color.R, 2.0) + Math.Pow(rgbColor.G - color.G, 2.0) + Math.Pow(rgbColor.B - color.B, 2.0);
3126

3227
if (sum == 0.0)
3328
{

src/Colorful.Console/ColorManager.cs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ public Color GetColor(ConsoleColor color)
4747
return colorStore.ConsoleColors[color];
4848
}
4949

50+
/// <summary>
51+
/// Replaces one System.Drawing.Color in the ColorManager with another.
52+
/// </summary>
53+
/// <param name="oldColor">The color to be replaced.</param>
54+
/// <param name="newColor">The replacement color.</param>
55+
public void ReplaceColor(Color oldColor, Color newColor)
56+
{
57+
ConsoleColor consoleColor = colorStore.Replace(oldColor, newColor);
58+
colorMapper.MapColor(consoleColor, newColor);
59+
}
60+
5061
/// <summary>
5162
/// Gets the ConsoleColor mapped to the System.Drawing.Color provided as an argument.
5263
/// </summary>
@@ -79,24 +90,24 @@ public ConsoleColor GetConsoleColor(Color color)
7990

8091
private ConsoleColor GetConsoleColorNative(Color color)
8192
{
82-
if (!CanChangeColor())
83-
{
84-
return colorStore.Colors.Last().Value;
85-
}
86-
else
93+
if (CanChangeColor() && colorStore.RequiresUpdate(color))
8794
{
88-
if (colorStore.RequiresUpdate(color))
89-
{
90-
ConsoleColor oldColor = (ConsoleColor)colorChangeCount;
95+
ConsoleColor oldColor = (ConsoleColor)colorChangeCount;
9196

92-
colorMapper.MapColor(oldColor, color);
93-
colorStore.Update(color, oldColor);
97+
colorMapper.MapColor(oldColor, color);
98+
colorStore.Update(oldColor, color);
9499

95-
colorChangeCount++;
96-
}
100+
colorChangeCount++;
101+
}
97102

103+
if (colorStore.Colors.ContainsKey(color))
104+
{
98105
return colorStore.Colors[color];
99106
}
107+
else
108+
{
109+
return colorStore.Colors.Last().Value;
110+
}
100111
}
101112

102113
private bool CanChangeColor()

src/Colorful.Console/ColorMapper.cs

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Drawing;
33
using System.Runtime.InteropServices;
4+
using System.Collections.Generic;
45

56
namespace Colorful
67
{
@@ -26,22 +27,6 @@ private struct SMALL_RECT
2627
internal short Bottom;
2728
}
2829

29-
[StructLayout(LayoutKind.Sequential)]
30-
private struct COLORREF
31-
{
32-
private uint ColorDWORD;
33-
34-
internal COLORREF(Color color)
35-
{
36-
ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
37-
}
38-
39-
internal COLORREF(uint r, uint g, uint b)
40-
{
41-
ColorDWORD = r + (g << 8) + (b << 16);
42-
}
43-
}
44-
4530
[StructLayout(LayoutKind.Sequential)]
4631
private struct CONSOLE_SCREEN_BUFFER_INFO_EX
4732
{
@@ -71,7 +56,7 @@ private struct CONSOLE_SCREEN_BUFFER_INFO_EX
7156
internal COLORREF white;
7257
}
7358

74-
const int STD_OUTPUT_HANDLE = -11; // per WinBase.h
59+
private const int STD_OUTPUT_HANDLE = -11; // per WinBase.h
7560
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // per WinBase.h
7661

7762
[DllImport("kernel32.dll", SetLastError = true)]
@@ -94,23 +79,92 @@ public void MapColor(ConsoleColor oldColor, Color newColor)
9479
MapColor(oldColor, newColor.R, newColor.G, newColor.B);
9580
}
9681

97-
private void MapColor(ConsoleColor color, uint r, uint g, uint b)
82+
/// <summary>
83+
/// Gets a collection of all 16 colors in the console buffer.
84+
/// </summary>
85+
/// <returns>Returns all 16 COLORREFs in the console buffer as a dictionary keyed by the COLORREF's alias
86+
/// in the buffer's ColorTable.</returns>
87+
public Dictionary<string, COLORREF> GetBufferColors()
88+
{
89+
Dictionary<string, COLORREF> colors = new Dictionary<string, COLORREF>();
90+
IntPtr hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 7
91+
CONSOLE_SCREEN_BUFFER_INFO_EX csbe = GetBufferInfo(hConsoleOutput);
92+
93+
colors.Add("black", csbe.black);
94+
colors.Add("darkBlue", csbe.darkBlue);
95+
colors.Add("darkGreen", csbe.darkGreen);
96+
colors.Add("darkCyan", csbe.darkCyan);
97+
colors.Add("darkRed", csbe.darkRed);
98+
colors.Add("darkMagenta", csbe.darkMagenta);
99+
colors.Add("darkYellow", csbe.darkYellow);
100+
colors.Add("gray", csbe.gray);
101+
colors.Add("darkGray", csbe.darkGray);
102+
colors.Add("blue", csbe.blue);
103+
colors.Add("green", csbe.green);
104+
colors.Add("cyan", csbe.cyan);
105+
colors.Add("red", csbe.red);
106+
colors.Add("magenta", csbe.magenta);
107+
colors.Add("yellow", csbe.yellow);
108+
colors.Add("white", csbe.white);
109+
110+
return colors;
111+
}
112+
113+
/// <summary>
114+
/// Sets all 16 colors in the console buffer using colors supplied in a dictionary.
115+
/// </summary>
116+
/// <param name="colors">A dictionary containing COLORREFs keyed by the COLORREF's alias in the buffer's
117+
/// ColorTable.</param>
118+
public void SetBatchBufferColors(Dictionary<string, COLORREF> colors)
119+
{
120+
IntPtr hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 7
121+
CONSOLE_SCREEN_BUFFER_INFO_EX csbe = GetBufferInfo(hConsoleOutput);
122+
123+
csbe.black = colors["black"];
124+
csbe.darkBlue = colors["darkBlue"];
125+
csbe.darkGreen = colors["darkGreen"];
126+
csbe.darkCyan = colors["darkCyan"];
127+
csbe.darkRed = colors["darkRed"];
128+
csbe.darkMagenta = colors["darkMagenta"];
129+
csbe.darkYellow = colors["darkYellow"];
130+
csbe.gray = colors["gray"];
131+
csbe.darkGray = colors["darkGray"];
132+
csbe.blue = colors["blue"];
133+
csbe.green = colors["green"];
134+
csbe.cyan = colors["cyan"];
135+
csbe.red = colors["red"];
136+
csbe.magenta = colors["magenta"];
137+
csbe.yellow = colors["yellow"];
138+
csbe.white = colors["white"];
139+
140+
SetBufferInfo(hConsoleOutput, csbe);
141+
}
142+
143+
private CONSOLE_SCREEN_BUFFER_INFO_EX GetBufferInfo(IntPtr hConsoleOutput)
98144
{
99145
CONSOLE_SCREEN_BUFFER_INFO_EX csbe = new CONSOLE_SCREEN_BUFFER_INFO_EX();
100146
csbe.cbSize = (int)Marshal.SizeOf(csbe); // 96 = 0x60
101147

102-
IntPtr hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 7
103148
if (hConsoleOutput == INVALID_HANDLE_VALUE)
104149
{
105150
throw new ColorMappingException(Marshal.GetLastWin32Error());
106151
}
107152

108153
bool brc = GetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe);
154+
109155
if (!brc)
110156
{
111157
throw new ColorMappingException(Marshal.GetLastWin32Error());
112158
}
113159

160+
return csbe;
161+
}
162+
163+
private void MapColor(ConsoleColor color, uint r, uint g, uint b)
164+
{
165+
IntPtr hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 7
166+
CONSOLE_SCREEN_BUFFER_INFO_EX csbe = GetBufferInfo(hConsoleOutput);
167+
114168
switch (color)
115169
{
116170
case ConsoleColor.Black:
@@ -163,10 +217,15 @@ private void MapColor(ConsoleColor color, uint r, uint g, uint b)
163217
break;
164218
}
165219

220+
SetBufferInfo(hConsoleOutput, csbe);
221+
}
222+
223+
private void SetBufferInfo(IntPtr hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO_EX csbe)
224+
{
166225
csbe.srWindow.Bottom++;
167226
csbe.srWindow.Right++;
168227

169-
brc = SetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe);
228+
bool brc = SetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe);
170229
if (!brc)
171230
{
172231
throw new ColorMappingException(Marshal.GetLastWin32Error());

src/Colorful.Console/ColorStore.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,36 @@ public ColorStore(ConcurrentDictionary<Color, ConsoleColor> colorMap, Concurrent
3838
/// <summary>
3939
/// Adds a new System.Drawing.Color to the ColorStore.
4040
/// </summary>
41-
/// <param name="newColor">The System.Drawing.Color to be added to the ColorStore.</param>
4241
/// <param name="oldColor">The ConsoleColor to be replaced by the new System.Drawing.Color.</param>
43-
public void Update(Color newColor, ConsoleColor oldColor)
42+
/// <param name="newColor">The System.Drawing.Color to be added to the ColorStore.</param>
43+
public void Update(ConsoleColor oldColor, Color newColor)
4444
{
4545
Colors.TryAdd(newColor, oldColor);
4646
ConsoleColors[oldColor] = newColor;
4747
}
4848

49+
/// <summary>
50+
/// Replaces one System.Drawing.Color in the ColorStore with another.
51+
/// </summary>
52+
/// <param name="oldColor">The color to be replaced.</param>
53+
/// <param name="newColor">The replacement color.</param>
54+
/// <returns>The ConsoleColor key of the System.Drawing.Color object that was replaced in the ColorStore.</returns>
55+
public ConsoleColor Replace(Color oldColor, Color newColor)
56+
{
57+
ConsoleColor consoleColorKey;
58+
bool oldColorExistedInColorStore = Colors.TryRemove(oldColor, out consoleColorKey);
59+
60+
if (!oldColorExistedInColorStore)
61+
{
62+
throw new ArgumentException("An attempt was made to replace a nonexistent color in the ColorStore!");
63+
}
64+
65+
Colors.TryAdd(newColor, consoleColorKey);
66+
ConsoleColors[consoleColorKey] = newColor;
67+
68+
return consoleColorKey;
69+
}
70+
4971
/// <summary>
5072
/// Notifies the caller as to whether or not the specified System.Drawing.Color needs to be added
5173
/// to the ColorStore.

src/Colorful.Console/ColorfulConsoleBack.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public static partial class Console
1414
private static ColorStore colorStore;
1515
private static ColorManagerFactory colorManagerFactory;
1616
private static ColorManager colorManager;
17+
private static Dictionary<string, COLORREF> defaultColorMap;
1718

1819
// Limitation of the Windows console window.
1920
private const int MAX_COLOR_CHANGES = 16;

src/Colorful.Console/ColorfulConsoleFront.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,11 @@ public static int WindowWidth
294294
}
295295

296296
public static event ConsoleCancelEventHandler CancelKeyPress = delegate { };
297-
297+
298298
static Console()
299299
{
300-
colorStore = GetColorStore();
301-
colorManagerFactory = new ColorManagerFactory();
302-
colorManager = colorManagerFactory.GetManager(colorStore, MAX_COLOR_CHANGES, INITIAL_COLOR_CHANGE_COUNT_VALUE);
300+
defaultColorMap = new ColorMapper().GetBufferColors();
301+
ReplaceAllColorsWithDefaults();
303302

304303
System.Console.CancelKeyPress += Console_CancelKeyPress;
305304
}
@@ -1309,12 +1308,24 @@ public static void Clear()
13091308
System.Console.Clear();
13101309
}
13111310

1311+
public static void ReplaceAllColorsWithDefaults()
1312+
{
1313+
colorStore = GetColorStore();
1314+
colorManagerFactory = new ColorManagerFactory();
1315+
colorManager = colorManagerFactory.GetManager(colorStore, MAX_COLOR_CHANGES, INITIAL_COLOR_CHANGE_COUNT_VALUE);
1316+
new ColorMapper().SetBatchBufferColors(defaultColorMap);
1317+
}
1318+
1319+
public static void ReplaceColor(Color oldColor, Color newColor)
1320+
{
1321+
colorManager.ReplaceColor(oldColor, newColor);
1322+
}
1323+
13121324
public static void Beep(int frequency, int duration)
13131325
{
13141326
System.Console.Beep(frequency, duration);
13151327
}
13161328

1317-
13181329
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
13191330
{
13201331
CancelKeyPress.Invoke(sender, e);

src/Colorful.Console/project.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "2.0.0",
2+
"version": "1.0.6",
33
"title": "Colorful.Console",
44
"description": "Style your C# console output!",
55
"authors": [ "Tom Akita", "Muhammad Rehan Saeed", "Matt Furden" ],
@@ -11,7 +11,7 @@
1111
"iconUrl": "http://colorfulconsole.com/images/colorful_icon_ngsize.png",
1212
"projectUrl": "http://colorfulconsole.com/",
1313
"licenseUrl": "https://github.com/tomakita/Colorful.Console/blob/master/LICENSE.md",
14-
"releaseNotes": "Added support for netstandard 1.3"
14+
"releaseNotes": "Added color replacement"
1515
},
1616

1717
"buildOptions": {

0 commit comments

Comments
 (0)