2009-09-03 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / class / System.Windows / System.Windows.Controls / TextBox.cs
blob175f959dd79de017edd31ce29a2c59f5da805712
1 //
2 // Contact:
3 // Moonlight List (moonlight-list@lists.ximian.com)
4 //
5 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 using Mono;
28 using System.Windows;
29 using System.Windows.Automation.Peers;
30 using System.Windows.Input;
31 using System.Windows.Media;
32 using System.Windows.Documents;
33 using System.Collections.Generic;
35 namespace System.Windows.Controls {
37 [TemplateVisualStateAttribute (Name = "Disabled", GroupName = "CommonStates")]
38 [TemplateVisualStateAttribute (Name = "Normal", GroupName = "CommonStates")]
39 [TemplateVisualStateAttribute (Name = "MouseOver", GroupName = "CommonStates")]
40 [TemplateVisualStateAttribute (Name = "ReadOnly", GroupName = "CommonStates")]
41 [TemplateVisualStateAttribute (Name = "Focused", GroupName = "FocusStates")]
42 [TemplateVisualStateAttribute (Name = "Unfocused", GroupName = "FocusStates")]
43 [TemplatePartAttribute (Name = "ContentElement", Type = typeof (FrameworkElement))]
44 [TemplatePartAttribute (Name = "DisabledVisualElement", Type = typeof (FrameworkElement))]
45 [TemplatePartAttribute (Name = "FocusVisualElement", Type = typeof (FrameworkElement))]
46 [TemplatePartAttribute (Name = "ReadOnlyVisualElement", Type = typeof (FrameworkElement))]
47 [TemplatePartAttribute (Name = "RootElement", Type = typeof (FrameworkElement))]
48 public partial class TextBox : Control {
49 object contentElement;
51 bool IsFocused {
52 get; set;
55 bool IsMouseOver {
56 get; set;
59 internal override void Initialize ()
61 base.Initialize ();
63 CursorPositionChanged += OnCursorPositionChanged;
64 IsEnabledChanged += delegate { ChangeVisualState (); };
65 Loaded += delegate { ChangeVisualState (); };
68 internal override void InvokeKeyDown (KeyEventArgs k)
70 base.InvokeKeyDown (k);
72 if (!k.Handled)
73 NativeMethods.text_box_base_on_character_key_down (native, k.NativeHandle);
76 protected override void OnKeyDown (KeyEventArgs k)
78 // Chain up to our parent first, so that TabNavigation
79 // works as well as allowing developers to filter our
80 // input.
81 base.OnKeyDown (k);
83 if (!k.Handled)
84 NativeMethods.text_box_base_on_key_down (native, k.NativeHandle);
87 protected override void OnKeyUp (KeyEventArgs k)
89 base.OnKeyUp (k);
91 if (!k.Handled)
92 NativeMethods.text_box_base_on_key_up (native, k.NativeHandle);
95 protected override void OnMouseLeftButtonDown (MouseButtonEventArgs e)
97 if (!e.Handled)
98 NativeMethods.text_box_base_on_mouse_left_button_down (native, e.NativeHandle);
100 base.OnMouseLeftButtonDown (e);
103 protected override void OnMouseLeftButtonUp (MouseButtonEventArgs e)
105 if (!e.Handled)
106 NativeMethods.text_box_base_on_mouse_left_button_up (native, e.NativeHandle);
108 base.OnMouseLeftButtonUp (e);
111 protected override void OnMouseMove (MouseEventArgs e)
113 NativeMethods.text_box_base_on_mouse_move (native, e.NativeHandle);
114 base.OnMouseMove (e);
117 protected override void OnMouseEnter (MouseEventArgs e)
119 IsMouseOver = true;
120 base.OnMouseEnter (e);
121 ChangeVisualState ();
124 protected override void OnMouseLeave (MouseEventArgs e)
126 IsMouseOver = false;
127 base.OnMouseLeave (e);
128 ChangeVisualState ();
131 protected override void OnGotFocus (RoutedEventArgs e)
133 IsFocused = true;
134 base.OnGotFocus (e);
135 NativeMethods.text_box_base_on_got_focus (native, e.NativeHandle);
136 ChangeVisualState ();
139 protected override void OnLostFocus (RoutedEventArgs e)
141 IsFocused = false;
142 base.OnLostFocus (e);
143 NativeMethods.text_box_base_on_lost_focus (native, e.NativeHandle);
144 ChangeVisualState ();
147 public string Text {
148 get {
149 return (string)GetValue (TextProperty) ?? "";
151 set {
152 if (value == null)
153 throw new ArgumentNullException ("Text cannot be null");
154 SetValue (TextProperty, value);
158 public void Select (int start, int length)
160 if (start < 0)
161 throw new ArgumentOutOfRangeException ("start");
163 if (length < 0)
164 throw new ArgumentOutOfRangeException ("length");
166 NativeMethods.text_box_base_select (this.native, start, length);
169 public void SelectAll ()
171 NativeMethods.text_box_base_select_all (native);
174 static UnmanagedEventHandler cursor_position_changed = Events.CreateSafeHandler (cursor_position_changed_cb);
175 static UnmanagedEventHandler selection_changed = Events.CreateSafeHandler (selection_changed_cb);
176 static UnmanagedEventHandler text_changed = Events.CreateSafeHandler (text_changed_cb);
178 static object CursorPositionChangedEvent = new object ();
179 static object SelectionChangedEvent = new object ();
180 static object TextChangedEvent = new object ();
182 void OnCursorPositionChanged (object sender, CursorPositionChangedEventArgs args)
184 if (contentElement == null)
185 contentElement = GetTemplateChild ("ContentElement");
187 if (contentElement != null && contentElement is ScrollViewer) {
188 ScrollViewer scrollview = contentElement as ScrollViewer;
189 double offset = scrollview.HorizontalOffset;
191 // Note: for horizontal scrollage, we offset by 1.0 pixel for the width of the cursor ibeam
193 if (args.CursorX < offset) {
194 // need to scroll to the left a bit
195 scrollview.ScrollToHorizontalOffset (Math.Max (args.CursorX - 1.0, 0.0));
196 } else if (args.CursorX > offset + scrollview.ViewportWidth) {
197 // need to scroll to the right
198 offset = (args.CursorX + 1.0) - scrollview.ViewportWidth;
199 scrollview.ScrollToHorizontalOffset (offset);
202 offset = scrollview.VerticalOffset;
203 if (args.CursorY < offset) {
204 // need to scroll up a bit
205 scrollview.ScrollToVerticalOffset (args.CursorY);
206 } else if (args.CursorY + args.CursorHeight > offset + scrollview.ViewportHeight) {
207 // need to scroll down a bit
208 offset = (args.CursorY + args.CursorHeight) - Math.Max (args.CursorHeight, scrollview.ViewportHeight);
209 scrollview.ScrollToVerticalOffset (offset);
214 void InvokeCursorPositionChanged (CursorPositionChangedEventArgs args)
216 CursorPositionChangedEventHandler h = (CursorPositionChangedEventHandler) EventList [CursorPositionChangedEvent];
218 if (h != null)
219 h (this, args);
222 static void cursor_position_changed_cb (IntPtr target, IntPtr calldata, IntPtr closure)
224 TextBox textbox = (TextBox) NativeDependencyObjectHelper.FromIntPtr (closure);
225 CursorPositionChangedEventArgs args = new CursorPositionChangedEventArgs (calldata);
227 textbox.InvokeCursorPositionChanged (args);
230 event CursorPositionChangedEventHandler CursorPositionChanged {
231 add {
232 RegisterEvent (CursorPositionChangedEvent, "CursorPositionChanged", cursor_position_changed, value);
234 remove {
235 UnregisterEvent (CursorPositionChangedEvent, "CursorPositionChanged", cursor_position_changed, value);
239 void InvokeSelectionChanged (RoutedEventArgs args)
241 RoutedEventHandler h = (RoutedEventHandler) EventList [SelectionChangedEvent];
243 if (h != null)
244 h (this, args);
247 static void selection_changed_cb (IntPtr target, IntPtr calldata, IntPtr closure)
249 TextBox textbox = (TextBox) NativeDependencyObjectHelper.FromIntPtr (closure);
250 RoutedEventArgs args = new RoutedEventArgs (calldata, false);
252 textbox.InvokeSelectionChanged (args);
255 public event RoutedEventHandler SelectionChanged {
256 add {
257 RegisterEvent (SelectionChangedEvent, "SelectionChanged", selection_changed, value);
259 remove {
260 UnregisterEvent (SelectionChangedEvent, "SelectionChanged", selection_changed, value);
264 void InvokeTextChanged (TextChangedEventArgs args)
266 TextChangedEventHandler h = (TextChangedEventHandler) EventList [TextChangedEvent];
268 if (h != null)
269 h (this, args);
272 static void text_changed_cb (IntPtr target, IntPtr calldata, IntPtr closure)
274 TextBox textbox = (TextBox) NativeDependencyObjectHelper.FromIntPtr (closure);
275 TextChangedEventArgs args = new TextChangedEventArgs (calldata);
277 textbox.InvokeTextChanged (args);
280 public event TextChangedEventHandler TextChanged {
281 add {
282 RegisterEvent (TextChangedEvent, "TextChanged", text_changed, value);
284 remove {
285 UnregisterEvent (TextChangedEvent, "TextChanged", text_changed, value);
289 void ChangeVisualState ()
291 ChangeVisualState (true);
294 void ChangeVisualState (bool useTransitions)
296 if (!IsEnabled) {
297 VisualStateManager.GoToState (this, "Disabled", useTransitions);
298 } else if (IsReadOnly) {
299 VisualStateManager.GoToState (this, "ReadOnly", useTransitions);
300 } else if (IsMouseOver) {
301 VisualStateManager.GoToState (this, "MouseOver", useTransitions);
302 } else {
303 VisualStateManager.GoToState (this, "Normal", useTransitions);
306 if (IsFocused) {
307 VisualStateManager.GoToState (this, "Focused", useTransitions);
308 } else {
309 VisualStateManager.GoToState (this, "Unfocused", useTransitions);
313 protected override AutomationPeer OnCreateAutomationPeer ()
315 return new TextBoxAutomationPeer (this);