]> O.S.I.I.S - jp/crow.git/commitdiff
make currentInterface public, other minor changes
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 28 Aug 2017 09:25:05 +0000 (11:25 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 28 Aug 2017 09:25:05 +0000 (11:25 +0200)
Crow.OpenTK.nuspec
src/CompilerServices/CompilerServices.cs
src/GraphicObjects/GraphicObject.cs
src/GraphicObjects/Group.cs
src/GraphicObjects/ScrollingObject.cs
src/GraphicObjects/ScrollingTextBox.cs

index e8ccb23b4b22fb5637610cf926ee1c2170543b29..21570980a2e3045dbadec35f802691d736bb4e35 100644 (file)
@@ -2,7 +2,7 @@
 <package >
        <metadata>
                <id>Crow.OpenTK</id>
-               <version>0.5.2</version>
+               <version>0.5.4</version>
                <title>C# Rapid Open Widget Toolkit</title>
                <authors>JP Bruyere</authors>
                <owners>Grand Tetras Software</owners>
@@ -18,10 +18,19 @@ Crow.OpenTK is the OpenTK ready version.
 CROW is a pure C# widget toolkit with templates, styles, compositing, and bindings.
 Crow.OpenTK is the OpenTK ready version.
 
+Native libraries dependencies:
+       - cairo
+       - librsvg (and its dependencies (glib2, libxml, fontconfig, etc)
+
+Precompiled binaries of those libs are available at http://ftp.gnome.org/pub/GNOME/binaries/
+
 For more information, please visit https://jpbruyere.github.io/Crow/.
                </summary>
                <releaseNotes>
-                       - debug.
+                       - embed Cairo bindings in Crow.
+                       - use of CairoRegion to handle clipping
+                       - IDisposable for GraphicObject
+                       - Border style Raised/Sunken
                </releaseNotes>
                <copyright>Copyright 2013-2017</copyright>
                <dependencies>
index 5409aa5e7b2210ac63148d7459fe30ae8d941f6b..752655f8a333d505c23adb97d54affc93223243f 100644 (file)
@@ -76,7 +76,7 @@ namespace Crow
                internal static MethodInfo miDSChangeEmitHelper = typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic);
                internal static MethodInfo miDSReverseBinding = typeof(Instantiator).GetMethod("dataSourceReverseBinding", BindingFlags.Static | BindingFlags.NonPublic);
 
-               internal static FieldInfo miSetCurIface = typeof(GraphicObject).GetField ("currentInterface", BindingFlags.NonPublic | BindingFlags.Instance);
+               internal static FieldInfo miSetCurIface = typeof(GraphicObject).GetField ("currentInterface", BindingFlags.Public | BindingFlags.Instance);
                internal static MethodInfo miFindByName = typeof (GraphicObject).GetMethod ("FindByName");
                internal static MethodInfo miGetGObjItem = typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) });
                internal static MethodInfo miLoadDefaultVals = typeof (GraphicObject).GetMethod ("loadDefaultValues");
index 93e812def3461c4e9681b59d9c4028ed6e507aae..7b9f0c56c795560fd41a0848f8e80ad4a7e5982a 100644 (file)
@@ -91,7 +91,7 @@ namespace Crow
                internal static ulong currentUid = 0;
                internal ulong uid = 0;
 
-               internal Interface currentInterface = null;
+               public Interface currentInterface = null;
 
                public Region Clipping;
 
