]> O.S.I.I.S - jp/crow.git/commitdiff
TextLineCollection.update(TextChange ...)
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Sat, 6 Feb 2021 16:55:00 +0000 (17:55 +0100)
committerj-p <jp_bruyere@hotmail.com>
Sat, 6 Feb 2021 19:28:02 +0000 (20:28 +0100)
Crow/Default.style
Crow/src/Text/TextLine.cs
Crow/src/Text/TextLineCollection.cs
Crow/src/Widgets/Label.cs
Crow/src/Widgets/TextBox.cs
Samples/common/ui/Interfaces/GraphicObject/textBox.crow [new file with mode: 0644]

index 0dc857635dc66117a9e6fb1d25d7d0dcc4b6cade..456376ece4ffe47d6d085c84035b10bc27be464f 100644 (file)
@@ -88,7 +88,6 @@ TextBox {
        Focusable = "True";
        //Text = "TextBox";
        Margin = "1";
-       //MouseCursor = "IBeam";
 }
 Menu {
        Margin = "0";
index f5798a3186cfbb513ca54c0cd8c0fe0794c3798a..14d2ba08ba07797a5f311fee64254da5235dc207 100644 (file)
@@ -35,10 +35,11 @@ namespace Crow.Text
                        LengthIncludingLineBreak = 0;
                        LengthInPixel = -1;
                }
-               public TextLine WithStartOffset (int start) => new TextLine (Start + start, End, EndIncludingLineBreak);
-
-               
-
+               public void SetLength (int newLength) {
+                       LengthInPixel = -1;
+                       Length = newLength;
+        }
+               public TextLine WithStartOffset (int start) => new TextLine (Start + start, End, EndIncludingLineBreak);                
                public int CompareTo (TextLine other) => Start - other.Start;
     }
 }
index 586c0d8c79db8c767db63fd133b6ce70863bea89..b64c75e234b3397fa8ebfe36931bb4f6a56a2fe8 100644 (file)
@@ -24,8 +24,91 @@ namespace Crow.Text
             
             length = _lines.Length;
         }
+        
+        public LineCollection (string _text, int capacity = 4) : this (capacity) {
+            Update (_text.AsSpan ());
+        }
         #endregion
 
+        public void Update (ReadOnlySpan<char> _text) {
+            length = 0;
+            int start = 0, i = 0;
+            while (i < _text.Length) {
+                char c = _text[i];
+                if (c == '\r') {
+                    if (++i < _text.Length) {
+                        if (_text[i] == '\n')
+                            Add (new TextLine (start, i - 1, ++i));
+                        else
+                            Add (new TextLine (start, i - 1, i));
+                    } else
+                        Add (new TextLine (start, i - 1, i));
+                    start = i;
+                } else if (c == '\n') {
+                    if (++i < _text.Length) {
+                        if (_text[i] == '\r')
+                            Add (new TextLine (start, i - 1, ++i));
+                        else
+                            Add (new TextLine (start, i - 1, i));
+                    } else
+                        Add (new TextLine (start, i - 1, i));
+                    start = i;
+
+                } else if (c == '\u0085' || c == '\u2028' || c == '\u2029')
+                    Add (new TextLine (start, i - 1, i));
+                else
+                    i++;
+            }
+
+            if (start < i)
+                Add (new TextLine (start, _text.Length, _text.Length));
+            else
+                Add (new TextLine (_text.Length, _text.Length, _text.Length));
+        }
+
+        public void Update (TextChange change) {
+            CharLocation locStart = GetLocation (change.Start);
+            int charsDiff = change.ChangedText.Length - change.Length;
+            int lineEnd = locStart.Line;
+            while (lineEnd < length - 1 && change.End >= lines[lineEnd + 1].Start)
+                lineEnd++;
+            int columnEnd = change.End - lines[lineEnd].Start;
+            int lineEndLineBreakLength = lines[lineEnd].LineBreakLength;
+
+            LineCollection newLines = new LineCollection (change.ChangedText);
+            int linesDiff = newLines.length - 1 - (lineEnd - locStart.Line);
+            TextLine endTl = lines[lineEnd];
+
+            if (linesDiff < 0)
+                RemoveAt (locStart.Line + 1, -linesDiff);
+            else if (linesDiff > 0) {
+                for (int i = 0; i < linesDiff; i++)
+                    Insert (locStart.Line + 1, default);
+            }
+
+            int remainingColumns = endTl.Length - columnEnd;
+            lineEnd += linesDiff;
+            lines[lineEnd].SetLength (0);
+            lines[locStart.Line].SetLength (locStart.Column + newLines[0].Length);
+            lines[lineEnd].Length += remainingColumns;
+            if (newLines.Count > 1) {
+                lines[lineEnd].Length += newLines[newLines.Count - 1].Length;                
+                lines[locStart.Line].LengthIncludingLineBreak = lines[locStart.Line].Length + newLines[0].LineBreakLength;
+            }
+            lines[lineEnd].LengthIncludingLineBreak = lines[lineEnd].Length + endTl.LineBreakLength;
+
+            for (int i = 1; i < newLines.Count - 1; i++) {
+                int l = locStart.Line + i;
+                lines[l] = newLines[i];
+                lines[l].Start = lines[l - 1].EndIncludingLineBreak;
+            }
+            if (lineEnd > 0)
+                lines[lineEnd].Start = lines[lineEnd - 1].EndIncludingLineBreak;
+
+            //shift start for remaining lines
+            for (int i = lineEnd + 1; i < length; i++)
+                lines[i].Start += charsDiff;            
+        }
         public int GetAbsolutePosition (CharLocation loc) => lines[loc.Line].Start + loc.Column;        
         public CharLocation GetLocation (int absolutePosition) {
             TextLine tl = new TextLine (absolutePosition);
@@ -76,26 +159,39 @@ namespace Crow.Text
             length--;
             return true;
         }
