Question

I created the following set of classes for creating my own library of controls. For now, it is based on a asbtract class ShapeControl : Control. However, I still have some troubles to draw without having some bad aliasing side effects (especially for the rounded rectangle), how can I get rid of them? (I already tried to changed the smoothness and the pixel offset, and to refresh and to change the order within the OnPaint() process... without that much success =/).

Any idea to properly use the properties "SmoothingMode" and "PixelOffset"?

public abstract class ShapeControl : Control
{
    public ShapeControl()
    {
        this.SetStyle(ControlStyles.SupportsTransparentBackColor |
                      ControlStyles.DoubleBuffer |
                      ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.UserPaint, true);

        this.PixelOffsetMode = PixelOffsetMode.HighQuality;
        this.SmoothingMode = SmoothingMode.HighQuality;

        this.TextAligmentHorizontal = StringAlignment.Center;
        this.TextAligmentVertical = StringAlignment.Center;

        this.MouseDown += new MouseEventHandler(Shape_MouseDown);
        this.MouseMove += new MouseEventHandler(Shape_MouseMove);

        this.BackColor = Color.FromArgb(0, 255, 255, 255);

        this.GradientColors = new List<Color>();

        this.GradientRadialFocus = 0.5f;
        this.GradientRadialScale = 1.0f;
        this.GradientRadialType = GradientRadialType.SigmaBell;
    }

