]> O.S.I.I.S - jp/crow.git/commitdiff
label, cached line width in pixel in LineSpan struct, use stackalloc for a single...
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 14 Jan 2021 07:07:43 +0000 (08:07 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 14 Jan 2021 07:07:43 +0000 (08:07 +0100)
26 files changed:
Crow/Crow.csproj
Crow/Default.style
Crow/src/DebugUtils/DebugLogger.cs
Crow/src/Mono.Cairo/Context.cs
Crow/src/Widgets/FileDialog.cs
Crow/src/Widgets/Label.cs
Crow/src/Widgets/OldLabel.cs [new file with mode: 0644]
Samples/BasicTests/BasicTests.cs
Samples/BasicTests/BasicTests.csproj
Samples/DebugLogAnalyzer/Program.cs
Samples/PerfTests/Program.cs
Samples/PerfTests/Properties/launchSettings.json
Samples/ShowCase/ShowCase.cs
Samples/common/SampleBase.cs
Samples/common/ui/Interfaces/Divers/testVisibility.crow
Samples/common/ui/Interfaces/Experimental/testDock2.crow [deleted file]
Samples/common/ui/Interfaces/PerfLabels/0.crow [deleted file]
Samples/common/ui/Interfaces/PerfLabels/0_single_Label.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/0_single_oldLabel.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/1.crow [deleted file]
Samples/common/ui/Interfaces/PerfLabels/1_single_lab_update.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/1_single_old_update.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/2.crow [deleted file]
Samples/common/ui/Interfaces/PerfLabels/2_labels_update.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/2_old_labels_update.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/PerfLabels/labels.crow [deleted file]

index 792794aa49d63cbe11f46e968d4af9a49f337298..ce2bd530180a78abf2124313316fb8b8592a1206 100644 (file)
                <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
                <GenerateDocumentationFile>true</GenerateDocumentationFile>
                <NoWarn>$(NoWarn);1591;1587;1570;1572;1573;1574</NoWarn>
-               <DefineConstants>DESIGN_MODE;_MEASURE_TIME</DefineConstants>            
+               <DefineConstants>DESIGN_MODE;MEASURE_TIME</DefineConstants>             
                <EnableDefaultItems>false</EnableDefaultItems>
                <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
                <AppConfig>App.config</AppConfig>
        </PropertyGroup>
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
                <DebugType>full</DebugType>
-               <DefineConstants>$(DefineConstants);_DEBUG_LOG;DEBUG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
+               <DefineConstants>$(DefineConstants);_DEBUG;_DEBUG_LOG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
                <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
        </PropertyGroup>
        <ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
index ae09ec1c83d8d152f870c26863196336e4aa5a80..104b303c6efd80118512ddac2e1a6595b5842586 100644 (file)
@@ -74,6 +74,11 @@ Label {
        Width = "Fit";
        Margin = "0";   
 }
+OldLabel {
+       Height = "Fit";
+       Width = "Fit";
+       Margin = "0";   
+}
 TextBox {
        Background = "White";
        Foreground = "Black";
index 0c3f38dce72c6abbe358dbfaf03e79fe08ab77c2..ce0fa21481d566c99e087bbcec69b300dfa97ed8 100644 (file)
@@ -232,22 +232,29 @@ namespace Crow
                                        parseTree (pc.getTemplateRoot, level + 1, y + 1);                               
                        }
                }
+
+#endif
                /// <summary>
                /// Clear all recorded events from logger.
                /// </summary>
-               public static void Reset ()
-               {
+               public static void Reset () {
+#if DEBUG_LOG
                        lock (logMutex) {
-                               startedEvents.Clear ();
+                       startedEvents.Clear ();
                                events.Clear ();
                                chrono.Restart ();
                        }
+                       Console.WriteLine ($"Crow Debug Log reseted");
+#else
+                       Console.WriteLine ($"Logging disabled, compile Crow with DEBUG and DEBUG_LOG defined to enable logging.");
+#endif
                }
                /// <summary>
                /// Save recorded events to disk
                /// </summary>
-               /// <param name="iface">Iface.</param>
-               public static void save(Interface iface, string dbgLogFilePath = "debug.log") {
+               /// <param name="iface">Iface.</param>          
+               public static void Save(Interface iface, string dbgLogFilePath = "debug.log") {
+#if DEBUG_LOG
                        lock (logMutex) {
 
                                foreach (Widget go in iface.GraphicTree)
@@ -266,6 +273,10 @@ namespace Crow
                                        saveEventList (s, events);
                                }
                        }
+                       Console.WriteLine ($"Crow Debug Log saved to: {dbgLogFilePath}");
+#else
+                       Console.WriteLine ($"Compile Crow with DEBUG and DEBUG_LOG defined to enable logging. No log saved.");
+#endif
                }
 
                static void saveEventList (StreamWriter s, List<DbgEvent> evts, int level = 0)
@@ -278,7 +289,6 @@ namespace Crow
                                        saveEventList (s, e.Events, level + 1);
                        }
                }
-#endif
        }
 }
 
index 57f6c517e8e2deec4e1d1fe270ee3c0b40bacd00..9ac41f9fb7c012f2a9164296f76f1561258a4964 100644 (file)
@@ -907,6 +907,11 @@ namespace Crow.Cairo {
                        
                        NativeMethods.cairo_text_extents (handle, ref bytes.Slice(0, encodedBytes + 1).GetPinnableReference(), out extents);
                }
