// OpenTween - Client of Twitter
// Copyright (c) 2015 kim_upsilon (@kim_upsilon)
// All rights reserved.
//
// This file is part of OpenTween.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
// for more details.
//
// You should have received a copy of the GNU General public License along
// with this program. If not, see , or write to
// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
// Boston, MA 02110-1301, USA.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace OpenTween
{
public enum FocusedControl
{
None,
ListTab,
StatusText,
PostBrowser,
}
///
/// ショートカットキーの条件と動作を定義するクラス
///
public class ShortcutCommand
{
private Keys[] shortcuts;
private FocusedControl focusedOn;
private FocusedControl notFocusedOn;
private Func onlyWhen;
private Func command;
private bool preventDefault;
///
/// ショートカットキーが動作する条件となるキー入力
///
public Keys[] Shortcuts
{
get { return this.shortcuts; }
}
///
/// ショートカットキーが動作する条件となるフォーカス状態
///
public FocusedControl FocusedOn
{
get { return this.focusedOn; }
}
///
/// ショートカットキーが動作する否定条件となるフォーカス状態
///
public FocusedControl NotFocusedOn
{
get { return this.notFocusedOn; }
}
///
/// コマンドを実行した後、コントロール既定の動作を無効化するか否か (デフォルトは true)
///
public bool PreventDefault
{
get { return this.preventDefault; }
}
private ShortcutCommand()
{
this.shortcuts = new Keys[0];
this.command = () => Task.FromResult(0);
this.onlyWhen = () => true;
this.focusedOn = FocusedControl.None;
this.notFocusedOn = FocusedControl.None;
this.preventDefault = true;
}
///
/// コマンドを実行する条件を満たしているか判定します
///
public bool IsMatch(Keys pressedKey, FocusedControl focusedOn)
{
if (!this.Shortcuts.Contains(pressedKey))
return false;
if (this.FocusedOn != FocusedControl.None && this.FocusedOn != focusedOn)
return false;
if (this.NotFocusedOn != FocusedControl.None && this.NotFocusedOn == focusedOn)
return false;
if (!this.onlyWhen())
return false;
return true;
}
///
/// コマンドを実行します
///
public async Task RunCommand()
{
await this.command();
}
///
/// 新規に ShortcutCommand インスタンスを作成するビルダーを返します
///
public static ShortcutCommand.Builder Create(params Keys[] shortcuts)
{
return new Builder().Keys(shortcuts);
}
public class Builder
{
private readonly ShortcutCommand instance;
internal Builder()
{
this.instance = new ShortcutCommand();
}
///
/// 指定されたキーが入力された時にショートカットを発動します
///
public Builder Keys(params Keys[] shortcuts)
{
this.instance.shortcuts = shortcuts;
return this;
}
///
/// 指定されたコントロールにフォーカスが当たっている時のみショートカットを有効にします
///
public Builder FocusedOn(FocusedControl focusedOn)
{
this.instance.focusedOn = focusedOn;
return this;
}
///
/// 指定されたコントロールにフォーカスが当たっている時はショートカットを有効にしません
///
public Builder NotFocusedOn(FocusedControl notFocusedOn)
{
this.instance.notFocusedOn = notFocusedOn;
return this;
}
///
/// 指定された条件が true になる間のみショートカットを有効にします
///
public Builder OnlyWhen(Func condition)
{
this.instance.onlyWhen = condition;
return this;
}
///
/// ショートカットが入力された時に行う動作の内容
///
public ShortcutCommand Do(Action action, bool preventDefault = true)
{
return this.Do(SynchronousTask(action), preventDefault);
}
///
/// ショートカットが入力された時に行う動作の内容
///
public ShortcutCommand Do(Func action, bool preventDefault = true)
{
this.instance.command = action;
this.instance.preventDefault = preventDefault;
return this.instance;
}
/// 何もしないタスク
private static Task noOpTask = Task.FromResult(0);
///
/// Action を Func<Task> に変換します
///
private static Func SynchronousTask(Action action)
{
return () => { action(); return noOpTask; };
}
}
}
}