    protected override void OnResize(EventArgs e)
    {
        this.Region = new Region(this.GraphicsPath);
        this.Invalidate();
        base.OnResize(e);
    }

    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            base.Text = value;
            this.Invalidate();
        }
    }
    public override Color BackColor
    {
        get
        {
            return base.BackColor;
        }
        set
        {
            base.BackColor = value;
            this.Invalidate();
        }
    }

    protected Point LastMouseDownLocation { get; set;}

    private void Shape_MouseMove(Object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.Left = e.X + this.Left - LastMouseDownLocation.X;
            this.Top = e.Y + this.Top - LastMouseDownLocation.Y;

            this.Invalidate();
        }
    }
    private void Shape_MouseDown(Object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.LastMouseDownLocation = e.Location;
        }
    }

    protected DashStyle InternalBorderStyle { get; set; }
    protected UInt32 InternalBorderWidth { get; set; }
    protected Color InternalBorderColor { get; set; }
    protected BackType InternalBackType { get; set; }
    protected List<Color> InternalGradientColors { get; set; }

    protected SmoothingMode InternalSmoothingMode { get; set; }
    protected PixelOffsetMode InternalPixelOffsetMode { get; set; }

    public DashStyle BorderStyle
    {
        get { return this.InternalBorderStyle; }
        set
        {
            if (this.InternalBorderStyle != value)
            {
                this.InternalBorderStyle = value;
                this.Invalidate();
            }
        }
    }
    public UInt32 BorderWidth
    {
        get { return this.InternalBorderWidth; }
        set
        {
            if (this.InternalBorderWidth != value)
            {
                this.InternalBorderWidth = value;
                this.Invalidate();
            }
        }
    }
    public Color BorderColor
    {
        get { return this.InternalBorderColor; }
        set
        {
            if (this.InternalBorderColor != value)
            {
                this.InternalBorderColor = value;
                this.Invalidate();
            }
        }
    }
    public BackType BackType
    {
        get { return this.InternalBackType; }
        set
        {
            if (this.InternalBackType != value)
            {
                this.InternalBackType = value;
                this.Invalidate();
            }
        }
    }
    public List<Color> GradientColors
    {
        get { return this.InternalGradientColors; }
        set
        {
            if (this.InternalGradientColors != value)
            {
                this.InternalGradientColors = value;
                this.Invalidate();
            }
        }
    }

    public SmoothingMode SmoothingMode
    {
        get { return this.InternalSmoothingMode; }
        set
        {
            if (this.InternalSmoothingMode != value)
            {
                this.InternalSmoothingMode = value;
                this.Invalidate();
            }
        }
    }
    public PixelOffsetMode PixelOffsetMode
    {
        get { return this.InternalPixelOffsetMode; }
        set
        {
            if (this.InternalPixelOffsetMode != value)
            {
                this.InternalPixelOffsetMode = value;
                this.Invalidate();
            }
        }
    }

    protected override Size DefaultSize
    {
        get
        {
            return new Size(100, 100);
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = this.SmoothingMode;
        e.Graphics.PixelOffsetMode = this.PixelOffsetMode;

        ProcessBack(e.Graphics);
        ProcessBorder(e.Graphics);
        ProcessText(e.Graphics);

        base.OnPaint(e);
    }

    protected void ProcessBack(Graphics graphics)
    {
        switch (this.BackType)
        {
            case BackType.Solid:
                // Nothing special...
                break;

            case BackType.GradientHorizontal:
            case BackType.GradientVertical:
            case BackType.GradientRadial:

                    Single angle = 42;

                    if (this.BackType == BackType.GradientHorizontal)
                    {
                        angle = 0;
                    }
                    else if (this.BackType == BackType.GradientVertical)
                    {
                        angle = 90;
                    }
                    else
                    {
                        angle = 42;
                    }

                    Brush brushGradient = null;

                    Boolean isALinearBrush = (this.BackType == BackType.GradientHorizontal) || (this.BackType == BackType.GradientVertical);

                    if (isALinearBrush)
                    {
                        LinearGradientBrush linearGradientBrushHorizontal = new LinearGradientBrush(this.ClientRectangle, Color.Black, Color.Black, angle, false);
                        brushGradient = linearGradientBrushHorizontal;
                    }
                    else
                    {
                        PathGradientBrush pathGradientBrush = new PathGradientBrush(this.GraphicsPath);
                        brushGradient = pathGradientBrush;
                    }

                    ColorBlend colorBlend = new ColorBlend();
                    HashSet<Single> positions = new HashSet<Single>();

                    if (this.GradientColors.Count > 1)
                    {
                        for (Single i = 0; i < this.GradientColors.Count; i++)
                        {
                            positions.Add(i / (this.GradientColors.Count - 1));
                        }

                        colorBlend.Colors = this.GradientColors.ToArray();
                    }
                    else
                    {
                        positions.Add(0);
                        positions.Add(1);

                        if (this.GradientColors.Count == 1)
                        {
                            colorBlend.Colors = new Color[2] { this.GradientColors[0], this.GradientColors[0] };
                        }
                        else
                        {
                            colorBlend.Colors = new Color[2] { this.BackColor, this.BackColor };
                        }
                    }

                    colorBlend.Positions = positions.ToArray();

                    if (isALinearBrush)
                    {
                        (brushGradient as LinearGradientBrush).InterpolationColors = colorBlend;
                    }
                    else
                    {
                        PathGradientBrush pathGradientBrush = brushGradient as PathGradientBrush;

                        if (this.GradientRadialType == GradientRadialType.SigmaBell)
                        {
                            pathGradientBrush.SetSigmaBellShape(this.GradientRadialFocus, this.GradientRadialScale);
                        }
                        else
                        {
                            pathGradientBrush.SetBlendTriangularShape(this.GradientRadialFocus, this.GradientRadialScale);
                        }
                        pathGradientBrush.CenterPoint = new PointF(this.ClientRectangle.Right / 2, this.ClientRectangle.Bottom / 2);
                        pathGradientBrush.InterpolationColors = colorBlend;
                    }

                    graphics.FillPath(brushGradient, this.GraphicsPath);
                    break;
        }
    }
    protected void ProcessBorder(Graphics graphics)
    {
        if (this.BorderWidth > 0)
        {
            // Hey wait... * 2, why?
            Pen pen = new Pen(this.BorderColor, this.BorderWidth * 2);
            pen.DashStyle = this.BorderStyle;
            graphics.DrawPath(pen, this.GraphicsPath);
            pen.Dispose();
        }
    }
    protected void ProcessText(Graphics graphics)
    {
        Brush brushText = new SolidBrush(this.ForeColor);
        StringFormat stringFormatText = new StringFormat();
        stringFormatText.Alignment = this.TextAligmentHorizontal;
        stringFormatText.LineAlignment = this.TextAligmentVertical;
        Rectangle rectangleText = new Rectangle(0, 0, this.Width, this.Height);

        graphics.DrawString(this.Text, this.Font, brushText, rectangleText, stringFormatText);
    }

    protected StringAlignment InternalTextAligmentHorizontal { get; set; }
    protected StringAlignment InternalTextAligmentVertical { get; set; }

    public StringAlignment TextAligmentHorizontal
    {
        get { return this.InternalTextAligmentHorizontal; }
        set
        {
            if (this.InternalTextAligmentHorizontal != value)
            {
                this.InternalTextAligmentHorizontal = value;
                this.Invalidate();
            }
        }
    }
    public StringAlignment TextAligmentVertical
    {
        get { return this.InternalTextAligmentVertical; }
        set
        {
            if (this.InternalTextAligmentVertical != value)
            {
                this.InternalTextAligmentVertical = value;
                this.Invalidate();
            }
        }
    }

    protected GradientRadialType InternalGradientRadialType { get; set; }
    public GradientRadialType GradientRadialType
    {
        get { return this.InternalGradientRadialType; }
        set
        {
            if (this.InternalGradientRadialType != value)
            {
                this.InternalGradientRadialType = value;
                this.Invalidate();
            }
        }
    }

    protected Single InternalGradientRadialFocus { get; set; }
    public Single GradientRadialFocus
    {
        get { return this.InternalGradientRadialFocus; }
        set
        {
            if (this.InternalGradientRadialFocus != value)
            {
                if (1.0f < value)
                {
                    this.InternalGradientRadialFocus = 1.0f;
                }
                else if (value < 0.0f)
                {
                    this.InternalGradientRadialFocus = 0.0f;
                }
                else
                {
                    this.InternalGradientRadialFocus = value;
                }

                this.Invalidate();
            }
        }
    }

    protected Single InternalGradientRadialScale { get; set; }
    public Single GradientRadialScale
    {
        get { return this.InternalGradientRadialScale; }
        set
        {
            if (this.InternalGradientRadialScale != value)
            {
                if (1.0f < value )
                {
                    this.InternalGradientRadialScale = 1.0f;
                }
                else if (value < 0.0f)
                {
                    this.InternalGradientRadialScale = 0.0f;
                }
                else
                {
                    this.InternalGradientRadialScale = value;
                }

                this.Invalidate();
            }
        }
    }

    protected abstract GraphicsPath GraphicsPath { get; }
}

