Toolbar: Button with text on toolbar

Bars for Windows Forms Forum

Posted 13 years ago by Motia
Avatar
Is it possible to create button with text and image on toolbar?
(Text under the image)

Comments (6)

Posted 13 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Yes, although our built in renderers don't draw things that way. You'd have to inherit one of our existing BarRenderer classes and override the DrawXXX and MeasureXXX methods to implement the drawing your way. But since our renderers are completely customizable, this is possible.


Actipro Software Support

Posted 12 years ago by Kelly Leahy - Software Architect, Milliman
Avatar
Sorry for resurrecting this old post, but I wanted to do this too, and I thought I'd add my solution here and see if you have any comments on it.

I've hardcoded the size of the buttons because I want them to all be the same size and laid out the same way. However, I'm not sure I'm handling all the boundary cases and doing the rendering in the correct order for the DrawButtonLink code.

Thanks,
Kelly
        private class MyBarRenderer : Office2003BarRenderer
        {
            public override Size MeasureCommandLink(Graphics g, BarCommandLink link)
            {
                if (link is BarButtonLink)
                    return new Size(48, 48);
                else
                    return base.MeasureCommandLink(g, link);
            }

            public override void DrawButtonLink(PaintEventArgs e, Rectangle bounds, BarButtonLink link)
            {
                // draw the border and fill based on the current 'state' (i.e. pressed, selected, etc.)
                _DrawBorderAndFill(link.GetDrawState(), ref backFill, ref border);

                // get the text, format, and image for the button.
                string s = link.GetText();
                StringFormat sf = DrawingHelper.GetStringFormat(StringAlignment.Center,
                    StringAlignment.Center, StringTrimming.None, false, false);
                Image img = link.GetImage();

                // compute the coordinates for the various items.
                Size sz1 = DrawingHelper.MeasureString(e.Graphics, s, this.BarDefaultFont, sf);
                sz1.Height += 2 * this.ToolBarTextMarginVertical;
                bounds.Height -= sz1.Height + this.ToolBarImageMargin;
                bounds.Y += this.ToolBarImageMargin;
                RectangleF textRect = new RectangleF(bounds.Left, bounds.Bottom, bounds.Width, sz1.Height);

                if (img != null)
                {
                    // render the image.
                    Point pt = DrawingHelper.GetCenteredRectangleLocation(bounds, img.Size);
                    DrawingHelper.DrawImage(e.Graphics, img, pt.X, pt.Y, 1, RotateFlipType.RotateNoneFlipNone);
                }

                // render the text.
                sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Hide;
                DrawingHelper.DrawString(e.Graphics, s, this.BarDefaultFont, this.BarDefaultForeColor,
                    textRect, sf);
            }

            private void _DrawBorderAndFill(Graphics g, Rectangle bounds, UIElementDrawState state)
            {
                BackgroundFill backFill = this.ToolBarDefaultBackgroundFill;
                SimpleBorder border = null;

                if ((state & UIElementDrawState.Hot) == UIElementDrawState.Hot)
                {
                    if ((state & UIElementDrawState.Pressed) == UIElementDrawState.Pressed)
                    {
                        backFill = this.ToolBarDefaultCommandLinkHotPressedBackgroundFill;
                        border = this.ToolBarDefaultCommandLinkHotPressedBorder;
                    }
                    else
                    {
                        backFill = this.ToolBarDefaultCommandLinkHotBackgroundFill;
                        border = this.ToolBarDefaultCommandLinkHotBorder;
                    }
                }
                else if ((state & UIElementDrawState.Checked) == UIElementDrawState.Checked)
                {
                    backFill = this.ToolBarDefaultCommandLinkCheckedBackgroundFill;
                    border = this.ToolBarDefaultCommandLinkCheckedBorder;
                }
                else if ((state & UIElementDrawState.Selected) == UIElementDrawState.Selected)
                {
                    backFill = this.ToolBarDefaultCommandLinkSelectedBackgroundFill;
                    border = this.ToolBarDefaultCommandLinkSelectedBorder;
                }

                // finally, use the computed fill and border to draw the background and border.
                backFill.Draw(e.Graphics, bounds);
                if (border != null)
                    border.Draw(e.Graphics, bounds);
            }
        }

Kelly Leahy Software Architect Milliman, USA

Posted 12 years ago by Kelly Leahy - Software Architect, Milliman
Avatar
It looks like I forgot the 'disabled'.

I've done this by using the 'DrawImageShadow' method on your DrawingHelper. Is this how you do it internally? Perhaps you could give me a few trade secrets so that I can match the behavior of your builtin implementation?

Here's my current code:
private class MyBarRenderer : Office2003BarRenderer
{
    public override Size MeasureCommandLink(Graphics g, BarCommandLink link)
    {
        if (link is BarButtonLink)
            return new Size(48, 48);
        else
            return base.MeasureCommandLink(g, link);
    }

