]> O.S.I.I.S - jp/crow.git/commitdiff
blinking text cursor, goto word start/end in label, shift/ctrl/alt right, paint ref...
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 2 Feb 2021 02:21:11 +0000 (03:21 +0100)
committerj-p <jp_bruyere@hotmail.com>
Sat, 6 Feb 2021 19:28:02 +0000 (20:28 +0100)
15 files changed:
Crow/Default.style
Crow/src/Interface.cs
Crow/src/Text/CharLocation.cs
Crow/src/Widgets/Border.cs
Crow/src/Widgets/DockStack.cs
Crow/src/Widgets/Group.cs
Crow/src/Widgets/Label.cs
Crow/src/Widgets/PrivateContainer.cs
Crow/src/Widgets/Scroller.cs
Crow/src/Widgets/TabView.cs
Crow/src/Widgets/TemplatedControl.cs
Crow/src/Widgets/TextBox.cs
Crow/src/Widgets/Widget.cs
Samples/ShowCase/ShowCase.cs
Samples/common/ui/Interfaces/Divers/testFocus.crow

index 104b303c6efd80118512ddac2e1a6595b5842586..0077a382bb31b385d34af779749fe4b13414fc5b 100644 (file)
@@ -82,6 +82,7 @@ OldLabel {
 TextBox {
        Background = "White";
        Foreground = "Black";
+       CursorColor = "Black";
        Selectable = "True";
        //Text = "TextBox";
        Margin = "1";
index b17a8dc55bf6e2d85fb254f0e538a5cd8467c7ef..e1b9bc77851eb5e27703334cecc35be3b4aa18b1 100644 (file)
@@ -253,9 +253,12 @@ namespace Crow
 
                public virtual void Quit () => Glfw3.SetWindowShouldClose (hWin, 1);
 
-               public bool Shift => Glfw3.GetKey(hWin, Glfw.Key.LeftShift) == InputAction.Press;
-               public bool Ctrl => Glfw3.GetKey (hWin, Glfw.Key.LeftControl) == InputAction.Press;
-               public bool Alt => Glfw3.GetKey (hWin, Glfw.Key.LeftAlt) == InputAction.Press;
+               public bool Shift => Glfw3.GetKey(hWin, Key.LeftShift) == InputAction.Press ||
+                       Glfw3.GetKey (hWin, Key.RightShift) == InputAction.Press;
+               public bool Ctrl => Glfw3.GetKey (hWin, Key.LeftControl) == InputAction.Press ||
+                       Glfw3.GetKey (hWin, Key.RightControl) == InputAction.Press;
+               public bool Alt => Glfw3.GetKey (hWin, Key.LeftAlt) == InputAction.Press ||
+                       Glfw3.GetKey (hWin, Key.RightAlt) == InputAction.Press;
 
                #region IDisposable Support
                private bool disposedValue = false; // To detect redundant calls
@@ -820,7 +823,7 @@ namespace Crow
                                                continue;
 
                                        ctx.Save ();
-                                       p.Paint (ref ctx);
+                                       p.Paint (ctx);
                                        ctx.Restore ();
                                }
 
@@ -842,7 +845,7 @@ namespace Crow
 
 #if DEBUG_CLIP_RECTANGLE
                                ctx.LineWidth = 1;
-                               ctx.SetSourceColor(Color.Magenta.AdjustAlpha (0.5));
+                               ctx.SetSource(1,0,0,0.5);
                                for (int i = 0; i < clipping.NumRectangles; i++)
                                        ctx.Rectangle(clipping.GetRectangle(i));
                                ctx.Stroke ();
@@ -867,11 +870,36 @@ namespace Crow
 
                                PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing);
                        }
+
+                       if (forceTextCursor) {
+                               if (FocusedWidget is Label lab && lab.SelectionIsEmpty) {                                       
+                                       Rectangle c = lab.DrawCursor (ctx);
+                                       if (textCursor != null && c != textCursor.Value)
+                                               RegisterClip (textCursor.Value);
+                                       textCursor = c;
+                                       surf.Flush ();                                  
+                               }
+                               blinkingCursor.Restart ();
+                               forceTextCursor = false;
+                       } else if (textCursor != null && blinkingCursor.ElapsedMilliseconds > blinkFrequency) {
+                               RegisterClip (textCursor.Value);
+                               textCursor = null;
+                               blinkingCursor.Restart ();
+                       } else if (FocusedWidget is Label lab && lab.SelectionIsEmpty) {                                                                
+                               if (blinkingCursor.ElapsedMilliseconds > blinkFrequency) {
+                                       textCursor = lab.DrawCursor (ctx);
+                                       surf.Flush ();
+                                       blinkingCursor.Restart ();
+                               }                               
+            }
                        
                        DbgLogger.EndEvent (DbgEvtType.Drawing, true);
                }
                #endregion
