using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace AeroWizard
{
///
/// Shows a list of all the pages in the WizardControl
///
[ProvideProperty("StepText", typeof(WizardPage))]
[ProvideProperty("StepTextIndentLevel", typeof(WizardPage))]
internal class StepList : ScrollableControl, IExtenderProvider
{
private const TextFormatFlags defBulletTextFormat = TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding;
private const TextFormatFlags defStringTextFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter;
private System.Drawing.Font boldFont;
private int bulletWidth;
private int defItemHeight;
private Dictionary indentLevels = new Dictionary();
private WizardControl myParent;
private System.Drawing.Font ptrFont;
private Dictionary stepTexts = new Dictionary();
///
/// Initializes a new instance of the class.
///
public StepList()
{
}
///
/// Occurs when a visual aspect of an owner-drawn StepList changes.
///
[Category("Appearance")]
public event EventHandler DrawItem;
///
/// Occurs when an owner-drawn StepList is created and the sizes of the list items are determined.
///
[Category("Appearance")]
public event EventHandler MeasureItem;
///
/// Gets or sets a value indicating whether the StepList is drawn by the operating system or by code that you provide.
///
///
/// true if the StepList is drawn by code that you provide; otherwise, false.
///
[DefaultValue(false), Category("Appearance"), Description("Indicates if controls is drawn by owner.")]
public bool OwnerDraw { get; set; }
///
/// Gets the default size of the control.
///
/// The default of the control.
protected override Size DefaultSize => new Size(150, 200);
///
/// Gets the step text.
///
/// The page.
/// Step text for the specified wizard page.
[DefaultValue((string)null), Category("Appearance"), Description("Alternate text to provide to the StepList. Default value comes the Text property of the WizardPage.")]
public string GetStepText(WizardPage page)
{
string value;
if (stepTexts.TryGetValue(page, out value))
return value;
return page.Text;
}
///
/// Gets the step text indent level.
///
/// The page.
/// Step text indent level for the specified wizard page.
[DefaultValue(0), Category("Appearance"), Description("Indentation level for text provided to the StepList.")]
public int GetStepTextIndentLevel(WizardPage page)
{
int value;
if (indentLevels.TryGetValue(page, out value))
return value;
return 0;
}
bool IExtenderProvider.CanExtend(object extendee) => (extendee is WizardPage);
///
/// Sets the step text.
///
/// The page.
/// The value.
public void SetStepText(WizardPage page, string value)
{
if (string.IsNullOrEmpty(value) || value == page.Text)
stepTexts.Remove(page);
else
stepTexts[page] = value;
Refresh();
}
///
/// Sets the step text indent level.
///
/// The page.
/// The indent level.
public void SetStepTextIndentLevel(WizardPage page, int value)
{
if (value < 0) value = 0;
if (value == 0)
indentLevels.Remove(page);
else
indentLevels[page] = value;
Refresh();
}
///
/// Raises the event.
///
/// The instance containing the event data.
protected virtual void OnDrawItem(DrawStepListItemEventArgs e)
{
var h = DrawItem;
if (h != null)
h(this, e);
}
///
/// Raises the event.
///
/// The instance containing the event data.
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
using (Graphics g = CreateGraphics())
{
defItemHeight = (int)Math.Ceiling(TextRenderer.MeasureText(g, "Wg", Font).Height * 1.2);
ptrFont = new Font("Marlett", Font.Size);
boldFont = new Font(Font, FontStyle.Bold);
bulletWidth = TextRenderer.MeasureText(g, "4", ptrFont, new Size(0, defItemHeight), defBulletTextFormat).Width;
}
}
///
/// Raises the event.
///
/// The instance containing the event data.
protected virtual void OnMeasureItem(MeasureStepListItemEventArgs e)
{
var h = MeasureItem;
if (h != null)
h(this, e);
}
///
/// Raises the event.
///
/// A that contains the event data.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (myParent == null) return;
int y = Padding.Top;
WizardPageCollection pages = myParent.Pages;
bool hit = false;
for (int i = 0; i < pages.Count; i++)
{
var curPage = pages[i];
if (!curPage.Suppress)
{
Size itemSize = new Size(Width - Padding.Horizontal, defItemHeight);
if (OwnerDraw)
{
var meArg = new MeasureStepListItemEventArgs(e.Graphics, Font, curPage, new Size(Width, defItemHeight));
OnMeasureItem(meArg);
itemSize = meArg.ItemSize;
}
if (y + itemSize.Height > (Height - Padding.Bottom))
break;
bool isSelected = myParent.SelectedPage == curPage;
if (isSelected) hit = true;
var eArg = new DrawStepListItemEventArgs(e.Graphics, Font, new Rectangle(new Point(Padding.Left, y), itemSize), curPage, isSelected, hit);
if (OwnerDraw)
OnDrawItem(eArg);
else
DefaultDrawItem(eArg);
y += itemSize.Height;
}
}
}
///
/// Raises the event.
///
/// An that contains the event data.
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
SetupControl(this.GetParent());
}
private static void Split(Rectangle rect, int xPos, out Rectangle r1, out Rectangle r2)
{
r1 = r2 = rect;
r1.Width = r2.X = xPos;
r2.Width = r2.Width - xPos;
}
private void DefaultDrawItem(DrawStepListItemEventArgs e)
{
Color fc = ForeColor, bc = BackColor;
int level = GetStepTextIndentLevel(e.Item);
bool isRTL = RightToLeft == System.Windows.Forms.RightToLeft.Yes;
var tffrtl = isRTL ? TextFormatFlags.Right : 0;
Rectangle rect, prect;
if (isRTL)
{
Split(e.Bounds, Width - bulletWidth, out rect, out prect);
prect.X = e.Bounds.Width - (bulletWidth * (level + 1));
rect.Width = Width - (bulletWidth * (level + 1));
}
else
{
Split(e.Bounds, bulletWidth, out prect, out rect);
prect.X = bulletWidth * level;
rect.X = bulletWidth * (level + 1);
}
if (!e.Completed)
fc = SystemColors.GrayText;
using (Brush br = new SolidBrush(bc))
e.Graphics.FillRectangle(br, Rectangle.Union(rect, prect));
TextRenderer.DrawText(e.Graphics, e.Completed ? (isRTL ? "3" : "4") : "a", ptrFont, prect, fc, defBulletTextFormat | tffrtl);
TextRenderer.DrawText(e.Graphics, GetStepText(e.Item), e.Selected ? boldFont : Font, rect, fc, defStringTextFormat | tffrtl);
}
private void pages_Changed(object sender, EventedList.ListChangedEventArgs e)
{
Refresh();
}
private void ResetStepText(WizardPage page)
{
SetStepText(page, null);
}
private void SetupControl(WizardControl p)
{
if (myParent != null)
{
WizardPageCollection pages = myParent.Pages;
pages.ItemAdded -= pages_Changed;
pages.ItemChanged -= pages_Changed;
pages.ItemDeleted -= pages_Changed;
}
myParent = p;
if (myParent != null)
{
WizardPageCollection pages = myParent.Pages;
pages.ItemAdded += pages_Changed;
pages.ItemChanged += pages_Changed;
pages.ItemDeleted += pages_Changed;
}
Refresh();
}
private bool ShouldSerializeStepText(WizardPage page) => (GetStepText(page) != page.Text);
}
}