using System;
using System.Collections.Generic;
using System.Linq;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Dependency;
using Chernobyl.DesignPatterns.Extension;
using Chernobyl.Event;
using Chernobyl.Graphics.Writing;
using Chernobyl.Input.Controls;
using Chernobyl.Switch;
namespace Chernobyl.Interface.Writing
{
///
/// Controls the editing of an instance through the use
/// of a keyboard.
///
public class TextEditor : Extension
{
///
/// Initializes a new instance of the class.
///
/// The instance that
/// takes and gives out services.
public TextEditor(IEventCollection services)
: this(services, null)
{ }
///
/// Initializes a new instance of the class.
///
/// The instance that
/// takes and gives out services.
/// The to attach to or null
/// if no should be attached to right now.
public TextEditor(IEventCollection services, IText extended) : this(services, extended, null)
{ }
///
/// Initializes a new instance of the class.
///
/// The instance that
/// takes and gives out services.
/// The to attach to or null
/// if no should be attached to right now.
/// The instance used
/// to mark the text being edited or null if this class should search the
/// instance that this class is attached to for the
/// extension. If a
/// extension is not found, then this instance will add one to the
/// instance being extended.
public TextEditor(IEventCollection services, IText extended, TextCursor textCursor)
{
Services = services;
services.Inject(this);
BackspaceRepeater = new Repeater(100);
DeleteRepeater = new Repeater(100);
TextCursor = textCursor;
Extended = extended;
}
///
/// An event handler that can be assigned to an event. This method removes
/// characters behind the cursor. By default, it is assigned to a
/// which is attached to the backspace keyboard
/// key.
///
/// The sender.
/// The instance containing
/// the event data.
public void OnBackspace(object sender, EventArgs e)
{
if(TextCursor.IndexLocation != Extended.MinimumDrawIndex)
{
IText text = Extended;
text.Writing = text.Writing.Remove(TextCursor.IndexLocation - 1, 1);
// if we just removed the end of the writing then we don't need
// to reduce the index location
if (TextCursor.IndexLocation != text.Writing.Length)
TextCursor.IndexLocation--;
}
}
///
/// An event handler that can be assigned to an event. This method removes
/// characters in front of the cursor. By default, it is assigned to a
/// which is attached to the delete keyboard
/// key.
///
/// The sender.
/// The instance containing
/// the event data.
public void OnDelete(object sender, EventArgs e)
{
IText text = Extended;
if(TextCursor.IndexLocation < text.Writing.Length)
text.Writing = text.Writing.Remove(TextCursor.IndexLocation, 1);
}
///
/// An event handler that can be assigned to an event. This method appends
/// characters to the extended instance at the
/// index location of the instances
/// .
///
/// The source of the event.
/// The instance
/// containing the event data.
public void OnTextEntered(object sender, ItemsEventArgs e)
{
IText text = Extended;
text.Writing = text.Writing.Insert(TextCursor.IndexLocation, new string(e.Items));
TextCursor.IndexLocation += e.Items.Length;
}
///
/// Attaches this extension to the passed in object so that is can be
/// extended.
///
/// The object to extend.
protected override void AttachTo(IText extended)
{
if (TextCursor == null)
{
IEnumerable textCursors = extended.Extensions.OfType();
// if there is no TextCursor on the IText instance, then we are
// going to add one.
if (textCursors.Count() == 0)
TextCursor = new TextCursor(Services, extended);
else
TextCursor = textCursors.First();
}
extended.Extensions.Add(this);
// assign ourselves to the necessary keys in the keyboard
AssignToKeyboardEvents();
}
///
/// Removes the decorator from an object so that it is no longer extended.
///
/// The object to remove the extension from.
protected override void DetachFrom(IText extended)
{
extended.Extensions.Remove(this);
TextCursor = null;
// un-assign ourselves from any keyboard events
UnassignFromKeyboardEvents();
}
///
/// The instance that this
/// gets it's keyboard events from.
///
[Inject]
public IKeyboard Keyboard
{
get { return _Keyboard; }
set
{
// if we have a previous keyboard we are going to need to un-assign
// ourself from it's events and assign ourself to the events from
// the newest keyboard. Otherwise, we will wait till we've
// attached to an IText before we assign ourselves to keyboard
// events
if (Extended != null)
{
if(_Keyboard != null)
UnassignFromKeyboardEvents();
_Keyboard = value;
AssignToKeyboardEvents();
}
else
_Keyboard = value;
}
}
///
/// Un-assigns an instance of this class to the necessary events from the
/// .
///
void UnassignFromKeyboardEvents()
{
Keyboard.TextEntered -= OnTextEntered;
// un-setup backspace events
Keyboard.Backspace.OnDown -= BackspaceRepeater.Start;
Keyboard.Backspace.OnUp -= BackspaceRepeater.Stop;
Keyboard.Backspace.OnDown -= OnBackspace;
BackspaceRepeater.SwitchedOn -= OnBackspace;
// un-setup delete events
Keyboard.Delete.OnDown -= DeleteRepeater.Start;
Keyboard.Delete.OnUp -= DeleteRepeater.Stop;
DeleteRepeater.Elapsed -= OnDelete;
DeleteRepeater.SwitchedOn -= OnDelete;
}
///
/// Assigns an instance of this class to the necessary events from the
/// .
///
void AssignToKeyboardEvents()
{
Keyboard.TextEntered += OnTextEntered;
// setup backspace events
Keyboard.Backspace.OnDown += BackspaceRepeater.Start;
Keyboard.Backspace.OnUp += BackspaceRepeater.Stop;
BackspaceRepeater.Elapsed += OnBackspace;
BackspaceRepeater.SwitchedOn += OnBackspace;
// setup delete events
Keyboard.Delete.OnDown += DeleteRepeater.Start;
Keyboard.Delete.OnUp += DeleteRepeater.Stop;
DeleteRepeater.Elapsed += OnDelete;
DeleteRepeater.SwitchedOn += OnDelete;
}
///
/// The that points to the location where text
/// should be edited.
///
TextCursor TextCursor { get; set; }
///
/// The used to control the repeat rates of
/// several keys.
///
Repeater BackspaceRepeater { get; set; }
///
/// The used to control the repeat rates of
/// several keys.
///
Repeater DeleteRepeater { get; set; }
///
/// The services instance that can take and give out services.
///
IEventCollection Services { get; set; }
///
/// The backing field to .
///
IKeyboard _Keyboard;
}
}