]> O.S.I.I.S - jp/crow.git/commitdiff
Label with TextBuffer wip
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 7 Mar 2025 13:44:53 +0000 (14:44 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 7 Mar 2025 13:44:53 +0000 (14:44 +0100)
Crow/Default.style
Crow/src/ExtensionsMethods.cs
Crow/src/IML/Instantiator.cs
Crow/src/Widgets/Label2.cs [new file with mode: 0644]
Drawing2D/src/TextBuffer.cs
Samples/common/ui/Interfaces/Experimental/label2.crow [new file with mode: 0644]

index 34fb5899d3ebfb0451c73dfa12ab3dca72993209..239f52de525b218e71b28240c6e983eead63d78a 100644 (file)
@@ -368,3 +368,11 @@ MessageBox, Popper, Slider, Spinner, TextInheritBox, NumericControl {
 TemplatedControl, GenericStack, Image {
        CacheEnabled="true";
 }
+Label2 {
+       Height = "Fit";
+       Width = "Fit";
+       Margin = "0";
+       ClipToClientRect = "false";
+       MouseEnter = "{Background=Blue}";
+       MouseLeave = "{Background=Transparent}";
+}
index 302caec9a4eb796e27ef8abc860ec4fe4fbaaa16..99d4d4bb615d897181931648a17d91a855813a3d 100644 (file)
@@ -10,6 +10,8 @@ using System.Linq.Expressions;
 using System.Reflection;
 
 using Drawing2D;
+using System.Reflection.PortableExecutable;
+using Glfw;
 
 namespace Crow
 {
@@ -195,6 +197,16 @@ namespace Crow
                                return null;
                        }
                }
+               public static int Count(this ReadOnlySpan<char> chars, char c) {
+                       int count = 0, pos = 0;
+
+                       while(pos < chars.Length) {
+                               if (chars[pos] == c)
+                                       count++;
+                               pos++;
+                       }
+                       return count;
+               }
        }
 }
 
