#region Using Directives
using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Reflection;
#endregion Using Directives
namespace ScintillaNET
{
///
/// Determines how whitespace should be displayed in a control.
///
///
/// By default, whitespace is determined by the lexer in use. Setting the
/// or properties overrides the lexer behavior.
///
[TypeConverterAttribute(typeof(WhitespaceConverter))]
public class Whitespace : TopLevelHelper
{
#region Constants
private const string BACK_COLORBAG = "Whitespace.BackColor";
private const string FORE_COLORBAG = "Whitespace.ForeColor";
private const string ALPHA_EXCEPTION = "Transparent colors are not supported."; // TODO Move into resource file.
#endregion Constants
#region Properties
///
/// Gets or sets the whitespace background color.
///
///
/// By default, the whitespace background color is determined by the lexer in use.
/// Setting the BackColor to anything other than overrides the lexer behavior.
/// Transparent colors are not supported.
///
///
/// A that represents the background color of whitespace characters.
/// The default is .
///
///
/// The specified has an alpha value that is less that .
///
[DefaultValue(typeof(Color), ""), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)]
[Category("Appearance"), Description("The background color of whitespace characters.")]
public Color BackColor
{
get
{
Color value;
Scintilla.ColorBag.TryGetValue(BACK_COLORBAG, out value);
return value;
}
set
{
if (value != Color.Empty && value.A < Byte.MaxValue)
throw new ArgumentException(ALPHA_EXCEPTION);
if (value != BackColor)
{
if (value == Color.Empty)
{
Scintilla.ColorBag.Remove(BACK_COLORBAG);
NativeScintilla.SetWhitespaceBack(false, 0);
}
else
{
Scintilla.ColorBag[BACK_COLORBAG] = value;
NativeScintilla.SetWhitespaceBack(true, Utilities.ColorToRgb(value));
}
}
}
}
///
/// Gets or sets the whitespace foreground color.
///
///
/// By default, the whitespace foreground color is determined by the lexer in use.
/// Setting the ForeColor to anything other than overrides the lexer behavior.
/// Transparent colors are not supported.
///
///
/// A that represents the foreground color of whitespace characters.
/// The default is .
///
///
/// The specified has an alpha value that is less that .
///
[DefaultValue(typeof(Color), ""), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)]
[Category("Appearance"), Description("The foreground color of whitespace characters.")]
public Color ForeColor
{
get
{
Color value;
Scintilla.ColorBag.TryGetValue(FORE_COLORBAG, out value);
return value;
}
set
{
if (value != Color.Empty && value.A < Byte.MaxValue)
throw new ArgumentException(ALPHA_EXCEPTION);
if (value != ForeColor)
{
if (value == Color.Empty)
{
Scintilla.ColorBag.Remove(FORE_COLORBAG);
NativeScintilla.SetWhitespaceFore(false, 0xFFFFFF);
}
else
{
Scintilla.ColorBag[FORE_COLORBAG] = value;
NativeScintilla.SetWhitespaceFore(true, Utilities.ColorToRgb(value));
}
}
}
}
///
/// Gets or sets the whitespace display mode.
///
/// One of the values. The default is
///
/// The specified value is not a valid value.
///
[DefaultValue(WhitespaceMode.Invisible), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)]
[Category("Appearance"), Description("The mode used to display whitespace.")]
public WhitespaceMode Mode
{
get { return (WhitespaceMode)NativeScintilla.GetViewWs(); }
set
{
if (!Enum.IsDefined(typeof(WhitespaceMode), value))
throw new InvalidEnumArgumentException("value", (int)value, typeof(WhitespaceMode));
if (value != Mode)
NativeScintilla.SetViewWs((int)value);
}
}
#endregion Properties
#region Constructors
internal Whitespace(Scintilla scintilla) : base(scintilla)
{
}
#endregion Constructors
#region Types
// This is an experimental type converter that will automatically build a string representation
// of all the public properties on the object. It provides better user feedback than the standard ExpandableObjectConverter.
// It is currently private to the Whitespace class because that is the only place it has been tested
// but it has obvious applications outside of this one class.
private class WhitespaceConverter : ExpandableObjectConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
// We only care about string representations...
if (destinationType != typeof(String))
base.ConvertTo(context, culture, value, destinationType);
try
{
// Enumerate all the public properties
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo pi in context.PropertyDescriptor.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
// Look for a DefaultAttribute and see if the value has changed
object[] attributes = pi.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attributes != null && attributes.Length > 0)
{
DefaultValueAttribute dv = (DefaultValueAttribute)attributes[0];
object propertyValue = pi.GetValue(value, null);
if (!dv.Value.Equals(propertyValue))
{
// Create a string representation of the value
if (sb.Length > 0)
sb.Append("; ");
sb.Append(pi.Name);
sb.Append("=");
TypeConverter tc = TypeDescriptor.GetConverter(pi.PropertyType);
if (tc != null)
sb.Append(tc.ConvertToString(propertyValue));
else if (propertyValue != null)
sb.Append(propertyValue.ToString());
}
}
else
{
// TODO Look for a "ShouldSerialize..." method to determine if the value has changed
}
}
return sb.ToString();
}
catch
{
// Don't throw an exception, just don't display anything
return String.Empty;
}
}
}
#endregion Types
}
}