public enum GradientRadialType
{
    SigmaBell,
    Triangular,
}

public enum BackType
{
    Solid,
    GradientHorizontal,
    GradientVertical,
    GradientRadial,
}



public class EllipseControl : ShapeControl
{
    protected override GraphicsPath GraphicsPath
    {
        get 
        { 
            GraphicsPath graphicsPath = new GraphicsPath();
            graphicsPath.AddEllipse(this.ClientRectangle);

            return graphicsPath;
        }
    }
}
public class RectangleControl : ShapeControl
{
    public RectangleControl()
        : base()
    {
        this.Radius = 5;
    }

    protected UInt32 InternalRadius { get; set; }
    public UInt32 Radius
    {
        get { return this.InternalRadius; }
        set
        {
            if (this.InternalRadius != value)
            {
                this.InternalRadius = value;
                this.Invalidate();
            }
        }
    }

    protected RectangleEdgeType InternalRectangleEdge { get; set; }
    public RectangleEdgeType RectangleEdge
    {
        get { return this.InternalRectangleEdge; }
        set
        {
            if (this.InternalRectangleEdge != value)
            {
                this.InternalRectangleEdge = value;
                this.Invalidate();
            }
        }
    }

    protected override GraphicsPath GraphicsPath
    {
        get 
        {
            GraphicsPath graphicsPath = new GraphicsPath();

            if (this.Radius == 0)
            {
                graphicsPath.AddRectangle(new Rectangle(0, 0, this.Width, this.Height));
            }
            else
            {
                Int32 width = this.Width;
                Int32 height = this.Height;
                Single radius = Convert.ToSingle(this.Radius);
                RectangleF rectangleF = this.ClientRectangle;
                Graphics graphics = null;

                graphicsPath = GenerateRoundedRectangle(graphics, rectangleF, radius, RectangleEdgeType.All);
            }

            return graphicsPath;
        }
    }