+               public void ShowText (Span<byte> bytes) =>
+                       NativeMethods.cairo_show_text (handle, ref bytes.GetPinnableReference ());
+               public void TextExtents (Span<byte> bytes, out TextExtents extents) =>
+                       NativeMethods.cairo_text_extents (handle, ref bytes.GetPinnableReference (), out extents);
+
 
                public TextExtents GlyphExtents (Glyph[] glyphs)
                {
index 8c58e632cf3efabff8adae788f4c682915514816..1a7ec842ba2ac83301376ace8bd472548a7c80da 100644 (file)
@@ -106,10 +106,11 @@ namespace Crow
                                SelectedDirectory = e.NewValue.ToString();
                }
                public void goUpDirClick (object sender, MouseButtonEventArgs e){
-                       string root = Directory.GetDirectoryRoot(CurrentDirectory);
-                       if (CurrentDirectory == root)
+                       string root = Directory.GetDirectoryRoot(CurrentDirectory);                     
+                       DirectoryInfo parentDir = Directory.GetParent (CurrentDirectory);
+                       if (parentDir == null)
                                return;
-                       CurrentDirectory = Directory.GetParent(CurrentDirectory).FullName;
+                       CurrentDirectory = parentDir.FullName;
                }
                void onFileSelect(object sender, MouseButtonEventArgs e){
                        if (string.IsNullOrEmpty (SelectedFile))
index 4d4f7f02ba597ddae65c50cbe000a7e57afc78ba..5724c7ff4f06d8900b02d9fa0b10259bb1b385b6 100644 (file)
@@ -16,13 +16,15 @@ namespace Crow {
                public readonly int Start;
                public readonly int End;
                public readonly int EndIncludingLineBreak;
+               public int LengthInPixel;
                public int Length => End - Start;
                public int LengthIncludingLineBreak => EndIncludingLineBreak - Start;
                public int LineBreakLength => EndIncludingLineBreak - End;
                public LineSpan (int start, int end, int endIncludingLineBreak) {
                        Start = start;
                        End = end;
-                       EndIncludingLineBreak = endIncludingLineBreak;                  
+                       EndIncludingLineBreak = endIncludingLineBreak;
+                       LengthInPixel = -1;
         }
                public LineSpan WithStartOffset (int start) => new LineSpan (Start + start, End, EndIncludingLineBreak);
                /*public ReadOnlySpan<char> GetSubString (string str) {                 
@@ -150,7 +152,7 @@ namespace Crow {
 
                 _text = value;
 
-                               lines = getLines;
+                               getLines ();
 
                                OnTextChanged (this, new TextChangeEventArgs (Text));
                                RegisterForGraphicUpdate ();
@@ -242,8 +244,8 @@ namespace Crow {
                        set {
                                if (value == _currentLine)
                                        return;
-                               if (value >= lines.Count)
-                                       _currentLine = lines.Count-1;
+                               if (value >= lines.Length)
+                                       _currentLine = lines.Length-1;
                                else if (value < 0)
                                        _currentLine = 0;
                                else
@@ -329,30 +331,33 @@ namespace Crow {
                [XmlIgnore]public bool selectionIsEmpty
                { get { return SelRelease < 0; } }
 
-               List<LineSpan> lines;
-               List<LineSpan> getLines {
-                       get {
-                               if (string.IsNullOrEmpty(_text))
-                                       return new List<LineSpan> (new LineSpan[] { new LineSpan (0, 0, 0) });
-                               if (!_multiline)
-                                       return new List<LineSpan> (new LineSpan[] { new LineSpan (0, _text.Length, _text.Length) });
-                               List<LineSpan> lines = new List<LineSpan> ();
-                               bool lineBreak = false;
-                               int start = 0, end = 0;
-                for (int i = 0; i < _text.Length; i++) {
-                                       if (_text[i].IsAnyLineBreakCharacter()) {
-                                               if (lineBreak)
-                                                       continue;
-                                               lineBreak = true;
-                                               end = i;
-                    }else if (lineBreak) {
-                                               lines.Add (new LineSpan (start, end, i));
-                                               start = end = i;
-                                               lineBreak = false;
-                    }
-                }
-                               return lines;
+               LineSpan[] lines;
+               void getLines () {
+                       if (string.IsNullOrEmpty (_text)) {
+                               lines = new LineSpan[] { new LineSpan (0, 0, 0) };
+                               return;
                        }
+                       if (!_multiline) {
+                               lines = new LineSpan[] { new LineSpan (0, _text.Length, _text.Length) };
+                               return;
+                       }
+
+                       List<LineSpan> _lines = new List<LineSpan> ();
+                       bool lineBreak = false;
+                       int start = 0, end = 0;
+            for (int i = 0; i < _text.Length; i++) {
+                               if (_text[i].IsAnyLineBreakCharacter()) {
+                                       if (lineBreak)
+                                               continue;
+                                       lineBreak = true;
+                                       end = i;
+                }else if (lineBreak) {
+                                       _lines.Add (new LineSpan (start, end, i));
+                                       start = end = i;
+                                       lineBreak = false;
+                }
+            }
+                       lines = _lines.ToArray();                       
                }
                /// <summary>
                /// Moves cursor one char to the left.
@@ -376,7 +381,7 @@ namespace Crow {
                public bool MoveRight(){
                        int tmp = _currentCol + 1;
                        if (tmp > lines [_currentLine].Length){
-                               if (CurrentLine == lines.Count - 1)
+                               if (CurrentLine == lines.Length - 1)
                                        return false;
                                CurrentLine++;
                                CurrentColumn = 0;
@@ -409,7 +414,7 @@ namespace Crow {
                {
                        if (selectionIsEmpty) {
                                if (CurrentColumn == 0) {
-                                       if (CurrentLine == 0 && lines.Count == 1)
+                                       if (CurrentLine == 0 && lines.Length == 1)
                                                return;
                                        CurrentLine--;
                                        CurrentColumn = lines [CurrentLine].Length;
@@ -485,7 +490,8 @@ namespace Crow {
                public override int measureRawSize(LayoutingType lt)
                {
                        if (lines == null)
-                               lines = getLines;
+                               getLines ();
+
                        if (!textMeasureIsUpToDate) {
                                using (Context gr = new Context (IFace.surf)) {
                                        //Cairo.FontFace cf = gr.GetContextFontFace ();
@@ -498,12 +504,14 @@ namespace Crow {
                                        fe = gr.FontExtents;
                                        te = new TextExtents ();
 
-                                       cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent+fe.Descent) * Math.Max (1, lines.Count));
+                                       cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent+fe.Descent) * Math.Max (1, lines.Length));
 
                                        try {
                                                TextExtents tmp = default;
-                                               for (int i = 0; i < lines.Count; i++) {                                                 
+                                               for (int i = 0; i < lines.Length; i++) {                                                        
                                                        gr.TextExtents (_text.GetLine (lines[i]), Interface.TAB_SIZE, out tmp);
+                                                       if (lines[i].LengthInPixel < 0)
+                                                               lines[i].LengthInPixel = (int)tmp.XAdvance;
                                                        if (tmp.XAdvance > te.XAdvance)
                                                                te = tmp;
                                                }
@@ -659,33 +667,47 @@ namespace Crow {
                                gr.Restore ();
                                return;
                        }
-                       for (int i = 0; i < lines.Count; i++) {
+
+                       Foreground.SetAsSource (IFace, gr);
+
+                       TextExtents extents;
+                       Span<byte> bytes = stackalloc byte[128];
+
+                       for (int i = 0; i < lines.Length; i++) {
                                if (lines[i].Length == 0)
                                        continue;
-                               ReadOnlySpan<char> chars = _text.GetLine (lines[i]);
-
+                               
+                               int size = lines[i].Length * 4 + 1;
+                               if (bytes.Length < size)
+                                       bytes = size > 512 ? new byte[size] : stackalloc byte[size];
+                               
+                               int encodedBytes = Encoding.UTF8.GetBytes (_text.GetLine (lines[i]), bytes);
+                               bytes[encodedBytes] = 0;
+
+                               if (lines[i].LengthInPixel < 0) {
+                                       gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+                                       lines[i].LengthInPixel = (int)extents.XAdvance;
+                               }
                                //string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
-                               int lineLength = (int)gr.TextExtents (chars, Interface.TAB_SIZE).XAdvance;
+                               
                                Rectangle lineRect = new Rectangle (
                                        rText.X,
                                        rText.Y + i * (int)(fe.Ascent+fe.Descent),
-                                       lineLength,
+                                       lines[i].LengthInPixel,
                                        (int)(fe.Ascent+fe.Descent));
 
-//                             if (TextAlignment == Alignment.Center ||
-//                                     TextAlignment == Alignment.Top ||
-//                                     TextAlignment == Alignment.Bottom)
-//                                     lineRect.X += (rText.Width - lineLength) / 2;
-//                             else if (TextAlignment == Alignment.Right ||
-//                                     TextAlignment == Alignment.TopRight ||
-//                                     TextAlignment == Alignment.BottomRight)
-//                                     lineRect.X += (rText.Width - lineLength);
+                               //                              if (TextAlignment == Alignment.Center ||
+                               //                                      TextAlignment == Alignment.Top ||
+                               //                                      TextAlignment == Alignment.Bottom)
+                               //                                      lineRect.X += (rText.Width - lineLength) / 2;
+                               //                              else if (TextAlignment == Alignment.Right ||
+                               //                                      TextAlignment == Alignment.TopRight ||
+                               //                                      TextAlignment == Alignment.BottomRight)
+                               //                                      lineRect.X += (rText.Width - lineLength);
 
-                               Foreground.SetAsSource (IFace, gr);
                                gr.MoveTo (lineRect.X,(double)rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i) ;
-
-                gr.ShowText (chars, Interface.TAB_SIZE);
-                               gr.Fill ();
+                gr.ShowText (bytes.Slice (0, encodedBytes));
+                               //gr.Fill ();
 
                                if (Selectable) {
                                        if (SelRelease >= 0 && i >= selectionStart.Y && i <= selectionEnd.Y) {
@@ -706,7 +728,7 @@ namespace Crow {
                                                        selRect.Left += cpStart;
                                                }
                                                if (i == selectionEnd.Y)
-                                                       selRect.Width -= (lineLength - cpEnd);
+                                                       selRect.Width -= (lines[i].LengthInPixel - cpEnd);
 
                                                gr.Rectangle (selRect);
                                                gr.FillPreserve ();
@@ -714,9 +736,11 @@ namespace Crow {
                                                gr.Clip ();
                                                gr.SetSource (SelectionForeground);
                                                gr.MoveTo (lineRect.X, rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i);
-                                               gr.ShowText (chars, Interface.TAB_SIZE);
+                                               gr.ShowText (bytes.Slice (0, encodedBytes));
                                                gr.Fill ();
                                                gr.Restore ();
+
+                                               Foreground.SetAsSource (IFace, gr);
                                        }
                                }
                        }
@@ -741,7 +765,7 @@ namespace Crow {
                        if (!_selectable)
                                return;
                        SelBegin = new Point(0,0);
-                       SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1);
+                       SelRelease = new Point (lines.LastOrDefault ().Length, lines.Length-1);
                        RegisterForRedraw ();
                }
                protected override void onUnfocused (object sender, EventArgs e)
@@ -818,8 +842,8 @@ namespace Crow {
                        CurrentLine = (int)(mouseLocalPos.Y / (fe.Ascent+fe.Descent));
                        
                        //fix cu
-                       if (CurrentLine >= lines.Count)
-                               CurrentLine = lines.Count - 1;
+                       if (CurrentLine >= lines.Length)
+                               CurrentLine = lines.Length - 1;
 
                        LineSpan ls = lines[CurrentLine];
                        ReadOnlySpan<char> curLine = _text.GetLine (lines[CurrentLine]);
diff --git a/Crow/src/Widgets/OldLabel.cs b/Crow/src/Widgets/OldLabel.cs
new file mode 100644 (file)
index 0000000..080bc5a
--- /dev/null
@@ -0,0 +1,842 @@
+// Copyright (c) 2013-2019  Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Crow.Cairo;
+using System.Text.RegularExpressions;
+using System.ComponentModel;
+
+namespace Crow {
+       public class OldLabel : Widget
+    {
+               #region CTOR
+               protected OldLabel () {}
+               public OldLabel(Interface iface, string style = null) : base (iface, style) { }
+               #endregion
+
+               public event EventHandler<TextChangeEventArgs> TextChanged;
+
+               public virtual void OnTextChanged(Object sender, TextChangeEventArgs e)
+               {
+                       textMeasureIsUpToDate = false;
+                       NotifyValueChanged ("Text", Text);
+                       TextChanged.Raise (this, e);
+               }
+        //TODO:change protected to private
+
+               #region private and protected fields
+               string _text = "label";
+        Alignment _textAlignment;
+               bool horizontalStretch;
+               bool verticalStretch;
+               bool _selectable;
+               bool _multiline;
+               Color selBackground;
+               Color selForeground;
+               Point mouseLocalPos = -1;//mouse coord in widget space, filled only when clicked
+               int _currentCol;        //0 based cursor position in string
+               int _currentLine;
+               Point _selBegin = -1;   //selection start (row,column)
+               Point _selRelease = -1; //selection end (row,column)
+               double textCursorPos;   //cursor position in cairo units in widget client coord.
+               double SelStartCursorPos = -1;
+               double SelEndCursorPos = -1;
+               bool SelectionInProgress = false;
+
+        protected Rectangle rText;
+               protected float widthRatio = 1f;
+               protected float heightRatio = 1f;
+               protected FontExtents fe;
+               protected TextExtents te;
+               #endregion
+
+               [DefaultValue("SteelBlue")]
+               public virtual Color SelectionBackground {
+                       get { return selBackground; }
+                       set {
+                               if (selBackground == value)
+                                       return;
+                               selBackground = value;
+                               NotifyValueChangedAuto (selBackground);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue("White")]
+               public virtual Color SelectionForeground {
+                       get { return selForeground; }
+                       set {
+                               if (selForeground == value)
+                                       return;
+                               selForeground = value;
+                               NotifyValueChangedAuto (selForeground);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue(Alignment.Left)]
+               public Alignment TextAlignment
+        {
+            get { return _textAlignment; }
+            set {
+                               if (value == _textAlignment)
+                                       return;
+                               _textAlignment = value;
+                               RegisterForRedraw ();
+                               NotifyValueChangedAuto (_textAlignment);
+                       }
+        }
+               [DefaultValue(false)]
+               public virtual bool HorizontalStretch {
+                       get { return horizontalStretch; }
+                       set {
+                               if (horizontalStretch == value)
+                                       return;
+                               horizontalStretch = value;
+                               RegisterForRedraw ();
+                               NotifyValueChangedAuto (horizontalStretch);
+                       }
+               }
+               [DefaultValue(false)]
+               public virtual bool VerticalStretch {
+                       get { return verticalStretch; }
+                       set {
+                               if (verticalStretch == value)
+                                       return;
+                               verticalStretch = value;
+                               RegisterForRedraw ();
+                               NotifyValueChangedAuto (verticalStretch);
+                       }
+               }
+               [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;
+
+                               OnTextChanged (this, new TextChangeEventArgs (Text));
+                               RegisterForGraphicUpdate ();
+            }
+        }
+               [DefaultValue(false)]
+               public bool Selectable
+               {
+                       get { return _selectable; }
+                       set
+                       {
+                               if (value == _selectable)
+                                       return;
+                               _selectable = value;
+                               NotifyValueChangedAuto (_selectable);
+                               SelBegin = -1;
+                               SelRelease = -1;
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue(false)]
+               public bool Multiline
+               {
+                       get { return _multiline; }
+                       set
+                       {
+                               if (value == _multiline)
+                                       return;
+                               _multiline = value;
+                               NotifyValueChangedAuto (_multiline);
+                               RegisterForGraphicUpdate();
+                       }
+               }
+               [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;
+                               NotifyValueChangedAuto (_currentCol);
+
+                               Rectangle cb = ClientRectangle;
+
+                               if (Width == Measure.Fit || cb.Width >= cachedTextSize.Width) {
+                                       xTranslation = 0;
+                                       return;
+                               }
+                               int xpos = xposition;
+                               if (xTranslation + xpos > cb.Width)
+                                       xTranslation = cb.Width - xpos;
+                               else if (xpos < -xTranslation)
+                                       xTranslation = -xpos;
+                               RegisterForRedraw ();
+                       }
+               }
+               int xTranslation = 0;
+               int xposition {
+                       get {
+                               using (Context gr = new Context (IFace.surf)) {
+                                       //Cairo.FontFace cf = gr.GetContextFontFace ();
+                                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                       gr.SetFontSize (Font.Size);
+                                       gr.FontOptions = Interface.FontRenderingOptions;
+                                       gr.Antialias = Interface.Antialias;
+                                       try {
+                                               string l = lines [_currentLine];
+                                               if (_currentCol < l.Length)
+                                                       l = l.Remove (Math.Min (_currentCol, l.Length));
+                                               l = l.Replace ("\t", new String (' ', Interface.TAB_SIZE));
+                                               return (int)Math.Ceiling (gr.TextExtents (l).XAdvance);
+                                       } catch {
+                                               System.Diagnostics.Debug.WriteLine ("xpos measuring fault in label");
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+
+               [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;
+                               NotifyValueChangedAuto (_currentLine);
+                       }
+               }
+               [XmlIgnore]public Point CurrentPosition {
+                       get { return new Point(_currentCol, CurrentLine); }
+               }
+               //TODO:using HasFocus for drawing selection cause SelBegin and Release binding not to work
+               /// <summary>
+               /// Selection begin position in char units
+               /// </summary>
+               [DefaultValue("-1")]
+               public Point SelBegin {
+                       get {
+                               return _selBegin;
+                       }
+                       set {
+                               if (value == _selBegin)
+                                       return;
+                               _selBegin = value;
+                               NotifyValueChangedAuto (_selBegin);
+                               NotifyValueChanged ("SelectedText", SelectedText);
+                       }
+               }
+               [DefaultValue("-1")]
+               public Point SelRelease {
+                       get {
+                               return _selRelease;
+                       }
+                       set {
+                               if (value == _selRelease)
+                                       return;
+                               _selRelease = value;
+                               NotifyValueChangedAuto (_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 < 0; } }
+
+               List<string> lines;
+               List<string> getLines {
+                       get {
+                               return _multiline ?
+                                       Regex.Split (_text, "\r\n|\r|\n|\\\\n").ToList() :
+                                       new List<string>(new string[] { _text });
+                       }
+               }
+               /// <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(){
+                       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, new TextChangeEventArgs (Text));
+                                       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, new TextChangeEventArgs (Text));
+               }
+               /// <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 ();
+                       if (_multiline) {
+                               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;
+                               }
+                       } else {
+                               lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, str);
+                               CurrentColumn += str.Length;
+                       }
+                       OnTextChanged (this, new TextChangeEventArgs (Text));
+               }
+               /// <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, new TextChangeEventArgs (Text));
+               }
+               bool textMeasureIsUpToDate = false;
+               Size cachedTextSize = default(Size);
+
+               #region GraphicObject overrides
+               public override int measureRawSize(LayoutingType lt)
+               {
+                       if (lines == null)
+                               lines = getLines;
+                       if (!textMeasureIsUpToDate) {
+                               using (Context gr = new Context (IFace.surf)) {
+                                       //Cairo.FontFace cf = gr.GetContextFontFace ();
+
+                                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                       gr.SetFontSize (Font.Size);
+                                       gr.FontOptions = Interface.FontRenderingOptions;
+                                       gr.Antialias = Interface.Antialias;
+
+                                       fe = gr.FontExtents;
+                                       te = new TextExtents ();
+
+                                       cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent+fe.Descent) * Math.Max (1, lines.Count));
+
+                                       try {
+                                               for (int i = 0; i < lines.Count; i++) {
+                                                       string l = lines[i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
+
+                                                       TextExtents tmp = gr.TextExtents (l);
+
+                                                       if (tmp.XAdvance > te.XAdvance)
+                                                               te = tmp;
+                                               }
+                                               cachedTextSize.Width = (int)Math.Ceiling (te.XAdvance);
+                                               textMeasureIsUpToDate = true;
+                                       } catch {                                                       
+                                               return -1;
+                                       }                                       
+                               }
+                       }
+                       return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width);
+               }
+               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;
+
+                       gr.Save ();
+                       gr.Translate (xTranslation, 0);
+
+                       rText = new Rectangle(new Size(
+                               measureRawSize(LayoutingType.Width), measureRawSize(LayoutingType.Height)));
+                       rText.Width -= 2 * Margin;
+                       rText.Height -= 2 * Margin;
+
+                       widthRatio = 1f;
+                       heightRatio = 1f;
+
+                       Rectangle cb = ClientRectangle;
+
+                       rText.X = cb.X;
+                       rText.Y = cb.Y;
+
+                       if (horizontalStretch) {
+                               widthRatio = (float)cb.Width / (float)rText.Width;
+                               if (!verticalStretch)
+                                       heightRatio = widthRatio;
+                       }
+
+                       if (verticalStretch) {
+                               heightRatio = (float)cb.Height / (float)rText.Height;
+                               if (!horizontalStretch)
+                                       widthRatio = heightRatio;
+                       }
+
+                       rText.Width = (int)(widthRatio * (float)rText.Width);
+                       rText.Height = (int)(heightRatio * (float)rText.Height);
+
+                       switch (TextAlignment)
+                       {
+                       case Alignment.TopLeft:     //ok
+                               rText.X = cb.X;
+                               rText.Y = cb.Y;
+                               break;
+                       case Alignment.Top:   //ok
+                               rText.Y = cb.Y;
+                               rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+                               break;
+                       case Alignment.TopRight:    //ok
+                               rText.Y = cb.Y;
+                               rText.X = cb.Right - rText.Width;
+                               break;
+                       case Alignment.Left://ok
+                               rText.X = cb.X;
+                               rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+                               break;
+                       case Alignment.Right://ok
+                               rText.X = cb.X + cb.Width - rText.Width;
+                               rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+                               break;
+                       case Alignment.Bottom://ok
+                               rText.X = cb.Width / 2 - rText.Width / 2;
+                               rText.Y = cb.Height - rText.Height;
+                               break;
+                       case Alignment.BottomLeft://ok
+                               rText.X = cb.X;
+                               rText.Y = cb.Bottom - rText.Height;
+                               break;
+                       case Alignment.BottomRight://ok
+                               rText.Y = cb.Bottom - rText.Height;
+                               rText.X = cb.Right - rText.Width;
+                               break;
+                       case Alignment.Center://ok
+                               rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+                               //rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+                               rText.Y = cb.Y + (int)Math.Floor((double)cb.Height / 2.0 - (double)rText.Height / 2.0);
+                               break;
+                       }
+
+                       //gr.FontMatrix = new Matrix(widthRatio * (float)Font.Size, 0, 0, heightRatio * (float)Font.Size, 0, 0);
+                       fe = gr.FontExtents;
+
+                       #region draw text cursor
+                       if (HasFocus && Selectable)
+                       {
+                               if (mouseLocalPos >= 0)
+                               {
+                                       computeTextCursor(gr);
+
+                                       if (SelectionInProgress)
+                                       {
+                                               if (SelBegin < 0){
+                                                       SelBegin = new Point(CurrentColumn, CurrentLine);
+                                                       SelStartCursorPos = textCursorPos;
+                                                       SelRelease = -1;
+                                               }else{
+                                                       SelRelease = new Point(CurrentColumn, CurrentLine);
+                                                       if (SelRelease == SelBegin)
+                                                               SelRelease = -1;
+                                                       else
+                                                               SelEndCursorPos = textCursorPos;
+                                               }
+                                       }else
+                                               computeTextCursorPosition(gr);
+                               }else
+                                       computeTextCursorPosition(gr);
+
+                               Foreground.SetAsSource (IFace, gr);
+                               gr.LineWidth = 1.0;
+                               gr.MoveTo (0.5 + textCursorPos + rText.X, rText.Y + CurrentLine * (fe.Ascent+fe.Descent));
+                               gr.LineTo (0.5 + textCursorPos + rText.X, rText.Y + (CurrentLine + 1) * (fe.Ascent+fe.Descent));
+                               gr.Stroke();
+                       }
+                       #endregion
+
+                       //****** debug selection *************
+//                     if (SelRelease >= 0) {
+//                             new SolidColor(Color.DarkGreen).SetAsSource(gr);
+//                             Rectangle R = new Rectangle (
+//                                                  rText.X + (int)SelEndCursorPos - 3,
+//                                                  rText.Y + (int)(SelRelease.Y * (fe.Ascent+fe.Descent)),
+//                                                  6,
+//                                                  (int)(fe.Ascent+fe.Descent));
+//                             gr.Rectangle (R);
+//                             gr.Fill ();
+//                     }
+//                     if (SelBegin >= 0) {
+//                             new SolidColor(Color.DarkRed).SetAsSource(gr);
+//                             Rectangle R = new Rectangle (
+//                                     rText.X + (int)SelStartCursorPos - 3,
+//                                     rText.Y + (int)(SelBegin.Y * (fe.Ascent+fe.Descent)),
+//                                     6,
+//                                     (int)(fe.Ascent+fe.Descent));
+//                             gr.Rectangle (R);
+//                             gr.Fill ();
+//                     }
+                       //*******************
+
+                       for (int i = 0; i < lines.Count; i++) {
+                               string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
+                               int lineLength = (int)gr.TextExtents (l).XAdvance;
+                               Rectangle lineRect = new Rectangle (
+                                       rText.X,
+                                       rText.Y + i * (int)(fe.Ascent+fe.Descent),
+                                       lineLength,
+                                       (int)(fe.Ascent+fe.Descent));
+
+//                             if (TextAlignment == Alignment.Center ||
+//                                     TextAlignment == Alignment.Top ||
+//                                     TextAlignment == Alignment.Bottom)
+//                                     lineRect.X += (rText.Width - lineLength) / 2;
+//                             else if (TextAlignment == Alignment.Right ||
+//                                     TextAlignment == Alignment.TopRight ||
+//                                     TextAlignment == Alignment.BottomRight)
+//                                     lineRect.X += (rText.Width - lineLength);
+                               if (string.IsNullOrWhiteSpace (l))
+                                       continue;
+
+                               Foreground.SetAsSource (IFace, gr);
+                               gr.MoveTo (lineRect.X,(double)rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i) ;
+
+                gr.ShowText (l);
+                               gr.Fill ();
+
+                               if (Selectable) {
+                                       if (SelRelease >= 0 && i >= selectionStart.Y && i <= selectionEnd.Y) {
+                                               gr.SetSource (selBackground);
+
+                                               Rectangle selRect = lineRect;
+
+                                               int cpStart = (int)SelStartCursorPos,
+                                               cpEnd = (int)SelEndCursorPos;
+
+                                               if (SelBegin.Y > SelRelease.Y) {
+                                                       cpStart = cpEnd;
+                                                       cpEnd = (int)SelStartCursorPos;
+                                               }
+
+                                               if (i == selectionStart.Y) {
+                                                       selRect.Width -= cpStart;
+                                                       selRect.Left += cpStart;
+                                               }
+                                               if (i == selectionEnd.Y)
+                                                       selRect.Width -= (lineLength - cpEnd);
+
+                                               gr.Rectangle (selRect);
+                                               gr.FillPreserve ();
+                                               gr.Save ();
+                                               gr.Clip ();
+                                               gr.SetSource (SelectionForeground);
+                                               gr.MoveTo (lineRect.X, rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i);
+                                               gr.ShowText (l);
+                                               gr.Fill ();
+                                               gr.Restore ();
+                                       }
+                               }
+                       }
+
+                       gr.Restore ();
+               }
+               #endregion
+
+               #region Mouse handling
+               void updatemouseLocalPos(Point mpos){
+                       mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
+                       mouseLocalPos.X -= xTranslation;
+                       if (mouseLocalPos.X < 0)
+                               mouseLocalPos.X = 0;
+                       if (mouseLocalPos.Y < 0)
+                               mouseLocalPos.Y = 0;
+               }
+               protected override void onFocused (object sender, EventArgs e)
+               {
+                       base.onFocused (sender, e);
+
+                       if (!_selectable)
+                               return;
+                       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 (!(SelectionInProgress && HasFocus && _selectable))
+                               return;
+
+                       updatemouseLocalPos (e.Position);
+
+                       RegisterForRedraw();
+               }
+               public override void onMouseDown (object sender, MouseButtonEventArgs e)
+               {
+                       if (HasFocus) {
+                               if (_selectable) {
+                                       updatemouseLocalPos (e.Position);
+                                       SelBegin = -1;
+                                       SelRelease = -1;
+                                       SelectionInProgress = true;
+                                       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 (!(HasFocus || _selectable))
+                               return;
+                       if (!SelectionInProgress)
+                               return;
+
+                       updatemouseLocalPos (e.Position);
+                       SelectionInProgress = false;
+                       RegisterForRedraw ();
+               }
+               public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseDoubleClick (sender, e);
+                       if (!(this.HasFocus || _selectable))
+                               return;
+                       
+                       GotoWordStart ();
+                       SelBegin = CurrentPosition;
+                       GotoWordEnd ();
+                       SelRelease = CurrentPosition;
+                       SelectionInProgress = false;
+                       RegisterForRedraw ();
+               }
+               #endregion
+
+               /// <summary>
+               /// Update Current Column, line and TextCursorPos
+               /// from mouseLocalPos
+               /// </summary>
+               void computeTextCursor(Context gr)
+               {
+                       TextExtents te;
+
+                       double cPos = 0f;
+
+                       CurrentLine = (int)(mouseLocalPos.Y / (fe.Ascent+fe.Descent));
+
+                       //fix cu
+                       if (CurrentLine >= lines.Count)
+                               CurrentLine = lines.Count - 1;
+
+                       switch (TextAlignment) {
+                       case Alignment.Center:
+                       case Alignment.Top:
+                       case Alignment.Bottom:
+                               cPos+= ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width/2.0;
+                               break;
+                       case Alignment.Right:
+                       case Alignment.TopRight:
+                       case Alignment.BottomRight:
+                               cPos += ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width;
+                               break;
+                       }
+
+                       for (int i = 0; i < lines[CurrentLine].Length; i++)
+                       {
+                               string c = lines [CurrentLine].Substring (i, 1);
+                               if (c == "\t")
+                                       c = new string (' ', Interface.TAB_SIZE);
+
+                               te = gr.TextExtents(c);
+
+                               double halfWidth = te.XAdvance / 2;
+
+                               if (mouseLocalPos.X <= cPos + halfWidth)
+                               {
+                                       CurrentColumn = i;
+                                       textCursorPos = cPos;
+                                       mouseLocalPos = -1;
+                                       return;
+                               }
+
+                               cPos += te.XAdvance;
+                       }
+                       CurrentColumn = lines[CurrentLine].Length;
+                       textCursorPos = cPos;
+
+                       //reset mouseLocalPos
+                       mouseLocalPos = -1;
+               }
+               /// <summary> Computes offsets in cairo units </summary>
+               void computeTextCursorPosition(Context gr)
+               {
+                       if (SelBegin >= 0)
+                               SelStartCursorPos = GetXFromTextPointer (gr, SelBegin);
+                       if (SelRelease >= 0)
+                               SelEndCursorPos = GetXFromTextPointer (gr, SelRelease);
+                       textCursorPos = GetXFromTextPointer (gr, new Point(CurrentColumn, CurrentLine));
+               }
+               /// <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.TAB_SIZE));
+                               return gr.TextExtents (l).XAdvance;
+                       } catch{
+                               return -1;
+                       }
+               }
+    }
+}
index 755c4a0beca4e500278a2cdb7c9491c1df215be9..dcf38db412f22d4a3a3d91361199a53cc8ce9dba 100644 (file)
@@ -28,14 +28,14 @@ namespace tests
                        // += KeyboardKeyDown1;
 
                        //testFiles = new string [] { @"Interfaces/Experimental/testDock.crow" };
-                       //testFiles = new string [] { @"Interfaces/Divers/welcome.crow" };
+                       testFiles = new string [] { @"Interfaces/Divers/welcome.crow" };
                        //testFiles = new string [] { @"Interfaces/TemplatedGroup/3.crow" };
                        //testFiles = new string [] { @"Interfaces/Divers/testShape.crow" };
                        //testFiles = new string [] { @"Interfaces/TemplatedControl/testEnumSelector.crow" };
                        //testFiles = new string [] { @"Interfaces/Divers/all.crow" };
                        //testFiles = new string [] { @"Interfaces/Divers/gauge.crow" };
                        //testFiles = new string [] { @"Interfaces/Stack/StretchedInFit4.crow" };
-                       testFiles = new string [] { @"Interfaces/TemplatedGroup/1.crow" };
+                       //testFiles = new string [] { @"Interfaces/TemplatedGroup/1.crow" };
                        //testFiles = new string [] { @"Interfaces/Divers/colorPicker2.crow" };
                        testFiles = testFiles.Concat (Directory.GetFiles (@"Interfaces/GraphicObject", "*.crow")).ToArray ();
                        testFiles = testFiles.Concat (Directory.GetFiles (@"Interfaces/Container", "*.crow")).ToArray ();
@@ -62,12 +62,7 @@ namespace tests
                                switch (key) {
                                case Key.Escape:
                                        Quit ();
-                                       break;
-                               case Key.F2:
-                                       //if (IsKeyDown (Key.LeftShift))
-                                               //DbgLogger.Reset ();
-                                       //DbgLogger.save (this);
-                                       return false;
+                                       break;                          
                                case Key.F3:
                                        idx--;
                                        break;
@@ -78,15 +73,6 @@ namespace tests
                                        //TestList.Add ("new string");
                                        NotifyValueChanged ("TestList", TestList);
                                        break;
-                               case Key.F5:
-                                       Load ("Interfaces/Divers/testFileDialog.crow").DataSource = this;
-                                       return false;
-                               case Key.F6:
-                                       Load ("Interfaces/Divers/0.crow").DataSource = this;
-                                       return false;
-                               case Key.F7:
-                                       Load ("Interfaces/Divers/perfMeasures.crow").DataSource = this;
-                                       return false;
                                default:
                                        return base.OnKeyDown (key);
                                }
@@ -105,7 +91,7 @@ namespace tests
 #endif
                                Load (testFiles [idx]).DataSource = this;
                        } catch (Exception ex) {
-                               (LoadIMLFragment ($"<Label Background='Red' Foreground='White' Height='Fit' Width='Stretched' Multiline='true' VerticalAlignment='Bottom' Margin='5' />") as Label).Text = ex.ToString();
+                               (LoadIMLFragment ($"<Label Background='Red' Foreground='White' Height='Fit' Width='Stretched' Multiline='true' VerticalAlignment='Bottom' Margin='5' />") as OldLabel).Text = ex.ToString();
                                Console.WriteLine (ex.Message + "\n" + ex.InnerException);
                                                                                                                                                                                                                                                 //MessageBox.Show (CurrentInterface, MessageBox.Type.Error, ex.Message + "\n" + ex.InnerException.Message).Modal = true;
                        }
index b92bf1021f303fbfcc57c5bc47e8ea557b230739..63d93cc3a64e742b9d747940bc02c22fe99780ad 100644 (file)
@@ -8,4 +8,7 @@
                        <LogicalName>ShowCase.%(Filename)%(Extension)</LogicalName>
                </EmbeddedResource>
        </ItemGroup>
+       <ItemGroup>
+         <None Remove="C:\Users\Jean-Philippe\source\Crow\Samples\common\ui\Interfaces\Experimental\testDock2.crow" />
+       </ItemGroup>
 </Project>
\ No newline at end of file
index bb793da357ccf6feeac4e15779a32dc98e2cb916..7493a84237bb5eb01270c9fee6acb3ef7c9557a0 100644 (file)
@@ -79,7 +79,7 @@ namespace DebugLogAnalyzer
                        TreeView tv = FindByName("dbgTV") as TreeView;
                        dbgTreeViewScroller = tv.FindByNameInTemplate ("scroller1") as Scroller;
 
-                       loadDebugFile ("/var/tmp/debug.log");
+                       loadDebugFile ("debug.log");
                }
 
                void loadDebugFile (string logFile)
index 7a62fd8c96e27e1da7f5956d292c6f00389ff6aa..73b9744845eef569dfe3c474b64913d9b188d82c 100644 (file)
@@ -16,6 +16,7 @@ namespace PerfTests
                readonly bool resetItors = false;
                readonly bool screenOutput = false;
                readonly string inDirectory = "Interfaces";//directory to test
+               readonly string outFilePath;
 
 
         Stream outStream;
@@ -24,7 +25,8 @@ namespace PerfTests
                bool logToDisk => writer != null;
 
                void writeHeader (TextWriter txtWriter) {
-                       txtWriter.WriteLine ($"Crow perf test ({clientRectangle.Width} X {clientRectangle.Height}), repeat count = {count}, reset style and templates = {resetItors}");
+                       txtWriter.WriteLine ($"Crow perf test ({clientRectangle.Width} X {clientRectangle.Height}), output to screen = { screenOutput }");
+                       txtWriter.WriteLine ($"repeat = {count}, update cycles = {updateCycles} reset Instantiators = {resetItors}");
                        txtWriter.WriteLine ($"git:{ThisAssembly.Git.Commit} {ThisAssembly.Git.Branch} {ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Minor}.{ThisAssembly.Git.SemVer.Patch} {ThisAssembly.Git.SemVer.Label}");
                }
 
@@ -39,6 +41,7 @@ namespace PerfTests
                        Console.WriteLine ("-r,--reset:\n\tenable clear iterators after each test file.");
                        Console.WriteLine ("-u,--update:\n\tmeasure 'n' update cycle with DateTime.Now string notified.");
                        Console.WriteLine ("-s,--screen:\n\tenable output to screen.");
+                       Console.WriteLine ("--help:\n\tthis help message.");
                }
 
                public TestInterface (string[] args, int width = 800, int height = 600)
@@ -86,7 +89,7 @@ namespace PerfTests
                                        case "--screen":
                                                screenOutput = true;
                                                break;
-
+                                       case "--help":
                                        default:                                                
                                                throw new Exception ();
                                        }
@@ -107,7 +110,8 @@ namespace PerfTests
                                        Directory.CreateDirectory (dirName);
 
                                string filename = "crow-" + DateTime.Now.ToString ("yyyy-MM-dd-HH-mm") +".perflog";
-                               outStream = new FileStream (Path.Combine (dirName, filename), FileMode.Create);
+                               outFilePath = Path.Combine (dirName, filename);
+                               outStream = new FileStream (outFilePath, FileMode.Create);
                                writer = new StreamWriter (outStream);
                                writeHeader (writer);
                                writer.WriteLine ("Path;Min;Mean;Max;Allocated;LostMem");
@@ -127,6 +131,9 @@ namespace PerfTests
                                throw new FileNotFoundException ("Input directory not found: " + dirName);
 
                        testDir (dirName);
+                       
+                       if (logToDisk)
+                               Console.WriteLine ($"\ntest log written to: {outFilePath}");            
                }
 
                protected override void Dispose (bool disposing) {
@@ -222,6 +229,7 @@ namespace PerfTests
                                        double lostMem = (double)(totMemAfter - totMemBefore) / 1024.0;
                                        if (logToDisk) {
                                                writer.WriteLine ($"{f};{min};{mean};{max};{allocAfter - allocBefore};{totMemAfter - totMemBefore}");
+                                               Console.Write (".");
                     } else {
                                                if (miliseconds)
                                                        Console.WriteLine ($"{label,-50}|{min,10}|{mean,10}|{max,10}| {allocated,8:0.0} | {lostMem,8:0.0} |");
index c5470b40578c925ddcd424cc123fae66406bdb31..278f5ab30cbeb54032863d253b77a2c644e1aa2f 100644 (file)
@@ -2,7 +2,7 @@
   "profiles": {
     "PerfTests": {
       "commandName": "Project",
-      "commandLineArgs": "-c 5 -u 99 -s -i Interfaces/PerfLabels"
+      "commandLineArgs": "-c 20 -u 99 -s -i Interfaces/PerfLabels"
     }
   }
 }
\ No newline at end of file
index 8af2c0023e45efd5e4612a31593355f1baec788b..d3b40d6fb8145cf3f09d8aa41581856da1961486 100644 (file)
@@ -175,15 +175,6 @@ namespace ShowCase
 
                        reloadFromFile ();
                }
-               public override bool OnKeyDown (Key key)
-               {
-                       switch (key) {
-                       case Key.F2:
-                               //DbgLogger.save (this);
-                               return true;
-                       }
-                       return base.OnKeyDown (key);
-               }
 
 
                public void goUpDirClick (object sender, MouseButtonEventArgs e)
index 65345be7a61a0df6fef580afb03ee975c6dcaf7e..bdc6608b1c3d4b9909256a83f13014de47291bbf 100644 (file)
@@ -8,6 +8,7 @@ using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Threading;
 using Crow;
+using Glfw;
 
 namespace Crow
 {
@@ -261,5 +262,25 @@ namespace Crow
                        base.OnInitialized ();
                }
 
+               public override bool OnKeyDown (Key key) {
+                       
+                       switch (key) {
+                       case Key.F5:
+                               Load ("Interfaces/Divers/testFileDialog.crow").DataSource = this;
+                               return true;
+                       case Key.F6:
+                               Load ("Interfaces/Divers/0.crow").DataSource = this;
+                               return true;
+                       case Key.F7:
+                               Load ("Interfaces/Divers/perfMeasures.crow").DataSource = this;
+                               return true;
+                       case Key.F2:
+                               if (IsKeyDown (Key.LeftShift))
+                                       DbgLogger.Reset ();
+                               DbgLogger.Save (this);
+                               return true;
+                       }
+                       return base.OnKeyDown (key);
+               }
        }
 }
\ No newline at end of file
index 9f9464c9d280ac2b7e69f21661c8790eb95bf33c..581bab06dc24be0fe3babddd23361f1139f9d04c 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
 <Container Margin="20" Background="Red" >
-       <Container Margin="20" Background="Green" MouseDown="{../go1.Visible=True}" >
+       <!--<Container Margin="20" Background="Green" MouseDown="{../go1.Visible=True}" >
                <Widget Name="go1" Margin="20" Background="DimGrey" Visible="false" MouseDown="{Visible=false}"
                        MouseEnter="{Background=Blue}"
                        MouseLeave="{Background=DimGrey}"/>
-       </Container>
+       </Container>-->
 </Container>
diff --git a/Samples/common/ui/Interfaces/Experimental/testDock2.crow b/Samples/common/ui/Interfaces/Experimental/testDock2.crow
deleted file mode 100644 (file)
index d4eb29a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<Docker >
-       <DockWindow Left="100" Top="100" Width="150" Height="150" Background="DarkRed"/>
-       <DockWindow Left="200" Top="200" Width="150" Height="150" Background="DarkGreen"/>
-       <DockWindow Left="300" Top="300" Width="150" Height="150" Background="Blue"/>
-       <DockWindow Left="400" Top="400" Width="150" Height="150" Background="Yellow"/>
-       <DockWindow Left="500" Top="500" Width="150" Height="150" Background="Yellow"/>
-</Docker>
-<!--<Group Background="DimGrey" Margin = "0" Focusable="true" >
-       <Window Top="100" Left="100" Focusable="true" Caption="View 1" Width="300" Height="300"><Widget Background="Green" Focusable="true" MouseEnter="{Background=Grey}" MouseLeave="{Background=Green}"/></Window>
-       <Window Top="200" Left="200" Focusable="true" Caption="View 2" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Blue" MouseEnter="{Background=Grey}" MouseLeave="{Background=Blue}"/></Window>
-       <Window Top="300" Left="300" Focusable="true" Caption="View 3" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Yellow" MouseEnter="{Background=Grey}" MouseLeave="{Background=Yellow}"/></Window>
-       <Window Top="400" Left="400" Focusable="true" Caption="View 4" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Black" MouseEnter="{Background=Grey}" MouseLeave="{Background=Black}"/></Window>
-</Group>-->
-<!--<Docker >
-       <DockWindow Resizable = "true" Top="100" Left="100" Caption="View 1" Width="300" Height="300">
-               <VerticalStack Background="DarkGreen" Focusable="true">
-                       <Label Text="{../../Left}" Background="Black" Width="Stretched"/>
-                       <Label Text="{../../Top}" Background="Black"/>
-                       <Label Text="{../../LogicalParent}" Background="Black"/>
-               </VerticalStack>
-       </DockWindow>
-       <DockWindow Top="200" Left="200" Focusable="true" Caption="View 2" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Blue" MouseEnter="{Background=Grey}" MouseLeave="{Background=Blue}"/></DockWindow>
-       <DockWindow Top="300" Left="300" Focusable="true" Caption="View 3" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Yellow" MouseEnter="{Background=Grey}" MouseLeave="{Background=Yellow}"/></DockWindow>
-       <DockWindow Top="400" Left="400" Focusable="true" Caption="View 4" Resizable = "true" Width="300" Height="300"><Widget Focusable="true" Background="Black" MouseEnter="{Background=Grey}" MouseLeave="{Background=Black}"/></DockWindow>
-</Docker>-->
\ No newline at end of file
diff --git a/Samples/common/ui/Interfaces/PerfLabels/0.crow b/Samples/common/ui/Interfaces/PerfLabels/0.crow
deleted file mode 100644 (file)
index 1430436..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0"?>
-<Label Text="no update in this file"/>
-
diff --git a/Samples/common/ui/Interfaces/PerfLabels/0_single_Label.crow b/Samples/common/ui/Interfaces/PerfLabels/0_single_Label.crow
new file mode 100644 (file)
index 0000000..1430436
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<Label Text="no update in this file"/>
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/0_single_oldLabel.crow b/Samples/common/ui/Interfaces/PerfLabels/0_single_oldLabel.crow
new file mode 100644 (file)
index 0000000..4157b6a
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<OldLabel Text="no update in this file"/>
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/1.crow b/Samples/common/ui/Interfaces/PerfLabels/1.crow
deleted file mode 100644 (file)
index 155e518..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0"?>
-<TextRun Text="{elapsed}" Fit="true" Background="Onyx"/>
-
diff --git a/Samples/common/ui/Interfaces/PerfLabels/1_single_lab_update.crow b/Samples/common/ui/Interfaces/PerfLabels/1_single_lab_update.crow
new file mode 100644 (file)
index 0000000..034518c
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<Label Text="{elapsed}" Fit="true" Background="Onyx"/>
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/1_single_old_update.crow b/Samples/common/ui/Interfaces/PerfLabels/1_single_old_update.crow
new file mode 100644 (file)
index 0000000..1a02ce7
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<OldLabel Text="{elapsed}" Fit="true" Background="Onyx"/>
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/2.crow b/Samples/common/ui/Interfaces/PerfLabels/2.crow
deleted file mode 100644 (file)
index 034518c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0"?>
-<Label Text="{elapsed}" Fit="true" Background="Onyx"/>
-
diff --git a/Samples/common/ui/Interfaces/PerfLabels/2_labels_update.crow b/Samples/common/ui/Interfaces/PerfLabels/2_labels_update.crow
new file mode 100644 (file)
index 0000000..8d944f0
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<HorizontalStack>
+       <VerticalStack Width="20%" Height="Fit">
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+       </VerticalStack>
+       <VerticalStack Width="20%" Height="Fit">
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+               <Label Text="{elapsed}" />
+       </VerticalStack>
+</HorizontalStack>
+
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/2_old_labels_update.crow b/Samples/common/ui/Interfaces/PerfLabels/2_old_labels_update.crow
new file mode 100644 (file)
index 0000000..f55bedc
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<HorizontalStack>
+       <VerticalStack Width="20%" Height="Fit">
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+       </VerticalStack>
+       <VerticalStack Width="20%" Height="Fit">
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+               <OldLabel Text="{elapsed}" />
+       </VerticalStack>        
+</HorizontalStack>
+
+
diff --git a/Samples/common/ui/Interfaces/PerfLabels/labels.crow b/Samples/common/ui/Interfaces/PerfLabels/labels.crow
deleted file mode 100644 (file)
index 57c49ad..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0"?>
-<HorizontalStack>
-       <VerticalStack Width="20%" Height="Fit">
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-       </VerticalStack>
-       <VerticalStack Width="20%" Height="Fit">
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-       </VerticalStack>
-       <VerticalStack Width="20%" Height="Fit">
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-       </VerticalStack>
-       <VerticalStack Width="20%" Height="Fit">
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-               <Label Text="{elapsed}" />
-       </VerticalStack>
-</HorizontalStack>
-
-