-
+               const long blinkFrequency = 300;                
+               internal Rectangle? textCursor = null;
+               internal bool forceTextCursor = true;
+               Stopwatch blinkingCursor = Stopwatch.StartNew ();
                #region GraphicTree handling
                /// <summary>Add widget to the Graphic tree of this interface and register it for layouting</summary>
                public Widget AddWidget(Widget g)
index 8a8b978461c341124c688ccf7106d0fe45fcef2f..f55dc45a63d0d9ce70a7031e679ad8332dd63db9 100644 (file)
@@ -15,7 +15,7 @@ namespace Crow.Text
                        VisualCharXPosition = visualX;
                }
                public bool HasVisualX => Column >= 0 && VisualCharXPosition >= 0;
-               
+               public void ResetVisualX () => VisualCharXPosition = -1;
                public static bool operator == (CharLocation a, CharLocation b)
                        => a.Equals (b);
                public static bool operator != (CharLocation a, CharLocation b)
index d9de7f6af0c5e68002e01a8fc23b758a116420da..b308f00f72cfa17403603e732b146876d9578efb 100644 (file)
@@ -111,7 +111,7 @@ namespace Crow
                        }
 
                        if (child != null)
-                               child.Paint (ref gr);
+                               child.Paint (gr);
                        gr.Restore ();
                }
                void drawborder2(Context gr){
index 728a35e19556764d850ab680597f6a16d7d86d0c..3b8594eaf7b2157683ab0f8088bbd5457b998856 100644 (file)
@@ -186,7 +186,7 @@ namespace Crow
                        childrenRWLock.EnterReadLock ();
 
                        foreach (Widget g in Children)
-                               g.Paint (ref gr);                       
+                               g.Paint (gr);                   
 
                        childrenRWLock.ExitReadLock ();
 
index b2b438cdeac37ca8d50f9f5d0e648f8b3466168f..a861eaf2d8efd207cf1cc3e375168d1c18e848df 100644 (file)
@@ -297,7 +297,7 @@ namespace Crow
                        childrenRWLock.EnterReadLock ();
 
                        for (int i = 0; i < Children.Count; i++) 
-                               Children[i].Paint (ref gr);                     
+                               Children[i].Paint (gr);                 
 
                        childrenRWLock.ExitReadLock ();
                        gr.Restore ();
@@ -331,7 +331,7 @@ namespace Crow
                                                continue;
                                        if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
                                                continue;
-                                       c.Paint (ref gr);
+                                       c.Paint (gr);
                                }
 
                                childrenRWLock.ExitReadLock ();
index 701a1283e0364a27e7105d9d8c257889df276a93..e7fe430f5d90f57413bf798614a9fad03d57a7d4 100644 (file)
@@ -36,6 +36,7 @@ namespace Crow
                protected string _text;
         TextAlignment _textAlignment;
                bool _multiline;
+               Color cursorColor;
                Color selBackground;
                Color selForeground;
 
@@ -60,7 +61,22 @@ namespace Crow
                /// <summary>
                /// Background color for selected text inside this label.
                /// </summary>
