Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Status Strip Feature Request #28

Open
fdncred opened this issue Jun 1, 2018 · 19 comments
Open

Status Strip Feature Request #28

fdncred opened this issue Jun 1, 2018 · 19 comments
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@fdncred
Copy link

fdncred commented Jun 1, 2018

Please add the ability to change the color of each individual item in the status strip, to include foreground color, back ground color as well as StartGradient and EndGradient colors.

@Wagnerp Wagnerp added the enhancement New feature or request label Jun 1, 2018
@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 1, 2018

A version is now available, just need to implement the text colour.

@fdncred
Copy link
Author

fdncred commented Jun 1, 2018

Quick turn @Wagnerp, Thanks!. Could you enable changing the text color aka ForeColor? Ideally it would work like this.

If (ForeColor != Color.Empty)
    draw the text in the color specified with the configured cleartext/antialiased properties.

If (BackColor != Color.Empty)
    draw the background using a solid brush.
else If (GradiantColorOne != Color.Empty || GradientColorTwo != Color.Empty)
   draw the background using the LinearGradientBrush()

At that point, one can control just about all the attributes of the status strip.

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 2, 2018

I think it's done, is this what you mean?

protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            Rectangle r = new Rectangle(0, 0, Width, Height);

            if (ForeColor != Color.Empty)
            {
                g.TextRenderingHint = TextRenderingHint.AntiAlias;

                Font typeface = new Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit);

                SolidBrush brush = new SolidBrush(ForeColor);

                g.DrawString(Text, typeface, brush, 0, 0);
            }
            else if (BackColor != Color.Empty)
            {
                using (SolidBrush sb = new SolidBrush(BackColor))
                {
                    g.FillRectangle(sb, r);
                }
            }
            else if (GradientColourOne != Color.Empty || GradientColourTwo != Color.Empty)
            {
                using (LinearGradientBrush lgb = new LinearGradientBrush(r, GradientColourOne, GradientColourTwo, GradientMode))
                {
                    g.FillRectangle(lgb, r);
                }
            }

            base.OnPaint(e);
        }

@fdncred
Copy link
Author

fdncred commented Jun 11, 2018

Been on vacation. Back now.
I was thinking something more like this. The main difference is that I changed your first "else if" into just an "if". The only "else if" should occur regarding the background, not the foreground.

protected override void OnPaint(PaintEventArgs e)
{
    Graphics g = e.Graphics;

    Rectangle r = new Rectangle(0, 0, Width, Height);

    if (ForeColor != Color.Empty)
    {
        g.TextRenderingHint = TextRenderingHint.AntiAlias;

        Font typeface = new Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit);

        SolidBrush brush = new SolidBrush(ForeColor);

        g.DrawString(Text, typeface, brush, 0, 0);
    }
    
    if (BackColor != Color.Empty)
    {
        using (SolidBrush sb = new SolidBrush(BackColor))
        {
            g.FillRectangle(sb, r);
        }
    }
    else if (GradientColourOne != Color.Empty || GradientColourTwo != Color.Empty)
    {
        using (LinearGradientBrush lgb = new LinearGradientBrush(r, GradientColourOne, GradientColourTwo, GradientMode))
        {
            g.FillRectangle(lgb, r);
        }
    }

    base.OnPaint(e);
}

The only other thing that's a bit wiggy is that you're hard coding the TextRenderingHint. Should that be extracted from the system? I believe if one is using ClearText it's not just AntiAlias, but I could be wrong. I'm not real familiar with TextRenderingHint.

You may also want to use a using statement in the first if as well for the brush.

One last thing - This doesn't quite work. It appears to draw the text foreground and background color in the color you specify and the write over it with the palette color. I'm not sure what's going on exactly. Perhaps the base.OnPaint() is causing the second draw.

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 11, 2018

I'll update the code. There is one bug, which I don't know exactly where it's coming from. The bug is creating a text ghosting effect. Will try your solution though.

@fdncred
Copy link
Author

fdncred commented Jun 11, 2018

I saw that too and noticed that the text wasn't aligned exactly the same way as the default renderer draws it. Thanks!

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 11, 2018

I think the base.OnPaint() call was the issue. Thanks for your suggestion.

@fdncred
Copy link
Author

fdncred commented Jun 11, 2018