-        public IEnumerator<TextLine> GetEnumerator () => new LineEnumerator (this);
+        public IEnumerator<TextLine> GetEnumerator () => new Enumerator (this);
         IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
 
-        public int IndexOf (TextLine item) {
-            throw new NotImplementedException ();
-        }
+        public int IndexOf (TextLine item) => Array.IndexOf (lines, item);
 
         public void Insert (int index, TextLine item) {
-            throw new NotImplementedException ();
+            if (lines.Length < length + 1) {
+                TextLine[] tmp = new TextLine[length * 2];
+                lines.AsSpan (0, index).CopyTo (tmp);
+                lines.AsSpan (index).CopyTo (tmp.AsSpan (index + 1));
+                lines = tmp;
+            }else
+                lines.AsSpan (index, length - index).CopyTo (lines.AsSpan (index + 1));            
+            lines[index] = item;
+            length++;
         }
 
         public void RemoveAt (int index) {
-            throw new NotImplementedException ();
+            if (index + 1 < length)
+                lines.AsSpan (index + 1, length - index - 1).CopyTo (lines.AsSpan (index));
+            length--;
+        }
+        public void RemoveAt (int index, int count) {
+            if (index + count < length)
+                lines.AsSpan (index + count, length - index - count).CopyTo (lines.AsSpan (index));
+            length -= count;
         }
 