-               [DefaultValue("SteelBlue")]
+               [DefaultValue ("White")]
+               public virtual Color CursorColor {
+                       get { return cursorColor; }
+                       set {
+                               if (cursorColor == value)
+                                       return;
+                               cursorColor = value;
+                               NotifyValueChangedAuto (cursorColor);
+                               RegisterForRedraw ();
+                       }
+               }
+
+               /// <summary>
+               /// Background color for selected text inside this label.
+               /// </summary>
+               [DefaultValue ("SteelBlue")]
                public virtual Color SelectionBackground {
                        get { return selBackground; }
                        set {
@@ -96,7 +112,9 @@ namespace Crow
                                if (value == _textAlignment)
                                        return;
                                _textAlignment = value;
-                               resetLocationXs ();
+
+                               currentLoc?.ResetVisualX ();
+                               selectionStart?.ResetVisualX ();
 
                                RegisterForRedraw ();
                                NotifyValueChangedAuto (_textAlignment);
@@ -209,29 +227,25 @@ namespace Crow
 
                        return true;
                }
-/*             
+               
                public void GotoWordStart(){
-                       CurrentColumn--;
+                       int pos = lines.GetAbsolutePosition (currentLoc.Value);                 
                        //skip white spaces
-                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
-                               CurrentColumn--;
-                       while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
-                               CurrentColumn--;
-                       if (!char.IsLetterOrDigit (this.CurrentChar))
-                               CurrentColumn++;
+                       while (pos > 0 && !char.IsLetterOrDigit (_text[pos-1]))
+                               pos--;
+                       while (pos > 0 && char.IsLetterOrDigit (_text[pos-1]))
+                               pos--;
+                       currentLoc = lines.GetLocation (pos);
                }
                public void GotoWordEnd(){
+                       int pos = lines.GetAbsolutePosition (currentLoc.Value);
                        //skip white spaces
-                       if (CurrentColumn >= lines [CurrentLine].Length - 1)
-                               return;
-                       while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
-                               CurrentColumn++;
-                       while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
-                               CurrentColumn++;
-                       if (char.IsLetterOrDigit (this.CurrentChar))
-                               CurrentColumn++;
-               }
-               */
+                       while (pos < _text.Length -1 && !char.IsLetterOrDigit (_text[pos]))
+                               pos++;
+                       while (pos < _text.Length - 1 && char.IsLetterOrDigit (_text[pos]))
+                               pos++;
+                       currentLoc = lines.GetLocation (pos);
+               }               
 
                protected void detectLineBreak () {
                        if (!_multiline)
@@ -301,29 +315,10 @@ namespace Crow
                        else
                                lines.Add (new TextLine (_text.Length, _text.Length, _text.Length));
                }
-               void resetLocationXs () {
-                       if (currentLoc.HasValue) {
-                               CharLocation cl = currentLoc.Value;
-                               cl.VisualCharXPosition = -1;
-                               currentLoc = cl;
-                       }
-                       if (selectionStart.HasValue) {
-                               CharLocation cl = selectionStart.Value;
-                               cl.VisualCharXPosition = -1;
-                               selectionStart = cl;
-                       }
-               }
-               double getX (int clientWidth, TextLine ls) {
-                       switch (TextAlignment) {
-                       case TextAlignment.Right:
-                               return clientWidth - ls.LengthInPixel;
-                       case TextAlignment.Center:
-                               return clientWidth / 2 - ls.LengthInPixel / 2;
-                       }
-                       return 0;
-               }
-
-               protected TextSpan Selection {
+               /// <summary>
+               /// Current Selected text span.
+               /// </summary>
+               public TextSpan Selection {
                        get {                           
                                CharLocation selStart = currentLoc.Value, selEnd = currentLoc.Value;
                                if (selectionStart.HasValue) {
@@ -344,6 +339,13 @@ namespace Crow
                                return new TextSpan (lines.GetAbsolutePosition (selStart), lines.GetAbsolutePosition (selEnd));
                        }
         }
+               public string SelectedText {
+                       get {
+                               TextSpan selection = Selection;
+                               return selection.IsEmpty ? "" : Text.AsSpan (selection.Start, selection.Length).ToString ();
+                       }
+        }
+               public bool SelectionIsEmpty => selectionStart.HasValue ? Selection.IsEmpty : true;
         public override bool UpdateLayout (LayoutingType layoutType) {
                        if ((LayoutingType.Sizing | layoutType) != LayoutingType.None) {
                                if (!System.Threading.Monitor.TryEnter (linesMutex))
@@ -393,6 +395,7 @@ namespace Crow
                        }
                        return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width);
                }
+               
         protected override void onDraw (Context gr)
                {
                        base.onDraw (gr);
@@ -417,8 +420,7 @@ namespace Crow
                                if (selectionStart.HasValue) {
                                        updateLocation (gr, cb.Width, ref selectionStart);
                                        if (currentLoc.Value != selectionStart.Value)
-                                               selectionNotEmpty = true;
-                                       
+                                               selectionNotEmpty = true;                                       
                                }
                                if (selectionNotEmpty) {
                                        if (currentLoc.Value.Line < selectionStart.Value.Line) {
@@ -434,13 +436,8 @@ namespace Crow
                                                selStart = selectionStart.Value;
                                                selEnd = currentLoc.Value;
                                        }
-                               } else {
-                                       Foreground.SetAsSource (IFace, gr);
-                                       gr.LineWidth = 1.0;
-                                       gr.MoveTo (0.5 + currentLoc.Value.VisualCharXPosition + cb.X, cb.Y + currentLoc.Value.Line * lineHeight);
-                                       gr.LineTo (0.5 + currentLoc.Value.VisualCharXPosition + cb.X, cb.Y + (currentLoc.Value.Line + 1) * lineHeight);
-                                       gr.Stroke ();
-                               }
+                               }else
+                                       IFace.forceTextCursor = true;
                        }
 
                        if (string.IsNullOrEmpty (_text)) {
@@ -573,7 +570,7 @@ namespace Crow
                                        else if (!selectionStart.HasValue)
                                                selectionStart = currentLoc;
                                        currentLoc = hoverLoc;
-
+                                       IFace.forceTextCursor = true;
                                        RegisterForRedraw ();
                                        e.Handled = true;
                                }                                       