index 40f6e580a902549c6d6e61e1bebc50fb349f2503..8d3fe05935d5fdf40d9ef20633c9cd1631bfa4bf 100644 (file)
@@ -56,7 +56,7 @@ namespace Crow.IML {
                public static int NextInstantiatorID = 0;
                public int currentInstantiatorID = 0;
                int currentDesignID = 0;
-               internal string NextDesignID { get { return string.Format ("{0}_{1}",currentInstantiatorID, currentDesignID++); }}
+               internal string NextDesignID => string.Format ("{0}_{1}",currentInstantiatorID, currentDesignID++);
 #endif
 
                #region CTOR
diff --git a/Crow/src/Widgets/Label2.cs b/Crow/src/Widgets/Label2.cs
new file mode 100644 (file)
index 0000000..d8ab257
--- /dev/null
@@ -0,0 +1,1049 @@
+// Copyright (c) 2013-2022  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.Linq;
+
+using System.ComponentModel;
+using Glfw;
+
+using Crow.Text;
+using Drawing2D;
+
+namespace Crow
+{
+    /// <summary>
+    /// Simple label widget possibly multiline but without tabulation handling.
+    /// </summary>
+    public class Label2 : ScrollingObject, IEditableTextWidget
+    {
+               #region CTOR
+               protected Label2 () {
+                       initCommands ();                        
+               }
+               public Label2(Interface iface, string style = null) : base (iface, style) { }
+        #endregion
+        protected override void onInitialized(object sender, EventArgs e)
+        {
+                       
+            base.onInitialized(sender, e);
+        }
+
+               TextBuffer buffer = new TextBuffer("");
+               protected bool disableTextChangedEvent;
+
+               public Command CMDCut, CMDCopy, CMDPaste;
+               void initCommands () {
+                       CMDCut = new ActionCommand ("Cut", Cut, "#icons.scissors.svg",  false);
+                       CMDCopy = new ActionCommand ("Copy", Copy, "#icons.copy-file.svg",  false);
+                       CMDPaste = new ActionCommand ("Paste", Paste, "#icons.paste-on-document.svg",  true);
+
+                       ContextCommands = new CommandGroup (CMDCut, CMDCopy, CMDPaste);
+               }
+
+               public event EventHandler<TextChangeEventArgs> TextChanged;
+               public event EventHandler<TextSelectionChangeEventArgs> SelectionChanged;
+               public virtual void OnTextChanged(object sender, TextChangeEventArgs e)
+               {
+                       TextChanged.Raise (this, e);
+               }
+               public virtual void OnSelectionChanged(Object sender, TextSelectionChangeEventArgs e)
+               {
+                       SelectionChanged.Raise (this, e);
+               }
+
+               #region Label
+               [DefaultValue("label")]
+        public string Text
+        {
+                       get => buffer.Span.ToString();
+            set
+            {
+                               if (buffer.ReadOnlySpan.SequenceEqual (value.AsSpan ()))
+                    return;
+
+                               update(new TextChange (0, buffer.Length, value));
+                               NotifyValueChanged ("Text", Text);
+            }
+        }
+               double targetColumn = -1;//handle line changes with long->short->long line length sequence.
+
+               protected CharLocation? hoverLoc = null;
+               protected CharLocation? currentLoc = null;
+               protected CharLocation? selectionStart = null;  //selection start (row,column)
+
+               protected virtual CharLocation? CurrentLoc {
+                       get => currentLoc;
+                       set {
+                               if (currentLoc == value)
+                                       return;
+                               currentLoc = value;
+                               NotifyValueChanged ("CurrentLine", CurrentLine);
+                               NotifyValueChanged ("CurrentColumn", CurrentColumn);
+                               NotifyValueChanged ("TabulatedColumn", TabulatedColumn);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+                       }
+               }
+               public int CurrentLine {
+                       get => currentLoc.HasValue ? currentLoc.Value.Line : 0;
+                       set {
+                               if (currentLoc?.Line == value)
+                                       return;
+                               currentLoc = new CharLocation (value, currentLoc.Value.Column, currentLoc.Value.VisualCharXPosition);
+                               NotifyValueChanged ("CurrentLine", CurrentLine);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+                       }
+               }
+               public int CurrentColumn {
+                       get => currentLoc.HasValue ? currentLoc.Value.Column < 0 ? 0 : currentLoc.Value.Column : 0;
+                       set {
+                               if (CurrentColumn == value)
+                                       return;
+                               currentLoc = new CharLocation (currentLoc.Value.Line, value);
+                               NotifyValueChanged ("CurrentColumn", CurrentColumn);
+
+                               CMDCopy.CanExecute = CMDCut.CanExecute = !SelectionIsEmpty;
+                       }
+               }
+               public int TabulatedColumn {
+                       get => currentLoc.HasValue ? currentLoc.Value.TabulatedColumn < 0 ? 0 : currentLoc.Value.TabulatedColumn : 0;
+               }
+
+               /// <summary>
+               /// Set current cursor position in label.
+               /// </summary>
+               /// <param name="position">Absolute character position in text.</param>
+               public void SetCursorPosition (int position) {
+                       CharLocation loc = buffer.GetLocation (position);
+                       loc.Column = Math.Min (loc.Column, buffer.GetLine (loc.Line).Length);
+                       CurrentLoc = loc;
+               }
+
+               Color selForeground, selBackground;
+
+               protected bool textMeasureIsUpToDate = false;
+               //protected object linesMutex = new object ();
+
+               protected Size cachedTextSize = default (Size);
+               protected FontExtents fe;
+               protected TextExtents te;
+               protected int tabSize;
+               TextAlignment _textAlignment;
+
+               /// <summary>
+               /// Background color for selected text inside this label.
+               /// </summary>
+               [DefaultValue ("LightSteelBlue")]
+               public virtual Color SelectionBackground {
+                       get { return selBackground; }
+                       set {
+                               if (selBackground == value)
+                                       return;
+                               selBackground = value;
+                               NotifyValueChangedAuto (selBackground);
+                               RegisterForRedraw ();
+                       }
+               }
+               /// <summary>
+               /// Selected text color inside this label.
+               /// </summary>
+               [DefaultValue("White")]
+               public virtual Color SelectionForeground {
+                       get { return selForeground; }
+                       set {
+                               if (selForeground == value)
+                                       return;
+                               selForeground = value;
+                               NotifyValueChangedAuto (selForeground);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue(4)]
+               public int TabSize {
+                       get => tabSize;
+                       set {
+                               if (tabSize == value)
+                                       return;
+                               tabSize = value;
+                               NotifyValueChanged("TabSize",tabSize);
+                       }
+               }
+               [DefaultValue(TextAlignment.Left)]
+               public TextAlignment TextAlignment
+        {
+            get { return _textAlignment; }
+            set {
+                               if (value == _textAlignment)
+                                       return;
+                               _textAlignment = value;
+
+                               CurrentLoc?.ResetVisualX ();
+                               SelectionStart?.ResetVisualX ();
+
+                               RegisterForRedraw ();
+                               NotifyValueChangedAuto (_textAlignment);
+                       }
+        }              
+               protected double lineHeight => fe.Ascent + fe.Descent;
+
+               protected virtual int getAbsoluteLineIndexFromVisualLineMove (int startLine, int visualLineDiff)
+                       => Math.Min (Math.Max (0, startLine + visualLineDiff), visualLineCount - 1);
+               /// <summary>
+               /// Moves cursor one char to the left.
+               /// </summary>
+               /// <returns><c>true</c> if move succeed</returns>
+               public bool MoveLeft(){
+                       targetColumn = -1;
+                       CharLocation loc = CurrentLoc.Value;
+                       if (loc.Column == 0) {
+                               if (loc.Line == 0)
+                                       return false;
+                               int newLine = getAbsoluteLineIndexFromVisualLineMove (loc.Line, -1);
+                               loc = new CharLocation (newLine, buffer.GetLine (newLine).Length);
+                       }else
+                               loc = new CharLocation (loc.Line, loc.Column - 1);
+                       updateLocation(ref loc);
+                       CurrentLoc = loc;
+                       return true;
+               }
+               public bool MoveRight () {
+                       targetColumn = -1;
+                       CharLocation loc = CurrentLoc.Value;
+                       if (loc.Column == buffer.GetLine (loc.Line).Length) {
+                               if (loc.Line == buffer.LinesCount - 1)
+                                       return false;
+                               loc = new CharLocation (
+                                       getAbsoluteLineIndexFromVisualLineMove (loc.Line, 1), 0);
+                       } else
+                               loc = new CharLocation (loc.Line, loc.Column + 1);
+                       updateLocation(ref loc);
+                       CurrentLoc = loc;                       
+                       return true;
+               }
+               public bool LineMove (int lineDiff) {
+                       if (!CurrentLoc.HasValue)
+                               return false;
+
+                       CharLocation loc = CurrentLoc.Value;
+                       int newLine = getAbsoluteLineIndexFromVisualLineMove (loc.Line, lineDiff);
+                       if (newLine == loc.Line)
+                               return false;
+
+                       using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
+                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                               gr.SetFontSize (Font.Size);
+                               CharLocation newLoc;
+                               double targetX;
+                               if (targetColumn > 0) {
+                                       targetX = targetColumn;
+                               } else {
+                                       if (!loc.HasVisualX)
+                                               updateLocation(gr, ref loc);
+                                       targetX = loc.VisualCharXPosition;
+                               }
+
+                               newLoc = new CharLocation(newLine, -1, targetX);
+                               updateLocation(ref newLoc);
+
+                               if (newLoc.VisualCharXPosition < targetX) {
+                                       if (targetColumn < 0)
+                                               targetColumn = loc.VisualCharXPosition;
+                               } else {
+                                       targetColumn = -1;
+                               }
+
+                               CurrentLoc = newLoc;
+                       }
+
+                       /*if (loc.Column > document.GetLine (newLine).Length) {
+                               if (targetColumn < 0)
+                                       targetColumn = loc.Column;
+                               CurrentLoc = new CharLocation (newLine, document.GetLine (newLine).Length);
+                       } else if (targetColumn < 0)
+                               CurrentLoc = new CharLocation (newLine, loc.Column);
+                       else if (targetColumn > document.GetLine (newLine).Length)
+                               CurrentLoc = new CharLocation (newLine, document.GetLine (newLine).Length);
+                       else
+                               CurrentLoc = new CharLocation (newLine, targetColumn);*/
+
+                       return true;
+               }
+
+               /// <summary>
+               /// Current Selected text span. May be used to set current position, or current selection.
+               /// </summary>
+               public TextSpan Selection {
+                       set {
+                               if (value.IsEmpty)
+                                       SelectionStart = null;
+                               else
+                                       SelectionStart = buffer.GetLocation (value.Start);
+                               CurrentLoc = buffer.GetLocation (value.End);
+                       }
+                       get {
+                               if (CurrentLoc == null)
+                                       return default;
+                               CharLocation selStart = CurrentLoc.Value, selEnd = CurrentLoc.Value;
+                               if (selectionStart.HasValue) {
+                                       if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
+                                               selStart = CurrentLoc.Value;
+                                               selEnd = selectionStart.Value;
+                                       } else {
+                                               selStart = selectionStart.Value;
+                                               selEnd = CurrentLoc.Value;
+                                       }
+                               }
+                               return new TextSpan (buffer.GetAbsolutePosition (selStart), buffer.GetAbsolutePosition (selEnd));
+                       }
+               }
+               public string SelectedText {
+                       get {
+                               TextSpan selection = Selection;
+                               return selection.IsEmpty ? "" : buffer.GetText (selection).ToString ();
+                       }
+               }
+               public bool SelectionIsEmpty => selectionStart.HasValue ? Selection.IsEmpty : true;
+               public CharLocation? SelectionStart {
+                       get => selectionStart;
+                       set {
+                               if (selectionStart == value)
+                                       return;
+                               selectionStart = value;
+                               if (SelectionChanged != null)
+                                       OnSelectionChanged (this, new TextSelectionChangeEventArgs (Selection));
+                       }
+               }               
+               /// <summary>
+               /// on screen visible line bounded by the client rectangle
+               /// </summary>
+               protected int visibleLines => (int)Math.Ceiling(ClientRectangle.Height / lineHeight);
+               /// <summary>
+               /// total line count
+               /// </summary>
+               protected virtual int visualLineCount => buffer.LinesCount;
+
+               protected virtual void measureTextBounds (IContext gr) {
+                       fe = gr.FontExtents;
+                       te = new TextExtents ();
+
+                       try {
+
+                               cachedTextSize.Height = (int)Math.Ceiling (lineHeight * Math.Max (1, visualLineCount));
+
+                               TextExtents tmp = default;
+                               int longestLine = 0;
+                               for (int i = 0; i < buffer.LinesCount; i++) {
+                                       TextLine l = buffer.GetLine (i);
+                                       if (l.LengthInPixel < 0) {
+                                               if (l.Length == 0)
+                                                       l.LengthInPixel = 0;// (int)Math.Ceiling (fe.MaxXAdvance);
+                                               else {
+                                                       gr.TextExtents (buffer.GetText (l), Interface.TAB_SIZE, out tmp);
+                                                       l.LengthInPixel = (int)Math.Ceiling (tmp.XAdvance);
+                                                       buffer.SetLine(i, l);
+                                               }
+                                       }
+                                       if (l.LengthInPixel > buffer.GetLine (longestLine).LengthInPixel)
+                                               longestLine = i;
+                               }
+                               cachedTextSize.Width = buffer.GetLine (longestLine).LengthInPixel;
+                               textMeasureIsUpToDate = true;
+
+                               updateMaxScrolls (LayoutingType.Height);
+                               updateMaxScrolls (LayoutingType.Width);
+                       } finally {
+                               
+                       }
+               }
+               protected virtual void drawContent (IContext gr) {                      
+                       Rectangle cb = ClientRectangle;
+                       fe = gr.FontExtents;
+                       double lineHeight = fe.Ascent + fe.Descent;
+
+                       CharLocation selStart = default, selEnd = default;
+                       bool selectionNotEmpty = false;
+
+                       gr.Translate (-ScrollX, 0);
+
+                       //document.EnterReadLock();
+                       
+                       try {
+                               //if (HasFocus) {
+                                       if (currentLoc?.Column < 0) {
+                                               updateLocation (gr, ref currentLoc);
+                                       } else
+                                               updateLocation (gr, ref currentLoc);
+                                       if (selectionStart.HasValue) {
+                                               updateLocation (gr, ref selectionStart);
+                                               if (CurrentLoc.Value != selectionStart.Value)
+                                                       selectionNotEmpty = true;
+                                       }
+                                       if (selectionNotEmpty) {
+                                               if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
+                                                       selStart = CurrentLoc.Value;
+                                                       selEnd = selectionStart.Value;
+                                               } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
+                                                       selStart = selectionStart.Value;
+                                                       selEnd = CurrentLoc.Value;
+                                               } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
+                                                       selStart = CurrentLoc.Value;
+                                                       selEnd = selectionStart.Value;
+                                               } else {
+                                                       selStart = selectionStart.Value;
+                                                       selEnd = CurrentLoc.Value;
+                                               }
+                                       }
+                               //}
+
+                               if (buffer.Length > 0) {
+                                       int skippedLines = (int)Math.Floor(ScrollY / lineHeight);
+                                       int curLine = skippedLines;
+                                       double y = -(ScrollY % lineHeight);
+
+                                       Foreground?.SetAsSource (IFace, gr);
+
+                                       TextExtents extents;
+                                       Span<byte> bytes = stackalloc byte[128];
+                                       
+                                       while (curLine < buffer.LinesCount && curLine - skippedLines < visibleLines) {
+                                               
+                                               int encodedBytes = -1;
+                                               TextLine l = buffer.GetLine (curLine);
+                                               if (l.Length > 0) {
+                                                       int size = l.Length * 4 + 1;
+                                                       if (bytes.Length < size)
+                                                               bytes = new byte[size];
+
+                                                       encodedBytes = buffer.GetText (l).ToUtf8 (bytes);
+                                                       bytes[encodedBytes++] = 0;
+
+                                                       if (l.LengthInPixel < 0) {
+                                                               gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+                                                               l.LengthInPixel = (int)extents.XAdvance;
+                                                               buffer.SetLine(curLine, l);
+                                                       }
+                                               }
+
+                                               RectangleD lineRect = new RectangleD (
+                                                       (int)cb.X,
+                                                       y + cb.Top, l.LengthInPixel, lineHeight);
+
+                                               if (encodedBytes > 0) {
+                                                       gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+                                                       gr.ShowText (bytes.Slice (0, encodedBytes));
+                                               }
+                                               /********** DEBUG TextLineCollection *************
+                                               gr.SetSource (Colors.Red);
+                                               gr.SetFontSize (9);
+                                               gr.MoveTo (700, lineRect.Y + fe.Ascent);
+                                               gr.ShowText ($"({lines[i].Start}, {lines[i].End}, {lines[i].EndIncludingLineBreak})");
+                                               gr.SetFontSize (Font.Size);
+                                               Foreground.SetAsSource (IFace, gr);
+                                               ********** DEBUG TextLineCollection *************/
+
+                                               if (selectionNotEmpty) {
+                                                       RectangleD selRect = lineRect;
+
+                                                       if (curLine >= selStart.Line && curLine <= selEnd.Line) {
+                                                               if (selStart.Line == selEnd.Line) {
+                                                                       selRect.X = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
+                                                               } else if (curLine == selStart.Line) {
+                                                                       double newX = selStart.VisualCharXPosition + cb.X;
+                                                                       selRect.Width -= (newX - selRect.X) - 10.0;
+                                                                       selRect.X = newX;
+                                                               } else if (curLine == selEnd.Line) {
+                                                                       selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
+                                                               } else
+                                                                       selRect.Width += 10.0;
+                                                       } else {
+                                                               y += lineHeight;
+                                                               curLine++;
+                                                               continue;
+                                                       }
+
+                                                       gr.SetSource (selBackground);
+                                                       gr.Rectangle (selRect);
+                                                       if (encodedBytes < 0)
+                                                               gr.Fill ();
+                                                       else {
+                                                               gr.FillPreserve ();
+                                                               gr.Save ();
+                                                               gr.Clip ();
+                                                               gr.SetSource (SelectionForeground);
+                                                               gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+                                                               gr.ShowText (bytes.Slice (0, encodedBytes));
+                                                               gr.Restore ();
+                                                       }
+                                                       Foreground.SetAsSource (IFace, gr);
+                                               }
+                                       
+                                               y += lineHeight;
+                                               curLine++;
+                                       }
+                               }
+                       } finally {
+                               //document.ExitReadLock ();
+                       }
+
+                       gr.Translate (ScrollX, 0);
+               }
+               protected int getLineIndexFromMousePosition (Point mouseLocalPos) =>
+                       (int)Math.Min (Math.Max (0, Math.Floor ((mouseLocalPos.Y + ScrollY)/ lineHeight)), visualLineCount - 1);
+               protected int getVisualLineIndex (Point mouseLocalPos) =>
+                       (int)Math.Min (Math.Max (0, Math.Floor (mouseLocalPos.Y / lineHeight)), visibleLines - 1);
+               protected virtual int visualCurrentLine => CurrentLoc.HasValue ? CurrentLoc.Value.Line : 0;
+
+               protected virtual void updateHoverLocation (Point mouseLocalPos) {
+                       int hoverLine = getLineIndexFromMousePosition (mouseLocalPos);
+                       NotifyValueChanged("MouseY", mouseLocalPos.Y + ScrollY);
+                       NotifyValueChanged("ScrollY", ScrollY);
+                       NotifyValueChanged("VisibleLines", visibleLines);
+                       NotifyValueChanged("HoverLine", hoverLine);
+                       CharLocation newLoc = new CharLocation (hoverLine, -1, mouseLocalPos.X + ScrollX);
+                       updateLocation (ref newLoc);
+                       hoverLoc = newLoc;
+               }
+               RectangleD? textCursor = null;
+
+               public virtual bool DrawCursor (IContext ctx, out Rectangle rect) {
+                       if (CurrentLoc == null) {
+                               rect = default;
+                               return false;
+                       }
+                       CharLocation loc = currentLoc.Value;
+
+                       if (!loc.HasVisualX) {
+                               ctx.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                               ctx.SetFontSize (Font.Size);
+
+                               if (currentLoc?.Column < 0) {
+                                       updateLocation (ctx, ref loc);
+                                       //update is locked, should not notify while updating graphics
+                                       //NotifyValueChanged ("CurrentColumn", CurrentColumn);
+                               } else
+                                       updateLocation (ctx, ref loc);
+
+                               textCursor = null;
+                       }
+                       currentLoc = loc;
+
+                       textCursor = computeTextCursor (new RectangleD (loc.VisualCharXPosition, lineHeight * visualCurrentLine, 1.0, lineHeight));
+
+                       if (textCursor == null) {
+                               rect = default;
+                               return false;
+                       }
+
+                       Rectangle c = ContextCoordinates (textCursor.Value + Slot.Position + ClientRectangle.Position);
+                       Foreground.SetAsSource (IFace, ctx, c);
+                       ctx.LineWidth = 1.0;
+                       ctx.MoveTo (0.5 + c.X, c.Y);
+                       ctx.LineTo (0.5 + c.X, c.Bottom);
+                       ctx.Stroke ();
+                       rect = c;
+                       return true;
+               }
+               protected void updateLocation(ref CharLocation loc) {
+                       if (loc.HasVisualX)
+                               return;
+                       using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
+                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                               gr.SetFontSize (Font.Size);
+                               updateLocation(gr, ref loc);
+                       }                               
+               }
+               [Obsolete("use override without clientWidth parameter")]                
+               protected void updateLocation (IContext gr, int clientWidth, ref CharLocation? location) {
+                       if (location == null)
+                               return;
+                       CharLocation loc = location.Value;
+                       updateLocation(gr, ref loc);
+                       location = loc;
+               }
+               protected void updateLocation (IContext gr, ref CharLocation? location) {
+                       if (location == null)
+                               return;
+                       CharLocation loc = location.Value;
+                       updateLocation(gr, ref loc);
+                       location = loc;
+               }                       
+               protected void updateLocation (IContext gr, ref CharLocation loc) {
+                       if (loc.HasVisualX)
+                               return;
+                       
+                       ReadOnlySpan<char> curLine = buffer.GetText(buffer.GetLine (loc.Line));
+                       if (loc.Column >= 0) {
+                               //int encodedBytes = Crow.Text.Encoding2.ToUtf8 (curLine.Slice (0, loc.Column), bytes);
+#if DEBUG
+                               if (loc.Column > curLine.Length) {
+                                       System.Diagnostics.Debug.WriteLine ($"loc.Column: {loc.Column} curLine.Length:{curLine.Length}");
+                                       loc.Column = curLine.Length;
+                               }
+#endif
+                               ReadOnlySpan<char> buff = curLine.Slice (0, loc.Column);
+                               loc.TabulatedColumn = buff.Count('\t') * (tabSize-1) + buff.Length;
+                               loc.VisualCharXPosition = gr.TextExtents (buff).XAdvance;
+                       } else {
+                               TextExtents te;
+                               Span<byte> bytes = stackalloc byte[5];//utf8 single char buffer + '\0'
+                               int totChar = 0;
+                               double cPos = 0;
+
+                               for (int i = 0; i < curLine.Length; i++) {
+                                       int encodedBytes = curLine.Slice (i, 1).ToUtf8 (bytes, ref totChar, tabSize);
+                                       bytes[encodedBytes] = 0;
+
+                                       gr.TextExtents (bytes, out te);
+                                       double halfWidth = te.XAdvance / 2;
+
+                                       if (loc.VisualCharXPosition <= cPos + halfWidth) {
+                                               loc.Column = i;
+                                               loc.VisualCharXPosition = cPos;
+                                               loc.TabulatedColumn = totChar;
+                                               return;
+                                       }
+
+                                       cPos += te.XAdvance;
+                               }
+                               loc.Column = curLine.Length;
+                               loc.VisualCharXPosition = cPos;
+                               loc.TabulatedColumn = totChar;
+                       }
+               }
+               /*protected void updateLocation (IContext gr, int clientWidth, ref CharLocation? location) {
+                       if (location == null)
+                               return;
+                       CharLocation loc = location.Value;
+                       //Console.WriteLine ($"updateLocation: {loc} text:{_text.Length}");
+                       if (loc.HasVisualX)
+                               return;
+                       if (loc.Column == 0) {
+                               loc.VisualCharXPosition = 0;
+                       } else {
+
+                               TextLine ls = document.GetLine (loc.Line);
+                               ReadOnlySpan<char> curLine = document.GetText (ls);                     
+                               double cPos = 0;
+
+                               if (loc.Column >= 0) {
+                                       //int encodedBytes = Crow.Text.Encoding2.ToUtf8 (curLine.Slice (0, loc.Column), bytes);
+       #if DEBUG
+                                       if (loc.Column > curLine.Length) {
+                                               System.Diagnostics.Debug.WriteLine ($"loc.Column: {loc.Column} curLine.Length:{curLine.Length}");
+                                               loc.Column = curLine.Length;
+                                       }
+       #endif
+                                       Span<byte> bytes = stackalloc byte[loc.Column*4+10];
+                                       int encodedBytes = curLine.Slice (0,loc.Column).ToUtf8 (bytes, 4);
+                                       bytes[encodedBytes++] = 0;
+                                       gr.TextExtents (bytes, out TextExtents te);
+                                       loc.VisualCharXPosition = te.XAdvance;
+                               } else {
+                                       TextExtents te;
+                                       Span<byte> bytes = stackalloc byte[5];//utf8 single char buffer + '\0'
+
+                                       for (int i = 0; i < ls.Length; i++) {
+                                               int encodedBytes = curLine.Slice (i, 1).ToUtf8 (bytes);
+                                               bytes[encodedBytes] = 0;
+
+                                               gr.TextExtents (bytes, out te);
+                                               double halfWidth = te.XAdvance / 2;
+
+                                               if (loc.VisualCharXPosition <= cPos + halfWidth) {
+                                                       loc.Column = i;
+                                                       loc.VisualCharXPosition = cPos;
+                                                       location = loc;
+                                                       return;
+                                               }
+
+                                               cPos += te.XAdvance;
+                                       }
+                                       loc.Column = ls.Length;
+                                       loc.VisualCharXPosition = cPos;
+                               }
+                       }
+                       location = loc;
+               }*/
+
+               protected void checkShift (KeyEventArgs e) {
+                       if (e.Modifiers.HasFlag (Modifier.Shift)) {
+                               if (!selectionStart.HasValue)
+                                       SelectionStart = CurrentLoc;
+                       } else
+                               SelectionStart = null;
+               }
+
+               #region GraphicObject overrides
+               public override void OnLayoutChanges (LayoutingType layoutType) {
+                       base.OnLayoutChanges (layoutType);
+                       updateMaxScrolls (layoutType);
+               }
+               /*public override bool UpdateLayout (LayoutingType layoutType) {
+                       if ((LayoutingType.Sizing | layoutType) != LayoutingType.None) {
+                               if (!System.Threading.Monitor.TryEnter (linesMutex))
+                                       return false;
+                       }
+                       try {
+                               bool result = base.UpdateLayout (layoutType);
+                               return result;
+                       } finally {
+                               System.Threading.Monitor.Exit (linesMutex);
+                       }
+               }*/
+               public override int measureRawSize(LayoutingType lt)
+               {
+                       DbgLogger.StartEvent(DbgEvtType.GOMeasure, this, lt);
+                       try {
+                               if (!textMeasureIsUpToDate) {
+                                       using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
+                                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                               gr.SetFontSize (Font.Size);
+                                               measureTextBounds (gr);
+                                       }
+                               }
+                               return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width);
+                       } finally {
+                               DbgLogger.EndEvent(DbgEvtType.GOMeasure);
+                       }
+               }
+               protected override void onDraw (IContext gr)
+               {
+                       base.onDraw (gr);
+
+                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                       gr.SetFontSize (Font.Size);
+
+                       if (!textMeasureIsUpToDate) {
+                               measureTextBounds (gr);
+                       }
+
+                       if (ClipToClientRect) {
+                               gr.Save ();
+                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+                               gr.Clip ();
+                       }
+
+                       drawContent (gr);
+
+                       if (ClipToClientRect)
+                               gr.Restore ();
+               }
+        public override bool Paint(IContext ctx)
+        {
+            bool painted = base.Paint(ctx);
+                       if (HasFocus && painted && IFace.drawTextCursor) {
+                               DrawCursor(ctx, out Rectangle r);
+                       }
+                       return painted;
+        }
+               #endregion
+
+               #region Mouse handling
+               protected override void onFocused (object sender, EventArgs e)
+               {
+                       base.onFocused (sender, e);
+
+                       if (CurrentLoc == null)
+                               CurrentLoc = new CharLocation (0, 0);
+
+                       RegisterForRedraw ();
+               }
+               public override void onMouseEnter (object sender, MouseMoveEventArgs e) {
+                       base.onMouseEnter (sender, e);
+                       if (!Focusable)
+                               return;
+                       IFace.MouseCursor = MouseCursor.ibeam;
+               }
+               public override void onMouseMove (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseMove (sender, e);
+                       mouseMove (e);
+               }
+               public override void onMouseWheel(object sender, MouseWheelEventArgs e)
+               {
+                       base.onMouseWheel(sender, e);
+                       mouseMove (e);
+               }
+               protected virtual void mouseMove (MouseEventArgs e) {
+                       updateHoverLocation (ScreenPointToLocal (e.Position));
+
+                       if (HasFocus && IFace.IsDown (MouseButton.Left)) {
+                               CurrentLoc = hoverLoc;
+                               autoAdjustScroll = true;
+                               IFace.forceTextCursor();
+                               RegisterForRedraw ();
+                       }
+               }
+               public override void onMouseDown (object sender, MouseButtonEventArgs e)
+               {
+                       if (!e.Handled && e.Button == Glfw.MouseButton.Left) {
+                               targetColumn = -1;
+                               if (HasFocus) {
+                                       if (!IFace.Shift)
+                                               SelectionStart = hoverLoc;
+                                       else if (!selectionStart.HasValue)
+                                               SelectionStart = CurrentLoc;
+                                       CurrentLoc = hoverLoc;
+                                       IFace.forceTextCursor();
+                                       RegisterForRedraw ();
+                                       e.Handled = true;
+                               }
+                       }
+                       base.onMouseDown (sender, e);
+
+                       //done at the end to set 'hasFocus' value after testing it
+               }
+               public override void onMouseUp (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseUp (sender, e);
+                       if (e.Button != MouseButton.Left || !HasFocus || !selectionStart.HasValue)
+                               return;
+                       if (selectionStart.Value == CurrentLoc.Value)
+                               SelectionStart = null;
+               }
+               public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
+               {
+                       base.onMouseDoubleClick (sender, e);
+                       if (e.Button != MouseButton.Left || !HasFocus)
+                               return;
+
+                       SelectionStart = buffer.GetWordStart (CurrentLoc.Value);
+                       CurrentLoc = buffer.GetWordEnd (CurrentLoc.Value);
+                       RegisterForRedraw ();
+               }
+               #endregion
+
+               #region Keyboard handling
+               public override void onKeyPress (object sender, KeyPressEventArgs e) {
+                       base.onKeyPress (sender, e);
+
+                       if (!e.Handled) {
+                               TextSpan selection = Selection;
+                               update (new TextChange (selection.Start, selection.Length, e.KeyChar.ToString ()));
+
+                               e.Handled = true;
+                       }
+                       /*Insert (e.KeyChar.ToString());
+
+                       SelRelease = -1;
+                       SelBegin = new Point(CurrentColumn, SelBegin.Y);
+
+                       RegisterForGraphicUpdate();*/
+               }
+               public override void onKeyDown (object sender, KeyEventArgs e) {
+                       Key key = e.Key;
+                       TextSpan selection = Selection;
+
+                       /*document.EnterReadLock();
+                       try {*/
+                               switch (key) {
+                               case Key.Backspace:
+                                       if (selection.IsEmpty) {
+                                               if (selection.Start == 0)
+                                                       return;
+                                               if (CurrentLoc.Value.Column == 0) {
+                                                       int lbLength = buffer.GetLine (CurrentLoc.Value.Line - 1).LineBreakLength;
+                                                       update (new TextChange (selection.Start - lbLength, lbLength, ""));
+                                               }else
+                                                       update (new TextChange (selection.Start - 1, 1, ""));
+                                       } else
+                                               update (new TextChange (selection.Start, selection.Length, ""));
+                                       break;
+                               case Key.Delete:
+                                       if (selection.IsEmpty) {
+                                               if (selection.Start == buffer.Length)
+                                                       return;
+                                               if (CurrentLoc.Value.Column >= buffer.GetLine (CurrentLoc.Value.Line).Length)
+                                                       update (new TextChange (selection.Start, buffer.GetLine (CurrentLoc.Value.Line).LineBreakLength, ""));
+                                               else
+                                                       update (new TextChange (selection.Start, 1, ""));
+                                       } else {
+                                               if (e.Modifiers == Modifier.Shift)
+                                                       IFace.Clipboard = SelectedText;
+                                               update (new TextChange (selection.Start, selection.Length, ""));
+                                       }
+                                       break;
+                               case Key.Insert:
+                                       if (e.Modifiers.HasFlag (Modifier.Shift))
+                                               Paste ();
+                                       else if (e.Modifiers.HasFlag (Modifier.Control))
+                                               Copy ();
+                                       break;
+                               case Key.KeypadEnter:
+                               case Key.Enter:
+                                       update (new TextChange (selection.Start, selection.Length, buffer.GetLineBreak ()));
+                                       break;
+                               case Key.Escape:
+                                       SelectionStart = null;
+                                       CurrentLoc = buffer.GetLocation (selection.Start);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Tab:
+                                       update (new TextChange (selection.Start, selection.Length, "\t"));
+                                       break;
+                               case Key.PageUp:
+                                       checkShift (e);
+                                       LineMove (-visibleLines);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.PageDown:
+                                       checkShift (e);
+                                       LineMove (visibleLines);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Home:
+                                       targetColumn = -1;
+                                       checkShift (e);
+                                       if (e.Modifiers.HasFlag (Modifier.Control))
+                                               CurrentLoc = new CharLocation (0, 0);
+                                       else
+                                               CurrentLoc = new CharLocation (CurrentLoc.Value.Line, 0);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.End:
+                                       checkShift (e);
+                                       int l = e.Modifiers.HasFlag (Modifier.Control) ? buffer.LinesCount - 1 : CurrentLoc.Value.Line;
+                                       CurrentLoc = new CharLocation (l, buffer.GetLine (l).Length);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Left:
+                                       checkShift (e);
+                                       if (e.Modifiers.HasFlag (Modifier.Control))
+                                               CurrentLoc = buffer.GetWordStart (CurrentLoc.Value);
+                                       else
+                                               MoveLeft ();
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Right:
+                                       checkShift (e);
+                                       if (e.Modifiers.HasFlag (Modifier.Control))
+                                               CurrentLoc = buffer.GetWordEnd (CurrentLoc.Value);
+                                       else
+                                               MoveRight ();
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Up:
+                                       checkShift (e);
+                                       LineMove (-1);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.Down:
+                                       checkShift (e);
+                                       LineMove (1);
+                                       RegisterForRedraw ();
+                                       break;
+                               case Key.A:
+                                       if (e.Modifiers.HasFlag (Modifier.Control)) {
+                                               SelectionStart = new CharLocation (0, 0);
+                                               CurrentLoc = buffer.EndLocation;
+                                       }
+                                       break;
+                               default:
+                                       base.onKeyDown (sender, e);
+                                       return;
+                               }
+                               autoAdjustScroll = true;
+                               IFace.forceTextCursor();
+                               e.Handled = true;
+                       /*} finally {
+                               document.ExitReadLock ();
+                       }*/
+               }
+               #endregion
+               #endregion
+
+
+               #region textBox
+               protected bool autoAdjustScroll = false;//if scrollXY is changed directly, dont try adjust scroll to cursor
+               protected virtual RectangleD? computeTextCursor (Rectangle cursor) {
+                       Rectangle cb = ClientRectangle;
+                       cursor -= new Point (ScrollX, ScrollY);
+
+                       if (autoAdjustScroll) {
+                               autoAdjustScroll = false;
+                               int goodMsrs = 0;
+                               if (cursor.Left < 0)
+                                       ScrollX += cursor.Left;
+                               else if (cursor.X > cb.Width)
+                                       ScrollX += cursor.X - cb.Width + 5;
+                               else
+                                       goodMsrs++;
+
+                               if (cursor.Y < 0)
+                                       ScrollY += cursor.Y;
+                               else if (cursor.Bottom > cb.Height)
+                                       ScrollY += cursor.Bottom - cb.Height;
+                               else
+                                       goodMsrs++;
+
+                               if (goodMsrs < 2)
+                                       return null;
+                       } else if (cursor.Right < 0 || cursor.X > cb.Width || cursor.Y < 0 || cursor.Bottom > cb.Height)
+                               return null;
+
+                       return cursor;
+               }
+
+               protected virtual void updateMaxScrolls (LayoutingType layout) {
+                       Rectangle cb = ClientRectangle;
+                       if (layout == LayoutingType.Width) {
+                               MaxScrollX = cachedTextSize.Width - cb.Width;
+                               NotifyValueChanged ("PageWidth", ClientRectangle.Width);
+                               if (cachedTextSize.Width > 0)
+                                       NotifyValueChanged ("ChildWidthRatio", Math.Min (1.0, (double)cb.Width / cachedTextSize.Width));
+                       } else if (layout == LayoutingType.Height) {
+                               MaxScrollY = cachedTextSize.Height - cb.Height;
+                               NotifyValueChanged ("PageHeight", ClientRectangle.Height);
+                               if (cachedTextSize.Height > 0)
+                                       NotifyValueChanged ("ChildHeightRatio", Math.Min (1.0, (double)cb.Height / cachedTextSize.Height));
+                       }
+               }
+               public virtual void Cut () {
+                       TextSpan selection = Selection;
+                       if (selection.IsEmpty)
+                               return;
+                       IFace.Clipboard = SelectedText;
+                       update (new TextChange (selection.Start, selection.Length, ""));
+               }
+               public virtual void Copy () {
+                       TextSpan selection = Selection;
+                       if (selection.IsEmpty)
+                               return;
+                       IFace.Clipboard = SelectedText;
+               }
+               public virtual void Paste () {
+                       TextSpan selection = Selection;
+                       update (new TextChange (selection.Start, selection.Length, IFace.Clipboard));
+               }
+
+               protected virtual void update (TextChange change) {
+                       buffer.Update(change);
+                       if (!disableTextChangedEvent)
+                               OnTextChanged (this, new TextChangeEventArgs (change));
+                       if (HasFocus) {
+                               SelectionStart = null;
+                               CharLocation newLoc = change.ChangedText == null ?
+                                       buffer.GetLocation (change.Start)       : buffer.GetLocation (change.Start + change.ChangedText.Length);
+                               updateLocation(ref newLoc);//ensure tabulated column is uptodate on each changes
+                               CurrentLoc = newLoc;
+                       }
+                       textMeasureIsUpToDate = false;
+                       IFace.forceTextCursor();
+                       autoAdjustScroll = true;
+
+                       RegisterForGraphicUpdate ();
+               }
+
+               #endregion
+       }
+}
index 25deb5fe6f274a169169d13ff48bbfbabf430a84..290fb757384f47b83813351b31e2d2d261d6a0b5 100644 (file)
@@ -8,7 +8,7 @@ using System.Collections.Generic;
 using Crow.Text;
 using Crow;
 