-        public class LineEnumerator : IEnumerator<TextLine>
+        public class Enumerator : IEnumerator<TextLine>
         {
             TextLine[] lines;
             int length, position = -1;
-            public LineEnumerator (LineCollection coll) {
+            public Enumerator (LineCollection coll) {
                 lines = coll.lines;
                 length = coll.length;
             }
index e176f8369cb0fb136479c49fd39026e056944873..6033a6f423f434332feb4582ee37d6258838640a 100644 (file)
@@ -255,47 +255,12 @@ namespace Crow
                        else
                                lines.Clear ();
 
-                       if (string.IsNullOrEmpty (_text)) {
+                       if (string.IsNullOrEmpty (_text))
                                lines.Add (new TextLine (0, 0, 0));
-                               return;
-                       }
-                       if (!_multiline) {
+                       else if (!_multiline)
                                lines.Add (new TextLine (0, _text.Length, _text.Length));
-                               return;
-                       }
-
-                       int start = 0, i = 0;
-                       while (i < _text.Length) {
-                               char c = _text[i];
-                               if (c == '\r') {
-                                       if (++i < _text.Length) {
-                                               if (_text[i] == '\n')
-                                                       lines.Add (new TextLine (start, i - 1, ++i));
-                                               else
-                                                       lines.Add (new TextLine (start, i - 1, i));
-                                       } else
-                                               lines.Add (new TextLine (start, i - 1, i));
-                                       start = i;
-                               } else if (c == '\n') {
-                                       if (++i < _text.Length) {
-                                               if (_text[i] == '\r')
-                                                       lines.Add (new TextLine (start, i - 1, ++i));
-                                               else
-                                                       lines.Add (new TextLine (start, i - 1, i));
-                                       } else
-                                               lines.Add (new TextLine (start, i - 1, i));
-                                       start = i;
-
-                               } else if (c == '\u0085' || c == '\u2028' || c == '\u2029')
-                                       lines.Add (new TextLine (start, i - 1, i));
-                               else
-                                       i++;
-                       }
-
-                       if (start < i)
-                               lines.Add (new TextLine (start, _text.Length, _text.Length));
                        else
-                               lines.Add (new TextLine (_text.Length, _text.Length, _text.Length));
+                               lines.Update (_text);
                }
                /// <summary>
                /// Current Selected text span.
@@ -417,6 +382,14 @@ namespace Crow
                                                        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 (HasFocus && selectionNotEmpty) {
                                                        RectangleD selRect = lineRect;
@@ -430,7 +403,7 @@ namespace Crow
                                                                                selRect.Width -= (newX - selRect.X) - 10.0;
                                                                                selRect.X = newX;
                                                                        } else if (i == selEnd.Line) {
-                                                                               selRect.Width = selEnd.VisualCharXPosition - selRect.X;
+                                                                               selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
                                                                        } else
                                                                                selRect.Width += 10.0;
                                                                } else {
@@ -519,6 +492,12 @@ namespace Crow
 
                        if (loc.Column >= 0) {
                                //int encodedBytes = Crow.Text.Encoding2.ToUtf8 (curLine.Slice (0, loc.Column), bytes);
+                               //DEBUG
+                               if (loc.Column > curLine.Length) {
+                                       Console.WriteLine ($"loc.Column: {loc.Column} curLine.Length:{curLine.Length}");
+                                       loc.Column = curLine.Length;
+                }
+
                                loc.VisualCharXPosition = gr.TextExtents (curLine.Slice (0, loc.Column), Interface.TAB_SIZE).XAdvance + cPos;
                                location = loc;
                                return;
index fc49df2b838383171e87dfb059346009946b6f46..d297caae87dbcc12617b3ed269c36957b7a594f8 100644 (file)
@@ -326,10 +326,10 @@ namespace Crow
                 src.Slice (0, change.Start).CopyTo (tmp);
                 change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
                 src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
-
             
                 _text = tmp.ToString ();
-                getLines ();
+                lines.Update (change);
+                //lines.Update (_text);
                 selectionStart = null;
 
                 currentLoc = lines.GetLocation (change.Start + change.ChangedText.Length);
diff --git a/Samples/common/ui/Interfaces/GraphicObject/textBox.crow b/Samples/common/ui/Interfaces/GraphicObject/textBox.crow
new file mode 100644 (file)
index 0000000..2094de4
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<HorizontalStack >
+       <VerticalStack Background="Jet" Height="Stretched" Width="50%" Margin="10" >
+               <TextBox Margin="0"  Text="Hello World this is a test string" Focusable="true" Font="serif,14"/>
+               <TextBox Margin="15" Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+                          Background="Grey" Focused="{Background=White}" Unfocused="{Background=Grey}"/>                               
+               <TextBox Name="lab" TextAlignment="Center" Width="Fit" Height="50"  Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+                          Background="Grey" Focused="{Background=White}" Unfocused="{Background=Grey}"/>
+               <TextBox TextAlignment="{TextAlignment}" Multiline="false" Width="300" Height="Fit"  Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+                          Background="Grey" Focused="{Background=White}" Unfocused="{Background=Grey}"/>
+       </VerticalStack>
+       <VerticalStack Background="Jet" Height="Stretched" Margin="10">
+               <TextBox Multiline="true" TextAlignment="{TextAlignment}" Width="320" Height="Fit"
+                                Text="{MultilineText}" Focusable="true" Font="consolas,12" 
+                                Background="Grey" Focused="{Background=White}" Unfocused="{Background=Grey}"/>
+               <VerticalStack Width="300" Height="100">
+                       <HorizontalStack>
+                               <TextBox Name="tb" Multiline="true" TextAlignment="{TextAlignment}" Width="Stretched" Height="Stretched"
+                                                ClipToClientRect="true"
+                                                Text="{MultilineText}" Focusable="true" Font="consolas,12" Margin="10"
+                                                Background="Grey" Focused="{Background=White}" Unfocused="{Background=Grey}"
+                                                />
+                               <ScrollBar Value="{²../tb.ScrollY}"
+                                               LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
+                                               CursorRatio="{../tb.ChildHeightRatio}" Maximum="{../tb.MaxScrollY}" />
+                       </HorizontalStack>
+                       <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
+                                       LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
+                                       CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
+               </VerticalStack>
+               <EnumSelector RadioButtonStyle="CheckBox2" Caption="Text Alignment" EnumValue="{²TextAlignment}" >
+                       <Template>
+                               <GroupBox Caption="{./Caption}" CornerRadius="{./CornerRadius}" Foreground="{./Foreground}" Background="{./Background}">
+                                       <VerticalStack Name="Content" Width="100"/>
+                               </GroupBox>
+                       </Template>
+               </EnumSelector>
+       </VerticalStack>
+</HorizontalStack>
\ No newline at end of file