Skip to content

Conversation

tznind
Copy link
Collaborator

@tznind tznind commented Sep 1, 2025

Fixes #4229 - Transparent foreground/background

This is the simplest way to get transparent background. It uses console native background on Color.Transparent (0,0,0,0).

Applies to both net and win

dotnet run -- -d v2

When the background color is Transparent we use CSI 49m instead of explicitly mark it 0,0,0,0 color. Similarly for foreground color.

image

Proposed Changes/Todos

  • Todo 1

Pull Request checklist:

  • I've named my PR in the form of "Fixes #issue. Terse description."
  • My code follows the style guidelines of Terminal.Gui - if you use Visual Studio, hit CTRL-K-D to automatically reformat your files before committing.
  • My code follows the Terminal.Gui library design guidelines
  • I ran dotnet test before commit
  • I have made corresponding changes to the API documentation (using /// style comments)
  • My changes generate no new warnings
  • I have checked my code and corrected any poor grammar or misspellings
  • I conducted basic QA to assure all features are working

@tznind tznind changed the title Fixes #4229 Make black clear background color instead of force black Fixes #4229 Support transparent backgrounds in v2 Sep 1, 2025
@metasong
Copy link

metasong commented Sep 3, 2025

thank you for this fix, it looks like a creative patch when set the background color to explicit black (default console color)!
I would like to see similar function in WindowsDriver

@tig
Copy link
Collaborator

tig commented Sep 3, 2025

Based on this, I think we should consdider changing the Default theme's Base BG to black.

Like this:

WindowsTerminal_oJOpu3MFX6

In Sheme.cs:

image

@tig
Copy link
Collaborator

tig commented Sep 3, 2025

BTW, this makes me uncomfortably happy.

@tznind
Copy link
Collaborator Author

tznind commented Sep 3, 2025

We could also just say if the background color has Alpha of 0 we do this.

And add a color member for Transparent if we dont already have one.

That might be more elegant as it would let you still use black as normal and not have surprises e.g. if users terminal default color is white for bg

@tznind tznind marked this pull request as ready for review September 5, 2025 18:51
@tznind tznind requested a review from tig as a code owner September 5, 2025 18:51
@tznind tznind changed the title Fixes #4229 Support transparent backgrounds in v2 Fixes #4229 Support transparent foreground/background in v2 Sep 5, 2025
@tznind tznind marked this pull request as draft September 5, 2025 18:54
@tznind
Copy link
Collaborator Author

tznind commented Sep 5, 2025

View_Resolves_Attributes_From_Scheme is failing. It seems using explicit Color (Transparent) isn't how the schemes are supposed to work.

I guess we should instead be using the StandardColor for Transparent instead... but those don't have alpha so.... I need to dig into it a bit more.

- Add StandardColor.Trnsparent

StandardColor is enum so limited to int which cannot model A 0xFF000000 is too many bytes for int32. So instead we use 0xF000000 and 'special case' it in Color constructor.
…dColor uint so it can have FF for alpha on all values
@tznind
Copy link
Collaborator Author

tznind commented Sep 6, 2025

Ok StandardColor being vanilla enum means you can't have alpha modelled. So all current values are just actually RGB. And in fact when passed to Color struct, results in an A of 0!

I've changes it to uint enum and added 0xFF000000 to all values except Transparent.

This should mean we get correct A values when mapping this enum to Color. And hence we can correctly distinguish 0xFF000000 (black) from 0x00000000 (Transparent).

Probably will blow up a lot of unit tests though 😓

@tznind
Copy link
Collaborator Author

tznind commented Sep 8, 2025

So this test fails when setting background color to Transparent. Its confusing because test seems only to be checking the Foreground but I'm changing the background - so can't understand why it would fail.

    [Fact]
    public void View_Resolves_Attributes_From_Scheme ()
    {
        View view = new Label { SchemeName = "Base" };

        foreach (VisualRole role in Enum.GetValues<VisualRole> ())
        {
            Attribute attr = view.GetAttributeForRole (role);
            Assert.NotEqual (default, attr.Foreground); // Defensive: avoid all-defaults
        }

        view.Dispose ();
    }

Specifically:

        Scheme CreateBase ()
        {
            return new ()
            {
-                Normal = new (StandardColor.LightBlue, StandardColor.RaisinBlack)
+                Normal = new (StandardColor.LightBlue, StandardColor.Transparent)
            };
        }

@tznind
Copy link
Collaborator Author

tznind commented Sep 8, 2025

Ah I see the issue, Focus is probably defined as the inverse of Normal and hence when normal ends up with a transparent background the foreground becomes transparent and hence default

// Derivation algorithm as documented
Attribute result = role switch
                   {
                       VisualRole.Focus =>
                           GetAttributeForRoleCore (VisualRole.Normal, stack) with
                           {
                               Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Background,
                               Background = GetAttributeForRoleCore (VisualRole.Normal, stack).Foreground
                           },

@tznind
Copy link
Collaborator Author

tznind commented Sep 8, 2025

As simplest solution and probably most sensible I've just set this explicitly as a rule
69b9c33

Transparent now means 'clear color' - that means that for background your likely to get either black (default terminal color) or black + semi transparent (user has configured % transparency). But transparent foreground is also 'clear color' but likely to be... well the inverse of the background anyway (i.e. white terminal with black text or black terminal with white text).

{ new Color(118, 118, 118), ColorName16.DarkGray },
{ new Color(169, 169, 169), ColorName16.DarkGray },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That correspond adding 20% of the opacity (118+255*0.20=118+51=169), which may be the opacity percentage used by the StandardColor? It's possible to comprove with a unit test the opacity percentage (20%) for all StandardColor?

@@ -306,7 +306,7 @@ private Attribute GetAttributeForRoleCore (VisualRole role, HashSet<VisualRole>
VisualRole.Focus =>
GetAttributeForRoleCore (VisualRole.Normal, stack) with
{
Foreground = GetAttributeForRoleCore (VisualRole.Normal, stack).Background,
Foreground = SwapTransparentForBlack(GetAttributeForRoleCore (VisualRole.Normal, stack).Background),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise a text in a transparent foreground with a opaque background is unreadable, correct?

/// <param name="redrawTextStyle">Style</param>
protected virtual void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
{
if (attr.Foreground == Color.Transparent)
Copy link
Collaborator

@BDisp BDisp Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, don' forget to consider the Force16Colors in v2net:

        if (Application.Force16Colors)
        {
            output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
            output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
        }
        else
        {
            ...
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simple fix for transparent backgrounds
4 participants