using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Reflection;
using System.Collections;
namespace NEnumGroupBox
{
public class EnumGroupBox : GroupBox
{
#region Public Enums
[Flags]
public enum ControlType
{
radioButton = 0,
checkBox = 1
}
[Flags]
public enum BuildDirection
{
row_by_row = 0,
col_by_col = 1
}
[Flags]
public enum CaptDescription
{
descNo = 0,
descYes = 1,
descNotNull = descYes << 1
}
#endregion
#region Constructor(s)
public EnumGroupBox():base()
{
m_EnumHorizontalStep = 80;
m_EnumVerticalStep = 24;
m_EnumSingleHeight = 16;
m_EnumSingleWidth = 80;
m_checkArgs = new CheckArgs();
m_Value = -1;
m_cols = -1;
m_rows = -1;
m_EnumUpperLeft = new System.Drawing.Point(8, 16);
m_EnumStep = new System.Drawing.Size(m_EnumHorizontalStep, m_EnumVerticalStep);
m_EnumSingleSize = new System.Drawing.Size(m_EnumSingleWidth, m_EnumSingleHeight);
m_AutoSize = false;
m_BuildDirection = BuildDirection.row_by_row;
m_numControls = -1;
m_captDescription = CaptDescription.descNo;
m_width = -1;
m_height = -1;
this.Text = "";
}
#endregion
#region Local Variables
private CheckArgs m_checkArgs;
private Enum m_SourceEnum;
private ControlType m_ButtonType;
private Type m_SourceEnumType;
private System.Drawing.Point m_EnumUpperLeft;
private System.Drawing.Size m_EnumSingleSize;
private System.Drawing.Size m_EnumStep;
private bool m_AutoSize;
private BuildDirection m_BuildDirection;
private bool m_noEvent;
private int m_EnumHorizontalStep;
private int m_EnumSingleHeight;
private int m_EnumSingleWidth;
private int m_EnumVerticalStep;
private int m_Left;
private int m_Top;
private int m_Value;
private int m_cols;
private int m_rows;
private int m_propCols;
private int m_propRows;
private int m_numControls;
private int m_width;
private int m_height;
private ArrayList m_controlList;
private Control[] m_controls;
private int[] m_int_values;
private string m_Title;
private string[] m_names;
private string[] m_description;
private string[] m_caption;
private CaptDescription m_captDescription;
#endregion
#region Properties
/// <summary>
/// Summary origin of captions
/// </summary>
[Description("Defines whether captions aren taken from DescriptionAttributes or from Item names")]
public CaptDescription EnumCaptDescription
{
set
{
try
{
checkRunTime();
m_captDescription = value;
}
catch (System.Exception)
{
// throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
cleanControls();
m_captDescription = value;
EnumSource(m_SourceEnum, m_ButtonType);
}
}
get
{
return m_captDescription;
}
}
/// <summary>
/// Summary number of columns
/// </summary>
[Description("Defines the number of columns the EnumGroupBox should have. -1 means that the number is calculated if EnumAutoSize is True")]
public int EnumCols
{
set
{
try
{
checkRunTime();
m_propCols = value;
}
catch (System.Exception)
{
// throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
m_propCols = value;
m_rows = -1;
cleanControls();
calcSize();
EnumSource(m_SourceEnum, m_ButtonType);
}
}
get
{
return m_propCols;
}
}
/// <summary>
/// Summary number of rows
/// </summary>
[Description("Defines the number of rows the EnumGroupBox should have. -1 means that the number is calculated if EnumAutoSize is True")]
public int EnumRows
{
set
{
try
{
checkRunTime();
m_propRows = value;
}
catch (System.Exception)
{
throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
}
}
get
{
return m_propRows;
}
}
/// <summary>
/// Summary defines order of building controls
/// </summary>
[Description("Defines the order how the single EnumGroupBox controls are generated")]
public BuildDirection EnumBuildDirection
{
set
{
try
{
checkRunTime();
m_BuildDirection = value;
}
catch (System.Exception)
{
// throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
cleanControls();
m_BuildDirection = value;
EnumSource(m_SourceEnum, m_ButtonType);
}
}
get
{
return m_BuildDirection;
}
}
/// <summary>
/// Summary defines autosizing of the EnumGroupBox
/// </summary>
[Description("Defines whether the EnumGroupBox sizes itself depending on the contained controls")]
public bool EnumAutoSize
{
set
{
try
{
checkRunTime();
m_AutoSize = value;
}
catch (System.Exception)
{
// throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
m_AutoSize = value;
cleanControls();
calcSize();
EnumSource(m_SourceEnum, m_ButtonType);
}
}
get
{
return m_AutoSize;
}
}
/// <summary>
/// Summary define constellation from outside
/// </summary>
public int Value
{
set
{
if (value != m_Value)
{
// throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
m_Value = value;
showOptions();
m_checkArgs.intValue = m_Value;
EnumChanged(this, m_checkArgs);
}
}
}
/// <summary>
/// Summary location of the upper left control inside the EnumGroupBox
/// </summary>
[Description("Defines the position of the upper left control inside the EnumGroupBox")]
public System.Drawing.Point EnumUpperLeft
{
set
{
try
{
checkRunTime();
m_EnumUpperLeft = value;
}
catch (System.Exception)
{
throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
}
}
get
{
return m_EnumUpperLeft;
}
}
/// <summary>
/// Summary size of a control inside the EnumGroupBox
/// default: EnumStep
/// </summary>
[Description("Defines the size of a single control inside the EnumGroupBox")]
public System.Drawing.Size EnumSingleSize
{
set
{
try
{
checkRunTime();
m_EnumSingleSize = value;
m_EnumSingleHeight = m_EnumSingleSize.Height;
m_EnumSingleWidth = m_EnumSingleSize.Width;
}
catch (System.Exception)
{
throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
}
}
get
{
return m_EnumSingleSize;
}
}
/// <summary>
/// Summary offset of the second, third, ... control
/// </summary>
[Description("Defines the distance between the single controls")]
public System.Drawing.Size EnumStep
{
set
{
try
{
checkRunTime();
m_EnumStep = value;
m_EnumHorizontalStep = m_EnumStep.Width;
m_EnumVerticalStep = m_EnumStep.Height;
}
catch (System.Exception)
{
throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
}
}
get
{
return m_EnumStep;
}
}
/// <summary>
/// Summary enum to describe by this EnumGroupBox
/// </summary>
public String[] EnumCaptions
{
set
{
try
{
checkRunTime();
if (value == null)
return;
for(int i=0;i<value.Length;i++)
if (i < m_caption.Length)
{
m_caption[i] = value[i];
m_controls[i].Text=value[i];
}
}
catch (System.Exception)
{
throw;
// if you allow runtime changes of this property, comment out 'throw;'
// and write the corresponding code here
}
}
}
#endregion
#region Public Methods
/// <summary>
/// Summary enum and control type for this EnumGroupBox
/// </summary>
public bool EnumSource (object enumSource, ControlType buttonType)
{
m_SourceEnum = (Enum)enumSource;
if (m_SourceEnum != null)
{
m_SourceEnumType = m_SourceEnum.GetType();
string enumName = m_SourceEnumType.Name;
m_ButtonType = buttonType;
if (m_SourceEnumType == null)
return false;
Array m_values = Enum.GetValues(m_SourceEnumType);
if (m_names == null)
{
m_names = Enum.GetNames(m_SourceEnumType);
m_description = new string[m_values.Length];
m_caption = new string[m_values.Length];
m_int_values = new int[m_values.Length];
m_values.CopyTo(m_int_values,0);
m_Value = m_int_values[getIndex(m_SourceEnum.ToString())];
for(int i=0;i<m_description.Length;i++)
{
FieldInfo fi= m_SourceEnum.GetType().GetField(m_values.GetValue(i).ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
m_description[i] = attributes[0].Description.ToString();
}
}
m_controlList = new ArrayList();
// retreive the name of the field corresponding to the actual enum
if (m_SourceEnumType.DeclaringType != null)
{
MemberInfo[] x = m_SourceEnumType.DeclaringType.GetMembers();
for (int i=0;i<x.Length;i++)
{
if (x[i].MemberType.Equals(MemberTypes.Property))
{
string z = x[i].ToString();
string[] n = z.Split(' ');
if (enumName.EndsWith(n[1]))
{
m_Title = null;
DescriptionAttribute[] attributes;
switch (m_captDescription)
{
case CaptDescription.descYes:
attributes = (DescriptionAttribute[])m_SourceEnum.GetType().GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
m_Title = attributes[0].Description.ToString();
if (m_Title == null)
m_Title = "";
break;
case CaptDescription.descNotNull:
attributes = (DescriptionAttribute[])m_SourceEnum.GetType().GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
m_Title = attributes[0].Description.ToString();
if (m_Title == null)
m_Title = x[i].Name;
break;
case CaptDescription.descNo:
m_Title = x[i].Name;
break;
}
break;
}
}
}
}
else
{
m_Title = "???";
}
this.Text = m_Title;
switch (buttonType)
{
case ControlType.checkBox:
CreateCheckBoxes();
break;
case ControlType.radioButton:
CreateRadioButtons();
break;
}
return true;
}
return false;
}
#endregion
#region Local Methods
private bool checkRunTime()
{
if (m_Title == null)
return true;
System.Exception e = new System.Exception("Property can be set in Designer only!");
throw(e);
}
private void cleanControls()
{
for (int i=0;i<m_controls.Length;i++)
{
this.Controls.Remove(m_controls[i]);
m_controls[i] = null;
}
m_controls = null;
}
private void CreateRadioButtons()
{
m_Top = m_EnumUpperLeft.Y;
m_Left = m_EnumUpperLeft.X;
if (m_numControls == -1)
{
m_numControls = m_names.Length+1;
calcSize();
}
for (int i=0;i<m_names.Length;i++)
{
if (m_captDescription == CaptDescription.descNo)
addControl(m_names[i], new RadioButton());
else
addControl(m_description[i], new RadioButton());
}
m_controls = new Control[m_controlList.Count];
m_controlList.CopyTo(m_controls);
m_controlList.Clear();
m_controlList = null;
showOptions();
}
private void CreateCheckBoxes()
{
m_Top = m_EnumUpperLeft.Y;
m_Left = m_EnumUpperLeft.X;
if (m_numControls == -1)
{
m_numControls = 0;
for (int i=0;i<m_names.Length;i++)
{
if (m_int_values[i] != 0)
m_numControls++;
}
calcSize();
}
for (int i=0;i<m_names.Length;i++)
{
if (m_int_values[i] != 0)
{
if (m_captDescription == CaptDescription.descNo)
addControl(m_names[i], new CheckBox());
else
addControl(m_description[i], new CheckBox());
}
}
m_controls = new Control[m_controlList.Count];
m_controlList.CopyTo(m_controls);
m_controlList.Clear();
m_controlList = null;
showOptions();
}
private void calcSize()
{
int rem = 0;
if (m_width == -1)
{
m_width = this.Width;
m_height = this.Height;
}
if (m_AutoSize)
{
if ((m_propCols == -1) && (m_propRows == -1))
{
m_cols = Math.DivRem(this.Width, m_EnumHorizontalStep, out rem);
if (rem != 0)
m_cols++;
m_rows = Math.DivRem(m_numControls, m_cols, out rem);
if (rem != 0)
m_rows++;
}
else if (m_propRows == -1)
{
m_cols = m_propCols;
m_rows = Math.DivRem(m_numControls, m_cols, out rem);
if (rem != 0)
m_rows++;
}
else if (m_propCols == -1)
{
m_rows = m_propRows;
m_cols = Math.DivRem(m_numControls, m_rows, out rem);
if (rem != 0)
m_cols++;
}
this.Height = m_EnumUpperLeft.Y + m_rows * m_EnumVerticalStep;
this.Width = 2 * m_EnumUpperLeft.X + m_cols * m_EnumHorizontalStep;
}
else
{
this.Width = m_width;
this.Height = m_height;
m_cols = Math.DivRem(this.Width, m_EnumHorizontalStep, out rem);
if (rem != 0)
m_cols++;
m_rows = Math.DivRem(m_numControls, m_cols, out rem);
if (rem != 0)
m_rows++;
}
}
private void addControl(string enumName, Control chk)
{
int i = getIndex(enumName);
if (i != -1) // emergency brake, -1 should never appear
{
chk.Tag = m_int_values[i];
chk.Name = m_names[i];
chk.Text = enumName;
chk.TabStop = false;
chk.Visible = true;
chk.Size = new System.Drawing.Size(m_EnumSingleWidth, m_EnumSingleHeight);
chk.Location = new System.Drawing.Point(m_Left, m_Top);
// calculate location for next control
if (m_BuildDirection == BuildDirection.row_by_row)
{
m_Left += m_EnumHorizontalStep;
// perhaps new row
if (m_Left > this.Width - m_EnumHorizontalStep)
{
m_Left = m_EnumUpperLeft.X;
m_Top += m_EnumVerticalStep;
}
}
else
{
m_Top += m_EnumVerticalStep;
// perhaps new column
if (m_Top > this.Height - m_EnumVerticalStep)
{
m_Top = m_EnumUpperLeft.Y;
m_Left += m_EnumHorizontalStep;
}
}
// add event handler
if (chk is CheckBox)
((CheckBox)chk).CheckStateChanged +=new EventHandler(EnumCheckChanged);
else if (chk is RadioButton)
((RadioButton)chk).CheckedChanged +=new EventHandler(EnumRadioChanged);
this.Controls.Add(chk);
if (m_controlList.Count < i)
m_controlList.Add(new CheckBox());
m_controlList.Insert(i, chk);
m_caption[i] = chk.Text;
}
}
private int getIndex(string enumName)
{
for (int i=0;i<m_names.Length;i++)
{
if (m_names[i].Equals(enumName))
{
return i;
}
if (enumName.Equals(m_description[i]))
{
return i;
}
}
return -1;
}
private void showOptions()
{
// supress EnumChanged event to be fired
m_noEvent = true;
foreach (Control x in this.Controls)
{
int val = (int)x.Tag;
if ((m_Value & val) == val)
{
if (x is CheckBox)
((CheckBox)x).CheckState = CheckState.Checked;
else if (x is RadioButton)
((RadioButton)x).Checked = true;
}
else
{
if (x is CheckBox)
((CheckBox)x).CheckState = CheckState.Unchecked;
else if (x is RadioButton)
((RadioButton)x).Checked = false;
}
}
// reactivate EnumChanged event
m_noEvent = false;
}
#endregion
#region Local Events
private void EnumCheckChanged(object sender, EventArgs e)
{
if (m_noEvent)
return;
CheckBox tst = (CheckBox)sender;
if (tst.CheckState == CheckState.Checked)
{
m_Value |= (int)(tst.Tag);
}
else if (tst.CheckState == CheckState.Unchecked)
{
m_Value &= ~(int)(tst.Tag);
}
m_checkArgs.intValue = m_Value;
EnumChanged(this, m_checkArgs);
}
private void EnumRadioChanged(object sender, EventArgs e)
{
if (m_noEvent)
return;
m_Value = (int)(((Control)sender).Tag);
m_checkArgs.intValue = m_Value;
EnumChanged(this, m_checkArgs);
}
#endregion
#region Custom Events
// The event arguments class, derived from EventArgs
public class CheckArgs : EventArgs
{
private object m_val;
public CheckArgs()
{
}
public object Value
{
get
{
return m_val;
}
}
// to hold the 'Set Property' internal, we use a different Property
internal object intValue
{
set
{
m_val = value;
}
}
}
// The delegate procedure we are assigning to EnumGroupBox
public delegate void CheckHandler(object sender, CheckArgs a);
// The Event Definition
public event CheckHandler EnumChanged;
#endregion
}
}