File: winforms\Managed\System\WinForms\ButtonInternal\RadioButtonBaseAdapter.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ButtonBase.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms.ButtonInternal {
    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms.Internal;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Drawing.Text;
    using System.Windows.Forms;
    using System.Windows.Forms.VisualStyles;
 
    internal abstract class RadioButtonBaseAdapter   : CheckableControlBaseAdapter {
 
        internal RadioButtonBaseAdapter(ButtonBase control) : base(control) {}
 
        protected new RadioButton Control {
            get {
                return ((RadioButton)base.Control);
            }
        }
 
        #region Drawing helpers
        protected void DrawCheckFlat(PaintEventArgs e, LayoutData layout, Color checkColor, Color checkBackground, Color checkBorder) {
            DrawCheckBackgroundFlat(e, layout.checkBounds, checkBorder, checkBackground);
            DrawCheckOnly(e, layout, checkColor, checkBackground, true);
        }
 
        protected void DrawCheckBackground3DLite(PaintEventArgs e, Rectangle bounds, Color checkColor, Color checkBackground, ColorData colors, bool disabledColors) {
            Graphics g = e.Graphics;            
            
            Color field = checkBackground;
            if (!Control.Enabled && disabledColors) {
                field = SystemColors.Control;
            }
 
            using (Brush fieldBrush = new SolidBrush(field)) {
                using (Pen dark = new Pen(colors.buttonShadow),
                       light = new Pen(colors.buttonFace),
                       lightlight = new Pen(colors.highlight)) {
 
                    bounds.Width--;
                    bounds.Height--;
                    // fall a little short of SW, NW, NE, SE because corners come out nasty
                    g.DrawPie(dark, bounds, (float)(135 + 1), (float)(90 - 2));
                    g.DrawPie(dark, bounds, (float)(225 + 1), (float)(90 - 2));
                    g.DrawPie(lightlight, bounds, (float)(315 + 1), (float)(90 - 2));
                    g.DrawPie(lightlight, bounds, (float)(45 + 1), (float)(90 - 2));
                    bounds.Inflate(-1, -1);
                    g.FillEllipse(fieldBrush, bounds);
                    g.DrawEllipse(light, bounds);
                }
            }
        }
 
        protected void DrawCheckBackgroundFlat(PaintEventArgs e, Rectangle bounds, Color borderColor, Color checkBackground) {
            Color field = checkBackground;
            Color border = borderColor;
            
            if (!Control.Enabled) {
                // if we are not in HighContrast mode OR we opted into the legacy behavior
                if (!SystemInformation.HighContrast || !AccessibilityImprovements.Level1) {
                    border = ControlPaint.ContrastControlDark;
                }
                // otherwise we are in HighContrast mode 
                field = SystemColors.Control;
            }
 
            double scale = GetDpiScaleRatio(e.Graphics);
 
            using( WindowsGraphics wg = WindowsGraphics.FromGraphics(e.Graphics) ) {
                using( WindowsPen borderPen = new WindowsPen(wg.DeviceContext, border) ) {
                    using( WindowsBrush fieldBrush = new WindowsSolidBrush(wg.DeviceContext, field) ) {                                                
                        // for Dev10 525537, in high DPI mode when we draw ellipse as three rectantles, 
                        // the quality of ellipse is poor. Draw it directly as ellipse
                        if(scale > 1.1) {
                            bounds.Width--;
                            bounds.Height--;
                            wg.DrawAndFillEllipse(borderPen, fieldBrush, bounds);
                            bounds.Inflate(-1, -1);
                        }
                        else {
                            DrawAndFillEllipse(wg, borderPen, fieldBrush, bounds);
                        }
                    }
                }
            }
        }
 
		// Helper method to overcome the poor GDI ellipse drawing routine
		// VSWhidbey #334097
		private static void DrawAndFillEllipse(WindowsGraphics wg, WindowsPen borderPen, WindowsBrush fieldBrush, Rectangle bounds)
		{
            Debug.Assert(wg != null,"Calling DrawAndFillEllipse with null wg");
		    if (wg == null) {
                return;
		    }
            
			wg.FillRectangle(fieldBrush, new Rectangle(bounds.X + 2, bounds.Y + 2, 8, 8));
			wg.FillRectangle(fieldBrush, new Rectangle(bounds.X + 4, bounds.Y + 1, 4, 10));
			wg.FillRectangle(fieldBrush, new Rectangle(bounds.X + 1, bounds.Y + 4, 10, 4));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 4, bounds.Y + 0), new Point(bounds.X + 8, bounds.Y + 0));
			wg.DrawLine(borderPen, new Point(bounds.X + 4, bounds.Y + 11), new Point(bounds.X + 8, bounds.Y + 11));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 2, bounds.Y + 1), new Point(bounds.X + 4, bounds.Y + 1));
			wg.DrawLine(borderPen, new Point(bounds.X + 8, bounds.Y + 1), new Point(bounds.X + 10, bounds.Y + 1));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 2, bounds.Y + 10), new Point(bounds.X + 4, bounds.Y + 10));
			wg.DrawLine(borderPen, new Point(bounds.X + 8, bounds.Y + 10), new Point(bounds.X + 10, bounds.Y + 10));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 0, bounds.Y + 4), new Point(bounds.X + 0, bounds.Y + 8));
			wg.DrawLine(borderPen, new Point(bounds.X + 11, bounds.Y + 4), new Point(bounds.X + 11, bounds.Y + 8));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 1, bounds.Y + 2), new Point(bounds.X + 1, bounds.Y + 4));
			wg.DrawLine(borderPen, new Point(bounds.X + 1, bounds.Y + 8), new Point(bounds.X + 1, bounds.Y + 10));
 
			wg.DrawLine(borderPen, new Point(bounds.X + 10, bounds.Y + 2), new Point(bounds.X + 10, bounds.Y + 4));
			wg.DrawLine(borderPen, new Point(bounds.X + 10, bounds.Y + 8), new Point(bounds.X + 10, bounds.Y + 10));
		}
 
        private static int GetScaledNumber(int n, double scale)
        {
            return (int)(n * scale);
        }
 
        protected void DrawCheckOnly(PaintEventArgs e, LayoutData layout, Color checkColor, Color checkBackground, bool disabledColors) {
 
            // check
            //
            if (Control.Checked) {
                if (!Control.Enabled && disabledColors) {
                    checkColor = SystemColors.ControlDark;
                }
 
                double scale = GetDpiScaleRatio(e.Graphics);
                using( WindowsGraphics wg = WindowsGraphics.FromGraphics(e.Graphics) ) {
                    using (WindowsBrush brush = new WindowsSolidBrush(wg.DeviceContext, checkColor)) {
                        // circle drawing doesn't work at this size
                        int offset = 5;                                                                   
                        Rectangle vCross = new Rectangle (layout.checkBounds.X + GetScaledNumber(offset, scale), layout.checkBounds.Y + GetScaledNumber(offset - 1, scale), GetScaledNumber(2, scale), GetScaledNumber(4, scale));
                        wg.FillRectangle(brush, vCross);
                        Rectangle hCross = new Rectangle (layout.checkBounds.X + GetScaledNumber(offset - 1, scale), layout.checkBounds.Y + GetScaledNumber(offset, scale), GetScaledNumber(4, scale), GetScaledNumber(2, scale));
                        wg.FillRectangle(brush, hCross);
                    }
                }
            }
        }
 
        protected ButtonState GetState() {
            ButtonState style = (ButtonState)0;
 
            if (Control.Checked) {
                style |= ButtonState.Checked;
            }
            else {
                style |= ButtonState.Normal;
            }
 
            if (!Control.Enabled) {
                style |= ButtonState.Inactive;
            }
 
            if (Control.MouseIsDown) {
                style |= ButtonState.Pushed;
            }
 
            return style;
 
        }
        
        protected void DrawCheckBox(PaintEventArgs e, LayoutData layout) {
            Graphics g = e.Graphics;
            
            Rectangle check = layout.checkBounds;
            if (!Application.RenderWithVisualStyles) {
                check.X--;      // compensate for Windows drawing slightly offset to right
            }
 
            ButtonState style = GetState();
            
            if (Application.RenderWithVisualStyles) {
                RadioButtonRenderer.DrawRadioButton(g, new Point(check.Left, check.Top), RadioButtonRenderer.ConvertFromButtonState(style, Control.MouseIsOver), Control.HandleInternal);
              }
            else {
                ControlPaint.DrawRadioButton(g, check, style);
            }
        }
 
        #endregion
 
        protected void AdjustFocusRectangle(LayoutData layout) {
            if (AccessibilityImprovements.Level2 && String.IsNullOrEmpty(Control.Text)) {
                // When a RadioButton has no text, AutoSize sets the size to zero 
                // and thus there's no place around which to draw the focus rectangle.
                // So, when AutoSize == true we want the focus rectangle to be rendered around the circle area.
                // Otherwise, it should encircle all the available space next to the box (like it's done in WPF and ComCtl32).
                layout.focus = Control.AutoSize ? layout.checkBounds : layout.field;
            }
        }
 
        internal override LayoutOptions CommonLayout() {
            LayoutOptions layout = base.CommonLayout();
            layout.checkAlign        = Control.CheckAlign;        
 
            return layout;
        }
        
    }
}