vbAccelerator - Contents of code file: FontCombo_FontComboBox.csusing System;
using System.Drawing;
using System.Drawing.Text;
using vbAccelerator.Components.Controls;
using vbAccelerator.Components.Collections;
using vbAccelerator.Components.Text;
namespace vbAccelerator.Components.Controls
{
/// <summary>
/// Summary description for FontCombo.
/// </summary>
public class FontComboBox : IconComboBox
{
/// <summary>
/// Collection of Most-Recently used fonts
/// </summary>
private MRUFonts mruFonts;
/// <summary>
/// Number of MRU fonts currently displayed
/// </summary>
private int mruItemCount = 0;
/// <summary>
/// Enable state before/whilst background thread loading in progress
/// </summary>
private bool origEnable = true;
/// <summary>
/// Whether the actual control's enable state can be modified
/// </summary>
private bool allowEnable = false;
/// <summary>
/// An interlock which prevents events from being raised when items
/// are being added or swapped into the MRU font list
/// </summary>
private bool interlock = false;
#region Events
/// <summary>
/// Raised when the font combo box has been populated. Fonts are
/// populated asynchronously on a background thread.
/// </summary>
public event EventHandler Populated;
#endregion
/// <summary>
/// Constructs a new instance of this class.
/// </summary>
public FontComboBox() : base()
{
base.MaxDropDownItems = 16;
base.DropDownWidth = 300;
base.AutoComplete = true;
mruFonts = new MRUFonts(this);
}
/// <summary>
/// Gets/sets whether the control is enabled. Whilst font loading
/// is occuring on a background thread, changes to this property
/// won't appear until loading has completed.
/// </summary>
public new bool Enabled
{
get
{
if (!allowEnable)
{
return origEnable;
}
else
{
return base.Enabled;
}
}
set
{
if (!allowEnable)
{
origEnable = value;
}
else
{
base.Enabled = value;
}
}
}
/// <summary>
/// Raises the <see cref="HandleCreated"/> event and populates
/// the combo box with fonts.
/// </summary>
/// <param name="e">Not used</param>
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
LoadFonts();
}
/// <summary>
/// Raises the <see cref="SelectedIndexChanged"/> event,
/// also the MRU cache is correctly populated.
/// </summary>
/// <param name="e"></param>
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (!interlock)
{
base.OnSelectedIndexChanged(e);
if ((base.SelectedIndex > -1) && (!base.DroppedDown))
{
addMRUFont(base.SelectedItem.ToString());
}
}
}
/// <summary>
/// Gets the collection of most-recently used fonts in the control.
/// </summary>
public MRUFonts MostRecentlyUsedFonts
{
get
{
return this.mruFonts;
}
}
/// <summary>
/// Adds a font family to the Most-Recently Used
/// font cache.
/// </summary>
/// <param name="familyName">Font family name to add</param>
private void addMRUFont(string familyName)
{
interlock = true;
if (mruFonts.Size > 0)
{
int presentIndex = -1;
for (int i = 0; i < mruItemCount; i++)
{
IconComboItem ici = (IconComboItem) base.Items[i];
if (ici.Text.ToString().Equals(familyName))
{
presentIndex = i;
break;
}
}
int oldMruItemCount = mruItemCount;
if (presentIndex > -1)
{
// remove existing item:
base.Items.RemoveAt(presentIndex);
mruItemCount--;
}
else if ((this.mruFonts.Size == mruItemCount))
{
// remove the last MRU font:
base.Items.RemoveAt(mruItemCount - 1);
mruItemCount--;
}
// Find the item:
int realItem = base.FindStringExact(familyName);
IconComboItem realIconComboItem = (IconComboItem)
base.Items[realItem];
// insert the item:
IconComboItem mruItem = new IconComboItem();
mruItem.Text = realIconComboItem.Text;
mruItem.Font = realIconComboItem.Font;
mruItem.Tag = "MRU";
base.Items.Insert(0, mruItem);
mruItemCount++;
if (oldMruItemCount > 0)
{
// remove underscore:
((IconComboItem) base.Items[oldMruItemCount - 1]).LineBelow =
false;
}
((IconComboItem) base.Items[mruItemCount - 1]).LineBelow = true;
mruFonts.Add(familyName);
base.SelectedIndex = 0;
}
interlock = false;
}
/// <summary>
/// Reparses the contents of the MRU Font object after it
/// has been updated by the user of the control.
/// </summary>
protected virtual void OnMRUChanged()
{
if (!interlock)
{
// redraw the MRU Fonts based on the newly specified ones.
interlock = true;
base.BeginUpdate();
for (int i = 0; i < mruItemCount; i++)
{
base.Items.Remove(0);
}
mruItemCount = 0;
if (mruFonts.Size > 0)
{
for (int i = mruFonts.Size - 1; i >= 0; i--)
{
IconComboItem ici = new IconComboItem();
int realItem = base.FindStringExact(mruFonts[i]);
IconComboItem realIconComboItem = (IconComboItem)
base.Items[realItem];
// insert the item:
IconComboItem mruItem = new IconComboItem();
mruItem.Text = realIconComboItem.Text;
mruItem.Font = realIconComboItem.Font;
mruItem.Tag = "MRU";
base.Items.Insert(0, ici);
}
((IconComboItem) base.Items[mruItemCount - 1]).LineBelow = true;
}
base.EndUpdate();
interlock = false;
}
}
/// <summary>
/// Initiates a load of all fonts asynchronously. The
/// <see cref="Populated"/> event will be fired once
/// all fonts are available. Called automatically
/// whenever the control is created.
/// </summary>
public void LoadFonts()
{
if (this.Site != null)
{
if (this.Site.DesignMode)
{
return;
}
}
origEnable = base.Enabled;
base.Enabled = false;
allowEnable = false;
interlock = true;
base.Items.Clear();
// run font population on a background thread
PopulateFontComboHandler populator = new
PopulateFontComboHandler(PopulateFontCombo);
populator.BeginInvoke(null, null);
}
#region Asynchronous Font Population
private delegate void PopulateFontComboHandler();
private void PopulateFontCombo()
{
// This graphics object is used for determining the Panose
// number of the font
Graphics graphics = Graphics.FromHwnd(base.Handle);
// Get the collection of installed fonts:
InstalledFontCollection fonts = new InstalledFontCollection();
// For each item:
foreach (FontFamily family in fonts.Families)
{
// Find which style can be rendered (if any!)
Font theFont = null;
if (family.IsStyleAvailable(FontStyle.Regular))
{
theFont = new Font(family.Name, 12);
}
else if (family.IsStyleAvailable(FontStyle.Bold))
{
theFont = new Font(family.Name, 12, FontStyle.Bold);
}
else if (family.IsStyleAvailable(FontStyle.Italic))
{
theFont = new Font(family.Name, 12, FontStyle.Italic);
}
// Here you could still add the item even if there are no
// styles you can render it in (although that probably
// wouldn't be much use...)
if (theFont != null)
{
// Create a new item:
IconComboItem ici = new IconComboItem();
// Set the text:
ici.Text = family.Name;
// Set the font to display the item in.
// Don't try and display fonts like Wingdings using
// the font itself:
if (FontUtility.PanoseFontFamilyType(graphics, theFont) !=
FontUtility.PanoseFontFamilyTypes.PAN_FAMILY_PICTORIAL)
{
ici.Font = theFont;
}
base.Items.Add(ici);
}
}
graphics.Dispose();
PopulateFontComboCompleteHandler complete = new
PopulateFontComboCompleteHandler(PopulateFontComboComplete);
complete.BeginInvoke(null, null);
}
private delegate void PopulateFontComboCompleteHandler();
private void PopulateFontComboComplete()
{
// Shift the MRU fonts to the top of the list:
for (int i = mruFonts.Count - 1; i >= 0; i--)
{
addMRUFont(mruFonts[i]);
}
base.Enabled = origEnable;
allowEnable = true;
interlock = false;
OnPopulateComplete(new EventArgs());
}
#endregion
/// <summary>
/// Raises the <see cref="Populated"/> event.
/// </summary>
/// <param name="e">Not used.</param>
protected virtual void OnPopulateComplete(EventArgs e)
{
if (this.Populated != null)
{
this.Populated(this, e);
}
}
/// <summary>
/// Most Recently Used fonts collection associated with
/// a <see cref="FontComboBox"/> control.
/// </summary>
[SerializableAttribute()]
public class MRUFonts : MRUQueue
{
/// <summary>
/// The owning control for this collection
/// </summary>
private FontComboBox owner = null;
/// <summary>
/// Constructs a new instance of this class, associating
/// it with the owning <see cref="FontComboBox"/>. Used
/// internally by the <see cref="FontComboBox"/> control.
/// </summary>
/// <param name="owner"></param>
public MRUFonts(FontComboBox owner) : base()
{
this.owner = owner;
}
/// <summary>
/// Gets the font family at the specified index.
/// </summary>
public new string this[int index]
{
get
{
return (string) base.innerList[index];
}
}
/// <summary>
/// Adds the specified font name to the MRU queue. If the queue
/// already contains the specified item, it is shifted up
/// to the first position. Otherwise, it is added at the
/// first position and any existing items are shuffled
/// downwards.
/// </summary>
/// <param name="fontName">fontName to add</param>
public virtual void Add(string fontName)
{
base.Add(fontName);
owner.OnMRUChanged();
}
/// <summary>
/// Clears the MRU collection and notifies the control
/// of the change.
/// </summary>
protected override void OnClear()
{
base.OnClear();
owner.OnMRUChanged();
}
/// <summary>
/// Changes the size of the MRU collection and notifies the
/// control of the change.
/// </summary>
protected override void OnSizeChanged()
{
base.OnSizeChanged();
owner.OnMRUChanged();
}
}
}
}
|
|