From d5a5d9516969d7a0fb665a72be7269e7bd51ad58 Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Thu, 18 Dec 2014 22:41:10 +0100 Subject: misa a jour --- src/GraphicObjects/TextBox.cs | 420 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 src/GraphicObjects/TextBox.cs (limited to 'src/GraphicObjects/TextBox.cs') diff --git a/src/GraphicObjects/TextBox.cs b/src/GraphicObjects/TextBox.cs new file mode 100644 index 00000000..4df0b3f7 --- /dev/null +++ b/src/GraphicObjects/TextBox.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenTK.Input; +using Cairo; +using System.Diagnostics; +using System.Xml.Serialization; +using System.Globalization; + +namespace go +{ + public class TextBoxWidget : Label + { + public static KeyboardDevice Keyboard; + public static char decimalSeparator = '.';//????? should follow locale policy + static bool _capitalOn = false; //???????????????? + public static bool capitalOn + { + get + { + return _capitalOn; + //Keyboard[Key.ShiftLeft] || Keyboard[Key.ShiftRight] ? + //!_capitalOn : _capitalOn; + } + set { _capitalOn = value; } + } + + Color selColor = Color.BlueBell; + Color selFontColor = Color.WhiteSmoke; + Point mouseLocalPos; //mouse coord in widget space, filled only when clicked + int _currentPos; //0 based cursor position in string + double textCursorPos; //cursor position in cairo units in widget client coord. + double SelStartCursorPos = -1; + double SelEndCursorPos = -1; + bool SelectionInProgress = false; + + [XmlIgnore] + public override bool HasFocus //trigger update when lost focus to errase text beam + { + get + { + return base.HasFocus; + } + set + { + base.HasFocus = value; + registerForGraphicUpdate(); + } + } + + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValue(true)] + public override bool Focusable + { + get { return base.Focusable; } + set { base.Focusable = value; } + } + + [XmlIgnore] + public GOEvent onTextChanged; + + [XmlIgnore] + public int currentPos + { + get { return _currentPos; } + set { _currentPos = value; } + } + + [XmlIgnore] + public int selBeginPos; + [XmlIgnore] + public int selReleasePos; + [XmlIgnore] + public int selectionStart //ordered selection start and end positions + { + get { return selReleasePos < 0 ? selBeginPos : Math.Min(selBeginPos, selReleasePos); } + } + [XmlIgnore] + public int selectionEnd + { get { return selReleasePos < 0 ? selReleasePos : Math.Max(selBeginPos, selReleasePos); } } + [XmlIgnore] + public string selectedText + { get { return selectionEnd < 0 ? null : Text.Substring(selectionStart, selectionEnd - selectionStart); } } + [XmlIgnore] + public bool selectionIsEmpty + { get { return string.IsNullOrEmpty(selectedText); } } + + public TextBoxWidget(string _initialValue, GOEvent _onTextChanged = null) + : base(_initialValue) + { + onTextChanged = _onTextChanged; + Focusable = true; + selColor = Color.SkyBlue; + selFontColor = Color.Black; + Foreground = Color.Black; + Background = Color.White; + TextAlignment = Alignment.LeftCenter; + } + + public TextBoxWidget() + { } + + public override void onDraw (Context gr) + { + base.onDraw (gr); +// gr.FontOptions.Antialias = Antialias.Subpixel; +// gr.FontOptions.HintMetrics = HintMetrics.On; + gr.SetFontSize(FontSize); + FontExtents fe = gr.FontExtents; + + #region draw text cursor + if (mouseLocalPos > 0) + { + computeTextCursor(gr); + + if (SelectionInProgress) + { + selReleasePos = currentPos; + SelEndCursorPos = textCursorPos; + } + else if (selBeginPos < 0) + { + selBeginPos = currentPos; + SelStartCursorPos = textCursorPos; + selReleasePos = -1; + } + else + computeTextCursorPosition(gr); + + } + else + computeTextCursorPosition(gr); + + if (HasFocus) + { + //TODO: + gr.Color = Color.White; + gr.LineWidth = 2; + gr.MoveTo(new PointD(textCursorPos + rText.X, rText.Y )); + gr.LineTo(new PointD(textCursorPos + rText.X, rText.Y + fe.Height)); + gr.Stroke(); + } + + #endregion + + if (selReleasePos >= 0) + { + gr.Color = selColor; + Rectangle selRect = + new Rectangle((int)SelStartCursorPos + rText.X, (int)(rText.Y), (int)(SelEndCursorPos - SelStartCursorPos), (int)fe.Height); + gr.Rectangle(selRect); + gr.Fill(); + + gr.Color = selFontColor; + } + else + gr.Color = Foreground; + + gr.MoveTo(rText.X, rText.Y + fe.Ascent); + #if _WIN32 || _WIN64 + gr.ShowText(txt); + #elif __linux__ + gr.ShowText(Text); + #endif + gr.Fill(); + + } + + #region Keyboard handling + public override void onKeyDown (object sender, KeyboardKeyEventArgs e) + { + base.onKeyDown (sender, e); + + Key key = e.Key; + + switch (key) + { + case Key.Back: + if (!selectionIsEmpty) + { + Text = Text.Remove(selectionStart, selectionEnd - selectionStart); + selReleasePos = -1; + currentPos = selBeginPos; + } + else if (currentPos > 0) + { + currentPos--; + Text = Text.Remove(currentPos, 1); + } + break; + case Key.Clear: + break; + case Key.Delete: + if (!selectionIsEmpty) + { + Text = Text.Remove(selectionStart, selectionEnd - selectionStart); + selReleasePos = -1; + currentPos = selBeginPos; + } + else if (currentPos < Text.Length) + Text = Text.Remove(currentPos, 1); + break; + case Key.Down: + break; + case Key.End: + currentPos = Text.Length; + break; + case Key.Enter: + case Key.KeypadEnter: + if (onTextChanged != null) + onTextChanged(this); + break; + case Key.Escape: + Text = ""; + currentPos = 0; + selReleasePos = -1; + break; + case Key.Home: + currentPos = 0; + break; + case Key.Insert: + break; + case Key.Left: + if (currentPos > 0) + currentPos--; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + break; + case Key.PageUp: + break; + case Key.RWin: + break; + case Key.Right: + if (currentPos < Text.Length) + currentPos++; + break; + case Key.Tab: + Text = Text.Insert(currentPos, "\t"); + currentPos++; + break; + case Key.Up: + break; + case Key.KeypadDecimal: + Text = Text.Insert(currentPos, new string(new char[] + { Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator) })); + currentPos++; + break; + case Key.Space: + Text = Text.Insert(currentPos, " "); + currentPos++; + break; + case Key.KeypadDivide: + case Key.Slash: + Text = Text.Insert(currentPos, "/"); + currentPos++; + break; + case Key.KeypadMultiply: + Text = Text.Insert(currentPos, "*"); + currentPos++; + break; + case Key.KeypadMinus: + case Key.Minus: + Text = Text.Insert(currentPos, "-"); + currentPos++; + break; + case Key.KeypadPlus: + case Key.Plus: + Text = Text.Insert(currentPos, "+"); + currentPos++; + break; + default: + if (!selectionIsEmpty) + { + Text = Text.Remove(selectionStart, selectionEnd - selectionStart); + currentPos = selBeginPos; + } + + string k = "?"; + if ((char)key >= 67 && (char)key <= 76) + k = ((int)key - 67).ToString(); + else if ((char)key >= 109 && (char)key <= 118) + k = ((int)key - 109).ToString(); + else if (capitalOn) + k = key.ToString(); + else + k = key.ToString().ToLower(); + + Text = Text.Insert(currentPos, k); + currentPos++; + + selReleasePos = -1; + selBeginPos = currentPos; + + break; + } + registerForGraphicUpdate(); + } + #endregion + + #region Mouse handling + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { +// SelectionInProgress = true; +// mouseLocalPos = e.Position - ScreenCoordBounds.TopLeft - rText.TopLeft; +// registerForGraphicUpdate(); + + base.onMouseEnter (sender, e); + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); + } + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + if ((sender as OpenTKGameWindow).activeWidget != this) + return; + + SelectionInProgress = true; + mouseLocalPos = e.Position - ScreenCoordinates(rText).TopLeft; + registerForGraphicUpdate(); + + } + public override void onMouseButtonDown (object sender, MouseButtonEventArgs e) + { + if (this.HasFocus){ + mouseLocalPos = Mouse.Position - ScreenCoordinates(rText).TopLeft - rText.TopLeft; + selBeginPos = -1; + selReleasePos = -1; + }else{ + selBeginPos = 0; + selReleasePos = Text.Length; + } + + //done at the end to set 'hasFocus' value after testing it + base.onMouseButtonDown (sender, e); + + registerForGraphicUpdate(); + } + public override void onMouseButtonUp (object sender, MouseButtonEventArgs e) + { + base.onMouseButtonUp (sender, e); + SelectionInProgress = false; + } + #endregion + + void computeTextCursor(Context gr) + { + FontExtents fe = gr.FontExtents; + TextExtents te; + + double cPos = 0f; + for (int i = 0; i < _text.Length; i++) + { +#if _WIN32 || _WIN64 + byte[] c = System.Text.UTF8Encoding.UTF8.GetBytes(Text.Substring(i, 1)); + te = gr.TextExtents(c); +#elif __linux__ + te = gr.TextExtents(Text.Substring(i, 1)); +#endif + double halfWidth = te.XAdvance / 2; + + if (mouseLocalPos.X <= cPos + halfWidth) + { + currentPos = i; + textCursorPos = cPos; + mouseLocalPos = -1; + return; + } + + cPos += te.XAdvance; + } + currentPos = _text.Length; + textCursorPos = cPos; + + //reset mouseLocalPos + mouseLocalPos = -1; + } + void computeTextCursorPosition(Context gr) + { + FontExtents fe = gr.FontExtents; + TextExtents te; + + double cPos = 0f; + + int limit = currentPos; + + if (selectionEnd > 0) + limit = Math.Max(currentPos, selectionEnd); + + for (int i = 0; i <= limit; i++) + { + if (i == currentPos) + textCursorPos = cPos; + if (i == selectionStart) + SelStartCursorPos = cPos; + if (i == selectionEnd) + SelEndCursorPos = cPos; + + if (i < Text.Length) + { +#if _WIN32 || _WIN64 + byte[] c = System.Text.UTF8Encoding.UTF8.GetBytes(Text.Substring(i, 1)); + te = gr.TextExtents(c); +#elif __linux__ + te = gr.TextExtents(Text.Substring(i,1)); +#endif + cPos += te.XAdvance; + } + } + + } + } +} -- cgit v1.3.1-4-g156e