@@ -629,26 +626,24 @@ namespace Crow
                                currentLoc = new CharLocation (l, lines[l].Length);
                                RegisterForRedraw ();
                                break;
-/*                     case Key.Insert:
-                               if (IFace.Shift)
-                                       this.Insert (IFace.Clipboard);
-                               else if (IFace.Ctrl && !selectionIsEmpty)
-                                       IFace.Clipboard = this.SelectedText;
-                               break;*/
+                       case Key.Insert:
+                               if (IFace.Ctrl && !SelectionIsEmpty)
+                                       IFace.Clipboard = SelectedText;
+                               break;
                        case Key.Left:
                                checkShift ();
-                               /*if (IFace.Ctrl)
+                               if (IFace.Ctrl)
                                        GotoWordStart ();
-                               else*/
-                               MoveLeft ();
+                               else
+                                       MoveLeft ();
                                RegisterForRedraw ();
                                break;
                        case Key.Right:
                                checkShift ();
-                               /*if (IFace.Ctrl)
-                                       GotoWordStart ();
-                               else*/
-                               MoveRight ();
+                               if (IFace.Ctrl)
+                                       GotoWordEnd ();
+                               else
+                                       MoveRight ();
                                RegisterForRedraw ();
                                break;
                        case Key.Up:
@@ -665,8 +660,8 @@ namespace Crow
                                base.onKeyDown (sender, e);
                                return;
                        }
+                       IFace.forceTextCursor = true;
                        e.Handled = true;                       
-                       
                }
                void checkShift () {
                        if (IFace.Shift) {
@@ -723,7 +718,42 @@ namespace Crow
                        loc.VisualCharXPosition = cPos;
                        location = loc;
                }
+               double getX (int clientWidth, TextLine ls) {
+                       switch (TextAlignment) {
+                       case TextAlignment.Right:
+                               return clientWidth - ls.LengthInPixel;
+                       case TextAlignment.Center:
+                               return clientWidth / 2 - ls.LengthInPixel / 2;
+                       }
+                       return 0;
+               }
 
+               RectangleD? textCursor = null;
+               internal Rectangle DrawCursor (Context ctx) {
+                       if (!currentLoc.Value.HasVisualX) {
+                               ctx.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                               ctx.SetFontSize (Font.Size);
+                               ctx.FontOptions = Interface.FontRenderingOptions;
+                               ctx.Antialias = Interface.Antialias;
+
+                               updateLocation (ctx, ClientRectangle.Width, ref currentLoc);
+                               textCursor = null;
+            }
+                       //if (textCursor == null) {
+                               Rectangle cb = ClientRectangle;
+                               int lineHeight = (int)(fe.Ascent + fe.Descent);
+                               textCursor = new RectangleD (currentLoc.Value.VisualCharXPosition + cb.X + Slot.X,
+                                                       cb.Y + Slot.Y + currentLoc.Value.Line * lineHeight, 1.0, lineHeight);
+                       //}
+                       Rectangle c = ScreenCoordinates (textCursor.Value);
+                       ctx.ResetClip ();
+                       ctx.SetSource (cursorColor);                    
+                       ctx.LineWidth = 1.0;
+                       ctx.MoveTo (0.5 + c.X, c.Y);
+                       ctx.LineTo (0.5 + c.X, c.Bottom);
+                       ctx.Stroke ();
+                       return c;
+               }
 
-    }
+       }
 }
index ebca78e89adb81b1d076185c2f270c85604d23fe..293323e44308b571695fc4641e9e3d99aacace53 100644 (file)
@@ -194,7 +194,7 @@ namespace Crow
 
                        if (child != null) {
                                if (child.Visible)
-                                       child.Paint (ref gr);
+                                       child.Paint (gr);
                        }
                        gr.Restore ();
                }
index a706d692f6dcf2f160fb2e7dfaeb2e40ec976d44..9065a51f5f269971be2b86290e71211560a90306 100644 (file)
@@ -197,7 +197,7 @@ namespace Crow
 
                        gr.Translate (-ScrollX, -ScrollY);
                        if (child != null)
