Skip to content

Commit

Permalink
GUI: Darken very bright colours and slightly lighten very dark colour…
Browse files Browse the repository at this point in the history
…s in main log window
  • Loading branch information
UnknownShadow200 committed Nov 30, 2023
1 parent e224f3f commit 9dead79
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 59 deletions.
193 changes: 193 additions & 0 deletions GUI/ColorUtils.cs
@@ -0,0 +1,193 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
https://opensource.org/license/ecl-2-0/
https://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.Drawing;

namespace MCGalaxy.Gui
{
public static class ColorUtils
{
struct RGB { public double R, G, B; }
struct HSV { public double H, S, V; }


/// <summary> Calculates the appropriate text colour for the given background colour </summary>
/// <remarks> Returns black or white colour depending on brightness of the given colour </remarks>
public static Color CalcTextColor(ColorDesc bgColor) {
// https://stackoverflow.com/questions/596216/formula-to-determine-perceived-brightness-of-rgb-color
RGB c = sRGBToLinear(bgColor);
double L = 0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B;
return L > 0.179 ? Color.Black : Color.White;
}


/// <summary> Converts gamma corrected RGB to linear RGB </summary>
static RGB sRGBToLinear(ColorDesc c) {
RGB rgb;
rgb.R = ToLinear(c.R);
rgb.G = ToLinear(c.G);
rgb.B = ToLinear(c.B);
return rgb;
}

/// <summary> Converts a gamma corrected value to a linear value </summary>
static double ToLinear(double c) {
c /= 255.0;
if (c <= 0.03928) return c / 12.92;
return Math.Pow((c + 0.055) / 1.055, 2.4);
}


/// <summary> Adjust text colour to be easier on the eye on a light or dark background </summary>
public static Color AdjustBrightness(ColorDesc color, bool nightMode) {
double brightness;
RGB rgb = sRGBToLinear(color);
HSV hsv = RGBToHSV(rgb);
brightness = WeightedW3C(rgb);
// TODO is there a better way of doingthis

if (nightMode) {
// lighten very dark colors
while (brightness < 0.1 && hsv.V >= 0 && hsv.V <= 0.99)
{
hsv.V += 0.01;
brightness = WeightedW3C(HSVToRGB(hsv));
}
} else {
// darken overly bright colors
while (brightness > 0.5 && hsv.V >= 0.01 && hsv.V <= 1)
{
hsv.V -= 0.01;
brightness = WeightedW3C(HSVToRGB(hsv));
}
}

rgb = HSVToRGB(hsv);
int R = ToRGB(rgb.R);
int G = ToRGB(rgb.G);
int B = ToRGB(rgb.B);
return Color.FromArgb(R, G, B);
}

static double sRGB(double c) {
if (c <= 0.00305) return c * 12.92;
return 1.055 * Math.Pow(c, 1.0 / 2.4) - 0.055;
}

static int ToRGB(double c) {
c = sRGB(c);
if (c < 0.0) return 0;
if (c > 1.0) return 255;
return (int)(c * 255);
}

static double WeightedW3C(RGB rgb) {
return rgb.R * 0.299 + rgb.G * 0.587 + rgb.B * 0.11;
}

// https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
static HSV RGBToHSV(RGB rgb) {
HSV hsv = default(HSV);
double maxc = Math.Max(rgb.R, Math.Max(rgb.G, rgb.B));
double minc = Math.Min(rgb.R, Math.Min(rgb.G, rgb.B));

hsv.V = maxc;
if (minc == maxc) return hsv;
double D = maxc - minc;

if (maxc == 0.0) return hsv;
hsv.S = D / maxc;

double rc = (maxc - rgb.R) / D;
double gc = (maxc - rgb.G) / D;
double bc = (maxc - rgb.B) / D;

if (rgb.R == maxc) {
hsv.H = 0.0 + bc - gc;
} else if (rgb.G == maxc) {
hsv.H = 2.0 + rc - bc;
} else {
hsv.H = 4.0 + gc - rc;
}

hsv.H *= 60.0;
if (hsv.H < 0.0) hsv.H += 360.0;
return hsv;
}

static RGB HSVToRGB(HSV hsv) {
double hh, p, q, t, ff;
int i;
RGB rgb = default(RGB);

if (hsv.S <= 0.0) {
rgb.R = hsv.V;
rgb.G = hsv.V;
rgb.B = hsv.V;
return rgb;
}

hh = hsv.H;
if(hh >= 360.0) hh = 0.0;
hh /= 60.0;

i = (int)hh;
ff = hh - i;
p = hsv.V * (1.0 - hsv.S);
q = hsv.V * (1.0 - (hsv.S * ff));
t = hsv.V * (1.0 - (hsv.S * (1.0 - ff)));

switch (i)
{
case 0:
rgb.R = hsv.V;
rgb.G = t;
rgb.B = p;
break;
case 1:
rgb.R = q;
rgb.G = hsv.V;
rgb.B = p;
break;
case 2:
rgb.R = p;
rgb.G = hsv.V;
rgb.B = t;
break;

case 3:
rgb.R = p;
rgb.G = q;
rgb.B = hsv.V;
break;
case 4:
rgb.R = t;
rgb.G = p;
rgb.B = hsv.V;
break;
case 5:
rgb.R = hsv.V;
rgb.G = p;
rgb.B = q;
break;
}
return rgb;
}
}
}
36 changes: 23 additions & 13 deletions GUI/Controls/ColoredTextBox.cs
Expand Up @@ -16,6 +16,7 @@
*/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
Expand Down Expand Up @@ -53,8 +54,8 @@ public class ColoredTextBox : RichTextBox {
get { return _nightMode; }
set {
_nightMode = value;
ForeColor = value ? Color.Black : Color.White;
BackColor = value ? Color.White : Color.Black;
BackColor = value ? Color.Black : Color.White;
ForeColor = value ? Color.White : Color.Black;
Invalidate();
}
}
Expand Down Expand Up @@ -151,25 +152,34 @@ public class ColoredTextBox : RichTextBox {


void AppendFormatted(string message, Color foreColor) {
int index = 0;
char col = 'S';
int index = 0;
char color = 'S';
message = UIHelpers.Format(message);

while (index < message.Length) {
char curCol = col;
string part = UIHelpers.OutputPart(ref col, ref index, message);
if (part.Length > 0) AppendColoredText(part, GetCol(curCol, foreColor));
while (index < message.Length)
{
char curCode = color;
string part = UIHelpers.OutputPart(ref color, ref index, message);
if (part.Length > 0) AppendColoredText(part, GetColor(curCode, foreColor, _nightMode));
}
}

static Color GetCol(char c, Color foreCol) {
if (c == 'S' || c == 'f' || c == 'F' || c == '0') return foreCol;
static Dictionary<int, Color> color_cache = new Dictionary<int, Color>();
static Color GetColor(char c, Color foreCol, bool nightMode) {
if (c == 'S' || c == 'f' || c == 'F') return foreCol;
Colors.Map(ref c);

ColorDesc col = Colors.Get(c);
if (col.Undefined) return foreCol;
ColorDesc color = Colors.Get(c);
if (color.Undefined) return foreCol;

return Color.FromArgb(col.R, col.G, col.B);
int key = color.R | (color.G << 8) | (color.B << 16);
Color rgb;

if (!color_cache.TryGetValue(key, out rgb)) {
rgb = ColorUtils.AdjustBrightness(color, nightMode);
color_cache[key] = rgb;
}
return rgb;
}
}
}
32 changes: 0 additions & 32 deletions GUI/GuiUtils.cs
Expand Up @@ -71,37 +71,5 @@ public static class GuiUtils
}
}
}

