For the description of most controls we use labels and I for one don't like to add a label manually for each control. Been using a component that paints values, but never got around to put it in a nice coat and with design time support up until now. The design time being the most work (although greatly alleviated by finding out how to use the isComplete parameter of the InstanceDescriptor ;-) ), the component is easy in use and deployment.
Usage: drop it to your form (or container control) and you get a new property on each control (”Label on LabelProviderName”).
You can simply type in the labeltext and a label will be painted on its parent.
To set more details, when the text is set a LabelInfo object will be created automatically. A plus sign appears in front of the property once it has been set, to indicate it can be expanded. Other properties for the label such as the Alignment, Font and Color can then be set.
To make things complete, the LabelProvider component itself also contains a set of those properties. This is the leading set. Unless a property is set specifically for a single label, the settings of the main component will be used for all labels. (The effects can be easily tried out in the designer)
Per request some quick setup instructions:
Usage
Add this code to your project (or a dll containing this code). The component will automatically show up in the visual studio 2005 toolbox. Drag the LabelProvider to your form or control in the form designer.
Now each control you select will have an additional property: ”Label on ...”, where ... is the name of the component. The text you type in in this property, will become the label for that control.
That's it for the normal label usage. For more settings, you can change the settings on the component itself. Or you can change the settings per label: press the [+] in front of the “Label on ...“ property for additional settings
Added per 22-9-6:
ability to show icon (or show only icon, then a tooltip will be shown for the text, thus the labelprovider becomes an infoprovider)
Changable cursor
Click event
Blinking possibility
Small thing added on 19-10-6:
text is drawn as disabled if the attached control is disabled
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Reflection;
namespace Subro.Controls
{
[
ProvideProperty(
"Label",
typeof(
Control))]
[
ToolboxBitmap(
typeof(
Label))]
[
DefaultEvent(
"LabelClicked")]
public class LabelProvider :
Component,
IExtenderProvider{
#region Constructors
public LabelProvider()
: this(null)
{
}
public LabelProvider(
IContainer container)
{
if (container !=
null)
container.Add(this);
defsettings.SettingChanged +=
new EventHandler(defsettings_SettingChanged);
}
#endregion
#region IExtenderProvider Members
public bool CanExtend(object extendee)
{
return extendee is Control;
}
int IndexOf(
Control c)
{
for (
int i = 0; i < list.Count; i++)
{
if (list[i].Control == c) return i;
}
return -1; }
[DefaultValue(null)]
public LabelInfo GetLabel(Control c)
{
int i = IndexOf(c);
if (i == -1)
{
return null;
}
return list[i].LabelInfo; }
public
void SetLabel(
Control c,
LabelInfo value)
{
int i = IndexOf(c);
if (value ==
null)
{
if (i == -1) return;
list[i].Dispose();
list.RemoveAt(i);
}
else if (i == -1)
{
list.Add(new ControlLabel(this, c, value));
}
else
{
list[i].LabelInfo = value;
} }
public
class LabelClickedEventArgs :
EventArgs{
public
readonly Control Control;
public readonly LabelInfo LabelInfo;
public LabelClickedEventArgs(
Control c,
LabelInfo inf)
{
this.Control = c;
this.LabelInfo = inf;
} }
public event EventHandler<LabelClickedEventArgs> LabelClicked;
void OnLabelClicked(
ControlLabel l)
{
if (LabelClicked !=
null)
LabelClicked(this, new LabelClickedEventArgs(l.Control, l.LabelInfo));
}
class
ControlLabel :
IDisposable{
public readonly Control Control;
LabelProvider Owner;
public ControlLabel(
LabelProvider Owner,
Control c,
LabelInfo li)
{
if (c == null) throw new ArgumentNullException();
this.Control = c;
this.LabelInfo = li;
this.Owner = Owner;
li.DefaultSettings = Owner.defsettings;
ResetParent();
Control.ParentChanged += ehParentChanged;
Control.LocationChanged += ehLocationChanged;
Control.EnabledChanged += new EventHandler(Control_EnabledChanged);
}
#region enter/leave
bool focused, cursorchanged;
public bool Focused
{
get { return focused; }
}
Control ParentControl
{
get { return Parent.Parent; }
}
Cursor beforeEnter;
public void CheckEnterLeave(Point p)
{
CheckEnterLeave(bounds.Contains(p));
}
void CheckEnterLeave(
bool hasfocus)
{
if (hasfocus != focused)
{
if (hasfocus)
{
if (inf.Cursor !=
null && inf.Cursor != ParentControl.Cursor)
{
beforeEnter = ParentControl.Cursor;
ParentControl.Cursor = inf.Cursor;
cursorchanged = true;
}
if (!inf.ShowText)
Parent.ShowTooltip(this, new Point((int)bounds.Right,(int)bounds.Top));
}
else
{
if (cursorchanged)
{
ParentControl.Cursor = beforeEnter;
cursorchanged = false;
}
Parent.RemoveTooltip(
this);
}
focused = hasfocus; } }
public
void Click()
{
Owner.OnLabelClicked(this);
}
#endregion
#region label
LabelInfo inf;
public LabelInfo LabelInfo
{
get
{
return inf;
}
set
{
RemoveInfoEvents();
inf =
value;
if (inf !=
null)
inf.SettingChanged += ehSettingChanged;
Invalidate(
true);
} }
void LabelInfo_SettingChanged(object sender, EventArgs e)
{
Invalidate(true);
}
void Control_EnabledChanged(object sender, EventArgs e)
{
Invalidate(false);
}
EventHandler ehSettingChanged
{
get
{
return new EventHandler(LabelInfo_SettingChanged);
} }
void RemoveInfoEvents()
{
if (inf !=
null)
{
inf.SettingChanged -= ehSettingChanged;
}
}
RectangleF bounds;
void Invalidate(
bool ClearBounds)
{
if (ClearBounds)
{
if (!bounds.IsEmpty) bounds = new RectangleF();
StopBlink();
}
if (Parent != null)
Parent.Invalidate(this);
}
public
bool BoundsSet
{
get { return !bounds.IsEmpty; }
}
public
RectangleF Bounds
{
get { return bounds; }
}
#endregion
#region label bounds
public bool ContainsLabel
{
get
{
return inf !=
null &&
(!string.IsNullOrEmpty(inf.Text) || inf.ShowIcon);
} }
public void Paint(Graphics g)
{
if (!ContainsLabel) return;
if (bounds.IsEmpty) InitBounds(g);
if (blinker != null && blinker.ShouldHide) return;
inf.Paint(g, bounds,this.Control.Enabled);
}
void InitBounds(Graphics g)
{
bounds = inf.GetBounds(g, Control.Bounds);
InitBlink(inf.Blink);
}
private
void InitBlink(
LabelInfo.
BlinkInfo blinkInfo)
{
if (blinkInfo == null || blinkInfo.Style == BlinkStyle.None || blinkInfo.Rate == 0) return;
blinker = new Blinker(blinkInfo, this);
}
void StopBlink()
{
if (blinker !=
null)
{
blinker.Stop();
blinker = null;
}
}
Blinker blinker;
class Blinker
{
bool hide;
LabelInfo.BlinkInfo inf;
ControlLabel Owner;
DateTime start =
DateTime.Now;
bool hasend;
DateTime end;
public Blinker(
LabelInfo.
BlinkInfo inf,
ControlLabel Owner)
{
this.inf = inf;
this.Owner = Owner;
hasend = inf.Style == BlinkStyle.LimitedTime && inf.Duration > 0;
if (hasend) end = start.AddMilliseconds(inf.Duration);
SetTimer();
}
System.Threading.Timer timer;
public
bool ShouldHide
{
get { return hide; }
}
void Invalidate()
{
if (Owner.Control.InvokeRequired)
Owner.Control.Invoke(new System.Threading.ThreadStart(Invalidate));
else
Owner.Invalidate(false);
}
void SwitchHide(object state)
{
if (hasend &&
DateTime.Now >= end)
Stop();
else
if (!stopped)
{
hide = !hide;
Invalidate();
}
}
void SetTimer()
{
timer =
new System.Threading.
Timer(
new System.Threading.
TimerCallback(SwitchHide),
null, inf.Rate, inf.Rate);
}
bool stopped;
public void Stop()
{
stopped =
true;
if (hide)
{
hide = false;
Invalidate();
}
//timer.Dispose();
//timer = null;}
}
#endregion
#region location changed
void Control_LocationChanged(
object sender,
EventArgs e)
{
Invalidate(true);
}
EventHandler ehLocationChanged
{
get { return new EventHandler(Control_LocationChanged); }
}
#endregion
#region Parent
ParentReference Parent;
void RemoveFromParent()
{
if (Parent !=
null)
{
Parent.Remove(this);
}
}
void ResetParent()
{
RemoveFromParent();
Parent = Owner.GetParentReference(this);
}
void Control_ParentChanged(object sender, EventArgs e)
{
ResetParent();
}
EventHandler ehParentChanged
{
get
{
return new EventHandler(Control_ParentChanged);
} }
#endregion
#region IDisposable Members
bool isdisposed;
public bool IsDisposed { get { return isdisposed; } }
public
void Dispose()
{
Control.ParentChanged -= ehParentChanged;
Control.LocationChanged -= ehLocationChanged;
Control.EnabledChanged -= new EventHandler(Control_EnabledChanged);
RemoveInfoEvents();
RemoveFromParent();
CheckEnterLeave(false);
isdisposed = true;
}
#endregion
}
List<
ParentReference> parents =
new List<
ParentReference>();
ParentReference GetParentReference(
ControlLabel cl)
{
Control Parent = cl.Control.Parent;
if (Parent ==
null)
return null;
ParentReference pr =
null;
for (
int i = 0; i < parents.Count; i++)
{
if (parents[i].Parent == Parent)
{
pr = parents[i];
break;
}
}
if (pr == null)
{
pr = new ParentReference(Parent, this);
parents.Add(pr);
}
pr.Add(cl);
return pr; }
class ParentReference
{
public
Control Parent;
LabelProvider Owner;
public ParentReference(
Control Parent,
LabelProvider Owner)
{
this.Parent = Parent;
this.Parent.Paint += ehPaint;
this.Owner = Owner;
Parent.MouseMove += new MouseEventHandler(Parent_MouseMove);
Parent.MouseLeave += new EventHandler(Parent_MouseLeave);
Parent.Click += new EventHandler(Parent_Click);
}
#region focus
void Parent_MouseMove(
object sender,
MouseEventArgs e)
{
CheckBounds();
}
void Parent_MouseLeave(
object sender,
EventArgs e)
{
CheckBounds();
}
void CheckBounds()
{
Point p = Parent.PointToClient(
Control.MousePosition);
foreach (
ControlLabel c
in children)
{
c.CheckEnterLeave(p);
}
}
void Parent_Click(object sender, EventArgs e)
{
foreach (
ControlLabel c
in GetFocusedControls())
{
c.Click();
}
}
IEnumerable<
ControlLabel> GetFocusedControls()
{
for (
int i = 0; i < children.Count; i++)
{
ControlLabel c = children[i];
if (!c.IsDisposed && c.Focused) yield return c;
if (c.IsDisposed) i--;
} }
#endregion
#region Paint
PaintEventHandler ehPaint
{
get
{
return new PaintEventHandler(Parent_Paint);
} }
void Parent_Paint(object sender, PaintEventArgs e)
{
foreach (
ControlLabel cl
in children)
{
cl.Paint(e.Graphics);
}
}
public void Invalidate(ControlLabel cl)
{
if (cl.BoundsSet)
Parent.Invalidate(new Region(cl.Bounds));
else
Invalidate();
}
/// <summary>
/// Invalidates all current labels
///
public void Invalidate()
{
Region r =
new Region();
foreach (
ControlLabel cl
in children)
{
if (cl.BoundsSet)
{
r.Union(cl.Bounds);
}
else{
Parent.Invalidate();
return;
}
}
Parent.Invalidate(r); }
#endregion
#region Children
List<
ControlLabel> children =
new List<
ControlLabel>();
public void Add(
ControlLabel cl)
{
children.Add(cl);
Invalidate(cl);
}
public void Remove(
ControlLabel cl)
{
children.Remove(cl);
Invalidate(cl);
if (children.Count == 0)
{
Dispose();
}
}
#endregion
#region tooltip
ToolTip tt;
public
void ShowTooltip(
ControlLabel c,
Point p)
{
if (tt ==
null)
{
tt = new ToolTip();
tt.ShowAlways = true;
}
tt.Show(c.LabelInfo.Text, Parent, p.X, p.Y, 5000);
//tt.SetToolTip(c.Control, c.LabelInfo.Text);
}
public void RemoveTooltip(
ControlLabel c)
{
if (tt == null) return;
tt.Hide(Parent);
//tt.SetToolTip(c.Control, null);
}
#endregion
public void Dispose()
{
Parent.Paint -= ehPaint;
Parent.MouseMove -=
new MouseEventHandler(Parent_MouseMove);
Parent.MouseLeave -=
new EventHandler(Parent_MouseLeave);
Parent.Click -=
new EventHandler(Parent_Click);
Owner.parents.Remove(
this);
if (tt !=
null)
{
tt.Dispose();
tt = null;
}
}
}
List<ControlLabel> list = new List<ControlLabel>();
#endregion
#region Default settings
private LabelInfo defsettings =
new LabelInfo(
null);
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content)]
public LabelInfo DefaultSettings
{
get { return defsettings; }
}
void defsettings_SettingChanged(object sender, EventArgs e)
{
foreach (
ParentReference p
in parents)
{
p.Invalidate();
}
}
public override ISite Site
{
get
{
return base.Site;
}
set
{
defsettings.DesignTime = value != null && value.DesignMode;
base.Site = value;
} }
#endregion
#region Designer
public class LabelLayoutEditor : UITypeEditor
{
public
override UITypeEditorEditStyle GetEditStyle(
ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
IWindowsFormsEditorService iw;
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
iw = (
IWindowsFormsEditorService)provider.GetService(
typeof(
IWindowsFormsEditorService));
LayoutPicker f =
new LayoutPicker();
if (value !=
null)
f.Result = (LabelLayout)value;
if (context.Instance
is LabelInfo)
{
LabelInfo inf = context.Instance
as LabelInfo;
if (inf.DefaultSettings !=
null && inf.DefaultSettings.Layout !=
LabelLayout.NotSet)
{
f.RevertValue = inf.DefaultSettings.Layout;
}
}
f.TablePanel.LayoutChosen += new EventHandler<LayoutPicker.LayoutPickerTable.LayoutChosenEventArgs>(TablePanel_LayoutChosen);
iw.DropDownControl(f);
return f.Result;
}
void TablePanel_LayoutChosen(
object sender,
LayoutPicker.
LayoutPickerTable.
LayoutChosenEventArgs e)
{
iw.CloseDropDown();
}
}
#endregion
}
[
TypeConverter(
typeof(
LabelInfo.
LabelInfoConverter))]
public class LabelInfo{
#region Constructor
public LabelInfo(
string Text)
{
this.Text = Text;
Init();
}
#endregion
#region setings
enum LabelInfoSettings
{
Font, Padding, Layout, ForeColor, BackColor, Icon, ShowIcon, ShowText, Cursor, BlinkStyle, BlinkRate, BlinkDuration
}
object[] settings;
void Init()
{
Array arr = Enum.GetValues(typeof(LabelInfoSettings));
settings = new object[arr.Length];
}
bool designtime;
internal bool DesignTime
{
get
{
if (owner != null) return owner.DesignTime;
return designtime;
}
set
{
if (designtime ==
value)
return;
designtime =
value;
if (designtime)
{
if (blink ==
null)
blink = new BlinkInfo(this);
} } }
object GetSetting(LabelInfoSettings setting)
{
int i = (
int)setting;
if (settings[i] ==
null)
{
if (owner !=
null)
return owner.GetSetting(setting);
return GetDefaultSetting(setting);
}
return settings[i]; }
T GetSetting<T>(
LabelInfoSettings setting)
{
object o = GetSetting(setting);
if (IsNullValue(setting, o))
return GetDefaultSetting<T>(setting);
return (T)o;
}
object GetDefaultSetting(LabelInfoSettings setting)
{
switch (setting)
{
case
LabelInfoSettings.Font:
return DefaultFont;
case LabelInfoSettings.Padding:
return 5;
case LabelInfoSettings.Layout:
return LabelLayout.Default;
case LabelInfoSettings.ForeColor:
return Color.Black;
case LabelInfoSettings.BackColor:
return Color.Empty;
case LabelInfoSettings.Icon:
return DefaultIcon;
case LabelInfoSettings.ShowIcon:
return false;
case LabelInfoSettings.ShowText:
return true;
case LabelInfoSettings.BlinkDuration:
return 5000;
case LabelInfoSettings.BlinkRate:
return 500;
case LabelInfoSettings.BlinkStyle:
return BlinkStyle.None;
}
return null; }
T GetDefaultSetting<T>(LabelInfoSettings setting)
{
return (T)GetDefaultSetting(setting);
}
bool IsNullValue(LabelInfoSettings setting, object value)
{
if (value ==
null)
return true;
if (value
is ValueType)
{
if (setting ==
LabelInfoSettings.Layout)
return (LabelLayout)value == LabelLayout.NotSet;
if (value
is Color)
return ((Color)value).IsEmpty;
if (value
is bool)
return false;
return (
int)
Convert.ChangeType(value,
typeof(
int)) == 0;
}
return false; }
bool HasSetting(LabelInfoSettings setting)
{
return settings[(int)setting] != null;
}
void SetSetting(LabelInfoSettings setting, object value)
{
object cur = GetSetting(setting);
if (IsNullValue(setting, value))
{
if (cur == null) return;
value = null;
}
else if (value.Equals(cur))
return;
settings[(int)setting] = value;
OnSettingChanged(); }
void ResetSetting(LabelInfoSettings setting)
{
settings[(int)setting] = owner == null ? GetDefaultSetting(setting) : null;
}
bool ShouldSerializeSetting(LabelInfoSettings setting)
{
object o = settings[(int)setting];
return !IsNullValue(setting, o);
}
public
event EventHandler SettingChanged;
void OnSettingChanged()
{
if (SettingChanged !=
null)
SettingChanged(this, EventArgs.Empty);
}
#endregion
#region Text
private string text;
[
NotifyParentProperty(
true)]
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
public string Text
{
get {
return text; }
set{
if (
value !=
null &&
value.Trim().Length == 0)
text = null;
else
text = value;
if (TextChanged !=
null)
TextChanged(this, EventArgs.Empty);
OnSettingChanged();
} }
public override string ToString()
{
return text;
}
public event EventHandler TextChanged;
#endregion
#region Layout
[AmbientValue(LabelLayout.NotSet)]
public LabelLayout Layout
{
get
{
return GetSetting<LabelLayout>(LabelInfoSettings.Layout);
}
set
{
SetSetting(LabelInfoSettings.Layout, value);
} }
bool ShouldSerializeLayout()
{
return ShouldSerializeSetting(LabelInfoSettings.Layout);
}
#endregion
#region Color
/// <summary>
/// The font color. NB: setting this value will overwrite the <see cref="ForeBrush"/> setting
/// [
AmbientValue(
typeof(
Color),
"Empty")]
public Color Color
{
get
{
return GetSetting<Color>(LabelInfoSettings.ForeColor);
}
set
{
SetSetting(LabelInfoSettings.ForeColor, value);
brush = null;
} }
bool ShouldSerializeColor()
{
return ShouldSerializeSetting(LabelInfoSettings.ForeColor);
}
void ResetColor()
{
ResetSetting(LabelInfoSettings.ForeColor);
}
[
AmbientValue(
typeof(
Color),
"Empty")]
public Color BackColor
{
get
{
return GetSetting<Color>(LabelInfoSettings.BackColor);
}
set
{
SetSetting(LabelInfoSettings.BackColor, value);
backbrush = null;
} }
bool ShouldSerializeBackColor()
{
return ShouldSerializeSetting(LabelInfoSettings.BackColor);
}
void ResetBackColor()
{
ResetSetting(LabelInfoSettings.BackColor);
}
#endregion
#region Brush
private
Brush brush, backbrush;
/// <summary>
/// In designtime, a solidbrush can be set through a color picker, but in runtime, the more advanced
/// brushes can be set as well
/// [
Browsable(
false)]
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
[
AmbientValue(
null)]
public Brush ForeBrush
{
get
{
if (brush ==
null)
{
if (owner ==
null)
brush = new SolidBrush(Color);
else
return owner.ForeBrush;
}
return brush; }
set
{
brush = value;
OnSettingChanged();
} }
Brush GetForeBrush()
{
if (brush !=
null)
return brush;
if (HasSetting(
LabelInfoSettings.ForeColor))
return new SolidBrush(Color);
return ForeBrush;
}
/// <summary>
/// In designtime, a solidbrush can be set through a color picker, but in runtime, the more advanced
/// brushes can be set as well
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[AmbientValue(null)]
public Brush BackBrush
{
get
{
if (backbrush ==
null && owner !=
null)
return owner.BackBrush;
return backbrush;
}
set
{
backbrush = value;
OnSettingChanged();
} }
Brush GetBackBrush()
{
if (backbrush !=
null)
return backbrush;
if (HasSetting(
LabelInfoSettings.BackColor))
return new SolidBrush(BackColor);
if (owner !=
null)
return owner.GetBackBrush();
return BackBrush;
}
#endregion
#region Bounds
static
bool HasLayout(
LabelLayout layoutFlags,
LabelLayout CheckBit)
{
return (layoutFlags & CheckBit) == CheckBit;
}
const int IconPadding = 0;
public void Paint(Graphics g, RectangleF rect,bool Enabled)
{
Brush b = GetBackBrush();
if (b !=
null)
g.FillRectangle(b, rect);
if (ShowIcon)
{
Point p =
new Point((
int)rect.X, (
int)(rect.Y + (rect.Height - Icon.Height) * .5));
if(Enabled)
g.DrawIcon(Icon, p.X, p.Y);
else
ControlPaint.DrawImageDisabled(g, Icon.ToBitmap(), p.X, p.Y, Color.Empty);
rect.Offset(Icon.Width + IconPadding, 0); }
if (ShowText)
{
if (Enabled)
g.DrawString(text, Font, GetForeBrush(), rect);
else
ControlPaint.DrawStringDisabled(g, text, Font, Color.LightGray, rect, null);
}
}
///
<summary>
/// Calculates where the label should be situated on its parent
///
/// <param name="g">
/// <returns>
public RectangleF GetBounds(
Graphics g,
Rectangle RelateTo)
{
SizeF
sizeI = ShowIcon ? Icon.Size : new SizeF(),
size = ShowText ? g.MeasureString(text, Font) : new SizeF();
if (!sizeI.IsEmpty)
{
if (size.IsEmpty)
size = sizeI;
else
{
size.Width += IconPadding + sizeI.Width;
if (sizeI.Height > size.Height) size.Height = sizeI.Height;
}
}
return GetBounds(size, RelateTo, Padding, Layout);
}
public static RectangleF GetBounds(
SizeF size,
Rectangle RelateTo,
int padding,
LabelLayout layout)
{
PointF pf = RelateTo.Location;
inth = RelateTo.Height,
w = RelateTo.Width;
if (HasLayout(layout,
LabelLayout.Left))
pf.X -= padding + size.Width;
else
if (HasLayout(layout,
LabelLayout.Right))
pf.X += padding + w;
else
if (HasLayout(layout,
LabelLayout.Center))
pf.X += (w - size.Width) / 2;
else
if (HasLayout(layout,
LabelLayout.RightFromCenter))
pf.X += w - size.Width;
if (HasLayout(layout,
LabelLayout.Top))
pf.Y -= padding + size.Height;
else
if (HasLayout(layout,
LabelLayout.Bottom))
pf.Y += h + padding;
else
if (HasLayout(layout,
LabelLayout.Middle))
pf.Y += (h - size.Height) / 2;
else
if (HasLayout(layout,
LabelLayout.UnderMiddle))
pf.Y += h - size.Height;
return new RectangleF(pf, size);
}
public static void PaintSymbol(
Graphics g,
Rectangle bounds,
LabelLayout Layout)
{
float perc = .50f;
RectangleF rect = bounds;
rect.Width *= perc;
rect.Height *= perc;
rect.X = (bounds.Width - rect.Width) / 2;
rect.Y = (bounds.Height - rect.Height) / 2;
int PenWidth = 2;
Rectangle r = Rectangle.Round(rect);
g.DrawRectangle(new Pen(Color.Navy, PenWidth), r);
SizeF size = rect.Size;
perc = .3f;
size.Width *= perc;
size.Height *= perc;
rect = LabelInfo.GetBounds(size, r, PenWidth + 1, Layout);
r = Rectangle.Round(rect);
g.DrawRectangle(new Pen(Color.YellowGreen, PenWidth), r);
}
#endregion
#region defaults
private LabelInfo owner;
/// <summary>
/// For design time support, the owner is set to determine the defaults
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public LabelInfo DefaultSettings
{
get { return owner; }
set { owner = value; }
}
#endregion
#region Font
static Font DefaultFont = new Font("Times New Roman", 10);
[AmbientValue(null)]
public Font Font
{
get
{
return GetSetting<Font>(LabelInfoSettings.Font);
}
set
{
SetSetting(LabelInfoSettings.Font, value);
} }
bool ShouldSerializeFont()
{
return ShouldSerializeSetting(LabelInfoSettings.Font);
}
void ResetFont()
{
ResetSetting(LabelInfoSettings.Font);
}
#endregion
#region Cursor
[
AmbientValue(
null)]
public Cursor Cursor
{
get
{
return GetSetting<Cursor>(LabelInfoSettings.Cursor);
}
set
{
SetSetting(LabelInfoSettings.Cursor, value);
} }
bool ShouldSerializeCursor()
{
return ShouldSerializeSetting(LabelInfoSettings.Cursor);
}
void ResetCursor()
{
ResetSetting(LabelInfoSettings.Cursor);
}
#endregion
#region Padding
/// <summary>
/// The amount of space that should exist between the end of the text and the control
///
[AmbientValue(-1)]
public int Padding
{
get
{
return GetSetting<int>(LabelInfoSettings.Padding);
}
set
{
SetSetting(LabelInfoSettings.Padding, value);
} }
bool ShouldSerializePadding()
{
return ShouldSerializeSetting(LabelInfoSettings.Padding);
}
void ResetPadding()
{
ResetSetting(LabelInfoSettings.Padding);
}
#endregion
#region Icon
[System.Runtime.InteropServices.DllImport("shell32.dll")]
extern static IntPtr ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);
static Icon GetIcon(int index)
{
//IntPtr handle = ExtractIcon(0, "user32.dll", index);
IntPtr handle = ExtractIcon(0, "shell32.dll", index);
Icon ic = Icon.FromHandle(handle);
Bitmap bmp = new Bitmap(16, 16);
Graphics.FromImage(bmp).DrawIcon(ic, new Rectangle(0, 0, bmp.Width, bmp.Height));
return Icon.FromHandle(bmp.GetHicon());
}
static Icon DefaultIcon = GetIcon(73);
[
AmbientValue(
null)]
public Icon Icon
{
get
{
return GetSetting<Icon>(LabelInfoSettings.Icon);
}
set
{
SetSetting(LabelInfoSettings.Icon, value);
} }
bool ShouldSerializeIcon()
{
return ShouldSerializeSetting(LabelInfoSettings.Icon);
}
void ResetIcon()
{
ResetSetting(LabelInfoSettings.Icon);
}
#endregion
#region ShowIcon
[AmbientValue(false)]
public bool ShowIcon
{
get
{
return GetSetting<bool>(LabelInfoSettings.ShowIcon);
}
set
{
SetSetting(LabelInfoSettings.ShowIcon, value);
} }
bool ShouldSerializeShowIcon()
{
return ShouldSerializeSetting(LabelInfoSettings.ShowIcon);
}
void ResetShowIcon()
{
ResetSetting(LabelInfoSettings.ShowIcon);
}
#endregion
#region ShowText
[AmbientValue(true)]
public bool ShowText
{
get
{
return GetSetting<bool>(LabelInfoSettings.ShowText);
}
set
{
SetSetting(LabelInfoSettings.ShowText, value);
} }
bool ShouldSerializeShowText()
{
return ShouldSerializeSetting(LabelInfoSettings.ShowText);
}
void ResetShowText()
{
ResetSetting(LabelInfoSettings.ShowText);
}
#endregion
#region Blink
BlinkInfo blink;
[
AmbientValue(
null)]
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content)]
public BlinkInfo Blink
{
get
{
if (blink ==
null)
{
blink = new BlinkInfo(this);
}
return blink;
}
}
bool ShouldSerializeBlink()
{
return
ShouldSerializeSetting(LabelInfoSettings.BlinkStyle)
|| ShouldSerializeSetting(LabelInfoSettings.BlinkRate)
|| ShouldSerializeSetting(LabelInfoSettings.BlinkDuration);
}
[
AmbientValue(
null)]
[
TypeConverter(
typeof(
ExpandableObjectConverter))]
public class BlinkInfo{
public
readonly LabelInfo Owner;
public BlinkInfo(
LabelInfo Owner)
{
this.Owner = Owner;
}
#region Style
[
AmbientValue(
true)]
public BlinkStyle Style
{
get
{
return Owner.GetSetting<BlinkStyle>(LabelInfoSettings.BlinkStyle);
}
set
{
Owner.SetSetting(LabelInfoSettings.BlinkStyle, value);
} }
bool ShouldSerializeStyle()
{
return Owner.ShouldSerializeSetting(LabelInfoSettings.BlinkStyle);
}
void ResetStyle()
{
Owner.ResetSetting(LabelInfoSettings.BlinkStyle);
}
#endregion
#region Rate
[AmbientValue(0)]
public int Rate
{
get
{
return Owner.GetSetting<int>(LabelInfoSettings.BlinkRate);
}
set
{
Owner.SetSetting(LabelInfoSettings.BlinkRate, value);
} }
bool ShouldSerializeRate()
{
return Owner.ShouldSerializeSetting(LabelInfoSettings.BlinkRate);
}
void ResetRate()
{
Owner.ResetSetting(LabelInfoSettings.BlinkRate);
}
#endregion
#region Duration
[AmbientValue(0)]
public int Duration
{
get
{
return Owner.GetSetting<int>(LabelInfoSettings.BlinkDuration);
}
set
{
Owner.SetSetting(LabelInfoSettings.BlinkDuration, value);
} }
bool ShouldSerializeDuration()
{
return Owner.ShouldSerializeSetting(LabelInfoSettings.BlinkDuration);
}
void ResetDuration()
{
Owner.ResetSetting(LabelInfoSettings.BlinkDuration);
}
#endregion
public
override string ToString()
{
if (Style == BlinkStyle.None) return "None";
string res = "Blink every " + Rate + " milliseconds";
if (Style == BlinkStyle.LimitedTime) res += " for a timespan of " + Duration + " milliseconds";
return res;
}
}
#endregion
#region Type Converter
public class DefaultInstanceConverter<T> :
ExpandableObjectConverter{
public
override bool CanConvertTo(
ITypeDescriptorContext context,
Type destinationType)
{
return base.CanConvertTo(context, destinationType)
|| destinationType == typeof(InstanceDescriptor);
}
public
override object ConvertTo(
ITypeDescriptorContext context, System.Globalization.
CultureInfo culture,
object value,
Type destinationType)
{
if (value
is T && destinationType ==
typeof(
InstanceDescriptor))
{
return GetInstanceDescriptor((T)value);
}
return base.ConvertTo(context, culture, value, destinationType); }
protected
virtual InstanceDescriptor GetInstanceDescriptor(T obj)
{
ConstructorInfo ci = obj.GetType().GetConstructor(
Type.EmptyTypes);
if (ci ==
null)
throw new Exception(obj.GetType().FullName + " does not contain parameterless constructors");
return new InstanceDescriptor(ci,
null,
false);
}
}
public
class LabelInfoConverter :
DefaultInstanceConverter<
LabelInfo>
{
protected
override InstanceDescriptor GetInstanceDescriptor(
LabelInfo li)
{
if (
string.IsNullOrEmpty(li.text))
return null;
bool isComplete =
true;
foreach (
LabelInfoSettings s
in Enum.GetValues(
typeof(
LabelInfoSettings)))
{
if (li.ShouldSerializeSetting(s))
{
isComplete = false;
break;
}
}
return new InstanceDescriptor(
typeof(LabelInfo).GetConstructor(new Type[] { typeof(string) }),
new object[] { li.text }, isComplete); }
public
override bool CanConvertFrom(
ITypeDescriptorContext context,
Type sourceType)
{
return base.CanConvertFrom(context, sourceType)
|| sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
Control c = context.Instance
as Control;
if (c !=
null && value
is string)
{
string txt = value
as string;
LabelInfo li = context.PropertyDescriptor.GetValue(c)
as LabelInfo;
if (li ==
null)
{
li = new LabelInfo(txt);
context.PropertyDescriptor.SetValue(c, li);
}
else
li.Text = txt;
return li;
}
return base.ConvertFrom(context, culture, value);
}
public override bool IsValid(
ITypeDescriptorContext context,
object value)
{
LabelInfo inf = value as LabelInfo;
if (inf == null) return false;
return !string.IsNullOrEmpty(inf.text);
}
}
#endregion
}
public
enum BlinkStyle{
None,
Permanent,
LimitedTime
}
[
Flags]
[
Editor(
typeof(
LabelProvider.
LabelLayoutEditor),
typeof(
UITypeEditor))]
public enum LabelLayout{
NotSet = 0,
Top = 1,
AboveMiddle = 2,
Middle = 4,
UnderMiddle = 8,
Bottom = 16,
Left = 32,
LeftFromCenter = 64,
Center = 128,
RightFromCenter = 256,
Right = 512,
Default = LabelLayout.Left | LabelLayout.AboveMiddle
}
#region LayoutPicker
/// <summary>
/// Control to select a <see cref="LabelLayout"/>. Used in design time for LabelLayout properties
/// [
ToolboxItem(
false)]
public class LayoutPicker :
UserControl{
public LayoutPicker()
{
table.Dock = DockStyle.Fill;
Controls.Add(table);
}
LayoutPickerTable table =
new LayoutPickerTable();
[
Browsable(
false)]
public LayoutPickerTable TablePanel
{
}
[DefaultValue(LabelLayout.Default)]
public LabelLayout Result
{
get { return table.Result; }
set { table.Result = value; }
}
LabelLayout revertvalue;
[DefaultValue(LabelLayout.NotSet)]
public LabelLayout RevertValue
{
get {
return revertvalue; }
set{
revertvalue =
value;
if ((revertvalue ==
LabelLayout.NotSet) == (lblRevert ==
null))
return;
if (lblRevert ==
null)
{
lblRevert = new Label();
lblRevert.ForeColor = Color.Blue;
lblRevert.Dock = DockStyle.Bottom;
lblRevert.Font = new Font(lblRevert.Font, FontStyle.Underline);
lblRevert.Click += new EventHandler(lblRevert_Click);
lblRevert.Text = "Set to parent";
lblRevert.TextAlign = ContentAlignment.MiddleCenter;
lblRevert.Cursor = Cursors.Hand;
Controls.Add(lblRevert);
}
else{
lblRevert.Dispose();
lblRevert = null;
}
}
}
void lblRevert_Click(object sender, EventArgs e)
{
Result = revertvalue;
table.InvokeLayoutChosen(false);
}
Label lblRevert;
public class LayoutPickerTable : TableLayoutPanel
{
Label MiddleControl =
new Label();
int cnt = 5;
public LayoutPickerTable()
: this(LabelLayout.Default)
{
}
public LayoutPickerTable(
LabelLayout Current)
{
res = startvalue = Current;
RowCount = ColumnCount = cnt;
float perc = 100 / cnt;
for (
int i = 0; i < cnt; i++)
{
ColumnStyles.Add(new ColumnStyle(SizeType.Percent, perc));
RowStyles.Add(new RowStyle(SizeType.Percent, perc));
}
for (
int i = 0; i < cnt; i++)
{
AddButton(i, 0);
AddButton(i, cnt - 1);
if (i > 0 && i < cnt - 1)
{
AddButton(0, i);
AddButton(cnt - 1, i);
}
}
MiddleControl.Dock = DockStyle.Fill;
MiddleControl.BackColor = Color.Gray;
MiddleControl.TextAlign = ContentAlignment.BottomCenter;
Controls.Add(MiddleControl, 1, 1);
SetRowSpan(MiddleControl, 3);
SetColumnSpan(MiddleControl, 3);
MiddleControl.Paint += new PaintEventHandler(MiddleControl_Paint);
}
void Navigate(
int Col,
int Row,
LayoutButton b)
{
TableLayoutPanelCellPosition cell = GetCellPosition(b);
Navigate(Col, Row, cell.Column, cell.Row);
}
void Navigate(int Col, int Row, int curcol, int currow)
{
currow =
Math.Max(0,
Math.Min(cnt - 1, Row + currow));
curcol =
Math.Max(0,
Math.Min(cnt - 1, Col + curcol));
LayoutButton b = GetControlFromPosition(curcol, currow)
as LayoutButton;
if (b ==
null)
{
Navigate(Col, Row, curcol, currow);
}
else
b.Focus();
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode ==
Keys.Cancel)
{
Cancel();
}
}
void Cancel()
{
Result = startvalue;
OnLayoutChosen(true);
}
void MiddleControl_Paint(
object sender,
PaintEventArgs e)
{
LabelInfo.PaintSymbol(e.Graphics, MiddleControl.Bounds, res);
}
LabelLayout startvalue;
class LayoutButton : Button
{
public
new readonly LabelLayout Layout;
public LayoutButton(
LabelLayout Layout)
{
this.Layout = Layout;
}
public override Color BackColor
{
get
{
if (Selected)
return Color.Gray;
return Control.DefaultBackColor;
}
set
{
//base.BackColor = value;
} }
public bool Selected
{
get
{
if (Parent == null) return false;
return Owner.res == Layout;
} }
LayoutPickerTable Owner
{
get { return Parent as LayoutPickerTable; }
}
protected override bool IsInputKey(Keys keyData)
{
switch (keyData)
{
case
Keys.Down:
Owner.Navigate(0, 1, this);
break;
case
Keys.Up:
Owner.Navigate(0, -1, this);
break;
case
Keys.Left:
Owner.Navigate(-1, 0, this);
break;
case
Keys.Right:
Owner.Navigate(1, 0, this);
break;
default:
return base.IsInputKey(keyData);
}
return true; } }
void AddButton(
int Column,
int Row)
{
LabelLayout lay = GetLayout(Column, Row);
LayoutButton b = new LayoutButton(lay);
b.Dock = DockStyle.Fill;
b.TabStop = false;
b.Click += new EventHandler(b_Click);
Controls.Add(b, Column, Row);
buttons.Add(b);
}
LabelLayout GetLayout(
int col,
int row)
{
res = 0;
if (col == 0)
res |= LabelLayout.Left;
else
if (col == cnt - 1)
res |= LabelLayout.Right;
else
res |= (LabelLayout)((int)LabelLayout.LeftFromCenter << col - 1);
if (row == 0)
res |= LabelLayout.Top;
else
if (row == cnt - 1)
res |= LabelLayout.Bottom;
else
res |= (LabelLayout)((int)LabelLayout.AboveMiddle << row - 1);
return res;
}
void b_Click(
object sender,
EventArgs e)
{
LayoutButton b = sender as LayoutButton;
Result = b.Layout;
OnLayoutChosen(false);
}
void OnLayoutChosen(bool Cancelled)
{
if (LayoutChosen !=
null)
LayoutChosen(this, new LayoutChosenEventArgs(Result, Cancelled));
}
public void InvokeLayoutChosen(bool Cancelled)
{
OnLayoutChosen(Cancelled);
}
public class LayoutChosenEventArgs : EventArgs
{
public
readonly bool Cancelled;
public readonly LabelLayout Result;
public LayoutChosenEventArgs(
LabelLayout Result,
bool Cancelled)
{
this.Result = Result;
this.Cancelled = Cancelled;
} }
public event EventHandler<LayoutChosenEventArgs> LayoutChosen;
LabelLayout res;
List<LayoutButton> buttons = new List<LayoutButton>();
public LabelLayout Result
{
get {
return res; }
set{
LayoutButton b = GetSelectedButton();
res =
value;
MiddleControl.Text = res.ToString();
if (b !=
null)
b.Invalidate();
if ((b = GetSelectedButton()) !=
null)
b.Invalidate();
} }
LayoutButton GetSelectedButton()
{
foreach (
LayoutButton btn
in buttons)
{
if (btn.Selected)
return btn;
}
return null; }
}
}
#endregion
}
. . .