]> O.S.I.I.S - jp/crowedit.git/commitdiff
SourceEditor wip
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 28 Aug 2017 09:42:31 +0000 (11:42 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 28 Aug 2017 09:42:31 +0000 (11:42 +0200)
16 files changed:
Crow.dll.config [new file with mode: 0644]
CrowEdit.csproj
CrowWindow.cs [new file with mode: 0644]
InterfaceControler.cs [new file with mode: 0644]
packages.config
src/CodeTextBuffer.cs [new file with mode: 0644]
src/CrowEdit.cs
src/CrowWindow.cs [deleted file]
src/InterfaceControler.cs [deleted file]
src/ScrollingObject.cs [deleted file]
src/ScrollingTextBox.cs [deleted file]
src/SourceEditor.cs [new file with mode: 0644]
src/SourceLine.cs [new file with mode: 0644]
src/TextBuffer.cs [deleted file]
src/Token.cs [new file with mode: 0644]
ui/main.crow

diff --git a/Crow.dll.config b/Crow.dll.config
new file mode 100644 (file)
index 0000000..ef7562a
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <dllmap os="!windows,osx" dll="libgio-2.0-0.dll" target="libgio-2.0.so.0"/>
+  <dllmap os="!windows,osx" dll="libglib-2.0-0.dll" target="libglib-2.0.so.0"/>
+  <dllmap os="!windows,osx" dll="libgobject-2.0-0.dll" target="libgobject-2.0.so.0"/>
+  <dllmap os="!windows,osx" dll="libgdk-3-0.dll" target="libgdk-3.so.0"/>
+  <dllmap os="!windows,osx" dll="libgdk_pixbuf-2.0-0.dll" target="libgdk_pixbuf-2.0.so.0"/>
+  <dllmap os="!windows,osx" dll="rsvg-2" target="librsvg-2.so.2"/>
+
+  
+  <dllmap os="windows" dll="rsvg-2" target="librsvg-2-2.dll"/>
+  
+  <dllmap os="osx" dll="libgio-2.0-0.dll" target="libgio-2.0.0.dylib"/>
+  <dllmap os="osx" dll="libgio-2.0-0.dll" target="libgio-2.0.0.dylib"/>
+  <dllmap os="osx" dll="libglib-2.0-0.dll" target="libglib-2.0.0.dylib"/>
+  <dllmap os="osx" dll="libgobject-2.0-0.dll" target="libgobject-2.0.0.dylib"/>
+  <dllmap os="osx" dll="libgdk-3.0.dll" target="libgdk-quartz-3.0.0.dylib"/>
+  <dllmap os="osx" dll="libgdk_pixbuf-2.0-0.dll" target="libgdk_pixbuf-2.0.0.dylib"/>
+</configuration>
index b34a2c4969d210d4a1fab81a32f3b47c640f741e..e3340b436230f69fd0b6b5d80a027852bcb0879d 100644 (file)
     <Reference Include="System" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Xml" />
-    <Reference Include="cairo-sharp">
-      <Package>gtk-sharp-3.0</Package>
-    </Reference>
     <Reference Include="Crow">
-      <HintPath>packages\Crow.OpenTK.0.5.1\lib\net45\Crow.dll</HintPath>
+      <HintPath>packages\Crow.OpenTK.0.5.4\lib\net45\Crow.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="src\CrowEdit.cs" />
+    <Compile Include="src\CrowEditExtentions.cs" />
+    <Compile Include="src\SourceLine.cs" />
+    <Compile Include="src\Token.cs" />
+    <Compile Include="src\CodeTextBuffer.cs" />
+    <Compile Include="CrowWindow.cs" />
+    <Compile Include="InterfaceControler.cs" />
     <Compile Include="OpenGL\Extensions.cs" />
     <Compile Include="OpenGL\Shader.cs" />
     <Compile Include="OpenGL\Texture.cs" />
     <Compile Include="OpenGL\vaoMesh.cs" />
-    <Compile Include="src\CrowEdit.cs" />
-    <Compile Include="src\CrowEditExtentions.cs" />
-    <Compile Include="src\CrowWindow.cs" />
-    <Compile Include="src\InterfaceControler.cs" />
-    <Compile Include="src\ScrollingObject.cs" />
-    <Compile Include="src\TextBuffer.cs" />
-    <Compile Include="src\ScrollingTextBox.cs" />
+    <Compile Include="src\SourceEditor.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="ui\" />
     <EmbeddedResource Include="ui\icons\outbox.svg" />
     <EmbeddedResource Include="ui\saveFile.crow" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/CrowWindow.cs b/CrowWindow.cs
new file mode 100644 (file)
index 0000000..e66fa7b
--- /dev/null
@@ -0,0 +1,371 @@
+//
+// CrowWindow.cs
+//
+// Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Threading;
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using System.Collections.Generic;
+
+namespace Crow
+{
+       public class CrowWindow : GameWindow, IValueChange
+    {
+               #region IValueChange implementation
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
+               public virtual void NotifyValueChanged(string MemberName, object _value)
+               {
+                       if (ValueChanged != null)
+                               ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value));
+               }
+               #endregion
+
+               #region FPS
+               int frameCpt = 0;
+               int _fps = 0;
+
+               public int fps {
+                       get { return _fps; }
+                       set {
+                               if (_fps == value)
+                                       return;
+
+                               _fps = value;
+                               #if MEASURE_TIME
+                               if (_fps > fpsMax) {
+                                       fpsMax = _fps;
+                                       ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax));
+                               } else if (_fps < fpsMin) {
+                                       fpsMin = _fps;
+                                       ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin));
+                               }
+                               #endif
+                               if (frameCpt % 20 == 0) {
+                                       ValueChanged.Raise (this, new ValueChangeEventArgs ("fps", _fps));
+                                       #if MEASURE_TIME
+                                       foreach (PerformanceMeasure m in ifaceControl[0].PerfMeasures)
+                                               m.NotifyChanges ();
+                                       #endif
+                               }
+                       }
+               }
+
+               #if MEASURE_TIME
+               public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10);
+
+               public int fpsMin = int.MaxValue;
+               public int fpsMax = 0;
+
+               void resetFps ()
+               {
+                       fpsMin = int.MaxValue;
+                       fpsMax = 0;
+                       _fps = 0;
+               }
+               #endif
+
+               #endregion
+
+               #region ctor
+               public CrowWindow(int _width = 800, int _height = 600, string _title="Crow",
+                       int colors = 32, int depth = 24, int stencil = 0, int samples = 1,
+                       int major=3, int minor=3)
+                       : this(_width, _height, new OpenTK.Graphics.GraphicsMode(colors, depth, stencil, samples),
+                               _title,GameWindowFlags.Default,DisplayDevice.Default,
+                               major,minor,OpenTK.Graphics.GraphicsContextFlags.Default)
+               {
+               }
+               public CrowWindow (int width, int height, OpenTK.Graphics.GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags)
+                       : base(width,height,mode,title,options,device,major,minor,flags)
+               {
+               }
+
+               #endregion
+
+               protected Shader shader;
+               public List<InterfaceControler> ifaceControl = new List<InterfaceControler>();
+               int focusedIdx = -1, activeIdx = -2;
+
+               void addInterfaceControler(InterfaceControler ifaceControler)
+               {
+                       ifaceControler.CrowInterface.Quit += Quit;
+                       ifaceControler.CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged;
+
+                       ifaceControl.Add (ifaceControler);
+               }
+               void openGLDraw(){
+                       //save GL states
+                       bool blend, depthTest, cullFace;
+                       GL.GetBoolean (GetPName.Blend, out blend);
+                       GL.GetBoolean (GetPName.DepthTest, out depthTest);
+                       GL.GetBoolean (GetPName.CullFace, out cullFace);
+                       GL.Enable (EnableCap.Blend);
+                       GL.Disable (EnableCap.DepthTest);
+                       GL.Disable (EnableCap.CullFace);
+
+                       #if MEASURE_TIME
+                       glDrawMeasure.StartCycle();
+                       #endif
+
+                       shader.Enable ();
+                       for (int i = 0; i < ifaceControl.Count; i++) {
+                               shader.SetMVP (ifaceControl [i].InterfaceMVP);
+                               ifaceControl [i].OpenGLDraw ();
+                       }
+
+                       #if MEASURE_TIME
+                       glDrawMeasure.StopCycle();
+                       #endif
+
+                       //restore GL states
+                       if (!blend)
+                               GL.Disable (EnableCap.Blend);
+                       if (depthTest)
+                               GL.Enable (EnableCap.DepthTest);
+                       if (cullFace)
+                               GL.Enable (EnableCap.CullFace);
+               }
+
+               public void Quit (object sender, EventArgs e)
+               {
+                       foreach (InterfaceControler ic in ifaceControl) {
+                               ic.Dispose ();
+                       }
+                       this.Exit ();
+               }
+               void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e)
+               {
+                       this.Cursor = new MouseCursor(
+                               (int)e.NewCursor.Xhot,
+                               (int)e.NewCursor.Yhot,
+                               (int)e.NewCursor.Width,
+                               (int)e.NewCursor.Height,
+                               e.NewCursor.data);
+               }
+
+               #region Events
+               //those events are raised only if mouse isn't in a graphic object
+               public event EventHandler<OpenTK.Input.MouseWheelEventArgs> MouseWheelChanged;
+               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonUp;
+               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonDown;
+               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseClick;
+               public event EventHandler<OpenTK.Input.MouseMoveEventArgs> MouseMove;
+               public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyDown;
+               public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyUp;
+
+               #endregion
+
+               public ProjectiveIFaceControler Add3DInterface(int width, int height, Matrix4 ifaceModelMat){
+                       ProjectiveIFaceControler tmp = new ProjectiveIFaceControler (new Rectangle (0, 0, width, height), ifaceModelMat);
+                       addInterfaceControler (tmp);
+                       return tmp;
+               }
+               public GraphicObject AddWidget (GraphicObject g, int interfaceIdx = 0){
+                       if (ifaceControl.Count == 0)//create default orthogonal interface
+                               addInterfaceControler (new InterfaceControler (
+                                       new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height)));
+                       ifaceControl [interfaceIdx].CrowInterface.AddWidget (g);
+                       return g;
+               }
+               public void DeleteWidget (GraphicObject g, int interfaceIdx = 0){
+                       ifaceControl [interfaceIdx].CrowInterface.DeleteWidget (g);
+               }
+               public GraphicObject Load (string path, int interfaceIdx = 0){
+                       if (ifaceControl.Count == 0)//create default orthogonal interface
+                               addInterfaceControler (new InterfaceControler (
+                                                       new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height)));
+                       return ifaceControl [interfaceIdx].CrowInterface.LoadInterface (path);
+               }
+               public GraphicObject FindByName (string nameToFind){
+                       for (int i = 0; i < ifaceControl.Count; i++) {
+                               GraphicObject tmp = ifaceControl [i].CrowInterface.FindByName (nameToFind);
+                               if (tmp != null)
+                                       return tmp;
+                       }
+                       return null;
+               }
+               public void ClearInterface (int interfaceIdx = 0){
+                       ifaceControl [interfaceIdx].CrowInterface.ClearInterface ();
+               }
+               /// <summary>Override this method for your OpenGL rendering calls</summary>
+               public virtual void OnRender(FrameEventArgs e)
+               {
+               }
+               /// <summary>Override this method to customize clear method between frames</summary>
+               public virtual void GLClear()
+               {
+                       GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
+               }
+
+               #region Game win overrides
+               protected override void OnLoad(EventArgs e)
+               {
+                       base.OnLoad(e);
+
+                       this.KeyPress += new EventHandler<OpenTK.KeyPressEventArgs>(OpenTKGameWindow_KeyPress);
+                       Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown);
+                       Keyboard.KeyUp += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyUp);
+                       Mouse.WheelChanged += new EventHandler<OpenTK.Input.MouseWheelEventArgs>(GL_Mouse_WheelChanged);
+                       Mouse.ButtonDown += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(GL_Mouse_ButtonDown);
+                       Mouse.ButtonUp += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(GL_Mouse_ButtonUp);
+                       Mouse.Move += new EventHandler<OpenTK.Input.MouseMoveEventArgs>(GL_Mouse_Move);
+
+                       #if DEBUG
+                       Console.WriteLine("\n\n*************************************");
+                       Console.WriteLine("GL version: " + GL.GetString (StringName.Version));
+                       Console.WriteLine("GL vendor: " + GL.GetString (StringName.Vendor));
+                       Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion));
+                       Console.WriteLine("*************************************\n");
+                       #endif
+
+                       shader = new Shader ();
+                       shader.Enable ();
+
+                       GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+               }
+               protected override void OnUpdateFrame(FrameEventArgs e)
+               {
+                       base.OnUpdateFrame(e);
+                       fps = (int)RenderFrequency;
+
+                       #if MEASURE_TIME
+                       if (frameCpt > 500) {
+                               resetFps ();
+                               frameCpt = 0;
+//                             #if DEBUG
+//                             GC.Collect();
+//                             GC.WaitForPendingFinalizers();
+//                             NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString());
+//                             #endif
+                       }
+                       #endif
+
+                       frameCpt++;
+               }
+               protected override void OnRenderFrame(FrameEventArgs e)
+               {
+                       GLClear ();
+
+                       base.OnRenderFrame(e);
+
+                       OnRender (e);
+                       openGLDraw ();
+
+
+                       SwapBuffers ();
+               }
+               protected override void OnResize(EventArgs e)
+               {
+                       base.OnResize (e);
+                       for (int i = 0; i < ifaceControl.Count; i++) {
+                               ifaceControl[i].ProcessResize(
+                                       new Rectangle(
+                                               0,
+                                               0,
+                                               this.ClientRectangle.Width,
+                                               this.ClientRectangle.Height));
+                       }
+               }
+               #endregion
+
+               #region Mouse and Keyboard Handling
+               void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){
+                       for (int i = 0; i < MouseState.MaxButtons; i++) {
+                               if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i))
+                                       e.EnableBit (i);
+                       }
+               }
+               protected virtual void GL_Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e)
+        {
+                       if (activeIdx == -2) {
+                               focusedIdx = -1;
+                               for (int i = 0; i < ifaceControl.Count; i++) {
+                                       if (ifaceControl [i].ProcessMouseMove (otk_e.X, otk_e.Y)) {
+                                               focusedIdx = i;
+                                               return;
+                                       }
+                               }
+                       } else if (focusedIdx >= 0) {
+                               ifaceControl [focusedIdx].ProcessMouseMove (otk_e.X, otk_e.Y);
+                               return;
+                       }
+                       if (focusedIdx < 0)
+                               MouseMove.Raise (sender, otk_e);
+        }
+               protected virtual void GL_Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e)
+        {
+                       activeIdx = -2;
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessMouseButtonUp ((int)otk_e.Button))
+                                       return;
+                       }
+                       MouseButtonUp.Raise (sender, otk_e);
+        }
+               protected virtual void GL_Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e)
+               {
+                       activeIdx = focusedIdx;
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessMouseButtonDown ((int)otk_e.Button))
+                                       return;
+                       }
+                       MouseButtonDown.Raise (sender, otk_e);
+        }
+               protected virtual void GL_Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e)
+        {
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessMouseWheelChanged (otk_e.DeltaPrecise))
+                                       return;
+                       }
+                       MouseWheelChanged.Raise (sender, otk_e);
+        }
+
+               protected virtual void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e)
+               {
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessKeyDown((int)otk_e.Key))
+                                       return;
+                       }
+                       KeyboardKeyDown.Raise (this, otk_e);
+        }
+               protected virtual void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e)
+               {
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessKeyUp((int)otk_e.Key))
+                                       return;
+                       }
+                       KeyboardKeyUp.Raise (this, otk_e);
+               }
+               protected virtual void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e)
+               {
+                       if (focusedIdx >= 0) {
+                               if (ifaceControl [focusedIdx].ProcessKeyPress (e.KeyChar))
+                                       return;
+                       }
+                       //TODO:create keyboardkeypress evt
+               }
+        #endregion
+    }
+}
diff --git a/InterfaceControler.cs b/InterfaceControler.cs
new file mode 100644 (file)
index 0000000..4da65d1
--- /dev/null
@@ -0,0 +1,267 @@
+//
+// InterfaceControler.cs
+//
+// Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace Crow
+{
+       public class ProjectiveIFaceControler : InterfaceControler {
+               Matrix4 modelview;
+               int[] viewport = new int[4];
+               Vector3 vEyePosition;
+
+               public Matrix4 ifaceModelMat;
+               Point localMousePos;
+
+               public ProjectiveIFaceControler(Rectangle ifaceBounds, Matrix4 _ifaceModelMat)
+                       : base(ifaceBounds){
+                       ifaceModelMat = _ifaceModelMat;
+               }
+
+               public override Matrix4 InterfaceMVP {
+                       get { return ifaceModelMat * modelview * projection; }
+               }
+
+               public override void initGL(){
+                       quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1);
+                       //ifaceModelMat = Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(Vector3.UnitY);
+                       CrowInterface.ProcessResize(iRect);
+                       createContext ();
+                       //CrowInterface.ProcessResize (iRect);
+               }
+               public override void ProcessResize (Rectangle newSize)
+               {
+               }
+               public override void OpenGLDraw ()
+               {
+                       GL.Enable (EnableCap.DepthTest);
+                       base.OpenGLDraw ();
+                       GL.Disable (EnableCap.DepthTest);
+               }
+               public void UpdateView (Matrix4 _projection, Matrix4 _modelview, int[] _viewport, Vector3 _vEyePosition)
+               {
+                       projection = _projection;
+                       modelview = _modelview;
+                       viewport = _viewport;
+                       vEyePosition = _vEyePosition;
+               }
+               public override bool ProcessMouseMove (int x, int y)
+               {
+                       Matrix4 mv = ifaceModelMat * modelview;
+                       Vector3 vMouse = UnProject(ref projection, ref mv, viewport, new Vector2 (x, y)).Xyz;
+                       Vector3 vE = vEyePosition.Transform (ifaceModelMat.Inverted());
+                       Vector3 vMouseRay = Vector3.Normalize(vMouse - vE);
+                       float a = vE.Z / vMouseRay.Z;
+                       vMouse = vE - vMouseRay * a;
+                       //vMouse = vMouse.Transform (interfaceModelView.Inverted());
+                       localMousePos = new Point ((int)Math.Truncate ((vMouse.X + 0.5f) * iRect.Width),
+                               iRect.Height - (int)Math.Truncate ((vMouse.Y + 0.5f) * iRect.Height));
+                       mouseIsInInterface = localMousePos.X.IsInBetween (0, iRect.Width) & localMousePos.Y.IsInBetween (0, iRect.Height);
+
+                       return mouseIsInInterface ? CrowInterface.ProcessMouseMove (localMousePos.X, localMousePos.Y) : false;
+               }
+               Vector4 UnProject(ref Matrix4 projection, ref Matrix4 view, int[] viewport, Vector2 mouse)
+               {
+                       Vector4 vec;
+
+                       vec.X = 2.0f * mouse.X / (float)viewport[2] - 1;
+                       vec.Y = -(2.0f * mouse.Y / (float)viewport[3] - 1);
+                       vec.Z = 0f;
+                       vec.W = 1.0f;
+
+                       Matrix4 viewInv = Matrix4.Invert(view);
+                       Matrix4 projInv = Matrix4.Invert(projection);
+
+                       Vector4.Transform(ref vec, ref projInv, out vec);
+                       Vector4.Transform(ref vec, ref viewInv, out vec);
+
+                       if (vec.W > float.Epsilon || vec.W < float.Epsilon)
+                       {
+                               vec.X /= vec.W;
+                               vec.Y /= vec.W;
+                               vec.Z /= vec.W;
+                       }
+
+                       return vec;
+               }
+       }
+       public class InterfaceControler : IDisposable {
+               public Interface CrowInterface;
+               public int texID;
+               public vaoMesh quad;
+               public Rectangle iRect = new Rectangle(0,0,2048,2048);
+               public bool mouseIsInInterface = false;
+
+               protected Matrix4 projection;
+               public virtual Matrix4 InterfaceMVP {
+                       get { return projection; }
+               }
+
+               #if MEASURE_TIME
+               public List<PerformanceMeasure> PerfMeasures;
+               public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10);
+               #endif
+
+               #region CTOR
+               public InterfaceControler(Rectangle ifaceBounds){
+                       iRect = ifaceBounds;
+
+                       CrowInterface = new Interface ();
+
+                       #if MEASURE_TIME
+                       PerfMeasures = new List<PerformanceMeasure> (
+                               new PerformanceMeasure[] {
+                                       this.CrowInterface.updateMeasure,
+                                       this.CrowInterface.layoutingMeasure,
+                                       this.CrowInterface.clippingMeasure,
+                                       this.CrowInterface.drawingMeasure,
+                                       this.glDrawMeasure
+                               }
+                       );
+                       #endif
+
+                       Thread t = new Thread (interfaceThread);
+                       t.IsBackground = true;
+                       t.Start ();
+
+                       initGL ();
+               }
+               #endregion
+
+               void interfaceThread()
+               {
+                       while (CrowInterface.ClientRectangle.Size.Width == 0)
+                               Thread.Sleep (5);
+
+                       while (true) {
+                               CrowInterface.Update ();
+                               Thread.Sleep (1);
+                       }
+               }
+
+               #region Mouse And Keyboard handling
+               public virtual void ProcessResize(Rectangle newSize){
+                       iRect = newSize;
+                       CrowInterface.ProcessResize(newSize);
+                       createContext ();
+                       GL.Viewport (0, 0, newSize.Width, newSize.Height);//TODO:find a better place for this
+               }
+               public virtual bool ProcessMouseMove(int x, int y){
+                       return CrowInterface.ProcessMouseMove (x, y);
+               }
+               public virtual bool ProcessMouseButtonUp(int button)
+               {
+                       return CrowInterface.ProcessMouseButtonUp (button);
+               }
+               public virtual bool ProcessMouseButtonDown(int button)
+               {
+                       return CrowInterface.ProcessMouseButtonDown (button);
+               }
+               public virtual bool ProcessMouseWheelChanged(float delta)
+               {
+                       return CrowInterface.ProcessMouseWheelChanged (delta);
+               }
+               public virtual bool ProcessKeyDown(int Key){
+                       return CrowInterface.ProcessKeyDown(Key);
+               }
+               public virtual bool ProcessKeyUp(int Key){
+                       return CrowInterface.ProcessKeyUp(Key);
+               }
+               public virtual bool ProcessKeyPress(char Key){
+                       return CrowInterface.ProcessKeyPress(Key);
+               }
+               #endregion
+
+               #region graphic context
+               public virtual void initGL(){
+                       projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1);
+                       quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1);
+                       createContext ();
+               }
+               /// <summary>Create the texture for the interface redering</summary>
+               public virtual void createContext()
+               {
+                       if (GL.IsTexture(texID))
+                               GL.DeleteTexture (texID);
+                       GL.GenTextures(1, out texID);
+                       GL.ActiveTexture (TextureUnit.Texture0);
+                       GL.BindTexture(TextureTarget.Texture2D, texID);
+
+                       GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
+                               iRect.Width, iRect.Height, 0,
+                               OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.bmp);
+
+                       GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
+                       GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
+
+                       GL.BindTexture(TextureTarget.Texture2D, 0);
+               }
+               /// <summary>Rendering of the interface</summary>
+               public virtual void OpenGLDraw()
+               {
+                       #if MEASURE_TIME
+                       glDrawMeasure.StartCycle();
+                       #endif
+
+                       GL.ActiveTexture (TextureUnit.Texture0);
+                       GL.BindTexture (TextureTarget.Texture2D, texID);
+                       if (Monitor.TryEnter(CrowInterface.RenderMutex)) {
+                               if (CrowInterface.IsDirty) {
+                                       GL.TexSubImage2D (TextureTarget.Texture2D, 0,
+                                               CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top,
+                                               CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height,
+                                               OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.dirtyBmp);
+                                       CrowInterface.IsDirty = false;
+                               }
+                               Monitor.Exit (CrowInterface.RenderMutex);
+                       }
+                       quad.Render (BeginMode.TriangleStrip);
+                       GL.BindTexture(TextureTarget.Texture2D, 0);
+
+                       #if MEASURE_TIME
+                       glDrawMeasure.StopCycle();
+                       #endif
+               }
+               #endregion
+
+               #region IDisposable implementation
+
+               public void Dispose ()
+               {
+                       if (GL.IsTexture(texID))
+                               GL.DeleteTexture (texID);
+                       if (quad != null)
+                               quad.Dispose ();
+               }
+
+               #endregion
+       }
+}
+
index 9875ed7e0d1d061b74b895a84c42f494bf68fec7..5740be925bb46a347fc184a86478981d95368858 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="Crow.OpenTK" version="0.5.1" targetFramework="net45" />
+  <package id="Crow.OpenTK" version="0.5.4" targetFramework="net45" />
   <package id="OpenTK" version="2.0.0" targetFramework="net45" />
 </packages>
