using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
namespace ICSharpCode.ShortcutsManagement.Dialogs
{
///
/// Notification type enumeration
///
public enum NotificationType
{
///
/// A valid gesture is entered so far
///
Valid,
///
/// Gesture is being entered, but is not valid yet
///
Invalid,
///
/// Gesture was successfully added to gestures collection
///
Added,
///
/// Failed to add gesture to gestures collection
///
Failed,
///
/// Notification message is not displayed
///
None
}
///
/// Represents a textbox suited for entering key gestures
///
public partial class MultiKeyGestureTextBox : UserControl
{
///
/// Identifies dependency property
///
public static readonly DependencyProperty TextBoxBorderThicknessProperty = DependencyProperty.Register(
"TextBoxBorderThickness",
typeof(int),
typeof(MultiKeyGestureTextBox),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsRender));
///
/// Gets or sets text box border thickness
///
public int TextBoxBorderThickness
{
get {
return (int)GetValue(TextBoxBorderThicknessProperty);
}
set {
SetValue(TextBoxBorderThicknessProperty, value);
}
}
///
/// Gets entered in text box
///
public KeyGesture Gesture
{
get {
if (enteredKeyGestureSequence == null || enteredKeyGestureSequence.Count == 0) {
return null;
}
if (enteredKeyGestureSequence.Count == 1) {
return new PartialKeyGesture(enteredKeyGestureSequence.First());
}
return new MultiKeyGesture(enteredKeyGestureSequence);
}
}
///
/// Occurs when gesture entered in text box changes
///
public event EventHandler GestureChanged;
///
/// Identifies dependency property
///
public static readonly DependencyProperty NotificationVisibilityProperty = DependencyProperty.Register(
"NotificationVisibility",
typeof(Visibility),
typeof(MultiKeyGestureTextBox),
new FrameworkPropertyMetadata(Visibility.Visible, FrameworkPropertyMetadataOptions.AffectsRender));
///
/// Gets or sets value which specifies whether notifications are displayed under textbox control
///
public Visibility NotificationVisibility
{
get {
return (Visibility)GetValue(NotificationVisibilityProperty);
}
set {
SetValue(NotificationVisibilityProperty, value);
}
}
///
/// Identifies dependency property
///
public static readonly DependencyProperty NotificationTypeProperty = DependencyProperty.Register(
"NotificationType",
typeof(NotificationType),
typeof(MultiKeyGestureTextBox),
new FrameworkPropertyMetadata(NotificationType.None, FrameworkPropertyMetadataOptions.AffectsRender));
///
/// Gets or sets notification type
///
public NotificationType NotificationType
{
get {
return (NotificationType)GetValue(NotificationTypeProperty);
}
set {
SetValue(NotificationTypeProperty, value);
}
}
///
/// Identifies dependency property
///
public static readonly DependencyProperty NotificationTextProperty = DependencyProperty.Register(
"NotificationText",
typeof(string),
typeof(MultiKeyGestureTextBox),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
///
/// Gets or sets displayed notification text
///
public string NotificationText
{
get {
return (string)GetValue(NotificationTextProperty);
}
set {
SetValue(NotificationTextProperty, value);
}
}
///
/// Last entered chords
///
private List enteredKeyGestureSequence = new List();
///
/// Time when last successfull chord was entered
///
private DateTime lastEnterTime = DateTime.Now;
///
/// Creates instance of
///
public MultiKeyGestureTextBox()
{
InitializeComponent();
}
///
/// Displays notifications under gesture text box
///
/// Notification text
/// Notification type
public void DisplayNotification(string notificationText, NotificationType type)
{
NotificationText = notificationText;
NotificationType = type;
}
///
/// Clears all text area, chords and hides notification
///
public void Clear()
{
enteredKeyGestureSequence = new List();
shortcutTextBox.Text = "";
DisplayNotification("", NotificationType.None);
}
///
/// Executed when clicked on "Clear" button to the right from gesture text box
///
/// Sender object
/// supporting data
private void clearTextBox_Click(object sender, RoutedEventArgs e)
{
Clear();
}
///
/// Executed when text inside textbox changes
///
/// Sender object
/// Event arguments
void shortcutTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (GestureChanged != null) {
GestureChanged.Invoke(sender, new EventArgs());
}
}
///
/// Raised before user presses any key inside text box
///
/// Sender object
/// Event argument
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
// If a key is holded for a longer time key event is raised repeatedly.
// We don't want to handle this kind of events
if (e.IsRepeat) {
return;
}
// If delete or backspace button is pressed
if (e.Key == Key.Back || e.Key == Key.Delete) {
Clear();
return;
}
// Check whether time given for chord entry haven't expired yet
if (DateTime.Now - lastEnterTime > MultiKeyGesture.DelayBetweenChords) {
if (enteredKeyGestureSequence.Count > 0) {
DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.TimeExpired}"), NotificationType.Invalid);
}
Clear();
lastEnterTime = DateTime.Now;
}
var partialKeyGesture = new PartialKeyGesture(e);
var lastGesture = enteredKeyGestureSequence.Count > 0 ? enteredKeyGestureSequence.LastOrDefault() : null;
var isLastGestureSpecialKey = lastGesture != null && (lastGesture.Key >= Key.F1) && (lastGesture.Key <= Key.F24);
var isLastGestureComplete = lastGesture != null && (lastGesture.Key != Key.None || isLastGestureSpecialKey);
var isContinuedGesture = lastGesture != null && partialKeyGesture.Modifiers - (partialKeyGesture.Modifiers ^ lastGesture.Modifiers) >= 0;
// If continuing previous chord
if (!isLastGestureComplete && isContinuedGesture) {
enteredKeyGestureSequence.RemoveAt(enteredKeyGestureSequence.Count - 1);
} else if (!isLastGestureComplete) {
// If previous chord is unfinished and second chord is already entered
// start from scratch.
DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.SequenceIsNotCoherent}"), NotificationType.Invalid);
Clear();
}
// If successfully finished another chord give more time
if (partialKeyGesture.Key != Key.None) {
lastEnterTime = DateTime.Now;
}
enteredKeyGestureSequence.Add(partialKeyGesture);
// Create a multi key gesture if entered more than one chord
if (enteredKeyGestureSequence.Count > 0) {
var multiKeyGesture = new MultiKeyGesture(enteredKeyGestureSequence);
var multiKeyGestureString = new MultiKeyGestureConverter().ConvertToInvariantString(multiKeyGesture);
shortcutTextBox.Text = multiKeyGestureString;
} else {
Clear();
}
if (!enteredKeyGestureSequence[0].IsFull) {
DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.FirstChordIsIncomplete}"), NotificationType.Invalid);
} else if (partialKeyGesture.Key == Key.None) {
DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.LastChordIsIncomplete}"), NotificationType.Invalid);
} else {
DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.GestureIsValid}"), NotificationType.Valid);
}
}
}
}