-
Notifications
You must be signed in to change notification settings - Fork 673
/
Responder.cs
301 lines (275 loc) · 9.58 KB
/
Responder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
//
// Core.cs: The core engine for gui.cs
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
// Pending:
// - Check for NeedDisplay on the hierarchy and repaint
// - Layout support
// - "Colors" type or "Attributes" type?
// - What to surface as "BackgroundCOlor" when clearing a window, an attribute or colors?
//
// Optimziations
// - Add rendering limitation to the exposed area
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Terminal.Gui {
/// <summary>
/// Responder base class implemented by objects that want to participate on keyboard and mouse input.
/// </summary>
public class Responder : IDisposable {
bool disposedValue;
#if DEBUG_IDISPOSABLE
/// <summary>
/// For debug purposes to verify objects are being disposed properly
/// </summary>
public bool WasDisposed = false;
/// <summary>
/// For debug purposes to verify objects are being disposed properly
/// </summary>
public int DisposedCount = 0;
/// <summary>
/// For debug purposes
/// </summary>
public static List<Responder> Instances = new List<Responder> ();
/// <summary>
/// For debug purposes
/// </summary>
public Responder ()
{
Instances.Add (this);
}
#endif
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Responder"/> can focus.
/// </summary>
/// <value><c>true</c> if can focus; otherwise, <c>false</c>.</value>
public virtual bool CanFocus { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Responder"/> has focus.
/// </summary>
/// <value><c>true</c> if has focus; otherwise, <c>false</c>.</value>
public virtual bool HasFocus { get; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Responder"/> can respond to user interaction.
/// </summary>
public virtual bool Enabled { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Responder"/> and all its child controls are displayed.
/// </summary>
public virtual bool Visible { get; set; } = true;
// Key handling
/// <summary>
/// This method can be overwritten by view that
/// want to provide accelerator functionality
/// (Alt-key for example).
/// </summary>
/// <remarks>
/// <para>
/// Before keys are sent to the subview on the
/// current view, all the views are
/// processed and the key is passed to the widgets
/// to allow some of them to process the keystroke
/// as a hot-key. </para>
/// <para>
/// For example, if you implement a button that
/// has a hotkey ok "o", you would catch the
/// combination Alt-o here. If the event is
/// caught, you must return true to stop the
/// keystroke from being dispatched to other
/// views.
/// </para>
/// </remarks>
public virtual bool ProcessHotKey (KeyEvent kb)
{
return false;
}
/// <summary>
/// If the view is focused, gives the view a
/// chance to process the keystroke.
/// </summary>
/// <remarks>
/// <para>
/// Views can override this method if they are
/// interested in processing the given keystroke.
/// If they consume the keystroke, they must
/// return true to stop the keystroke from being
/// processed by other widgets or consumed by the
/// widget engine. If they return false, the
/// keystroke will be passed using the ProcessColdKey
/// method to other views to process.
/// </para>
/// <para>
/// The View implementation does nothing but return false,
/// so it is not necessary to call base.ProcessKey if you
/// derive directly from View, but you should if you derive
/// other View subclasses.
/// </para>
/// </remarks>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
public virtual bool ProcessKey (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// This method can be overwritten by views that
/// want to provide accelerator functionality
/// (Alt-key for example), but without
/// interefering with normal ProcessKey behavior.
/// </summary>
/// <remarks>
/// <para>
/// After keys are sent to the subviews on the
/// current view, all the view are
/// processed and the key is passed to the views
/// to allow some of them to process the keystroke
/// as a cold-key. </para>
/// <para>
/// This functionality is used, for example, by
/// default buttons to act on the enter key.
/// Processing this as a hot-key would prevent
/// non-default buttons from consuming the enter
/// keypress when they have the focus.
/// </para>
/// </remarks>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
public virtual bool ProcessColdKey (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// Method invoked when a key is pressed.
/// </summary>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
/// <returns>true if the event was handled</returns>
public virtual bool OnKeyDown (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// Method invoked when a key is released.
/// </summary>
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
/// <returns>true if the event was handled</returns>
public virtual bool OnKeyUp (KeyEvent keyEvent)
{
return false;
}
/// <summary>
/// Method invoked when a mouse event is generated
/// </summary>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
/// <param name="mouseEvent">Contains the details about the mouse event.</param>
public virtual bool MouseEvent (MouseEvent mouseEvent)
{
return false;
}
/// <summary>
/// Method invoked when a mouse event is generated for the first time.
/// </summary>
/// <param name="mouseEvent"></param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnMouseEnter (MouseEvent mouseEvent)
{
return false;
}
/// <summary>
/// Method invoked when a mouse event is generated for the last time.
/// </summary>
/// <param name="mouseEvent"></param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnMouseLeave (MouseEvent mouseEvent)
{
return false;
}
/// <summary>
/// Method invoked when a view gets focus.
/// </summary>
/// <param name="view">The view that is losing focus.</param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnEnter (View view)
{
return false;
}
/// <summary>
/// Method invoked when a view loses focus.
/// </summary>
/// <param name="view">The view that is getting focus.</param>
/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
public virtual bool OnLeave (View view)
{
return false;
}
/// <summary>
/// Method invoked when the <see cref="CanFocus"/> property from a view is changed.
/// </summary>
public virtual void OnCanFocusChanged () { }
/// <summary>
/// Method invoked when the <see cref="Enabled"/> property from a view is changed.
/// </summary>
public virtual void OnEnabledChanged () { }
/// <summary>
/// Method invoked when the <see cref="Visible"/> property from a view is changed.
/// </summary>
public virtual void OnVisibleChanged () { }
/// <summary>
/// Utilty function to determine <paramref name="method"/> is overridden in the <paramref name="subclass"/>.
/// </summary>
/// <param name="subclass">The view.</param>
/// <param name="method">The method name.</param>
/// <returns><see langword="true"/> if it's overridden, <see langword="false"/> otherwise.</returns>
internal static bool IsOverridden (Responder subclass, string method)
{
MethodInfo m = subclass.GetType ().GetMethod (method,
BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.DeclaredOnly);
if (m == null) {
return false;
}
return m.GetBaseDefinition ().DeclaringType != m.DeclaringType;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <remarks>
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </remarks>
/// <param name="disposing"></param>
protected virtual void Dispose (bool disposing)
{
if (!disposedValue) {
if (disposing) {
// TODO: dispose managed state (managed objects)
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resource.
/// </summary>
public void Dispose ()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose (disposing: true);
GC.SuppressFinalize (this);
#if DEBUG_IDISPOSABLE
WasDisposed = true;
foreach (var instance in Instances.Where (x => x.WasDisposed).ToList ()) {
Instances.Remove (instance);
}
#endif
}
}
}