Open tig opened 1 year ago
I was thinking about how a default theme could be dynamically created based only on an inherited foreground and background. This is quite difficult. FWIW, I thought I'd lay down my ideas.
.Normal would just use the current colors, of course:
fg = defFore; bg = defBack;
.Focus would just swap background and foreground [EDIT: though this collides with selection]:
fg = defBack; bg = defFore;
.Disabled, I think, should compute a grayscale foreground color based on the background, adjusted for Luma. See Luma() below. We could use the following for RGB colors, or round to the nearest grayscale ConsoleColor (though see NB below):
fg = Luma(defBack) > 0.5 ? Gray(255 * Luma(defBack) - 63) : Gray(255 * Luma(defBack) + 63);
bg = defBack;
.HotNormal is where things get tough:
fg = AccentColor(defFore); bg = defBack;
To get an accent color, my first thought was to use an inverse of the RGB of the foreground color. However, this wouldn't work for middle-grayish colors, would often result in ugly combinations, and it wouldn't take Luma into account. It's somewhat easy to handpick a color for each of the 16 ConsoleColors like my AccentColor() implementation below, though this is obviously a matter of taste, and taking both foreground and background into consideration does complicate things quite a bit.
AccentColor() would be somewhat more complicated using RGB (TrueColor or not), but I suppose the suggestions I offer below could still be used if we approximate numerically 16 zones of "reddish" or "dark-blueish" or "blackish" colors [something like the existing Color.ToConsoleColor()], but then we could adjust the accent result based on the calculated saturation and brightness.
.HotFocus is similar, but swapping background and foreground:
fg = AccentColorAdjusted(defFore); bg = defFore;
However, we probably don't want to introduce another color which might clash with HotNormal, so we wouldn't just use fg = AccentColor(defBack);
So my thought is to either re-use the AccentColor(defFore) when there is sufficient difference in Luma between foreground and background, otherwise flip the accent ConsoleColor from dark to bright or bright to dark (or a similar approximation for RGB values).
NB: On the other hand, since each of the ConsoleColors can be set by the user and might even have little bearing on the actual color, it's dangerous to make assumptions. Even assuming the defaults were kept, there's variance between platforms and terminal emulations, e.g., whether bright colors are allowed as backgrounds. Under Windows, depending on the upgrade path the user might still be using legacy colors or the newer Campbell colors.
However, is it even possible to programmatically determine the RGB values of the currently used colors? E.g., using Windows Terminal, we'd have to find and read the appropriate .json file; using Windows conhost, in some circumstances these values would be in the registry, and in some circumstances they'd be in the .lnk file used to launch it; with a multitude of implementations for other shells and platforms and terminal emulations.
EDIT: Also, how is this supposed to work with the bitmap background? How do we ensure a transparent color is used so the bitmap isn't hidden when we've drawn spaces after, e.g., a window is dragged around? Does it just draw the bitmap anywhere the current background color exists? And I assume these implementation details could differ between shells... EDIT 2: It appears that my assumption was correct, for WT at least, so no need to worry about transparency there.
float Luma(Color c) {
return 0.2126 * c.ScR + 0.7152 * c.ScG + 0.0722 * c.ScB; }
Color Gray(int x) {
return Color(x, x, x); }
static ConsoleColor AccentColor(ConsoleColor fg, ConsoleColor bg) {
ConsoleColor newc = new();
switch (fg) {
case ConsoleColor.Gray:
case ConsoleColor.White:
newc = bg == ConsoleColor.DarkGreen ? ConsoleColor.Black : ConsoleColor.DarkGreen; break;
case ConsoleColor.DarkGreen:
newc = bg == ConsoleColor.White ? ConsoleColor.Green : ConsoleColor.White; break;
case ConsoleColor.DarkGray:
case ConsoleColor.Black:
newc = bg == ConsoleColor.Green ? ConsoleColor.White : ConsoleColor.Green; break;
case ConsoleColor.Green:
newc = bg == ConsoleColor.Black ? ConsoleColor.DarkCyan : ConsoleColor.Black; break;
case ConsoleColor.DarkBlue:
newc = bg == ConsoleColor.Cyan ? ConsoleColor.Yellow : ConsoleColor.Cyan; break;
case ConsoleColor.Cyan:
newc = bg == ConsoleColor.DarkBlue ? ConsoleColor.DarkGray : ConsoleColor.DarkBlue; break;
case ConsoleColor.DarkRed:
case ConsoleColor.DarkMagenta:
newc = bg == ConsoleColor.White ? ConsoleColor.Yellow : ConsoleColor.White; break;
case ConsoleColor.Magenta:
case ConsoleColor.Red:
newc = bg == ConsoleColor.Black ? ConsoleColor.DarkYellow : ConsoleColor.Black; break;
case ConsoleColor.Yellow:
newc = bg == ConsoleColor.DarkBlue ? ConsoleColor.Black : ConsoleColor.DarkBlue; break;
case ConsoleColor.DarkCyan:
case ConsoleColor.Blue:
newc = bg == ConsoleColor.Yellow ? ConsoleColor.White : ConsoleColor.Yellow; break; }
return newc; }
.Focus would just swap background and foreground:
Normally inverted colors is used for selection, like used in TextField
and TextView
. Usually it can be fg = other color; bg = Normal Fore;
Normally inverted colors is used for selection, like used in
TextField
andTextView
. Usually it can be fg = other color; bg = Normal Fore;
I was hoping to limit the number of accent colors to compute, but that's true.
See https://github.com/PowerShell/GraphicalTools/issues/211
This request argues for being able to use PowerShell's $PSSytyle as a source for settings.
ColorScheme
members(Just notes for now - please ignore)
Normal
- The attribute for normal text in a view when the view has focus.NormalNotFocused
- The attribute for normal text when the view has the focus.Hot
- The attribute for text in a focused view that indicates aa hot key or shortcut.HotNotFocused
- The attribute for text in a non-focused view that indicates a hot key or shortcut.Selected
- The attribute for text of something selected in a focused view.SelectedNotFocused
- The attribute for text of something selected in a not focused view.Editable
- The attribute for normal text in a view when the view has focus.EditableNotFocused
- The attribute for normal text when the view has the focus.Disabled
- The default foreground and background color for text when the view is disabled. Also used for normally editable content that is readonly.Relevant / informational:
I think I mentioned it in the color discussion I started but in the spirit of that link, I'll link this project here, as well, as a potential resource for whatever we end up with:
Developers (like me) love tweaking their terminal colors/themes.
Terminal.Gui, today, overrides all this, defining it's own themes.
This means that when I run a TUI app, the effect is glaring and doesn't honor all the hard work I put into tweaking my terminal theme. E.g.:
In addition we always clear the Toplevel background vs, letting any bitmap the user has set show through.
For v2, I'd like to see Terminal.Gui pick up the colors theme of the Terminal and use it, by default.
Of course, this implies we nail #48 too.
I think this means a Tenet for v2:
Other things that should be addressed as part of this:
ColorScheme
to be a value type (or similar). I spent an hour yesterday on an issue where I had donevar cs = colorScheme
vsvar cs = new ColorScheme(colorScheme)
.GetNormalColor
hackery - see https://github.com/gui-cs/Terminal.Gui/issues/2816