* X11Keyboard.cs: Detect and use the num lock mask.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / UpDownBase.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Miguel de Icaza (miguel@novell.com).
24 //
25 //
26 /*
27
28 TODO:
29
30         - Force the size of the entry: it can not be resized vertically
31           ever, the size is set by the size of the font
32
33 */
34 using System;
35 using System.Drawing;
36
37 namespace System.Windows.Forms {
38         public abstract class UpDownBase : ContainerControl {
39
40                 internal class Spinner : Control, IDisposable {
41                         UpDownBase updownbase;
42                         Rectangle up, down, pressed;
43                         Timer timer;
44                         bool up_pressed, down_pressed;
45                         bool captured, mouse_in;
46
47                         //
48                         // Interval values
49                         //
50                         const int StartInterval = 1000;
51                         const int RepeatInterval = 400;
52                         const int ChangeInterval = 75;
53                         const int MinimumInterval = 20;
54                         
55                         internal Spinner (UpDownBase updownbase)
56                         {
57                                 this.updownbase = updownbase;
58                         }
59
60                         protected override void OnPaint (PaintEventArgs args)
61                         {
62                                 Draw (args.ClipRectangle);
63                                 args.Graphics.DrawImage (ImageBuffer, 0, 0);
64                         }
65
66                         protected override void OnLayout (LayoutEventArgs args)
67                         {
68                                 base.OnLayout (args);
69                                 Rectangle bounds = Bounds;
70
71                                 up = new Rectangle (0, 0, bounds.Width, bounds.Height/2);
72                                 down = new Rectangle (0, bounds.Height/2, bounds.Width, bounds.Height/2);
73                         }
74
75                         protected override void OnMouseDown (MouseEventArgs args)
76                         {
77                                 base.OnMouseDown (args);
78
79                                 if (args.Button != MouseButtons.Left)
80                                         return;
81
82                                 if (up.Contains (args.X, args.Y)){
83                                         up_pressed = true;
84                                         pressed = up;
85                                 } else if (down.Contains (args.X, args.Y)){
86                                         down_pressed = true;
87                                         pressed = down;
88                                 } else
89                                         return;
90
91                                 Click ();
92                                 Invalidate (pressed);
93                                 Capture = true;
94                                 InitTimer ();
95                                 
96                                 mouse_in = down_pressed | up_pressed;
97                         }
98
99                         protected override void OnMouseUp (MouseEventArgs args)
100                         {
101                                 if (Capture){
102                                         if (up_pressed){
103                                                 up_pressed = false;
104                                                 Invalidate (up);
105                                         }
106                                         if (down_pressed){
107                                                 down_pressed = false;
108                                                 Invalidate (down);
109                                         }
110                                 }
111                                 Capture = false;
112                         }
113
114                         //
115                         // Sets up the auto-repeat timer, we give a one second
116                         // delay, and then we use the keyboard settings for auto-repeat.
117                         //
118                         void InitTimer ()
119                         {
120                                 timer = new Timer ();
121                                 int kd = SystemInformation.KeyboardDelay;
122                                 kd = kd < 0 ? 0 : (kd > 4 ? 4 : kd);
123                                 timer.Interval = StartInterval;
124                                 timer.Tick += new EventHandler (ClockTick);
125                                 timer.Enabled = true;
126                         }
127
128                         void ClockTick (object o, EventArgs a)
129                         {
130                                 if (timer == null)
131                                         throw new Exception ("The timer that owns this callback is null!");
132                                 
133                                 int interval = timer.Interval;
134
135                                 if (interval == StartInterval)
136                                         interval = RepeatInterval;
137                                 else
138                                         interval -= ChangeInterval;
139
140                                 if (interval < MinimumInterval)
141                                         interval = MinimumInterval;
142                                 timer.Interval = interval;
143
144                                 Click ();
145                         }
146
147                         void Click ()
148                         {
149                                 if (up_pressed)
150                                         updownbase.UpButton ();
151                                 if (down_pressed)
152                                         updownbase.DownButton ();
153                         }
154
155                         protected override void OnMouseMove (MouseEventArgs args)
156                         {
157                                 base.OnMouseMove (args);
158                                 if (Capture){
159                                         bool old = mouse_in;
160
161                                         if (pressed.Contains (args.X, args.Y)){
162                                                 if (timer == null)
163                                                         InitTimer ();
164                                                 mouse_in = true;
165                                         } else {
166                                                 if (timer != null){
167                                                         timer.Enabled = false;
168                                                         timer.Dispose ();
169                                                         timer = null;
170                                                 }
171                                                 mouse_in = false;
172                                         }
173                                         if (mouse_in ^ old){
174                                                 Console.WriteLine ("STATE CHANGE");
175                                                 if (mouse_in)
176                                                         Click ();
177                                                 Invalidate (pressed);
178                                         }
179                                 }
180                         }
181                         
182                         void DrawUp ()
183                         {
184                                 ButtonState bs;
185
186                                 bs = mouse_in && up_pressed ? ButtonState.Pushed : ButtonState.Normal;
187                                 ThemeEngine.Current.CPDrawScrollButton (DeviceContext, up, ScrollButton.Up, bs);
188                         }
189                         
190                         void DrawDown ()
191                         {
192                                 ButtonState bs;
193
194                                 bs = mouse_in && down_pressed ? ButtonState.Pushed : ButtonState.Normal;
195                                 ThemeEngine.Current.CPDrawScrollButton (DeviceContext, down, ScrollButton.Down, bs);
196                         }
197
198                         void Draw (Rectangle clip)
199                         {
200                                 if (clip.Contains (up))
201                                         DrawUp ();
202                                 if (clip.Contains (down))
203                                         DrawDown ();
204                         }
205
206                         void IDisposable.Dispose ()
207                         {
208                                 if (timer != null){
209                                         timer.Stop ();
210                                         timer.Dispose ();
211                                 }
212                                 timer = null;
213                                 base.Dispose ();
214                         }
215                 }
216
217                 int desired_height = 0;
218                 Label entry;
219                 Spinner spinner;
220
221                 int scrollbar_button_size = ThemeEngine.Current.ScrollBarButtonSize;
222                 
223                 public UpDownBase () : base ()
224                 {
225                         SuspendLayout ();
226
227                         entry = new Label ();
228                         entry.Text = "I will be an Entry";
229                         entry.Font = Font;
230                         entry.Size = new Size (100, Font.Height + 4);
231                         entry.Location = new Point (0, 0);
232                         Controls.Add (entry);
233
234                         spinner = new Spinner (this);
235                         Controls.Add (spinner);
236                         
237                         ResumeLayout ();
238                         
239                 }
240
241 #region UpDownBase overwritten methods
242                 
243                 protected override void OnMouseWheel (MouseEventArgs args)
244                 {
245                         base.OnMouseWheel (args);
246
247                         if (args.Delta > 0)
248                                 UpButton ();
249                         else if (args.Delta < 0)
250                                 DownButton ();
251                 }
252
253                 protected virtual void OnChanged (object source, EventArgs e)
254                 {
255                         // Not clear, the docs state that this will raise the
256                         // Changed event, but that event is not listed anywhere.
257                 }
258
259                 protected override void OnFontChanged (EventArgs e)
260                 {
261                         base.OnFontChanged (e);
262
263                         entry.Font = Font;
264                         desired_height = entry.Height;
265                         Height = desired_height;
266                 }
267
268                 protected override void OnHandleCreated (EventArgs e)
269                 {
270                         base.OnHandleCreated (e);
271                         desired_height = entry.Height;
272                 }
273                                 
274                 protected override void OnLayout (LayoutEventArgs args)
275                 {
276                         base.OnLayout (args);
277
278                         Rectangle bounds = Bounds;
279                         int entry_width = bounds.Right - scrollbar_button_size - 1;
280
281                         entry.SetBounds (bounds.X, bounds.Y, entry_width, bounds.Height);
282                         spinner.SetBounds (entry_width + 1, bounds.Y, scrollbar_button_size, bounds.Height);
283                 }
284
285                 protected override void OnPaint (PaintEventArgs e)
286                 {
287                         base.OnPaint (e);
288                 }
289
290                 protected override void SetVisibleCore (bool state)
291                 {
292                         base.SetVisibleCore (state);
293                 }
294
295                 protected override void WndProc (ref Message m)
296                 {
297                         base.WndProc (ref m);
298                 }
299
300                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
301                 {
302                         //
303                         // Force the size to be our height.
304                         //
305                         base.SetBoundsCore (x, y, width, desired_height, specified);
306                 }
307                 
308                 protected override void Dispose (bool disposing)
309                 {
310                         if (spinner != null){
311                                 if (disposing){
312                                         spinner.Dispose ();
313                                         entry.Dispose ();
314                                 }
315                         }
316                         spinner = null;
317                         entry = null;
318                         base.Dispose (true);
319                 }
320                 
321 #endregion
322                 
323 #region UpDownBase virtual methods
324                 //
325                 // These are hooked up to the various events from the Entry line that
326                 // we do not have yet, and implement the keyboard behavior (use a different
327                 // widget to test)
328                 //
329                 protected virtual void OnTextBoxKeyDown (object source, KeyEventArgs e)
330                 {
331                 }
332                 
333                 protected virtual void OnTextBoxKeyPress (object source, KeyPressEventArgs e)
334                 {
335                 }
336
337                 protected virtual void OnTextBoxLostFocus (object source, EventArgs e)
338                 {
339                 }
340
341                 protected virtual void OnTextBoxResize (object source, EventArgs e)
342                 {
343                 }
344
345                 protected virtual void OnTextBoxTextChanged (object source, EventArgs e)
346                 {
347                 }
348
349                 protected virtual void ValidateEditText ()
350                 {
351                 }
352 #endregion
353
354 #region UpDownBase standard methods
355                 public void Select (int start, int length)
356                 {
357                         // Selects text from start for lenght chars.
358                 }
359 #endregion
360
361 #region Abstract methods
362                 public abstract void DownButton ();
363                 public abstract void UpButton ();
364                 public abstract void UpdateEditText ();
365 #endregion
366         }
367 }