OSDN Git Service

C# 8.0 のnull許容参照型を有効化
[opentween/open-tween.git] / OpenTween / ShortcutCommand.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2015 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 #nullable enable
23
24 using System;
25 using System.Collections.Generic;
26 using System.Linq;
27 using System.Text;
28 using System.Threading.Tasks;
29 using System.Windows.Forms;
30
31 namespace OpenTween
32 {
33     public enum FocusedControl
34     {
35         None,
36         ListTab,
37         StatusText,
38         PostBrowser,
39     }
40
41     /// <summary>
42     /// ショートカットキーの条件と動作を定義するクラス
43     /// </summary>
44     public class ShortcutCommand
45     {
46         private Func<bool> onlyWhen;
47         private Func<Task> command;
48
49         /// <summary>
50         /// ショートカットキーが動作する条件となるキー入力
51         /// </summary>
52         public Keys[] Shortcuts { get; private set; }
53
54         /// <summary>
55         /// ショートカットキーが動作する条件となるフォーカス状態
56         /// </summary>
57         public FocusedControl FocusedOn { get; private set; }
58
59         /// <summary>
60         /// ショートカットキーが動作する否定条件となるフォーカス状態
61         /// </summary>
62         public FocusedControl NotFocusedOn { get; private set; }
63
64         /// <summary>
65         /// コマンドを実行した後、コントロール既定の動作を無効化するか否か (デフォルトは true)
66         /// </summary>
67         public bool PreventDefault { get; private set; }
68
69         private ShortcutCommand()
70         {
71             this.Shortcuts = Array.Empty<Keys>();
72             this.command = () => Task.CompletedTask;
73             this.onlyWhen = () => true;
74             this.FocusedOn = FocusedControl.None;
75             this.NotFocusedOn = FocusedControl.None;
76             this.PreventDefault = true;
77         }
78
79         /// <summary>
80         /// コマンドを実行する条件を満たしているか判定します
81         /// </summary>
82         public bool IsMatch(Keys pressedKey, FocusedControl focusedOn)
83         {
84             if (!this.Shortcuts.Contains(pressedKey))
85                 return false;
86
87             if (this.FocusedOn != FocusedControl.None && this.FocusedOn != focusedOn)
88                 return false;
89
90             if (this.NotFocusedOn != FocusedControl.None && this.NotFocusedOn == focusedOn)
91                 return false;
92
93             if (!this.onlyWhen())
94                 return false;
95
96             return true;
97         }
98
99         /// <summary>
100         /// コマンドを実行します
101         /// </summary>
102         public async Task RunCommand()
103             => await this.command();
104
105         /// <summary>
106         /// 新規に ShortcutCommand インスタンスを作成するビルダーを返します
107         /// </summary>
108         public static ShortcutCommand.Builder Create(params Keys[] shortcuts)
109             => new Builder().Keys(shortcuts);
110
111         public class Builder
112         {
113             private readonly ShortcutCommand instance;
114
115             internal Builder()
116                 => this.instance = new ShortcutCommand();
117
118             /// <summary>
119             /// 指定されたキーが入力された時にショートカットを発動します
120             /// </summary>
121             public Builder Keys(params Keys[] shortcuts)
122             {
123                 this.instance.Shortcuts = shortcuts;
124                 return this;
125             }
126
127             /// <summary>
128             /// 指定されたコントロールにフォーカスが当たっている時のみショートカットを有効にします
129             /// </summary>
130             public Builder FocusedOn(FocusedControl focusedOn)
131             {
132                 this.instance.FocusedOn = focusedOn;
133                 return this;
134             }
135
136             /// <summary>
137             /// 指定されたコントロールにフォーカスが当たっている時はショートカットを有効にしません
138             /// </summary>
139             public Builder NotFocusedOn(FocusedControl notFocusedOn)
140             {
141                 this.instance.NotFocusedOn = notFocusedOn;
142                 return this;
143             }
144
145             /// <summary>
146             /// 指定された条件が true になる間のみショートカットを有効にします
147             /// </summary>
148             public Builder OnlyWhen(Func<bool> condition)
149             {
150                 this.instance.onlyWhen = condition;
151                 return this;
152             }
153
154             /// <summary>
155             /// ショートカットが入力された時に行う動作の内容
156             /// </summary>
157             public ShortcutCommand Do(Action action, bool preventDefault = true)
158                 => this.Do(SynchronousTask(action), preventDefault);
159
160             /// <summary>
161             /// ショートカットが入力された時に行う動作の内容
162             /// </summary>
163             public ShortcutCommand Do(Func<Task> action, bool preventDefault = true)
164             {
165                 this.instance.command = action;
166                 this.instance.PreventDefault = preventDefault;
167
168                 return this.instance;
169             }
170
171             /// <summary>
172             /// Action を Func&lt;Task&gt; に変換します
173             /// </summary>
174             private static Func<Task> SynchronousTask(Action action)
175                 => () => { action(); return Task.CompletedTask; };
176         }
177     }
178 }