Are you saying you got it to work? Because commenting that out only enabled the ForeColor - not the BackColor (assuming you're not trying to use the Gradient). Also, Did you figure out how to align the text because it was a little off on the left side when I tried it.

In the attached image the text on the Gradient background is supposed to be Red and the Third status items shows misaligned text when you have the OnPaint enabled (not commented out).
playground_2018-06-11_11-45-52

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 11, 2018

I think so. Don't know about the alignment though. Might look into a possible TextGlow colour property to make the text stand out more.

@fdncred
Copy link
Author

fdncred commented Jun 13, 2018

Just downloaded the latest code base. FG works BG doesn't work.

var e = new ExtendedControls.ExtendedToolkit.ToolstripControls.ExtendedToolStripStatusLabel();
e.Text = "This is a test of the emergency blah blah";
e.ForeColor = Color.Red;
e.BackColor = Color.Black;
statusStrip1.Items.Add(e);

I put this code in the public Form1() method of your playground app to test it.

I then changed the code to this:

var e = new ExtendedControls.ExtendedToolkit.ToolstripControls.ExtendedToolStripStatusLabel();
e.Text = "This is a test of the emergency blah blah";
e.ForeColor = Color.Red;
//e.BackColor = Color.Black;
e.GradientColourOne = Color.Black;
e.GradientColourTwo = Color.DarkGray;
e.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
statusStrip1.Items.Add(e);

And the text doesn't show up at all

@fdncred
Copy link
Author

fdncred commented Jun 13, 2018

I think I have it mostly working now. The problem is the background was drawing over the foreground. So I moved the DrawString last in the OnPaint() method.

        protected override void OnPaint(PaintEventArgs e)
        {
            // Set a graphics variable
            Graphics g = e.Graphics;

            // Rectangle variable
            Rectangle r = new Rectangle(0, 0, Width, Height);

            if (BackColor != Color.Empty)
            {
                using (SolidBrush sb = new SolidBrush(BackColor))
                {
                    g.FillRectangle(sb, r);
                }
            }
            else if (GradientColourOne != Color.Empty || GradientColourTwo != Color.Empty)
            {
                using (LinearGradientBrush lgb = new LinearGradientBrush(r, GradientColourOne, GradientColourTwo, GradientMode))
                {
                    g.FillRectangle(lgb, r);
                }
            }

            if (ForeColor != Color.Empty)
            {
                g.TextRenderingHint = TextRenderingHint.AntiAlias | TextRenderingHint.ClearTypeGridFit;

                Font typeface = new Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit);

                SolidBrush brush = new SolidBrush(ForeColor);

                g.DrawString(Text, typeface, brush, 0, 0);
            }

            //base.OnPaint(e);
        }

On my system, adding ClearyTypeGridFit also helps render the text closer to what the OS does.

And I'm not sure what TextGlow is supposed to do since there is nothing regarding it in the OnPaint and it's not calling the base. I figure Glow isn't doing anything at this point.

I also had to change how BackColor is being used

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        //public override Color BackColor { get => new Color(); set {; } }
        public Color BackColor { get; set; }

@fdncred
Copy link
Author

fdncred commented Jun 13, 2018

Now that the background is able to be changed one could do something like this to alert a user. This also works with Gradients.

ss

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 14, 2018

I've added the code that you have suggested, and it does look better. I've added new code for an alert option, but can't understand why it doesn't work. The TextGlow feature doesn't currently work at the moment, as I'm still working on a C# implementation, because most of the examples I've come across are written in VisualBasic.

@fdncred
Copy link
Author

fdncred commented Jun 14, 2018

Regarding the Alert. I brought your code over and debugged it. The problem was you were setting the wrong variables and not forcing a redraw. Try this.

public async void BlinkLabel()
{
    while (true)
    {
        await Task.Delay(_flashInterval);
        BackColor = BackColor == AlertColourOne ? AlertColourTwo : AlertColourOne;
        ForeColor = AlertTextColour;
        // Force a redraw
        Invalidate();
    }
}

The same is true for SoftBlink()

public async void SoftBlink(Color alertColour1, Color alertColour2, Color alertTextColour, short cycleInterval, bool bkClr)
{
    var sw = new Stopwatch();
    sw.Start();
    short halfCycle = (short)Math.Round(cycleInterval * 0.5);

    while (true)
    {
        await Task.Delay(1);
        var n = sw.ElapsedMilliseconds % cycleInterval;
        var per = (double)Math.Abs(n - halfCycle) / halfCycle;
        var red = (short)Math.Round((alertColour2.R - alertColour1.R) * per) + alertColour1.R;
        var grn = (short)Math.Round((alertColour2.G - alertColour1.G) * per) + alertColour1.G;
        var blw = (short)Math.Round((alertColour2.B - alertColour1.B) * per) + alertColour1.B;
        var clr = Color.FromArgb(red, grn, blw);

        if (bkClr)
        {
            BackColor = clr;
        }
        else
        {
            //ctrl.ForeColor = clr;
            //ForeColor = alertTextColour;
            ForeColor = clr;
        }

        // Force a redraw
        Invalidate();
    }
}