-                               child.Paint (ref gr);
+                               child.Paint (gr);
                        gr.Restore ();
                }
 
index 9a88d72f0e07a36a6e844271d134de9123f302c1..b7c963d182adfff7e9a13472b5ace1cf1ac41154 100644 (file)
@@ -260,17 +260,17 @@ namespace Crow
 
                        int i = 0;
                        while (i < selTabViewIdx) {
-                               tabItms [i].Paint (ref gr);
+                               tabItms [i].Paint (gr);
                                i++;
                        }
                        i = tabItms.Length - 1;
                        while (i > selTabViewIdx) {
-                               tabItms [i].Paint (ref gr);
+                               tabItms [i].Paint (gr);
                                i--;
                        }
 
                        if (selTabViewIdx >= 0)
-                               tabItms [selTabViewIdx].Paint (ref gr);
+                               tabItms [selTabViewIdx].Paint (gr);
 
                        childrenRWLock.ExitReadLock ();
 
index 74c71fe2801d788b5eabb2307f9a0aab34379c58..9f60e0a8a903577d552846094977783337dca2bf 100644 (file)
@@ -98,7 +98,7 @@ namespace Crow
                        }
 
                        if (child != null)
-                               child.Paint (ref gr);
+                               child.Paint (gr);
                        gr.Restore ();
                }
                #endregion
index a677795fb203f8df0e46ca909d4f73e2ece0cf7b..0c060c60ccb2bd5373791f42a57af5357903e2ec 100644 (file)
@@ -53,7 +53,7 @@ namespace Crow
                         update (new TextChange (selection.Start, 1, ""));
                 } else {
                     if (IFace.Shift)
-                        IFace.Clipboard = Text.AsSpan (selection.Start, selection.Length).ToString ();
+                        IFace.Clipboard = SelectedText;
                     update (new TextChange (selection.Start, selection.Length, ""));
                 }
                 break;
@@ -61,7 +61,7 @@ namespace Crow
                 if (IFace.Shift)
                     update (new TextChange (selection.Start, selection.Length, IFace.Clipboard));
                 else if (IFace.Ctrl && !selection.IsEmpty)
-                    IFace.Clipboard = Text.AsSpan (selection.Start, selection.Length).ToString ();
+                    IFace.Clipboard = SelectedText;
                 break;
             case Key.KeypadEnter:
             case Key.Enter:
@@ -116,6 +116,7 @@ namespace Crow
 
             currentLoc = lines.GetLocation (change.Start + change.ChangedText.Length);
             textMeasureIsUpToDate = false;
+            IFace.forceTextCursor = true;
 
             NotifyValueChanged ("Text", Text);
             OnTextChanged (this, new TextChangeEventArgs (change));
index 05e258efaabb174d33871dfa8c9922c3922d2176..255e17563bc24a42fc8776ce79753ad5c9939968 100644 (file)
@@ -1796,7 +1796,7 @@ namespace Crow
                }
                /// <summary> Chained painting routine on the parent context of the actual cached version
                /// of the widget </summary>
-               public virtual void Paint (ref Context ctx)
+               public virtual void Paint (Context ctx)
                {
                        DbgLogger.StartEvent (DbgEvtType.GOPaint, this);
 
index b504648eb1da25210b10fc82a91448a0671192fb..db91b1cfd72239c96e4e0a3ddbb898b65d16c019 100644 (file)
@@ -244,10 +244,10 @@ namespace ShowCase
                                        g.DataSource = this;
                                }
                        } catch (InstantiatorException itorex) {
-                               Console.WriteLine (itorex);
+                               //Console.WriteLine (itorex);
                                showError (itorex.InnerException);
                        } catch (Exception ex) {
-                               Console.WriteLine (ex);
+                               //Console.WriteLine (ex);
                                showError (ex);
                        }
                }
index d8f914ee87edb54e9179b5eb2bfda0c2683d5868..2e2ebe7e14cc15301e288f5fed3ea5fdec4f486f 100644 (file)
@@ -40,7 +40,7 @@
                <Label Text="{ActiveWidget}" Font="mono, 8"/>
        </HorizontalStack>
        <Container Fit="true" Margin="50" Background="SlateGrey">
-               <Label Text="MouseEvents" Margin="3" Focusable="true" Fit="true"
+               <Label Text="MouseEvents" Margin="3" Focusable="false" Fit="true"
                        Background="Jet"
                        Foreground="DimGrey"
                        TextAlignment="Center"