diff --git a/src/CodeTextBuffer.cs b/src/CodeTextBuffer.cs
new file mode 100644 (file)
index 0000000..988b9c3
--- /dev/null
@@ -0,0 +1,88 @@
+//
+//  CodeTextBuffer.cs
+//
+//  Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+//  Copyright (c) 2017 jp
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace Crow
+{
+       public class CodeTextBuffer : List<SourceLine>
+       {
+               public CodeTextBuffer () : base()
+               {
+               }
+
+               public int longestLineIdx = 0;
+               public int longestLineCharCount = 0;
+
+               public CodeTextBuffer (string rawSource) : this (){
+                       if (string.IsNullOrEmpty (rawSource))
+                               return;
+                       string[] lines = Regex.Split (rawSource, "\r\n|\r|\n|\\\\n");
+                       for (int i = 0; i < lines.Length; i++) {
+                               if (lines [i].Length > longestLineCharCount) {
+                                       longestLineCharCount = lines [i].Length;
+                                       longestLineIdx = i;
+                               }
+                               this.Add (new SourceLine ( lines [i] ));
+                       }
+               }
+
+               /// <summary>
+               /// return all lines with linebreaks
+               /// </summary>
+               public string FullText{
+                       get {
+                               string tmp = "";
+                               foreach (SourceLine sl in this)
+                                       tmp += sl.RawText + Interface.LineBreak;
+                               return tmp;
+                       }
+               }                       
+
+               public void Tokenize (int lineIndex) {
+                       //handle multiline block comments
+                       if (lineIndex > 0){
+                               if (this [lineIndex - 1].Tokens?.LastOrDefault ().Type == TokenType.BlockComment)
+                                       this [lineIndex].PresetCurrentToken (TokenType.BlockComment);
+                       }
+                       this [lineIndex].Tokenize ();
+               }
+
+               public void InsertLine(int index, SourceLine line){
+                       base.Insert (index, line);
+               }
+               public void RemoveLine (int index) {
+                       base.RemoveAt (index);
+               }
+
+               //public void Tokenize (int lineIndex) {
+               //      //handle multiline block comments
+               //      if (lineIndex > 0){
+               //              if (this [lineIndex - 1].Tokens?.LastOrDefault ().Type == TokenType.BlockComment)
+               //                      this [lineIndex].PresetCurrentToken (TokenType.BlockComment);
+               //      }
+               //      this [lineIndex].Tokenize ();
+               //}
+       }
+}
+
index 1e0323f61a9ab94c684e0cca2987c69424b4e49b..ea9ef6be87ff5d881cab98eb233b10e0ec64630d 100644 (file)
@@ -54,11 +54,11 @@ namespace CrowEdit
                public bool IsDirty { get { return _text != _origText; }}
 
                public string CurrentDir {
-                       get { return _curDir; }
+                       get { return Configuration.Get<string>("CurrentDir"); }
                        set {
-                               if (_curDir == value)
+                               if (CurrentDir == value)
                                        return;
-                               _curDir = value;
+                               Configuration.Set ("CurrentDir", value);
                                NotifyValueChanged ("CurrentDir", _curDir);
                        }
                }