index e7d7d4d4a163d10fbff249903d60624bd228d095..917087cc782d2ab444a0850fa6d86d2aef29ccbe 100644 (file)
@@ -74,9 +74,6 @@ namespace Crow
                {
                        child.LayoutChanged -= OnChildLayoutChanges;
 
-                       //check if HoverWidget is removed from Tree
-
-
                        lock (children)
                Children.Remove(child);
                        child.Dispose ();
index 8b9bc58aff54b01a01f776861a1e404e44b40c72..42acdbf9d9d02bd1a366641a067279be6a3b2905 100644 (file)
@@ -43,6 +43,11 @@ namespace Crow
 
                int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed;
 
+               /// <summary>
+               /// if true, key stroke are handled in derrived class
+               /// </summary>
+               protected bool KeyEventsOverrides = false;
+
                /// <summary> Horizontal Scrolling Position </summary>
                [XmlAttributeAttribute][DefaultValue(0)]
                public virtual int ScrollX {
@@ -142,15 +147,18 @@ namespace Crow
                {
                        base.onMouseWheel (sender, e);
                        if (currentInterface.Keyboard.IsKeyDown (Key.ShiftLeft))
-                               ScrollY += e.Delta * MouseWheelSpeed;
-                       else
                                ScrollX += e.Delta * MouseWheelSpeed;
+                       else
+                               ScrollY -= e.Delta * MouseWheelSpeed;
                }
                /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
                public override void onKeyDown (object sender, KeyboardKeyEventArgs e)
                {
                        base.onKeyDown (sender, e);
 
+                       if (KeyEventsOverrides)
+                               return;
+
                        switch (e.Key) {
                        case Key.Up:
                                ScrollY--;
index f79716570a993e3e2fa063ff16ed176d516840a0..c409d02295a92f2b841fd879b0292cdc0914e879 100644 (file)
@@ -30,23 +30,762 @@ using System.ComponentModel;
 using System.Collections;
 using Cairo;
 using System.Text;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Linq;
 
 namespace Crow
 {
+       /// <summary>
+       /// Scrolling text box optimized for monospace fonts, for coding
+       /// </summary>
        public class ScrollingTextBox : ScrollingObject
        {
                #region CTOR
                public ScrollingTextBox ():base()
                {
-                       
+                       KeyEventsOverrides = true;
+               }
+               #endregion
 
+               public event EventHandler TextChanged;
+
+               public virtual void OnTextChanged(Object sender, EventArgs e)
+               {
+                       TextChanged.Raise (this, e);
                }
+
+               #region private and protected fields
+               string lineBreak = Interface.LineBreak;
+               int visibleLines = 1;
+               List<string> lines;
+               string _text = "label";
+               Color selBackground;
+               Color selForeground;
+               Point mouseLocalPos = 0;//mouse coord in widget space
+               int _currentCol;        //0 based cursor position in string
+               int _currentLine;
+               Point _selBegin = -1;   //selection start (row,column)
+               Point _selRelease = -1; //selection end (row,column)
+
+               protected Rectangle rText;
+               protected FontExtents fe;
+               protected TextExtents te;
                #endregion
 
-               struct test<T> {
-                       public T a;
+               [XmlAttributeAttribute][DefaultValue("label")]
+               public string Text
+               {
+                       get {
+                               return lines == null ?
+                                       _text : lines.Aggregate((i, j) => i + Interface.LineBreak + j);
+                       }
+                       set
+                       {
+                               if (string.Equals (value, _text, StringComparison.Ordinal))
+                                       return;
+
+                               _text = value;
+
+                               if (string.IsNullOrEmpty(_text))
+                                       _text = "";
+
+                               lines = getLines;
+                               MaxScrollY = Math.Max (0, lines.Count - visibleLines);
+
+                               OnTextChanged (this, null);
+                               RegisterForGraphicUpdate ();
+                       }
                }
 
-       }
-}
 
+               [XmlAttributeAttribute][DefaultValue("BlueGray")]
+               public virtual Color SelectionBackground {
+                       get { return selBackground; }
+                       set {
+                               if (value == selBackground)
+                                       return;
+                               selBackground = value;
+                               NotifyValueChanged ("SelectionBackground", selBackground);
+                               RegisterForRedraw ();
+                       }
+               }
+               [XmlAttributeAttribute][DefaultValue("White")]
+               public virtual Color SelectionForeground {
+                       get { return selForeground; }
+                       set {
+                               if (value == selForeground)
+                                       return;
+                               selForeground = value;
+                               NotifyValueChanged ("SelectionForeground", selForeground);
+                               RegisterForRedraw ();
+                       }
+               }
+               [XmlAttributeAttribute][DefaultValue(0)]
+               public int CurrentColumn{
+                       get { return _currentCol; }
+                       set {
+                               if (value == _currentCol)
+                                       return;
+                               if (value < 0)
+                                       _currentCol = 0;
+                               else if (value > lines [_currentLine].Length)
+                                       _currentCol = lines [_currentLine].Length;
+                               else
+                                       _currentCol = value;
+                               NotifyValueChanged ("CurrentColumn", _currentCol);
+                       }
+               }
+               [XmlAttributeAttribute][DefaultValue(0)]
+               public int CurrentLine{
+                       get { return _currentLine; }
+                       set {
+                               if (value == _currentLine)
+                                       return;
+                               if (value >= lines.Count)
+                                       _currentLine = lines.Count-1;
+                               else if (value < 0)
+                                       _currentLine = 0;
+                               else
+                                       _currentLine = value;
+                               //force recheck of currentCol for bounding
+                               int cc = _currentCol;
+                               _currentCol = 0;
+                               CurrentColumn = cc;
+                               NotifyValueChanged ("CurrentLine", _currentLine);
+
+                               if (CurrentLine < ScrollY)
+                                       ScrollY = CurrentLine;
+                               else if (CurrentLine >= ScrollY + visibleLines)
+                                       ScrollY = Math.Max (0, CurrentLine - visibleLines + 1);
+                       }
+               }
+               [XmlIgnore]public Point CurrentPosition {
+                       get { return new Point(CurrentColumn, CurrentLine); }
+               }
+               //TODO:using HasFocus for drawing selection cause SelBegin and Release binding not to work
+               /// <summary>
+               /// Selection begin position in char units (line, column)
+               /// </summary>
+               [XmlAttributeAttribute][DefaultValue("-1")]
+               public Point SelBegin {
+                       get { return _selBegin; }
+                       set {
+                               if (value == _selBegin)
+                                       return;
+                               _selBegin = value;
+                               System.Diagnostics.Debug.WriteLine ("SelBegin=" + _selBegin);
+                               NotifyValueChanged ("SelBegin", _selBegin);
+                               NotifyValueChanged ("SelectedText", SelectedText);
+                       }
+               }
+               /// <summary>
+               /// Selection release position in char units (line, column)
+               /// </summary>
+               [XmlAttributeAttribute][DefaultValue("-1")]
+               public Point SelRelease {
+                       get {
+                               return _selRelease;
+                       }
+                       set {
+                               if (value == _selRelease)
+                                       return;
+                               _selRelease = value;
+                               NotifyValueChanged ("SelRelease", _selRelease);
+                               NotifyValueChanged ("SelectedText", SelectedText);
+                       }
+               }
+               /// <summary>
+               /// return char at CurrentLine, CurrentColumn
+               /// </summary>
+               [XmlIgnore]protected Char CurrentChar
+               {
+                       get {
+                               return lines [CurrentLine] [CurrentColumn];
+                       }
+               }
+               /// <summary>
+               /// ordered selection start and end positions in char units
+               /// </summary>
+               [XmlIgnore]protected Point selectionStart
+               {
+                       get {
+                               return SelRelease < 0 || SelBegin.Y < SelRelease.Y ? SelBegin :
+                                       SelBegin.Y > SelRelease.Y ? SelRelease :
+                                       SelBegin.X < SelRelease.X ? SelBegin : SelRelease;
+                       }
+               }
+               [XmlIgnore]public Point selectionEnd
+               {
+                       get {
+                               return SelRelease < 0 || SelBegin.Y > SelRelease.Y ? SelBegin :
+                                       SelBegin.Y < SelRelease.Y ? SelRelease :
+                                       SelBegin.X > SelRelease.X ? SelBegin : SelRelease;
+                       }
+               }
+               [XmlIgnore]public string SelectedText
+               {
+                       get {
+
+                               if (SelRelease < 0 || SelBegin < 0)
+                                       return "";
+                               if (selectionStart.Y == selectionEnd.Y)
+                                       return lines [selectionStart.Y].Substring (selectionStart.X, selectionEnd.X - selectionStart.X);
+                               string tmp = "";
+                               tmp = lines [selectionStart.Y].Substring (selectionStart.X);
+                               for (int l = selectionStart.Y + 1; l < selectionEnd.Y; l++) {
+                                       tmp += Interface.LineBreak + lines [l];
+                               }
+                               tmp += Interface.LineBreak + lines [selectionEnd.Y].Substring (0, selectionEnd.X);
+                               return tmp;
+                       }
+               }
+               [XmlIgnore]public bool selectionIsEmpty
+               { get { return SelRelease == SelBegin; } }
+
+               List<string> getLines {
+                       get {
+                               return Regex.Split (_text, "\r\n|\r|\n|\\\\n").ToList();
+                       }
+               }
+               /// <summary>
+               /// Moves cursor one char to the left.
+               /// </summary>
+               /// <returns><c>true</c> if move succeed</returns>
+               public bool MoveLeft(){
+                       int tmp = _currentCol - 1;
+                       if (tmp < 0) {
+                               if (_currentLine == 0)
+                                       return false;
+                               CurrentLine--;
+                               CurrentColumn = int.MaxValue;
+                       } else
+                               CurrentColumn = tmp;
+                       return true;
+               }
+               /// <summary>
+               /// Moves cursor one char to the right.
+               /// </summary>
+               /// <returns><c>true</c> if move succeed</returns>
+               public bool MoveRight(){
+                       int tmp = _currentCol + 1;
+                       if (tmp > lines [_currentLine].Length){
+                               if (CurrentLine == lines.Count - 1)
+                                       return false;
+                               CurrentLine++;
+                               CurrentColumn = 0;
+                       } else
+                               CurrentColumn = tmp;
+                       return true;
+               }
+               public void GotoWordStart(){
+                       if (lines[CurrentLine].Length == 0)
+                               return;
+                       CurrentColumn--;
+                       //skip white spaces
+                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
+                               CurrentColumn--;
+                       while (char.IsLetterOrDigit (lines [CurrentLine] [CurrentColumn]) && CurrentColumn > 0)
+                               CurrentColumn--;
+                       if (!char.IsLetterOrDigit (this.CurrentChar))
+                               CurrentColumn++;
+               }
+               public void GotoWordEnd(){
+                       //skip white spaces
+                       if (CurrentColumn >= lines [CurrentLine].Length - 1)
+                               return;
+                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
+                               CurrentColumn++;
+                       while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
+                               CurrentColumn++;
+                       if (char.IsLetterOrDigit (this.CurrentChar))
+                               CurrentColumn++;
+               }
+               public void DeleteChar()
+               {
+                       if (selectionIsEmpty) {
+                               if (CurrentColumn == 0) {
+                                       if (CurrentLine == 0 && lines.Count == 1)
+                                               return;
+                                       CurrentLine--;
+                                       CurrentColumn = lines [CurrentLine].Length;
+                                       lines [CurrentLine] += lines [CurrentLine + 1];
+                                       lines.RemoveAt (CurrentLine + 1);
+                                       OnTextChanged (this, null);
+                                       return;
+                               }
+                               CurrentColumn--;
+                               lines [CurrentLine] = lines [CurrentLine].Remove (CurrentColumn, 1);
+                       } else {
+                               int linesToRemove = selectionEnd.Y - selectionStart.Y + 1;
+                               int l = selectionStart.Y;
+
+                               if (linesToRemove > 0) {
+                                       lines [l] = lines [l].Remove (selectionStart.X, lines [l].Length - selectionStart.X) +
+                                               lines [selectionEnd.Y].Substring (selectionEnd.X, lines [selectionEnd.Y].Length - selectionEnd.X);
+                                       l++;
+                                       for (int c = 0; c < linesToRemove-1; c++)
+                                               lines.RemoveAt (l);
+                                       CurrentLine = selectionStart.Y;
+                                       CurrentColumn = selectionStart.X;
+                               } else
+                                       lines [l] = lines [l].Remove (selectionStart.X, selectionEnd.X - selectionStart.X);
+                               CurrentColumn = selectionStart.X;
+                               SelBegin = -1;
+                               SelRelease = -1;
+                       }
+                       OnTextChanged (this, null);
+               }
+
+               #region GraphicObject overrides
+               public override Font Font {
+                       get { return base.Font; }
+                       set {
+                               base.Font = value;
+
+                               using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) {
+                                       using (Context gr = new Context (img)) {
+                                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                               gr.SetFontSize (Font.Size);
+
+                                               fe = gr.FontExtents;
+                                       }
+                               }
+                               MaxScrollY = 0;
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               protected override int measureRawSize(LayoutingType lt)
+               {
+                       if (lt == LayoutingType.Height)
+                               return (int)Math.Ceiling(fe.Height * lines.Count) + Margin * 2;
+
+                       string txt = _text.Replace("\t", new String (' ', Interface.TabSize));
+
+
+                       int maxChar = 0;
+                       foreach (string s in Regex.Split (txt, "\r\n|\r|\n|\\\\n")) {
+                               if (maxChar < s.Length)
+                                       maxChar = s.Length;
+                       }
+                       return (int)(fe.MaxXAdvance * maxChar) + Margin * 2;
+               }
+               public override void OnLayoutChanges (LayoutingType layoutType)
+               {
+                       base.OnLayoutChanges (layoutType);
+
+                       if (layoutType == LayoutingType.Height)
+                               updateVisibleLines ();
+               }
+               protected override void onDraw (Context gr)
+               {
+                       base.onDraw (gr);
+
+                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                       gr.SetFontSize (Font.Size);
+                       gr.FontOptions = Interface.FontRenderingOptions;
+                       gr.Antialias = Interface.Antialias;
+
+                       Rectangle cb = ClientRectangle;
+
+                       Foreground.SetAsSource (gr);
+
+                       bool selectionInProgress = false;
+
+                       #region draw text cursor
+                       if (SelBegin != SelRelease)
+                               selectionInProgress = true;
+                       else if (HasFocus){
+                               gr.SetSourceColor(Color.Red);
+                               gr.LineWidth = 2.0;
+                               double cursorX = cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance;
+                               gr.MoveTo (0.5 + cursorX, cb.Y + (CurrentLine - ScrollY) * fe.Height);
+                               gr.LineTo (0.5 + cursorX, cb.Y + (CurrentLine + 1 - ScrollY) * fe.Height);
+                               gr.Stroke();
+                       }
+                       #endregion
+
+                       Foreground.SetAsSource (gr);
+
+                       for (int i = 0; i < visibleLines; i++) {
+                               int curL = i + ScrollY;
+                               if (curL >= lines.Count)
+                                       break;
+                               string lstr = lines[curL];
+
+                               gr.MoveTo (cb.X, cb.Y + fe.Ascent + fe.Height * i);
+                               gr.ShowText (lstr);
+                               gr.Fill ();
+
+                               if (selectionInProgress && curL >= selectionStart.Y && curL <= selectionEnd.Y) {
+
+                                       double rLineX = cb.X,
+                                       rLineY = cb.Y + i * fe.Height,
+                                       rLineW = lstr.Length * fe.MaxXAdvance;
+
+                                       System.Diagnostics.Debug.WriteLine ("sel start: " + selectionStart + " sel end: " + selectionEnd);
+                                       if (curL == selectionStart.Y) {
+                                               rLineX += (selectionStart.X - ScrollX) * fe.MaxXAdvance;
+                                               rLineW -= selectionStart.X * fe.MaxXAdvance;
+                                       }
+                                       if (curL == selectionEnd.Y)
+                                               rLineW -= (lstr.Length - selectionEnd.X) * fe.MaxXAdvance;
+
+                                       gr.Save ();
+                                       gr.Operator = Operator.Source;
+                                       gr.Rectangle (rLineX, rLineY, rLineW, fe.Height);
+                                       gr.SetSourceColor (SelectionBackground);
+                                       gr.FillPreserve ();
+                                       gr.Clip ();
+                                       gr.Operator = Operator.Over;
+                                       gr.SetSourceColor (SelectionForeground);
+                                       gr.MoveTo (cb.X, cb.Y + fe.Ascent + fe.Height * i);
+                                       gr.ShowText (lstr);
+                                       gr.Fill ();
+                                       gr.Restore ();
+                               }
+                       }
+               }
+               #endregion
+
+               #region Mouse handling
+               void updatemouseLocalPos(Point mpos){
+                       Point mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
+                       if (mouseLocalPos.X < 0)
+                               CurrentColumn--;
+                       else
+                               CurrentColumn = ScrollX +  (int)Math.Round (mouseLocalPos.X / fe.MaxXAdvance);
+
+                       if (mouseLocalPos.Y < 0)
+                               CurrentLine--;
+                       else
+                               CurrentLine = ScrollY + (int)Math.Floor (mouseLocalPos.Y / fe.Height);
+               }
+               public override void onMouseEnter (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseEnter (sender, e);
+                       currentInterface.MouseCursor = XCursor.Text;
+               }
+               public override void onMouseLeave (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseLeave (sender, e);
+                       currentInterface.MouseCursor = XCursor.Default;
+               }
+               protected override void onFocused (object sender, EventArgs e)
+               {
+                       base.onFocused (sender, e);
+
+                       //                      SelBegin = new Point(0,0);
+                       //                      SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1);
+                       RegisterForRedraw ();
+               }
+               protected override void onUnfocused (object sender, EventArgs e)
+               {
+                       base.onUnfocused (sender, e);
+
+                       //                      SelBegin = -1;
+                       //                      SelRelease = -1;
+                       RegisterForRedraw ();
+               }
+               public override void onMouseMove (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseMove (sender, e);
+
+                       if (!e.Mouse.IsButtonDown (MouseButton.Left))
+                               return;
+                       if (!HasFocus || SelBegin < 0)
+                               return;
+
+                       updatemouseLocalPos (e.Position);
+                       SelRelease = CurrentPosition;
+
+                       RegisterForRedraw();
+               }
+               public override void onMouseDown (object sender, MouseButtonEventArgs e)
+               {
+                       if (this.HasFocus){
+                               updatemouseLocalPos (e.Position);
+                               SelBegin = SelRelease = CurrentPosition;
+                               RegisterForRedraw();//TODO:should put it in properties
+                       }
+
+                       //done at the end to set 'hasFocus' value after testing it
+                       base.onMouseDown (sender, e);
+               }
+               public override void onMouseUp (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseUp (sender, e);
+
+                       if (SelBegin == SelRelease)
+                               SelBegin = SelRelease = -1;
+
+                       updatemouseLocalPos (e.Position);
+                       RegisterForRedraw ();
+               }
+               public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseDoubleClick (sender, e);
+
+                       GotoWordStart ();
+                       SelBegin = CurrentPosition;
+                       GotoWordEnd ();
+                       SelRelease = CurrentPosition;
+                       RegisterForRedraw ();
+               }
+               #endregion
+
+               #region Keyboard handling
+               public override void onKeyDown (object sender, KeyboardKeyEventArgs e)
+               {
+                       base.onKeyDown (sender, e);
+
+                       Key key = e.Key;
+
+                       switch (key)
+                       {
+                       case Key.Back:
+                               if (CurrentPosition == 0)
+                                       return;
+                               this.DeleteChar();
+                               break;
+                       case Key.Clear:
+                               break;
+                       case Key.Delete:
+                               if (selectionIsEmpty) {
+                                       if (!MoveRight ())
+                                               return;
+                               }else if (e.Shift)
+                                       currentInterface.Clipboard = this.SelectedText;
+                               this.DeleteChar ();
+                               break;
+                       case Key.Enter:
+                       case Key.KeypadEnter:
+                               if (!selectionIsEmpty)
+                                       this.DeleteChar ();
+                               this.InsertLineBreak ();
+                               break;
+                       case Key.Escape:
+                               Text = "";
+                               CurrentColumn = 0;
+                               SelRelease = -1;
+                               break;
+                       case Key.Home:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = new Point (CurrentColumn, CurrentLine);
+                                       if (e.Control)
+                                               CurrentLine = 0;
+                                       CurrentColumn = 0;
+                                       SelRelease = new Point (CurrentColumn, CurrentLine);
+                                       break;
+                               }
+                               SelRelease = -1;
+                               if (e.Control)
+                                       CurrentLine = 0;
+                               CurrentColumn = 0;
+                               break;
+                       case Key.End:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       if (e.Control)
+                                               CurrentLine = int.MaxValue;
+                                       CurrentColumn = int.MaxValue;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;
+                               if (e.Control)
+                                       CurrentLine = int.MaxValue;
+                               CurrentColumn = int.MaxValue;
+                               break;
+                       case Key.Insert:
+                               if (e.Shift)
+                                       this.Insert (currentInterface.Clipboard);
+                               else if (e.Control && !selectionIsEmpty)
+                                       currentInterface.Clipboard = this.SelectedText;
+                               break;
+                       case Key.Left:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = new Point(CurrentColumn, CurrentLine);
+                                       if (e.Control)
+                                               GotoWordStart ();
+                                       else if (!MoveLeft ())
+                                               return;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;
+                               if (e.Control)
+                                       GotoWordStart ();
+                               else
+                                       MoveLeft();
+                               break;
+                       case Key.Right:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       if (e.Control)
+                                               GotoWordEnd ();
+                                       else if (!MoveRight ())
+                                               return;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;
+                               if (e.Control)
+                                       GotoWordEnd ();
+                               else
+                                       MoveRight ();
+                               break;
+                       case Key.Up:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       CurrentLine--;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;
+                               CurrentLine--;
+                               break;
+                       case Key.Down:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       CurrentLine++;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;
+                               CurrentLine++;
+                               break;
+                       case Key.Menu:
+                               break;
+                       case Key.NumLock:
+                               break;
+                       case Key.PageDown:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       CurrentLine += visibleLines;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }
+                               SelRelease = -1;                                
+                               CurrentLine += visibleLines;
+                               break;
+                       case Key.PageUp:
+                               if (e.Shift) {
+                                       if (selectionIsEmpty)
+                                               SelBegin = CurrentPosition;
+                                       CurrentLine -= visibleLines;
+                                       SelRelease = CurrentPosition;
+                                       break;
+                               }                               
+                               CurrentLine -= visibleLines;
+                               break;
+                       case Key.RWin:
+                               break;
+                       case Key.Tab:
+                               this.Insert ("\t");
+                               break;
+                       default:
+                               break;
+                       }
+                       RegisterForGraphicUpdate();
+               }
+               public override void onKeyPress (object sender, KeyPressEventArgs e)
+               {
+                       base.onKeyPress (sender, e);
+
+                       this.Insert (e.KeyChar.ToString());
+
+                       SelRelease = -1;
+                       SelBegin = -1; //new Point(CurrentColumn, SelBegin.Y);
+
+                       RegisterForGraphicUpdate();
+               }
+               #endregion
+
+
+               /// <summary> Compute x offset in cairo unit from text position </summary>
+               double GetXFromTextPointer(Context gr, Point pos)
+               {
+                       try {
+                               string l = lines [pos.Y].Substring (0, pos.X).
+                                       Replace ("\t", new String (' ', Interface.TabSize));
+                               return gr.TextExtents (l).XAdvance;
+                       } catch{
+                               return -1;
+                       }
+               }
+
+               /// <summary> line break could be '\r' or '\n' or '\r\n' </summary>
+               string detectLineBreakKind(){
+                       string strLB = "";
+
+                       if (string.IsNullOrEmpty(_text))
+                               return Interface.LineBreak;
+                       int i = 0;
+                       while ( i < _text.Length) {
+                               if (_text [i] == '\r') {
+                                       strLB += '\r';
+                                       i++;
+                               }
+                               if (i < _text.Length) {
+                                       if (_text [i] == '\r')
+                                               return "\r";
+                                       if (_text [i] == '\n')
+                                               strLB += '\n';
+                               }
+                               if (!string.IsNullOrEmpty (strLB))
+                                       return strLB;
+                               i++;
+                       }
+                       return Interface.LineBreak;
+               }
+
+               void updateVisibleLines(){
+                       visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / fe.Height);
+                       MaxScrollY = Math.Max (0, lines.Count - visibleLines);
+
+                       System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines);
+                       System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY);
+               }
+
+
+               /// <summary>
+               /// Insert new string at caret position, should be sure no line break is inside.
+               /// </summary>
+               /// <param name="str">String.</param>
+               protected void Insert(string str)
+               {
+                       if (!selectionIsEmpty)
+                               this.DeleteChar ();
+                       string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray();
+                       lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[0]);
+                       CurrentColumn += strLines[0].Length;
+                       for (int i = 1; i < strLines.Length; i++) {
+                               InsertLineBreak ();
+                               lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[i]);
+                               CurrentColumn += strLines[i].Length;
+                       }
+                       OnTextChanged (this, null);
+                       RegisterForGraphicUpdate();
+               }
+
+               /// <summary>
+               /// Insert a line break.
+               /// </summary>
+               protected void InsertLineBreak()
+               {
+                       lines.Insert(CurrentLine + 1, lines[CurrentLine].Substring(CurrentColumn));
+                       lines [CurrentLine] = lines [CurrentLine].Substring (0, CurrentColumn);
+                       CurrentLine++;
+                       CurrentColumn = 0;
+                       OnTextChanged (this, null);
+               }
+       }
+}
\ No newline at end of file