Also, I noticed that your property defaults aren't getting set when using Code First versus using the designer. So, I added the defaults to the constructor as well, otherwise the AlertBlinkInterval was set to 0 no matter what I set it to in my code.

public ExtendedToolStripStatusLabel()
{
    Alert = false;
    AlertColourOne = Color.White;
    AlertColourTwo = Color.Black;
    AlertTextColour = Color.Red;
    GradientColourOne = Color.Empty;
    GradientColourTwo = Color.Empty;
    TextGlow = Color.White;
    GradientMode = LinearGradientMode.ForwardDiagonal;
    TextGlowSpread = 5;
    AlertBlinkInterval = 256;
}

The only other thing I'd add to your Alert functionality is duration. So you can set the alert and tell it to "blink" for 5 seconds (or some duration) and then go back to normal.

@fdncred
Copy link
Author

fdncred commented Jun 14, 2018

Here's my changes with blinkDuration. I set the default duration to 10 seconds arbitrarily. Maybe there should be a property for that?

public async void BlinkLabel(long blinkDuration = 10_000)
{
    var sw = Stopwatch.StartNew();
    var fg = ForeColor;
    var bg = BackColor;

    while (sw.ElapsedMilliseconds < blinkDuration)
    {
        await Task.Delay(_flashInterval);
        BackColor = BackColor == AlertColourOne ? AlertColourTwo : AlertColourOne;
        ForeColor = AlertTextColour;
        // Force a redraw
        Invalidate();
    }

    BackColor = bg;
    ForeColor = fg;
    Invalidate();
    sw.Stop();
}

public async void SoftBlink(Color alertColour1, Color alertColour2, Color alertTextColour, short cycleInterval, bool bkClr, long blinkDuration = 10_000)
{
    var sw = Stopwatch.StartNew();
    short halfCycle = (short)Math.Round(cycleInterval * 0.5);
    var fg = ForeColor;
    var bg = BackColor;

    while (sw.ElapsedMilliseconds < blinkDuration)
    {
        await Task.Delay(1);
        var n = sw.ElapsedMilliseconds % cycleInterval;
        var per = (double)Math.Abs(n - halfCycle) / halfCycle;
        var red = (short)Math.Round((alertColour2.R - alertColour1.R) * per) + alertColour1.R;
        var grn = (short)Math.Round((alertColour2.G - alertColour1.G) * per) + alertColour1.G;
        var blw = (short)Math.Round((alertColour2.B - alertColour1.B) * per) + alertColour1.B;
        var clr = Color.FromArgb(red, grn, blw);

        if (bkClr)
            BackColor = clr;
        else
            ForeColor = clr;

        // Force a redraw
        Invalidate();
    }

    BackColor = bg;
    ForeColor = fg;
    Invalidate();
    sw.Stop();
}

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 14, 2018

I've uploaded new code with a definable BlinkDuration property. Thanks for your bug testing, it's much appreciated.

@fdncred
Copy link
Author

fdncred commented Jun 14, 2018

You are welcome.

Don't these lines need to default to the property BlinkDuration?
https://github.com/Wagnerp/Krypton-Toolkit-Suite-Extended-NET-4.70/blob/75200438afff2779d4e08fab47923942612b5cae/Source/Krypton%20Toolkit%20Suite%20Extended/Extended%20Controls/ExtendedToolkit/ToolstripControls/ExtendedToolStripStatusLabel.cs#L423
like

public async void BlinkLabel(long blinkDuration = BlinkDuration) 

https://github.com/Wagnerp/Krypton-Toolkit-Suite-Extended-NET-4.70/blob/75200438afff2779d4e08fab47923942612b5cae/Source/Krypton%20Toolkit%20Suite%20Extended/Extended%20Controls/ExtendedToolkit/ToolstripControls/ExtendedToolStripStatusLabel.cs#L451

public async void SoftBlink(Color alertColour1, Color alertColour2, Color alertTextColour, short cycleInterval, bool bkClr, long blinkDuration = BlinkDuration) 

Otherwise the BlinkDuration property does nothing since it's not used anywhere. Or am I missing something?

@Wagnerp
Copy link
Collaborator

Wagnerp commented Jun 14, 2018

I'll put it in. I don't know if these methods need to be put into the OnPaint method, as it's not doing anything when called, if so I can create an enum + property for the user to choose from.

@Wagnerp
Copy link
Collaborator

Wagnerp commented Sep 29, 2018

Note to myself: Revisit at some point.

@Wagnerp Wagnerp self-assigned this Sep 29, 2018
@Wagnerp Wagnerp added the help wanted Extra attention is needed label Apr 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants