aboutsummaryrefslogtreecommitdiffstatsci
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2021-01-16 15:01:07 +0100
committerj-p <jp_bruyere@hotmail.com>2021-02-06 20:28:02 +0100
commit0299b2c358f322a4ff012dbc8f9989dfe7cc3d2a (patch)
tree984c7bac2189d8bf68f249ee103ff16d2774fdcd
parentff03f75e02af643215d74fa7c99cdc983e048ce7 (diff)
selection in focusable label
-rw-r--r--Crow/src/Widgets/Label.cs271
-rw-r--r--Samples/common/ui/Interfaces/GraphicObject/label.crow26
2 files changed, 206 insertions, 91 deletions
diff --git a/Crow/src/Widgets/Label.cs b/Crow/src/Widgets/Label.cs
index cd01eb69..3232c4e4 100644
--- a/Crow/src/Widgets/Label.cs
+++ b/Crow/src/Widgets/Label.cs
@@ -10,6 +10,7 @@ using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Text;
using System.Diagnostics;
+using Glfw;
namespace Crow {
internal struct TextSpan
@@ -122,12 +123,7 @@ namespace Crow {
CharLocation? hoverLoc = null;
CharLocation? currentLoc = null;
CharLocation? selectionStart = null; //selection start (row,column)
-
-
- //protected Rectangle rText;
- protected float widthRatio = 1f;
- protected float heightRatio = 1f;
protected FontExtents fe;
protected TextExtents te;
#endregion
@@ -159,6 +155,18 @@ namespace Crow {
RegisterForRedraw ();
}
}
+ 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;
+ }
+ }
/// <summary>
/// If measure is not 'Fit', align text inside the bounds of this label.
/// </summary>
@@ -170,38 +178,12 @@ namespace Crow {
if (value == _textAlignment)
return;
_textAlignment = value;
+ resetLocationXs ();
+
RegisterForRedraw ();
NotifyValueChangedAuto (_textAlignment);
}
- }
- /// <summary>
- /// If Width is not 'Fit', Stretch text through the whole slot width.
- /// </summary>
- [DefaultValue(false)]
- public virtual bool HorizontalStretch {
- get { return horizontalStretch; }
- set {
- if (horizontalStretch == value)
- return;
- horizontalStretch = value;
- RegisterForRedraw ();
- NotifyValueChangedAuto (horizontalStretch);
- }
- }
- /// <summary>
- /// If Height is not 'Fit', stretch text through the whole slot height.
- /// </summary>
- [DefaultValue(false)]
- public virtual bool VerticalStretch {
- get { return verticalStretch; }
- set {
- if (verticalStretch == value)
- return;
- verticalStretch = value;
- RegisterForRedraw ();
- NotifyValueChangedAuto (verticalStretch);
- }
- }
+ }
/// <summary>
/// Text to display in this label. May include linebreaks if Multiline is 'true'.
/// If Multiline is false, linebreaks will be treated as unrecognized unicode char.
@@ -223,22 +205,7 @@ namespace Crow {
RegisterForGraphicUpdate ();
}
}
-
- /*[DefaultValue(false)]
- public bool Selectable
- {
- get => _selectable;
- set
- {
- if (value == _selectable)
- return;
- _selectable = value;
- NotifyValueChangedAuto (_selectable);
- SelBegin = -1;
- SelRelease = -1;
- RegisterForRedraw ();
- }
- }*/
+
/// <summary>
/// If 'true', linebreaks will be interpreted. If 'false', linebreaks are threated as unprintable
/// unicode characters.
@@ -400,17 +367,67 @@ namespace Crow {
/// Moves cursor one char to the left.
/// </summary>
/// <returns><c>true</c> if move succeed</returns>
+ */
public bool MoveLeft(){
- int tmp = _currentCol - 1;
- if (tmp < 0) {
- if (_currentLine == 0)
+ targetColumn = -1;
+ CharLocation loc = currentLoc.Value;
+ if (loc.Column == 0) {
+ if (loc.Line == 0)
+ return false;
+ currentLoc = new CharLocation (loc.Line - 1, lines[loc.Line - 1].Length);
+ }else
+ currentLoc = new CharLocation (loc.Line, loc.Column - 1);
+ return true;
+ }
+ public bool MoveRight () {
+ targetColumn = -1;
+ CharLocation loc = currentLoc.Value;
+ if (loc.Column == lines[loc.Line].Length) {
+ if (loc.Line == lines.Length - 1)
return false;
- CurrentLine--;
- CurrentColumn = int.MaxValue;
+ currentLoc = new CharLocation (loc.Line + 1, 0);
} else
- CurrentColumn = tmp;
+ currentLoc = new CharLocation (loc.Line, loc.Column + 1);
+ return true;
+ }
+ int targetColumn = -1;
+ public bool MoveUp () {
+ CharLocation loc = currentLoc.Value;
+ if (loc.Line == 0)
+ return false;
+
+ if (loc.Column > lines[loc.Line - 1].Length) {
+ if (targetColumn < 0)
+ targetColumn = loc.Column;
+ currentLoc = new CharLocation (loc.Line - 1, lines[loc.Line - 1].Length);
+ }else if (targetColumn < 0)
+ currentLoc = new CharLocation (loc.Line - 1, loc.Column);
+ else if (targetColumn > lines[loc.Line - 1].Length)
+ currentLoc = new CharLocation (loc.Line - 1, lines[loc.Line - 1].Length);
+ else
+ currentLoc = new CharLocation (loc.Line - 1, targetColumn);
+
return true;
}
+ public bool MoveDown () {
+ CharLocation loc = currentLoc.Value;
+ if (loc.Line == lines.Length - 1)
+ return false;
+
+ if (loc.Column > lines[loc.Line + 1].Length) {
+ if (targetColumn < 0)
+ targetColumn = loc.Column;
+ currentLoc = new CharLocation (loc.Line + 1, lines[loc.Line + 1].Length);
+ } else if (targetColumn < 0)
+ currentLoc = new CharLocation (loc.Line + 1, loc.Column);
+ else if (targetColumn > lines[loc.Line + 1].Length)
+ currentLoc = new CharLocation (loc.Line + 1, lines[loc.Line + 1].Length);
+ else
+ currentLoc = new CharLocation (loc.Line + 1, targetColumn);
+
+ return true;
+ }
+ /*
/// <summary>
/// Moves cursor one char to the right.
/// </summary>
@@ -596,8 +613,8 @@ namespace Crow {
int longestLine = 0;
for (int i = 0; i < lines.Length; i++) {
if (lines[i].LengthInPixel < 0) {
- if (lines[i].Length == 0 && lines[i].HasLineBreak)
- lines[i].LengthInPixel = 10;// (int)Math.Ceiling (fe.MaxXAdvance);
+ if (lines[i].Length == 0)
+ lines[i].LengthInPixel = 0;// (int)Math.Ceiling (fe.MaxXAdvance);
else {
gr.TextExtents (_text.GetLine (lines[i]), Interface.TAB_SIZE, out tmp);
lines[i].LengthInPixel = (int)Math.Ceiling (tmp.XAdvance);
@@ -639,11 +656,17 @@ namespace Crow {
int lineHeight = (int)(fe.Ascent + fe.Descent);
CharLocation selStart = default, selEnd = default;
+ bool selectionNotEmpty = false;
if (HasFocus) {
updateLocation (gr, cb.Width, ref currentLoc);
- if (selectionStart.HasValue) {
+ if (selectionStart.HasValue) {
updateLocation (gr, cb.Width, ref selectionStart);
+ if (currentLoc.Value != selectionStart.Value)
+ selectionNotEmpty = true;
+
+ }
+ if (selectionNotEmpty) {
if (currentLoc.Value.Line < selectionStart.Value.Line) {
selStart = currentLoc.Value;
selEnd = selectionStart.Value;
@@ -688,17 +711,13 @@ namespace Crow {
bytes[encodedBytes++] = 0;
if (lines[i].LengthInPixel < 0) {
- if (lines[i].Length == 0 && lines[i].HasLineBreak)
- lines[i].LengthInPixel = 10;// (int)Math.Ceiling (fe.MaxXAdvance);
- else {
- gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
- lines[i].LengthInPixel = (int)extents.XAdvance;
- }
+ gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+ lines[i].LengthInPixel = (int)extents.XAdvance;
}
}
Rectangle lineRect = new Rectangle (
- Width.IsFit ? cb.X : (int)getX (cb.Width, ref lines[i]) + cb.X,
+ Width.IsFit && !Multiline ? cb.X : (int)getX (cb.Width, ref lines[i]) + cb.X,
cb.Y + i * lineHeight,
lines[i].LengthInPixel,
lineHeight);
@@ -708,7 +727,7 @@ namespace Crow {
gr.ShowText (bytes.Slice (0, encodedBytes));
}
- if (HasFocus && selectionStart.HasValue) {
+ if (HasFocus && selectionNotEmpty) {
Rectangle selRect = lineRect;
if (_multiline) {
if (i >= selStart.Line && i <= selEnd.Line) {
@@ -717,11 +736,12 @@ namespace Crow {
selRect.Width = (int)(selEnd.VisualCharXPosition - selStart.VisualCharXPosition);
} else if (i == selStart.Line) {
int newX = (int)selStart.VisualCharXPosition + cb.X;
- selRect.Width -= (newX - selRect.X);
+ selRect.Width -= (newX - selRect.X) - 10;
selRect.X = newX;
} else if (i == selEnd.Line) {
selRect.Width = (int)selEnd.VisualCharXPosition - selRect.X;
- }
+ } else
+ selRect.Width += 10;
} else
continue;
} else {
@@ -779,16 +799,18 @@ namespace Crow {
RegisterForRedraw ();
}
}
- Point grabMousePos = -1;
+
public override void onMouseDown (object sender, MouseButtonEventArgs e)
{
- if (e.Button == Glfw.MouseButton.Left) {
- if (HasFocus) {
- grabMousePos = e.Position - ScreenCoordinates (Slot).TopLeft - ClientRectangle.TopLeft;
- if (IFace.Shift)
- currentLoc = hoverLoc;
- else
- currentLoc = selectionStart = hoverLoc;
+ if (e.Button == Glfw.MouseButton.Left) {
+ targetColumn = -1;
+ if (HasFocus) {
+ if (!IFace.Shift)
+ selectionStart = hoverLoc;
+ else if (!selectionStart.HasValue)
+ selectionStart = currentLoc;
+ currentLoc = hoverLoc;
+
RegisterForRedraw ();
e.Handled = true;
}
@@ -800,14 +822,12 @@ namespace Crow {
public override void onMouseUp (object sender, MouseButtonEventArgs e)
{
base.onMouseUp (sender, e);
- if (e.Button != Glfw.MouseButton.Left)
- return;
- Point mouseLocalPos = e.Position - ScreenCoordinates (Slot).TopLeft - ClientRectangle.TopLeft;
- if (mouseLocalPos == grabMousePos) {
- selectionStart = null;
- e.Handled = true;
- }
- RegisterForRedraw ();
+ if (e.Button != Glfw.MouseButton.Left || !HasFocus || !selectionStart.HasValue)
+ return;
+ if (selectionStart.Value == currentLoc.Value) {
+ selectionStart = null;
+ //RegisterForRedraw ();
+ }
}
public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
{
@@ -824,11 +844,80 @@ namespace Crow {
}
#endregion
- /// <summary>
- /// Update Current Column, line and TextCursorPos
- /// from mouseLocalPos
- /// </summary>
- void updateLocation(Context gr, int clientWidth, ref CharLocation? location)
+ #region Keyboard handling
+ void checkShift () {
+ if (IFace.Shift) {
+ if (!selectionStart.HasValue)
+ selectionStart = currentLoc;
+ } else
+ selectionStart = null;
+ }
+ public override void onKeyDown (object sender, KeyEventArgs e) {
+
+ switch (e.Key) {
+ case Key.Escape:
+ selectionStart = null;
+ RegisterForRedraw ();
+ break;
+ case Key.Home:
+ checkShift ();
+ if (IFace.Ctrl)
+ currentLoc = new CharLocation (0, 0);
+ else
+ currentLoc = new CharLocation (currentLoc.Value.Line, 0);
+ RegisterForRedraw ();
+ break;
+ case Key.End:
+ checkShift ();
+ int l = IFace.Ctrl ? lines.Length - 1 : currentLoc.Value.Line;
+ 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.Left:
+ checkShift ();
+ /*if (IFace.Ctrl)
+ GotoWordStart ();
+ else*/
+ MoveLeft ();
+ RegisterForRedraw ();
+ break;
+ case Key.Right:
+ checkShift ();
+ /*if (IFace.Ctrl)
+ GotoWordStart ();
+ else*/
+ MoveRight ();
+ RegisterForRedraw ();
+ break;
+ case Key.Up:
+ checkShift ();
+ MoveUp ();
+ RegisterForRedraw ();
+ break;
+ case Key.Down:
+ checkShift ();
+ MoveDown ();
+ RegisterForRedraw ();
+ break;
+ default:
+ base.onKeyDown (sender, e);
+ return;
+ }
+ e.Handled = true;
+
+ }
+ #endregion
+ /// <summary>
+ /// Update Current Column, line and TextCursorPos
+ /// from mouseLocalPos
+ /// </summary>
+ void updateLocation (Context gr, int clientWidth, ref CharLocation? location)
{
if (location == null)
return;
@@ -837,7 +926,7 @@ namespace Crow {
return;
LineSpan ls = lines[loc.Line];
ReadOnlySpan<char> curLine = _text.GetLine (lines[loc.Line]);
- double cPos = Width.IsFit ? 0 : getX (clientWidth, ref ls);
+ double cPos = Width.IsFit && !Multiline ? 0 : getX (clientWidth, ref ls);
if (loc.Column >= 0) {
loc.VisualCharXPosition = gr.TextExtents (curLine.Slice (0, loc.Column), Interface.TAB_SIZE).XAdvance + cPos;
diff --git a/Samples/common/ui/Interfaces/GraphicObject/label.crow b/Samples/common/ui/Interfaces/GraphicObject/label.crow
new file mode 100644
index 00000000..ad47ccf7
--- /dev/null
+++ b/Samples/common/ui/Interfaces/GraphicObject/label.crow
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<HorizontalStack >
+ <VerticalStack Background="Jet" Height="Stretched" Width="50%" Margin="10" >
+ <Label Margin="0" Text="Hello World this is a test string" Focusable="true" Font="serif,14"/>
+ <Label Margin="15" Background="DarkGrey" Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+ Focused="{Background=Onyx}" Unfocused="{Background=DarkGrey}"/>
+ <Label Background="DarkGrey" Width="300" Height="50" Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+ Focused="{Background=Onyx}" Unfocused="{Background=DarkGrey}"/>
+ <Label TextAlignment="Right" Background="DarkGrey" Width="300" Height="50" Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+ Focused="{Background=Onyx}" Unfocused="{Background=DarkGrey}"/>
+ <Label Name="lab" TextAlignment="Center" Background="DarkGrey" Width="Fit" Height="50" Text="Hello World this is a test string" Focusable="true" Font="serif,14"
+ Focused="{Background=Onyx}" Unfocused="{Background=DarkGrey}"/>
+ </VerticalStack>
+ <VerticalStack Background="Jet" Height="Stretched" Margin="10">
+ <Label Multiline="true" TextAlignment="{TextAlignment}" Background="DarkGrey" Width="Fit" Height="Fit"
+ Text="{MultilineText}" Focusable="true" Font="consolas,14"
+ Focused="{Background=Onyx}" Unfocused="{Background=DarkGrey}"/>
+ <EnumSelector RadioButtonStyle="CheckBox2" Caption="Text Alignment" EnumValue="{²TextAlignment}" >
+ <Template>
+ <GroupBox Caption="{./Caption}" CornerRadius="{./CornerRadius}" Foreground="{./Foreground}" Background="{./Background}">
+ <VerticalStack Name="Content"/>
+ </GroupBox>
+ </Template>
+ </EnumSelector>
+ </VerticalStack>
+</HorizontalStack> \ No newline at end of file