@@ -190,6 +190,9 @@ namespace CrowEdit
                {
                        base.OnLoad (e);
 
+                       if (CurrentDir == null)
+                               CurrentDir = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
+
                        this.ValueChanged += CrowEdit_ValueChanged;
                        initCommands ();
 
diff --git a/src/CrowWindow.cs b/src/CrowWindow.cs
deleted file mode 100644 (file)
index b1308d1..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-//
-// CrowWindow.cs
-//
-// Author:
-//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Threading;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
-using System.Collections.Generic;
-
-namespace Crow
-{
-       public class CrowWindow : GameWindow, IValueChange
-    {
-               #region IValueChange implementation
-               public event EventHandler<ValueChangeEventArgs> ValueChanged;
-               public virtual void NotifyValueChanged(string MemberName, object _value)
-               {
-                       if (ValueChanged != null)
-                               ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value));
-               }
-               #endregion
-
-               #region FPS
-               int frameCpt = 0;
-               int _fps = 0;
-
-               public int fps {
-                       get { return _fps; }
-                       set {
-                               if (_fps == value)
-                                       return;
-
-                               _fps = value;
-                               #if MEASURE_TIME
-                               if (_fps > fpsMax) {
-                                       fpsMax = _fps;
-                                       ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax));
-                               } else if (_fps < fpsMin) {
-                                       fpsMin = _fps;
-                                       ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin));
-                               }
-                               #endif
-                               if (frameCpt % 3 == 0)
-                                       ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps));
-                               #if MEASURE_TIME
-//                             foreach (PerformanceMeasure m in PerfMeasures)
-//                                     m.NotifyChanges();
-                               #endif
-                       }
-               }
-
-               #if MEASURE_TIME
-               public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10);
-
-               public int fpsMin = int.MaxValue;
-               public int fpsMax = 0;
-
-               void resetFps ()
-               {
-                       fpsMin = int.MaxValue;
-                       fpsMax = 0;
-                       _fps = 0;
-               }
-               #endif
-
-               #endregion
-
-               #region ctor
-               public CrowWindow(int _width = 800, int _height = 600, string _title="Crow",
-                       int colors = 32, int depth = 24, int stencil = 0, int samples = 1,
-                       int major=3, int minor=3)
-                       : this(_width, _height, new OpenTK.Graphics.GraphicsMode(colors, depth, stencil, samples),
-                               _title,GameWindowFlags.Default,DisplayDevice.Default,
-                               major,minor,OpenTK.Graphics.GraphicsContextFlags.Default)
-               {
-               }
-               public CrowWindow (int width, int height, OpenTK.Graphics.GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags)
-                       : base(width,height,mode,title,options,device,major,minor,flags)
-               {
-               }
-
-               #endregion
-
-               protected Shader shader;
-               public List<InterfaceControler> ifaceControl = new List<InterfaceControler>();
-               int focusedIdx = -1, activeIdx = -2;
-
-               void addInterfaceControler(InterfaceControler ifaceControler)
-               {
-                       ifaceControler.CrowInterface.Quit += Quit;
-                       ifaceControler.CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged;
-
-                       ifaceControl.Add (ifaceControler);
-               }
-               void openGLDraw(){
-                       //save GL states
-                       bool blend, depthTest, cullFace;
-                       GL.GetBoolean (GetPName.Blend, out blend);
-                       GL.GetBoolean (GetPName.DepthTest, out depthTest);
-                       GL.GetBoolean (GetPName.CullFace, out cullFace);
-                       GL.Enable (EnableCap.Blend);
-                       GL.Disable (EnableCap.DepthTest);
-                       GL.Disable (EnableCap.CullFace);
-
-                       #if MEASURE_TIME
-                       glDrawMeasure.StartCycle();
-                       #endif
-
-                       shader.Enable ();
-                       for (int i = 0; i < ifaceControl.Count; i++) {
-                               shader.SetMVP (ifaceControl [i].InterfaceMVP);
-                               ifaceControl [i].OpenGLDraw ();
-                       }
-
-                       #if MEASURE_TIME
-                       glDrawMeasure.StopCycle();
-                       #endif
-
-                       //restore GL states
-                       if (!blend)
-                               GL.Disable (EnableCap.Blend);
-                       if (depthTest)
-                               GL.Enable (EnableCap.DepthTest);
-                       if (cullFace)
-                               GL.Enable (EnableCap.CullFace);
-               }
-
-               public void Quit (object sender, EventArgs e)
-               {
-                       foreach (InterfaceControler ic in ifaceControl) {
-                               ic.Dispose ();
-                       }
-                       this.Exit ();
-               }
-               void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e)
-               {
-                       this.Cursor = new MouseCursor(
-                               (int)e.NewCursor.Xhot,
-                               (int)e.NewCursor.Yhot,
-                               (int)e.NewCursor.Width,
-                               (int)e.NewCursor.Height,
-                               e.NewCursor.data);
-               }
-
-               #region Events
-               //those events are raised only if mouse isn't in a graphic object
-               public event EventHandler<OpenTK.Input.MouseWheelEventArgs> MouseWheelChanged;
-               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonUp;
-               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonDown;
-               public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseClick;
-               public event EventHandler<OpenTK.Input.MouseMoveEventArgs> MouseMove;
-               public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyDown;
-               public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyUp;
-
-               #endregion
-
-               public ProjectiveIFaceControler Add3DInterface(int width, int height, Matrix4 ifaceModelMat){
-                       ProjectiveIFaceControler tmp = new ProjectiveIFaceControler (new Rectangle (0, 0, width, height), ifaceModelMat);
-                       addInterfaceControler (tmp);
-                       return tmp;
-               }
-               public GraphicObject AddWidget (GraphicObject g, int interfaceIdx = 0){
-                       if (ifaceControl.Count == 0)//create default orthogonal interface
-                               addInterfaceControler (new InterfaceControler (
-                                       new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height)));
-                       ifaceControl [interfaceIdx].CrowInterface.AddWidget (g);
-                       return g;
-               }
-               public void DeleteWidget (GraphicObject g, int interfaceIdx = 0){
-                       ifaceControl [interfaceIdx].CrowInterface.DeleteWidget (g);
-               }
-               public GraphicObject Load (string path, int interfaceIdx = 0){
-                       if (ifaceControl.Count == 0)//create default orthogonal interface
-                               addInterfaceControler (new InterfaceControler (
-                                                       new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height)));
-                       return ifaceControl [interfaceIdx].CrowInterface.LoadInterface (path);
-               }
-               public GraphicObject FindByName (string nameToFind){
-                       for (int i = 0; i < ifaceControl.Count; i++) {
-                               GraphicObject tmp = ifaceControl [i].CrowInterface.FindByName (nameToFind);
-                               if (tmp != null)
-                                       return tmp;
-                       }
-                       return null;
-               }
-               public void ClearInterface (int interfaceIdx = 0){
-                       ifaceControl [interfaceIdx].CrowInterface.ClearInterface ();
-               }
-               /// <summary>Override this method for your OpenGL rendering calls</summary>
-               public virtual void OnRender(FrameEventArgs e)
-               {
-               }
-               /// <summary>Override this method to customize clear method between frames</summary>
-               public virtual void GLClear()
-               {
-                       GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
-               }
-
-               #region Game win overrides
-               protected override void OnLoad(EventArgs e)
-               {
-                       base.OnLoad(e);
-
-                       this.KeyPress += new EventHandler<OpenTK.KeyPressEventArgs>(OpenTKGameWindow_KeyPress);
-                       Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown);
-                       Keyboard.KeyUp += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyUp);
-                       Mouse.WheelChanged += new EventHandler<OpenTK.Input.MouseWheelEventArgs>(GL_Mouse_WheelChanged);
-                       Mouse.ButtonDown += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(GL_Mouse_ButtonDown);
-                       Mouse.ButtonUp += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(GL_Mouse_ButtonUp);
-                       Mouse.Move += new EventHandler<OpenTK.Input.MouseMoveEventArgs>(GL_Mouse_Move);
-
-                       #if DEBUG
-                       Console.WriteLine("\n\n*************************************");
-                       Console.WriteLine("GL version: " + GL.GetString (StringName.Version));
-                       Console.WriteLine("GL vendor: " + GL.GetString (StringName.Vendor));
-                       Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion));
-                       Console.WriteLine("*************************************\n");
-                       #endif
-
-                       shader = new Shader ();
-                       shader.Enable ();
-
-                       GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-               }
-               protected override void OnUpdateFrame(FrameEventArgs e)
-               {
-                       base.OnUpdateFrame(e);
-                       fps = (int)RenderFrequency;
-
-                       #if MEASURE_TIME
-                       if (frameCpt > 500) {
-                               resetFps ();
-                               frameCpt = 0;
-//                             #if DEBUG
-//                             GC.Collect();
-//                             GC.WaitForPendingFinalizers();
-//                             NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString());
-//                             #endif
-                       }
-                       #endif
-
-                       frameCpt++;
-               }
-               protected override void OnRenderFrame(FrameEventArgs e)
-               {
-                       GLClear ();
-
-                       base.OnRenderFrame(e);
-
-                       OnRender (e);
-                       openGLDraw ();
-
-
-                       SwapBuffers ();
-               }
-               protected override void OnResize(EventArgs e)
-               {
-                       base.OnResize (e);
-                       for (int i = 0; i < ifaceControl.Count; i++) {
-                               ifaceControl[i].ProcessResize(
-                                       new Rectangle(
-                                               0,
-                                               0,
-                                               this.ClientRectangle.Width,
-                                               this.ClientRectangle.Height));
-                       }
-               }
-               #endregion
-
-               #region Mouse and Keyboard Handling
-               void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){
-                       for (int i = 0; i < MouseState.MaxButtons; i++) {
-                               if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i))
-                                       e.EnableBit (i);
-                       }
-               }
-               protected virtual void GL_Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e)
-        {
-                       if (activeIdx == -2) {
-                               focusedIdx = -1;
-                               for (int i = 0; i < ifaceControl.Count; i++) {
-                                       if (ifaceControl [i].ProcessMouseMove (otk_e.X, otk_e.Y)) {
-                                               focusedIdx = i;
-                                               return;
-                                       }
-                               }
-                       } else if (focusedIdx >= 0) {
-                               ifaceControl [focusedIdx].ProcessMouseMove (otk_e.X, otk_e.Y);
-                               return;
-                       }
-                       if (focusedIdx < 0)
-                               MouseMove.Raise (sender, otk_e);
-        }
-               protected virtual void GL_Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e)
-        {
-                       activeIdx = -2;
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessMouseButtonUp ((int)otk_e.Button))
-                                       return;
-                       }
-                       MouseButtonUp.Raise (sender, otk_e);
-        }
-               protected virtual void GL_Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e)
-               {
-                       activeIdx = focusedIdx;
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessMouseButtonDown ((int)otk_e.Button))
-                                       return;
-                       }
-                       MouseButtonDown.Raise (sender, otk_e);
-        }
-               protected virtual void GL_Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e)
-        {
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessMouseWheelChanged (otk_e.DeltaPrecise))
-                                       return;
-                       }
-                       MouseWheelChanged.Raise (sender, otk_e);
-        }
-
-               protected virtual void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e)
-               {
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessKeyDown((int)otk_e.Key))
-                                       return;
-                       }
-                       KeyboardKeyDown.Raise (this, otk_e);
-        }
-               protected virtual void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e)
-               {
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessKeyUp((int)otk_e.Key))
-                                       return;
-                       }
-                       KeyboardKeyUp.Raise (this, otk_e);
-               }
-               protected virtual void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e)
-               {
-                       if (focusedIdx >= 0) {
-                               if (ifaceControl [focusedIdx].ProcessKeyPress (e.KeyChar))
-                                       return;
-                       }
-                       //TODO:create keyboardkeypress evt
-               }
-        #endregion
-    }
-}
diff --git a/src/InterfaceControler.cs b/src/InterfaceControler.cs
deleted file mode 100644 (file)
index 4d988c1..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-//
-// InterfaceControler.cs
-//
-// Author:
-//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
-using System.Threading;
-using System.Collections.Generic;
-
-namespace Crow
-{
-       public class ProjectiveIFaceControler : InterfaceControler {
-               Matrix4 modelview;
-               int[] viewport = new int[4];
-               Vector3 vEyePosition;
-
-               public Matrix4 ifaceModelMat;
-               Point localMousePos;
-
-               public ProjectiveIFaceControler(Rectangle ifaceBounds, Matrix4 _ifaceModelMat)
-                       : base(ifaceBounds){
-                       ifaceModelMat = _ifaceModelMat;
-               }
-
-               public override Matrix4 InterfaceMVP {
-                       get { return ifaceModelMat * modelview * projection; }
-               }
-
-               public override void initGL(){
-                       quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1);
-                       //ifaceModelMat = Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(Vector3.UnitY);
-                       CrowInterface.ProcessResize(iRect);
-                       createContext ();
-                       //CrowInterface.ProcessResize (iRect);
-               }
-               public override void ProcessResize (Rectangle newSize)
-               {
-               }
-               public override void OpenGLDraw ()
-               {
-                       GL.Enable (EnableCap.DepthTest);
-                       base.OpenGLDraw ();
-                       GL.Disable (EnableCap.DepthTest);
-               }
-               public void UpdateView (Matrix4 _projection, Matrix4 _modelview, int[] _viewport, Vector3 _vEyePosition)
-               {
-                       projection = _projection;
-                       modelview = _modelview;
-                       viewport = _viewport;
-                       vEyePosition = _vEyePosition;
-               }
-               public override bool ProcessMouseMove (int x, int y)
-               {
-                       Matrix4 mv = ifaceModelMat * modelview;
-                       Vector3 vMouse = UnProject(ref projection, ref mv, viewport, new Vector2 (x, y)).Xyz;
-                       Vector3 vE = vEyePosition.Transform (ifaceModelMat.Inverted());
-                       Vector3 vMouseRay = Vector3.Normalize(vMouse - vE);
-                       float a = vE.Z / vMouseRay.Z;
-                       vMouse = vE - vMouseRay * a;
-                       //vMouse = vMouse.Transform (interfaceModelView.Inverted());
-                       localMousePos = new Point ((int)Math.Truncate ((vMouse.X + 0.5f) * iRect.Width),
-                               iRect.Height - (int)Math.Truncate ((vMouse.Y + 0.5f) * iRect.Height));
-                       mouseIsInInterface = localMousePos.X.IsInBetween (0, iRect.Width) & localMousePos.Y.IsInBetween (0, iRect.Height);
-
-                       return mouseIsInInterface ? CrowInterface.ProcessMouseMove (localMousePos.X, localMousePos.Y) : false;
-               }
-               Vector4 UnProject(ref Matrix4 projection, ref Matrix4 view, int[] viewport, Vector2 mouse)
-               {
-                       Vector4 vec;
-
-                       vec.X = 2.0f * mouse.X / (float)viewport[2] - 1;
-                       vec.Y = -(2.0f * mouse.Y / (float)viewport[3] - 1);
-                       vec.Z = 0f;
-                       vec.W = 1.0f;
-
-                       Matrix4 viewInv = Matrix4.Invert(view);
-                       Matrix4 projInv = Matrix4.Invert(projection);
-
-                       Vector4.Transform(ref vec, ref projInv, out vec);
-                       Vector4.Transform(ref vec, ref viewInv, out vec);
-
-                       if (vec.W > float.Epsilon || vec.W < float.Epsilon)
-                       {
-                               vec.X /= vec.W;
-                               vec.Y /= vec.W;
-                               vec.Z /= vec.W;
-                       }
-
-                       return vec;
-               }
-       }
-       public class InterfaceControler : IDisposable {
-               public Interface CrowInterface;
-               public int texID;
-               public vaoMesh quad;
-               public Rectangle iRect = new Rectangle(0,0,2048,2048);
-               public bool mouseIsInInterface = false;
-
-               protected Matrix4 projection;
-               public virtual Matrix4 InterfaceMVP {
-                       get { return projection; }
-               }
-
-               #if MEASURE_TIME
-               public List<PerformanceMeasure> PerfMeasures;
-               public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10);
-               #endif
-
-               #region CTOR
-               public InterfaceControler(Rectangle ifaceBounds){
-                       iRect = ifaceBounds;
-
-                       CrowInterface = new Interface ();
-
-                       #if MEASURE_TIME
-                       PerfMeasures = new List<PerformanceMeasure> (
-                               new PerformanceMeasure[] {
-                                       this.CrowInterface.updateMeasure,
-                                       this.CrowInterface.layoutingMeasure,
-                                       this.CrowInterface.clippingMeasure,
-                                       this.CrowInterface.drawingMeasure,
-                                       this.glDrawMeasure
-                               }
-                       );
-                       #endif
-
-                       Thread t = new Thread (interfaceThread);
-                       t.IsBackground = true;
-                       t.Start ();
-
-                       initGL ();
-               }
-               #endregion
-
-               void interfaceThread()
-               {
-                       while (CrowInterface.ClientRectangle.Size.Width == 0)
-                               Thread.Sleep (5);
-
-                       while (true) {
-                               CrowInterface.Update ();
-                               //Thread.Sleep (1);
-                       }
-               }
-
-               #region Mouse And Keyboard handling
-               public virtual void ProcessResize(Rectangle newSize){
-                       iRect = newSize;
-                       CrowInterface.ProcessResize(newSize);
-                       createContext ();
-                       GL.Viewport (0, 0, newSize.Width, newSize.Height);//TODO:find a better place for this
-               }
-               public virtual bool ProcessMouseMove(int x, int y){
-                       return CrowInterface.ProcessMouseMove (x, y);
-               }
-               public virtual bool ProcessMouseButtonUp(int button)
-               {
-                       return CrowInterface.ProcessMouseButtonUp (button);
-               }
-               public virtual bool ProcessMouseButtonDown(int button)
-               {
-                       return CrowInterface.ProcessMouseButtonDown (button);
-               }
-               public virtual bool ProcessMouseWheelChanged(float delta)
-               {
-                       return CrowInterface.ProcessMouseWheelChanged (delta);
-               }
-               public virtual bool ProcessKeyDown(int Key){
-                       return CrowInterface.ProcessKeyDown(Key);
-               }
-               public virtual bool ProcessKeyUp(int Key){
-                       return CrowInterface.ProcessKeyUp(Key);
-               }
-               public virtual bool ProcessKeyPress(char Key){
-                       return CrowInterface.ProcessKeyPress(Key);
-               }
-               #endregion
-
-               #region graphic context
-               public virtual void initGL(){
-                       projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1);
-                       quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1);
-                       createContext ();
-               }
-               /// <summary>Create the texture for the interface redering</summary>
-               public virtual void createContext()
-               {
-                       if (GL.IsTexture(texID))
-                               GL.DeleteTexture (texID);
-                       GL.GenTextures(1, out texID);
-                       GL.ActiveTexture (TextureUnit.Texture0);
-                       GL.BindTexture(TextureTarget.Texture2D, texID);
-
-                       GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
-                               iRect.Width, iRect.Height, 0,
-                               OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.bmp);
-
-                       GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
-                       GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
-
-                       GL.BindTexture(TextureTarget.Texture2D, 0);
-               }
-               /// <summary>Rendering of the interface</summary>
-               public virtual void OpenGLDraw()
-               {
-                       #if MEASURE_TIME
-                       glDrawMeasure.StartCycle();
-                       #endif
-
-                       GL.ActiveTexture (TextureUnit.Texture0);
-                       GL.BindTexture (TextureTarget.Texture2D, texID);
-                       if (Monitor.TryEnter(CrowInterface.RenderMutex)) {
-                               if (CrowInterface.IsDirty) {
-                                       GL.TexSubImage2D (TextureTarget.Texture2D, 0,
-                                               CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top,
-                                               CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height,
-                                               OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.dirtyBmp);
-                                       CrowInterface.IsDirty = false;
-                               }
-                               Monitor.Exit (CrowInterface.RenderMutex);
-                       }
-                       quad.Render (BeginMode.TriangleStrip);
-                       GL.BindTexture(TextureTarget.Texture2D, 0);
-
-                       #if MEASURE_TIME
-                       glDrawMeasure.StopCycle();
-                       #endif
-               }
-               #endregion
-
-               #region IDisposable implementation
-
-               public void Dispose ()
-               {
-                       if (GL.IsTexture(texID))
-                               GL.DeleteTexture (texID);
-                       if (quad != null)
-                               quad.Dispose ();
-               }
-
-               #endregion
-       }
-}
-
diff --git a/src/ScrollingObject.cs b/src/ScrollingObject.cs
deleted file mode 100644 (file)
index f0463ae..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-//
-// ScrollingObject.cs
-//
-// Author:
-//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Xml.Serialization;
-using System.ComponentModel;
-using System.Collections;
-using Cairo;
-
-
-namespace Crow
-{
-       public class ScrollingObject : GraphicObject
-       {
-               #region CTOR
-               public ScrollingObject ():base()
-               {
-               }
-               #endregion
-
-               int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed;
-
-               /// <summary> Horizontal Scrolling Position </summary>
-               [XmlAttributeAttribute][DefaultValue(0)]
-               public virtual int ScrollX {
-                       get { return scrollX; }
-                       set {
-                               if (scrollX == value)
-                                       return;
-
-                               int newS = value;
-                               if (newS < 0)
-                                       newS = 0;
-                               else if (newS > maxScrollX)
-                                       newS = maxScrollX;
-
-                               if (newS == scrollX)
-                                       return;
-
-                               scrollX = value;
-
-                               NotifyValueChanged ("ScrollX", scrollX);
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               /// <summary> Vertical Scrolling Position </summary>
-               [XmlAttributeAttribute][DefaultValue(0)]
-               public virtual int ScrollY {
-                       get { return scrollY; }
-                       set {
-                               if (scrollY == value)
-                                       return;
-
-                               int newS = value;
-                               if (newS < 0)
-                                       newS = 0;
-                               else if (newS > maxScrollY)
-                                       newS = maxScrollY;
-
-                               if (newS == scrollY)
-                                       return;
-
-                               scrollY = value;
-
-                               NotifyValueChanged ("ScrollY", scrollY);
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               /// <summary> Horizontal Scrolling maximum value </summary>
-               [XmlAttributeAttribute][DefaultValue(0)]
-               public virtual int MaxScrollX {
-                       get { return maxScrollX; }
-                       set {
-                               if (maxScrollX == value)
-                                       return;
-
-                               maxScrollX = value;
-
-                               if (scrollX > maxScrollX)
-                                       ScrollX = maxScrollX;
-                               
-                               NotifyValueChanged ("MaxScrollX", maxScrollX);
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               /// <summary> Vertical Scrolling maximum value </summary>
-               [XmlAttributeAttribute][DefaultValue(0)]
-               public virtual int MaxScrollY {
-                       get { return maxScrollY; }
-                       set {
-                               if (maxScrollY == value)
-                                       return;
-
-                               maxScrollY = value;
-
-                               if (scrollY > maxScrollY)
-                                       ScrollY = maxScrollY;
-
-                               NotifyValueChanged ("MaxScrollY", maxScrollY);
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               /// <summary> Mouse Wheel Scrolling multiplier </summary>
-               [XmlAttributeAttribute][DefaultValue(1)]
-               public virtual int MouseWheelSpeed {
-                       get { return mouseWheelSpeed; }
-                       set {
-                               if (mouseWheelSpeed == value)
-                                       return;
-                               
-                               mouseWheelSpeed = value;
-
-                               NotifyValueChanged ("MouseWheelSpeed", mouseWheelSpeed);
-                       }
-               }
-
-               /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
-               public override void onMouseWheel (object sender, MouseWheelEventArgs e)
-               {
-                       base.onMouseWheel (sender, e);
-                       if (CurrentInterface.Keyboard.IsKeyDown (Key.ShiftLeft))
-                               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);
-
-                       switch (e.Key) {
-                       case Key.Up:
-                               ScrollY--;
-                               break;
-                       case Key.Down:
-                               ScrollY++;
-                               break;
-                       case Key.Left:
-                               ScrollX--;
-                               break;
-                       case Key.Right:
-                               ScrollX++;
-                               break;
-                       case Key.Home:
-                               ScrollX = 0;
-                               ScrollY = 0;
-                               break;
-                       case Key.End:
-                               ScrollX = MaxScrollX;
-                               ScrollY = MaxScrollY;
-                               break;
-                       }
-               }
-       }
-}
-
diff --git a/src/ScrollingTextBox.cs b/src/ScrollingTextBox.cs
deleted file mode 100644 (file)
index a9b429a..0000000
+++ /dev/null
@@ -1,768 +0,0 @@
-//
-// ScrollingTextBox.cs
-//
-// Author:
-//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Xml.Serialization;
-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()
-               {
-
-
-               }
-               #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
-
-               [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);
-                       }
-               }
-               [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 * 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){
-                       mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
-                       if (mouseLocalPos.X < 0)
-                               mouseLocalPos.X = 0;
-                       if (mouseLocalPos.Y < 0)
-                               mouseLocalPos.Y = 0;
-
-                       CurrentLine = ScrollY + (int)Math.Floor (mouseLocalPos.Y / fe.Height);
-                       CurrentColumn = ScrollX +  (int)Math.Round (mouseLocalPos.X / fe.MaxXAdvance);
-               }
-               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:
-                               break;
-                       case Key.PageUp:
-                               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
diff --git a/src/SourceEditor.cs b/src/SourceEditor.cs
new file mode 100644 (file)
index 0000000..8f1748e
--- /dev/null
@@ -0,0 +1,813 @@
+//
+// ScrollingTextBox.cs
+//
+// Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using System.Collections;
+using Cairo;
+using System.Text;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Linq;
+using System.Diagnostics;
+
+namespace Crow
+{
+       /// <summary>
+       /// Scrolling text box optimized for monospace fonts, for coding
+       /// </summary>
+       public class SourceEditor : ScrollingObject
+       {
+               #region CTOR
+               public SourceEditor ():base()
+               {
+
+
+               }
+               #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;
+               int visibleColumns = 1;
+               CodeTextBuffer buffer;
+               string _text = "label";
+               Color selBackground;
+               Color selForeground;
+               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
+
+               [XmlAttributeAttribute][DefaultValue("label")]
+               public string Text
+               {
+                       get {
+                               return buffer == null ?
+                                       _text : buffer.FullText;
+                       }
+                       set
+                       {
+                               if (string.Equals (value, _text, StringComparison.Ordinal))
+                                       return;
+
+                               _text = value;
+
+                               if (string.IsNullOrEmpty(_text))
+                                       _text = "";
+
+                               buffer = new CodeTextBuffer (_text);
+                               MaxScrollY = Math.Max (0, buffer.Count - visibleLines);
+                               MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns);
+
+                               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 > buffer [_currentLine].Length)
+                                       _currentCol = buffer [_currentLine].Length;
+                               else
+                                       _currentCol = value;
+
+                               if (_currentCol < ScrollX)
+                                       ScrollX = _currentCol;
+                               else if (_currentCol >= ScrollX + visibleColumns)
+                                       ScrollX = _currentCol - visibleColumns + 1;
+
+                               NotifyValueChanged ("CurrentColumn", _currentCol);
+                       }
+               }
+               [XmlAttributeAttribute][DefaultValue(0)]
+               public int CurrentLine{
+                       get { return _currentLine; }
+                       set {
+                               if (value == _currentLine)
+                                       return;
+                               if (value >= buffer.Count)
+                                       _currentLine = buffer.Count-1;
+                               else if (value < 0)
+                                       _currentLine = 0;
+                               else
+                                       _currentLine = value;
+                               //force recheck of currentCol for bounding
+                               int cc = _currentCol;
+                               _currentCol = 0;
+                               CurrentColumn = cc;
+                               //System.Diagnostics.Debug.WriteLine ("Scroll:{0} visibleLines:{1} CurLine:{2}", ScrollY, visibleLines, CurrentLine);
+                               if (_currentLine < ScrollY)
+                                       ScrollY = _currentLine;
+                               else if (_currentLine >= ScrollY + visibleLines)
+                                       ScrollY = _currentLine - visibleLines + 1;
+                               NotifyValueChanged ("CurrentLine", _currentLine);
+                       }
+               }
+               [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 buffer [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 buffer [selectionStart.Y].RawText.Substring (selectionStart.X, selectionEnd.X - selectionStart.X);
+                               string tmp = "";
+                               tmp = buffer [selectionStart.Y].RawText.Substring (selectionStart.X);
+                               for (int l = selectionStart.Y + 1; l < selectionEnd.Y; l++) {
+                                       tmp += Interface.LineBreak + buffer [l];
+                               }
+                               tmp += Interface.LineBreak + buffer [selectionEnd.Y].RawText.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 > buffer [_currentLine].Length){
+                               if (CurrentLine == buffer.Count - 1)
+                                       return false;
+                               CurrentLine++;
+                               CurrentColumn = 0;
+                       } else
+                               CurrentColumn = tmp;
+                       return true;
+               }
+               public void GotoWordStart(){
+                       if (buffer[CurrentLine].Length == 0)
+                               return;
+                       CurrentColumn--;
+                       //skip white spaces
+                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
+                               CurrentColumn--;
+                       while (char.IsLetterOrDigit (buffer [CurrentLine] [CurrentColumn]) && CurrentColumn > 0)
+                               CurrentColumn--;
+                       if (!char.IsLetterOrDigit (this.CurrentChar))
+                               CurrentColumn++;
+               }
+               public void GotoWordEnd(){
+                       //skip white spaces
+                       if (CurrentColumn >= buffer [CurrentLine].Length - 1)
+                               return;
+                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < buffer [CurrentLine].Length-1)
+                               CurrentColumn++;
+                       while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < buffer [CurrentLine].Length-1)
+                               CurrentColumn++;
+                       if (char.IsLetterOrDigit (this.CurrentChar))
+                               CurrentColumn++;
+               }
+               public void DeleteChar()
+               {
+                       if (selectionIsEmpty) {
+                               if (CurrentColumn == 0) {
+                                       if (CurrentLine == 0 && buffer.Count == 1)
+                                               return;
+                                       CurrentLine--;
+                                       CurrentColumn = buffer [CurrentLine].Length;
+                                       buffer [CurrentLine].RawText += buffer [CurrentLine + 1].RawText;
+                                       buffer.RemoveLine (CurrentLine + 1);
+                                       OnTextChanged (this, null);
+                                       return;
+                               }
+                               CurrentColumn--;
+                               buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Remove (CurrentColumn, 1);
+                       } else {
+                               int linesToRemove = selectionEnd.Y - selectionStart.Y + 1;
+                               int l = selectionStart.Y;
+
+                               if (linesToRemove > 0) {
+                                       buffer [l].RawText = buffer [l].RawText.Remove (selectionStart.X, buffer [l].Length - selectionStart.X) +
+                                               buffer [selectionEnd.Y].RawText.Substring (selectionEnd.X, buffer [selectionEnd.Y].Length - selectionEnd.X);
+                                       l++;
+                                       for (int c = 0; c < linesToRemove-1; c++)
+                                               buffer.RemoveLine (l);
+                                       CurrentLine = selectionStart.Y;
+                                       CurrentColumn = selectionStart.X;
+                               } else
+                                       buffer [l].RawText = buffer [l].RawText.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 * buffer.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 ();
+                       else if (layoutType == LayoutingType.Width)
+                               updateVisibleColumns ();
+               }
+               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;
+
+                       Foreground.SetAsSource (gr);
+
+                       #region draw text cursor
+                       if (SelBegin != SelRelease)
+                               selectionInProgress = true;
+                       else if (HasFocus){
+                               gr.LineWidth = 1.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
+
+                       for (int i = 0; i < visibleLines; i++) {
+                               int curL = i + ScrollY;
+                               if (curL >= buffer.Count)
+                                       break;
+                               string lstr = buffer[curL].RawText;
+                               if (ScrollX < lstr.Length)
+                                       lstr = lstr.Substring (ScrollX);
+                               else
+                                       lstr = "";
+
+                               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 = buffer [pos.Y].RawText.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, buffer.Count - visibleLines);
+
+                       System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines);
+                       System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY);
+               }
+               void updateVisibleColumns(){
+                       visibleColumns = (int)Math.Floor ((double)ClientRectangle.Width / fe.MaxXAdvance);
+                       MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns);
+
+                       System.Diagnostics.Debug.WriteLine ("update visible columns: " + visibleColumns);
+                       System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX);
+               }
+
+
+
+               /// <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();
+                       buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Insert (CurrentColumn, strLines[0]);
+                       CurrentColumn += strLines[0].Length;
+                       for (int i = 1; i < strLines.Length; i++) {
+                               InsertLineBreak ();
+                               buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Insert (CurrentColumn, strLines[i]);
+                               CurrentColumn += strLines[i].Length;
+                       }
+                       OnTextChanged (this, null);
+                       RegisterForGraphicUpdate();
+               }
+
+               /// <summary>
+               /// Insert a line break.
+               /// </summary>
+               protected void InsertLineBreak()
+               {
+                       buffer.InsertLine(CurrentLine + 1, new SourceLine (buffer[CurrentLine].RawText.Substring(CurrentColumn)));
+                       buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Substring (0, CurrentColumn);
+                       CurrentLine++;
+                       CurrentColumn = 0;
+                       OnTextChanged (this, null);
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/SourceLine.cs b/src/SourceLine.cs
new file mode 100644 (file)
index 0000000..cb777c6
--- /dev/null
@@ -0,0 +1,156 @@
+//
+//  SourceLine.cs
+//
+//  Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+//  Copyright (c) 2017 jp
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+
+namespace Crow
+{
+       /// <summary>
+       /// basic structure for line of source code
+       /// </summary>
+       public class SourceLine
+       {
+               public string RawText;
+               public List<Token> Tokens = null;
+
+               public int Length {
+                       get { return string.IsNullOrEmpty (RawText)? 0 : RawText.Length; }
+               }
+               public char this[int index]{
+                       get { return RawText [index]; }
+
+               } 
+               int ptr;        //character pointer in the source string
+               Token tok;      //current token parsed before addition to the token list
+
+               public SourceLine ()
+               {
+               }
+               public SourceLine (string rawText){
+                       RawText = rawText;
+               }
+
+               /// <summary>
+               /// Tokenize this instance.
+               /// This tokenization step is used for display mainly, so literals are not interpreted
+               /// </summary>
+               public bool Tokenize(){
+                       Tokens = new List<Token>();
+                       ptr = 0;
+
+                       while (!eol) {
+                               Char c = readChar ();
+
+                               //block comments
+                               if (tok?.Type == TokenType.BlockComment) {
+                                       tok.Content += c;
+                                       if (c == '*') {
+                                               if (peekChar () == '/') {
+                                                       tok.Content += readChar ();
+                                                       saveCurTok ();
+                                               }
+                                       }
+                                       continue;
+                               } else if (tok?.Type == TokenType.StringLiteral) {
+                                       tok.Content += c;
+                                       if (c == '\\')//may escape " char, so next char is read;
+                                               tok.Content += readChar ();
+                                       else if (c == '"')
+                                               saveCurTok ();                                  
+                                       continue;
+                               } else if (tok?.Type == TokenType.CharacterLiteral) {
+                                       tok.Content += c;
+                                       if (c == '\\')//may escape ' char, so next char is read;
+                                               tok.Content += readChar ();
+                                       else if (c == '\'')
+                                               saveCurTok ();                                  
+                                       continue;
+                               } else if (tok?.Type == TokenType.WhiteSpace) {
+                                       if (char.IsWhiteSpace (c)) {
+                                               tok.Content += c;
+                                               continue;
+                                       }
+                                       saveCurTok ();
+                                       //if (char.IsLetter (c))
+                                               
+                               }
+
+                               //single char tokens
+                               if (c == '{')
+                                       tok.Type = TokenType.OpenBlock;
+                               else if (c == '}')
+                                       tok.Type = TokenType.CloseBlock;
+                               else if (c == '(')
+                                       tok.Type = TokenType.OpenParenth;
+                               else if (c == ')')
+                                       tok.Type = TokenType.CloseParenth;
+                               
+
+                               if (tok == null) {
+                                       tok = new Token () { Content = new string (c, 1) };
+
+                                       if (char.IsWhiteSpace (c))
+                                               tok.Type = TokenType.WhiteSpace;
+                                       else if (char.IsDigit (c))
+                                               tok.Type = TokenType.DigitalLiteral;
+                                       else if (char.IsLetter (c))
+                                               tok.Type = TokenType.Unknown;
+                                       else if (c == '"')
+                                               tok.Type = TokenType.StringLiteral;
+                                       else {//put here all single step parsing token, reseting tok directely
+                                               saveCurTok ();
+                                       }
+                               }
+
+
+                                       
+                               ptr++;
+                       }
+                       return true;
+               }
+               /// <summary> add tok to token list and reset it to null </summary>
+               void saveCurTok(){
+                       Tokens.Add (tok);
+                       tok = null;
+               }
+               public void PresetCurrentToken (TokenType tokType, string content = null){
+                       tok = new Token (tokType,content);
+               }
+
+               bool eol { get { return ptr < RawText.Length; }}
+               char readChar() {                       
+                       char c = RawText [ptr];
+                       ptr++;
+                       return c;
+               }
+               char peekChar() {
+                       return RawText [ptr];
+               }
+
+//             public static implicit operator SourceLine(string rawText){
+//                     return new SourceLine() { RawText = rawText };
+//             }
+//             public static implicit operator string(SourceLine sl){
+//                     return sl?.RawText;
+//             }
+       }
+}
+
diff --git a/src/TextBuffer.cs b/src/TextBuffer.cs
deleted file mode 100644 (file)
index f4afe8e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-//  TextBuffer.cs
-//
-//  Author:
-//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-//  Copyright (c) 2017 jp
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-using System;
-
-namespace Crow
-{
-       public class TextBuffer
-       {
-               public TextBuffer ()
-               {
-               }
-       }
-}
-
diff --git a/src/Token.cs b/src/Token.cs
new file mode 100644 (file)
index 0000000..7639ca2
--- /dev/null
@@ -0,0 +1,60 @@
+//
+//  Token.cs
+//
+//  Author:
+//       Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+//  Copyright (c) 2017 jp
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+using System;
+
+namespace Crow
+{
+       public enum TokenType {
+               Unknown,
+               WhiteSpace,
+               OpenParenth,
+               CloseParenth,
+               OpenBlock,
+               CloseBlock,
+               StatementEnding,
+               UnaryOp,
+               BinaryOp,
+               Affectation,
+               StringLiteral,
+               CharacterLiteral,
+               DigitalLiteral,
+               Literal,
+               Identifier,
+               Indexer,
+               Type,
+               LineComment,
+               BlockComment,
+       }
+       public class Token
+       {
+               public TokenType Type;
+               public string Content;
+
+               public Token ()
+               {
+               }
+               public Token (TokenType tokType, string content = null){
+                       Type = tokType;
+                       Content = content;
+               }
+       }
+}
+
index 84f17006d2da9deab55db8909de783cd9198ab1f..981b5ca50206a8169c2098fcf741c888768e78b4 100755 (executable)
@@ -21,9 +21,9 @@
                                <MenuItem Command="{CMDHelp}"/>
                        </MenuItem>
                </Menu>
-               <HorizontalStack Height="Stretched" Background="Ivory">
-                       <ScrollingTextBox Focusable="true" Name="editor" Font="couriernew, 16" VerticalAlignment="Top" Margin="10"
-                                       Foreground="Jet"
+               <HorizontalStack Height="Stretched" >
+                       <SourceEditor Focusable="true" Name="editor" Font="couriernew, 16" VerticalAlignment="Top" Margin="10"
+                                       Foreground="Jet" Background="Ivory" Width="Stretched" Height="Stretched"
                                        Text="{Text}"  KeyDown="textView_KeyDown"/>
                        <ScrollBar Name="scrollbarY" Value="{²../editor.ScrollY}" 
                                Maximum="{../editor.MaxScrollY}" Orientation="Vertical" 
@@ -39,6 +39,8 @@
                        <Label Text="{../../editor.CurrentColumn}"/>
                        <Label Text="Line:"/>
                        <Label Text="{../../editor.CurrentLine}"/>
+                       <Label Text="ScrollX:"/>
+                       <Label Text="{../../editor.ScrollX}"/>
                </HorizontalStack>
        </VerticalStack>
 </Window>
\ No newline at end of file