From 15e38550c58942ff2604c3ca34abd2de78aa3944 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 8 Jun 2020 23:39:31 +0100 Subject: [PATCH] Fixed a layout bug that preventing the redrawing on Pos and Dim changes. Now the TextAlignment is working well. I move them to the view for a generic uses to others views. --- Terminal.Gui/Core/View.cs | 120 +++++++++++++++++++++++++++++++-- Terminal.Gui/Views/Button.cs | 66 ++---------------- Terminal.Gui/Views/Label.cs | 22 ------ UICatalog/Scenarios/Buttons.cs | 93 ++++++++++++++----------- 4 files changed, 173 insertions(+), 128 deletions(-) diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 113fb8113..c612d16b8 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -17,6 +17,27 @@ using System.Linq; using NStack; namespace Terminal.Gui { + /// + /// Text alignment enumeration, controls how text is displayed. + /// + public enum TextAlignment { + /// + /// Aligns the text to the left of the frame. + /// + Left, + /// + /// Aligns the text to the right side of the frame. + /// + Right, + /// + /// Centers the text in the frame. + /// + Centered, + /// + /// Shows the text as justified text in the frame. + /// + Justified + } /// /// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the @@ -299,6 +320,7 @@ namespace Terminal.Gui { set { x = value; SetNeedsLayout (); + SetNeedsDisplay (frame); } } @@ -314,6 +336,7 @@ namespace Terminal.Gui { set { y = value; SetNeedsLayout (); + SetNeedsDisplay (frame); } } @@ -331,6 +354,7 @@ namespace Terminal.Gui { set { width = value; SetNeedsLayout (); + SetNeedsDisplay (frame); } } @@ -344,6 +368,7 @@ namespace Terminal.Gui { set { height = value; SetNeedsLayout (); + SetNeedsDisplay (frame); } } @@ -1457,7 +1482,7 @@ namespace Terminal.Gui { /// The hot-key to look for. /// The returning hot-key position. /// The character immediately to the right relative to the hot-key position - /// + /// It aims to facilitate the preparation for procedures. public virtual ustring GetTextFromHotKey(ustring text, Rune hotKey, out int hotPos, out Rune showHotKey) { Rune hot_key = (Rune)0; @@ -1471,7 +1496,7 @@ namespace Terminal.Gui { if (c == hotKey) { hot_pos = i; } else if (hot_pos > -1) { - hot_key = (char)c; + hot_key = c; break; } } @@ -1482,10 +1507,12 @@ namespace Terminal.Gui { // Use first upper-case char if there are no hot-key in the text. i = 0; foreach (Rune c in shown_text) { - if (Rune.IsUpper (c)) { - hot_key = (char)c; - hot_pos = i; - break; + if ((char)c != 0xFFFD) { + if (Rune.IsUpper (c)) { + hot_key = c; + hot_pos = i; + break; + } } i++; } @@ -1514,6 +1541,87 @@ namespace Terminal.Gui { return shown_text; } + /// + /// A generic virtual method at the level of View to manipulate any hot-keys with process. + /// + /// The text to manipulate to align. + /// The passed in hot-key position. + /// The returning hot-key position. + /// The to align to. + /// It performs the process to the caller. + public virtual ustring GetTextAlignment (ustring shown_text, int hot_pos, out int c_hot_pos, TextAlignment textAlignment) + { + int start; + var caption = shown_text; + c_hot_pos = hot_pos; + + if (Frame.Width > shown_text.Length + 1) { + switch (textAlignment) { + case TextAlignment.Left: + caption += new string (' ', Frame.Width - caption.RuneCount); + break; + case TextAlignment.Right: + start = Frame.Width - caption.RuneCount; + caption = $"{new string (' ', Frame.Width - caption.RuneCount)}{caption}"; + if (c_hot_pos > -1) { + c_hot_pos += start; + } + break; + case TextAlignment.Centered: + start = Frame.Width / 2 - caption.RuneCount / 2; + caption = $"{new string (' ', start)}{caption}{new string (' ', Frame.Width - caption.RuneCount - start)}"; + if (c_hot_pos > -1) { + c_hot_pos += start; + } + break; + case TextAlignment.Justified: + var words = caption.Split (" "); + var wLen = GetWordsLength (words, c_hot_pos, out int runeCount, out int w_hot_pos); + var space = (Frame.Width - runeCount) / (caption.Length - wLen); + caption = ""; + for (int i = 0; i < words.Length; i++) { + if (i == words.Length - 1) { + caption += new string (' ', Frame.Width - caption.RuneCount - 1); + caption += words [i]; + } else { + caption += words [i]; + } + if (i < words.Length - 1) { + caption += new string (' ', space); + } + } + if (c_hot_pos > -1) { + if (wLen - runeCount == 0) { + c_hot_pos += (wLen - runeCount == 0 ? w_hot_pos * (space) - space - w_hot_pos + 1 : space + wLen - runeCount); + } else { + c_hot_pos += space + wLen - runeCount; + } + } + break; + } + } + + return caption; + } + + int GetWordsLength (ustring [] words, int hotPos, out int runeCount, out int wordHotPos) + { + int length = 0; + int rCount = 0; + int wHotPos = -1; + for (int i = 0; i < words.Length; i++) { + if (wHotPos == -1 && rCount + words [i].RuneCount >= hotPos) + wHotPos = i; + length += words [i].Length; + rCount += words [i].RuneCount; + } + if (wHotPos == -1 && hotPos > -1) + wHotPos = words.Length; + runeCount = rCount; + wordHotPos = wHotPos; + return length; + } + /// /// Pretty prints the View /// diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index 148f86ea3..2d87e2dd1 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -6,6 +6,7 @@ // using System; +using System.Net.Sockets; using NStack; namespace Terminal.Gui { @@ -137,9 +138,7 @@ namespace Terminal.Gui { } set { - if (text?.Length != value?.Length) { - SetWidthHeight (value, is_default); - } + SetWidthHeight (value, is_default); text = value; Update (); } @@ -152,7 +151,7 @@ namespace Terminal.Gui { get => textAlignment; set { textAlignment = value; - SetNeedsDisplay (); + Update (); } } @@ -181,51 +180,8 @@ namespace Terminal.Gui { Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal); Move (0, 0); - var caption = shown_text; - c_hot_pos = hot_pos; - int start; - - if (Frame.Width > shown_text.Length + 1) { - switch (TextAlignment) { - case TextAlignment.Left: - caption += new string (' ', Frame.Width - caption.RuneCount); - break; - case TextAlignment.Right: - start = Frame.Width - caption.RuneCount; - caption = $"{new string (' ', Frame.Width - caption.RuneCount)}{caption}"; - if (c_hot_pos > -1) { - c_hot_pos += start; - } - break; - case TextAlignment.Centered: - start = Frame.Width / 2 - caption.RuneCount / 2; - caption = $"{new string (' ', start)}{caption}{new string (' ', Frame.Width - caption.RuneCount - start)}"; - if (c_hot_pos > -1) { - c_hot_pos += start; - } - break; - case TextAlignment.Justified: - var words = caption.Split (" "); - var wLen = GetWordsLength (words, out int runeCount); - var space = (Frame.Width - runeCount) / (caption.Length - wLen); - caption = ""; - for (int i = 0; i < words.Length; i++) { - if (i == words.Length - 1) { - caption += new string (' ', Frame.Width - caption.RuneCount - 1); - caption += words [i]; - } else { - caption += words [i]; - } - if (i < words.Length - 1) { - caption += new string (' ', space); - } - } - if (c_hot_pos > -1) { - c_hot_pos += space - 1 + (wLen - runeCount == 0 ? 0 : wLen - runeCount + 1); - } - break; - } - } + var caption = GetTextAlignment (shown_text, hot_pos, out int s_hot_pos, TextAlignment); + c_hot_pos = s_hot_pos; Driver.AddStr (caption); @@ -236,18 +192,6 @@ namespace Terminal.Gui { } } - int GetWordsLength (ustring [] words, out int runeCount) - { - int length = 0; - int rCount = 0; - for (int i = 0; i < words.Length; i++) { - length += words [i].Length; - rCount += words [i].RuneCount; - } - runeCount = rCount; - return length; - } - /// public override void PositionCursor () { diff --git a/Terminal.Gui/Views/Label.cs b/Terminal.Gui/Views/Label.cs index 88d81bf6d..c387441b3 100644 --- a/Terminal.Gui/Views/Label.cs +++ b/Terminal.Gui/Views/Label.cs @@ -11,28 +11,6 @@ using System.Linq; using NStack; namespace Terminal.Gui { - /// - /// Text alignment enumeration, controls how text is displayed. - /// - public enum TextAlignment { - /// - /// Aligns the text to the left of the frame. - /// - Left, - /// - /// Aligns the text to the right side of the frame. - /// - Right, - /// - /// Centers the text in the frame. - /// - Centered, - /// - /// Shows the text as justified text in the frame. - /// - Justified - } - /// /// The Label displays a string at a given position and supports multiple lines separted by newline characters. /// diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index 9895fc41a..29f70cc01 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -89,7 +89,7 @@ namespace UICatalog { textChanger.Clicked = () => textChanger.Text += "!"; Win.Add (button = new Button ("Lets see if this will move as \"Text Changer\" grows") { - X = Pos.Right(textChanger) + 2, + X = Pos.Right (textChanger) + 2, Y = Pos.Y (textChanger), }); @@ -105,7 +105,7 @@ namespace UICatalog { var computedFrame = new FrameView ("Computed Layout") { X = 0, Y = Pos.Bottom (removeButton) + 1, - Width = Dim.Percent(50), + Width = Dim.Percent (50), Height = 5 }; Win.Add (computedFrame); @@ -113,7 +113,7 @@ namespace UICatalog { // Demonstrates how changing the View.Frame property can move Views var moveBtn = new Button ("Move This \u263b Button _via Pos") { X = 0, - Y = Pos.Center() - 1, + Y = Pos.Center () - 1, Width = 30, ColorScheme = Colors.Error, }; @@ -124,7 +124,7 @@ namespace UICatalog { computedFrame.Add (moveBtn); // Demonstrates how changing the View.Frame property can SIZE Views (#583) - var sizeBtn = new Button ("Size This \u263a Button _via Pos") { + var sizeBtn = new Button ("Size This Button _via Pos") { X = 0, Y = Pos.Center () + 1, Width = 30, @@ -132,14 +132,14 @@ namespace UICatalog { }; sizeBtn.Clicked = () => { sizeBtn.Width = sizeBtn.Frame.Width + 5; - computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly + //computedFrame.LayoutSubviews (); // FIXED: This call should not be needed. View.X is not causing relayout correctly }; computedFrame.Add (sizeBtn); var absoluteFrame = new FrameView ("Absolute Layout") { - X = Pos.Right(computedFrame), + X = Pos.Right (computedFrame), Y = Pos.Bottom (removeButton) + 1, - Width = Dim.Fill(), + Width = Dim.Fill (), Height = 5 }; Win.Add (absoluteFrame); @@ -172,34 +172,6 @@ namespace UICatalog { X = 4, Y = Pos.Bottom (label) + 1, SelectedItem = 2, - SelectedItemChanged = (args) => { - switch (args.SelectedItem) { - case 0: - moveBtn.TextAlignment = TextAlignment.Left; - sizeBtn.TextAlignment = TextAlignment.Left; - moveBtnA.TextAlignment = TextAlignment.Left; - sizeBtnA.TextAlignment = TextAlignment.Left; - break; - case 1: - moveBtn.TextAlignment = TextAlignment.Right; - sizeBtn.TextAlignment = TextAlignment.Right; - moveBtnA.TextAlignment = TextAlignment.Right; - sizeBtnA.TextAlignment = TextAlignment.Right; - break; - case 2: - moveBtn.TextAlignment = TextAlignment.Centered; - sizeBtn.TextAlignment = TextAlignment.Centered; - moveBtnA.TextAlignment = TextAlignment.Centered; - sizeBtnA.TextAlignment = TextAlignment.Centered; - break; - case 3: - moveBtn.TextAlignment = TextAlignment.Justified; - sizeBtn.TextAlignment = TextAlignment.Justified; - moveBtnA.TextAlignment = TextAlignment.Justified; - sizeBtnA.TextAlignment = TextAlignment.Justified; - break; - } - } }; Win.Add (radioGroup); @@ -208,7 +180,9 @@ namespace UICatalog { { // Remove the '_' var i = txt.IndexOf ('_'); - var start = txt [0, i]; + ustring start = ""; + if (i > -1) + start = txt [0, i]; txt = start + txt [i + 1, txt.Length]; // Move over one or go to start @@ -224,9 +198,11 @@ namespace UICatalog { return txt; } - var moveHotKeyBtn = new Button ("Click to Change th_is Button's Hotkey") { + var mhkb = "Click to Change th_is Button's Hotkey"; + var moveHotKeyBtn = new Button (mhkb) { X = 2, Y = Pos.Bottom (radioGroup) + 1, + Width = mhkb.Length + 10, ColorScheme = Colors.TopLevel, }; moveHotKeyBtn.Clicked = () => { @@ -234,15 +210,54 @@ namespace UICatalog { }; Win.Add (moveHotKeyBtn); - var moveUnicodeHotKeyBtn = new Button (" ~  s  gui.cs   master ↑10 = Сохранить") { + var muhkb = " ~  s  gui.cs   master ↑10 = Сохранить"; + var moveUnicodeHotKeyBtn = new Button (muhkb) { X = Pos.Right (moveHotKeyBtn) + 6, Y = Pos.Bottom (radioGroup) + 1, + Width = muhkb.Length + 30, ColorScheme = Colors.TopLevel, }; moveUnicodeHotKeyBtn.Clicked = () => { moveUnicodeHotKeyBtn.Text = MoveHotkey (moveUnicodeHotKeyBtn.Text); }; Win.Add (moveUnicodeHotKeyBtn); + + radioGroup.SelectedItemChanged += (args) => { + switch (args.SelectedItem) { + case 0: + moveBtn.TextAlignment = TextAlignment.Left; + sizeBtn.TextAlignment = TextAlignment.Left; + moveBtnA.TextAlignment = TextAlignment.Left; + sizeBtnA.TextAlignment = TextAlignment.Left; + moveHotKeyBtn.TextAlignment = TextAlignment.Left; + moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Left; + break; + case 1: + moveBtn.TextAlignment = TextAlignment.Right; + sizeBtn.TextAlignment = TextAlignment.Right; + moveBtnA.TextAlignment = TextAlignment.Right; + sizeBtnA.TextAlignment = TextAlignment.Right; + moveHotKeyBtn.TextAlignment = TextAlignment.Right; + moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Right; + break; + case 2: + moveBtn.TextAlignment = TextAlignment.Centered; + sizeBtn.TextAlignment = TextAlignment.Centered; + moveBtnA.TextAlignment = TextAlignment.Centered; + sizeBtnA.TextAlignment = TextAlignment.Centered; + moveHotKeyBtn.TextAlignment = TextAlignment.Centered; + moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Centered; + break; + case 3: + moveBtn.TextAlignment = TextAlignment.Justified; + sizeBtn.TextAlignment = TextAlignment.Justified; + moveBtnA.TextAlignment = TextAlignment.Justified; + sizeBtnA.TextAlignment = TextAlignment.Justified; + moveHotKeyBtn.TextAlignment = TextAlignment.Justified; + moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Justified; + break; + } + }; } } -} +} \ No newline at end of file