public static class ColorUtils
{
struct RGB { public double R, G, B; }
struct HSV { public double H, S, V; }


/// <summary> Returns black or white color depending on brightness of the given color </summary>
public static Color CalcBackgroundColor(Color color) {
// https://stackoverflow.com/questions/596216/formula-to-determine-perceived-brightness-of-rgb-color
RGB c = sRGBToLinear(color);
double L = 0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B;
return L > 0.179 ? Color.Black : Color.White;
}


/// <summary> Converts gamma corrected RGB to linear RGB </summary>
static RGB sRGBToLinear(Color c) {
RGB rgb;
rgb.R = Linear(c.R);
rgb.G = Linear(c.G);
rgb.B = Linear(c.B);
return rgb;
}

/// <summary> Converts gamma corrected value to linear value </summary>
static double Linear(double c) {
c /= 255.0;
if (c <= 0.03928) return c / 12.92;
return Math.Pow((c + 0.055) / 1.055, 2.4);
}
}
}

1 change: 1 addition & 0 deletions GUI/MCGalaxyGUI.csproj
Expand Up @@ -50,6 +50,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ColorUtils.cs" />
<Compile Include="Controls\ColoredTextBox.cs">
<SubType>Component</SubType>
</Compile>
Expand Down
16 changes: 6 additions & 10 deletions GUI/Popups/ColorSelector.cs
Expand Up @@ -10,18 +10,14 @@ internal sealed partial class ColorSelector : Form
{
public char ColorCode;

internal static Color LookupColor(char colCode, out Color textCol) {
Color rgb = default(Color);
ColorDesc col = Colors.Get(colCode);
internal static Color LookupColor(char colorCode, out Color textColor) {
ColorDesc color = Colors.Get(colorCode);

if (col.Undefined) {
rgb = Color.White;
} else {
rgb = Color.FromArgb(col.R, col.G, col.B);
}
if (color.Undefined)
color = new ColorDesc(255, 255, 255);

textCol = ColorUtils.CalcBackgroundColor(rgb);
return rgb;
textColor = ColorUtils.CalcTextColor(color);
return Color.FromArgb(color.R, color.G, color.B);
}


Expand Down
2 changes: 1 addition & 1 deletion GUI/Window/Window.Main.cs
Expand Up @@ -163,8 +163,8 @@ public partial class Window : Form {


void tsLog_Night_Click(object sender, EventArgs e) {
tsLog_night.Checked = !tsLog_night.Checked;
main_txtLog.NightMode = tsLog_night.Checked;
tsLog_night.Checked = !tsLog_night.Checked;
}

void tsLog_Colored_Click(object sender, EventArgs e) {
Expand Down
7 changes: 4 additions & 3 deletions MCGalaxy/Bots/Instructions/FunInstructions.cs
Expand Up @@ -56,7 +56,8 @@ protected class Metadata { public short Seconds, Speed; }
}

public override string[] Help { get { return help; } }
static string[] help = new string[] { "&T/BotAI add [name] spin <interval> <speed>",
static string[] help = new string[] {
"&T/BotAI add [name] spin <interval> <speed>",
"&HCauses the bot to spin around for a period of time.",
"&H <interval> is in tenths of a second, so an interval of 20 means " +
"spin for two seconds. (defaults to 1 second)",
Expand Down Expand Up @@ -98,8 +99,8 @@ public sealed class NodInstruction : SpinInstruction
}

public override string[] Help { get { return help; } }
static string[] help = new string[] { "" +
"T/BotAI add [name] nod <interval> <speed>",
static string[] help = new string[] {
"&T/BotAI add [name] nod <interval> <speed>",
"&HCauses the bot to nod up and down for a period of time.",
"&H <interval> is in tenths of a second, so an interval of 20 means " +
"nod for two seconds. (defaults to 1 second)",
Expand Down

0 comments on commit 9dead79

Please sign in to comment.