    public override void DrawButtonLink(PaintEventArgs e, Rectangle bounds, BarButtonLink link)
    {
        // draw the border and fill based on the current 'state' (i.e. pressed, selected, etc.)
        _DrawBorderAndFill(e.Graphics, bounds, link.GetDrawState());

        // get the text, format, and image for the button.
        string s = link.GetText();
        StringFormat sf = DrawingHelper.GetStringFormat(StringAlignment.Center,
            StringAlignment.Center, StringTrimming.None, false, false);
        Image img = link.GetImage();

        // compute the coordinates for the various items.
        Size sz1 = DrawingHelper.MeasureString(e.Graphics, s, this.BarDefaultFont, sf);
        sz1.Height += 2 * this.ToolBarTextMarginVertical;
        bounds.Height -= sz1.Height + this.ToolBarImageMargin;
        bounds.Y += this.ToolBarImageMargin;
        RectangleF textRect = new RectangleF(bounds.Left, bounds.Bottom, bounds.Width, sz1.Height);

        if (img != null)
        {
            // render the image.
            Point pt = DrawingHelper.GetCenteredRectangleLocation(bounds, img.Size);
            if (link.GetEnabled())
                DrawingHelper.DrawImage(e.Graphics, img, pt.X, pt.Y, 1, RotateFlipType.RotateNoneFlipNone);
            else
            {
                DrawingHelper.DrawImageShadow(e.Graphics, img, pt.X, pt.Y, 0.25f, RotateFlipType.RotateNoneFlipNone);
            }
        }

        // render the text.
        sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Hide;
        Color c = link.GetEnabled() ? this.BarDefaultForeColor : this.BarDefaultDisabledForeColor;
        DrawingHelper.DrawString(e.Graphics, s, this.BarDefaultFont, c, textRect, sf);
    }

    private void _DrawBorderAndFill(Graphics g, Rectangle bounds, UIElementDrawState state)
    {
        BackgroundFill backFill = this.ToolBarDefaultBackgroundFill;
        SimpleBorder border = null;

        if ((state & UIElementDrawState.Disabled) == UIElementDrawState.Disabled)
        {
            // do nothing - use the defaults.
        }
        else if ((state & UIElementDrawState.Hot) == UIElementDrawState.Hot)
        {
            if ((state & UIElementDrawState.Pressed) == UIElementDrawState.Pressed)
            {
                backFill = this.ToolBarDefaultCommandLinkHotPressedBackgroundFill;
                border = this.ToolBarDefaultCommandLinkHotPressedBorder;
            }
            else
            {
                backFill = this.ToolBarDefaultCommandLinkHotBackgroundFill;
                border = this.ToolBarDefaultCommandLinkHotBorder;
            }
        }
        else if ((state & UIElementDrawState.Checked) == UIElementDrawState.Checked)
        {
            backFill = this.ToolBarDefaultCommandLinkCheckedBackgroundFill;
            border = this.ToolBarDefaultCommandLinkCheckedBorder;
        }
        else if ((state & UIElementDrawState.Selected) == UIElementDrawState.Selected)
        {
            backFill = this.ToolBarDefaultCommandLinkSelectedBackgroundFill;
            border = this.ToolBarDefaultCommandLinkSelectedBorder;
        }

        // finally, use the computed fill and border to draw the background and border.
        backFill.Draw(g, bounds);
        if (border != null)
            border.Draw(g, bounds);
    }
}

Kelly Leahy Software Architect Milliman, USA

Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Actually for disabled images we do this sort of thing:
// Build a color matrix for transparency
ColorMatrix cm = new ColorMatrix(new float[][] {
    new float[] { 0.3f, 0.3f, 0.3f, 0, 0 },
    new float[] { 0.59f, 0.59f, 0.59f, 0, 0 },
    new float[] { 0.11f, 0.11f, 0.11f, 0, 0 },
    new float[] { 0, 0, 0, 0.5f, 0 },
    new float[] { 0, 0, 0, 0, 1 }
    });

// Create an image attributes
ImageAttributes im = new ImageAttributes();
im.SetColorMatrix(cm);

// Draw image
e.Graphics.DrawImage(image, new Rectangle(x, y, image.Width, image.Height), 
    0, 0, image.Width, image.Height, GraphicsUnit.Pixel, im);


Actipro Software Support

Posted 12 years ago by Kelly Leahy - Software Architect, Milliman
Avatar
oooh. yeah, that looks MUCH better :)

I knew what I was doing was stupid, but I didn't have the time or inclination to investigate the 'proper' way of doing it. Does everything else look reasonable? Am I missing anything big?

Kelly Leahy Software Architect Milliman, USA

Posted 12 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
It looks good to me from a code perspective.


Actipro Software Support

The latest build of this product (v2018.1 build 0341) was released 9 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.