    private static GraphicsPath GenerateRoundedRectangle(Graphics graphics, RectangleF rectangle, Single radius, RectangleEdgeType filter)
    {
        Single diameter;
        GraphicsPath path = new GraphicsPath();
        {
            if (radius >= (Math.Min(rectangle.Width, rectangle.Height)) / 2.0)
                return GenerateCapsule(graphics, rectangle);

            diameter = radius * 2.0F;
            SizeF sizeF = new SizeF(diameter, diameter);
            RectangleF arc = new RectangleF(rectangle.Location, sizeF);
            if ((RectangleEdgeType.TopLeft & filter) == RectangleEdgeType.TopLeft)
            {
                path.AddArc(arc, 180, 90);
            }
            else
            {
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
                path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
            }
            arc.X = rectangle.Right - diameter;
            if ((RectangleEdgeType.TopRight & filter) == RectangleEdgeType.TopRight)
            {
                path.AddArc(arc, 270, 90);
            }
            else
            {
                path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
                path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X + arc.Width, arc.Y);
            }
            arc.Y = rectangle.Bottom - diameter;
            if ((RectangleEdgeType.BottomRight & filter) == RectangleEdgeType.BottomRight)
            {
                path.AddArc(arc, 0, 90);
            }
            else
            {
                path.AddLine(arc.X + arc.Width, arc.Y, arc.X + arc.Width, arc.Y + arc.Height);
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X + arc.Width, arc.Y + arc.Height);
            }
            arc.X = rectangle.Left;

            if ((RectangleEdgeType.BottomLeft & filter) == RectangleEdgeType.BottomLeft)
            {
                path.AddArc(arc, 90, 90);
            }
            else
            {
                path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X, arc.Y + arc.Height);
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
            }
            path.CloseFigure();
        }
        return path;
    }
    private static GraphicsPath GenerateCapsule( Graphics graphics, RectangleF rectangle)
    {
        Single diameter;
        RectangleF arc;
        GraphicsPath path = new GraphicsPath();

        try
        {
            if (rectangle.Width > rectangle.Height)
            {
                diameter = rectangle.Height;
                SizeF sizeF = new SizeF(diameter, diameter);
                arc = new RectangleF(rectangle.Location, sizeF);
                path.AddArc(arc, 90, 180);
                arc.X = rectangle.Right - diameter;
                path.AddArc(arc, 270, 180);
            }
            else if (rectangle.Width < rectangle.Height)
            {
                diameter = rectangle.Width;
                SizeF sizeF = new SizeF(diameter, diameter);
                arc = new RectangleF(rectangle.Location, sizeF);
                path.AddArc(arc, 180, 180);
                arc.Y = rectangle.Bottom - diameter;
                path.AddArc(arc, 0, 180);
            }
            else
            {
                path.AddEllipse(rectangle);
            }
        }
        catch 
        { 
            path.AddEllipse(rectangle); 
        }
        finally 
        { 
            path.CloseFigure(); 
        }

        return path;
    }
}

public enum RectangleEdgeType
{
    None = 0,
    TopLeft = 1,
    TopRight = 2,
    BottomLeft = 4,
    BottomRight = 8,
    All = TopLeft | TopRight | BottomLeft | BottomRight
}
Was it helpful?

Solution

From PathGradientBrush

Path gradient brushes do not obey the SmoothingMode property of the Graphics object used to do the drawing. Areas filled using a PathGradientBrush object are rendered the same way (aliased) regardless of the smoothing mode.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top