-namespace CrowEditBase
+namespace Crow.Text
 {
        public class TextBuffer {
                static int bufferExpension = 100;
@@ -94,6 +94,27 @@ namespace CrowEditBase
                public ReadOnlySpan<char> GetText (TextSpan textSpan) => buffer.Span.Slice(textSpan.Start, textSpan.Length);
                public int GetAbsolutePosition (CharLocation loc) => lines.GetAbsolutePosition (loc);
                public CharLocation EndLocation => new CharLocation (lines.Count - 1, lines[lines.Count - 1].Length);
+               public virtual CharLocation GetWordStart (CharLocation loc) {
+                       int pos = GetAbsolutePosition (loc);
+                       //skip white spaces
+                       ReadOnlySpan<char> txt = ReadOnlySpan;
+                       while (pos > 0 && !char.IsLetterOrDigit (txt[pos-1]))
+                               pos--;
+                       while (pos > 0 && char.IsLetterOrDigit (txt[pos-1]))
+                               pos--;
+                       return GetLocation (pos);
+               }
+               public virtual CharLocation GetWordEnd (CharLocation loc) {
+                       int pos = GetAbsolutePosition (loc);
+                       //skip white spaces
+                       ReadOnlySpan<char> txt = ReadOnlySpan;
+                       while (pos < Length - 1 && !char.IsLetterOrDigit (txt[pos]))
+                               pos++;
+                       while (pos < Length - 1 && char.IsLetterOrDigit (txt[pos]))
+                               pos++;
+                       return GetLocation (pos);
+               }
+
         public override string ToString() => ReadOnlySpan.ToString();
     }
 }
\ No newline at end of file
diff --git a/Samples/common/ui/Interfaces/Experimental/label2.crow b/Samples/common/ui/Interfaces/Experimental/label2.crow
new file mode 100644 (file)
index 0000000..705dce7
--- /dev/null
@@ -0,0 +1,228 @@
+<?xml version="1.0"?>
+<Wrapper>
+       <Label2 Text="{MultilineText}" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="{MultilineText}" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="{MultilineText}" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="{MultilineText}" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+       <Label2 Text="this is a test labeel" Background="Blue" Foreground="WhiteSmoke" Margin="10" Width="Fit" Height="Fit" Focusable="true"/>
+</Wrapper>