diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
index 6a133064b..11ddcff6c 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
@@ -39,14 +39,14 @@ namespace Terminal.Gui {
}
static bool sync = false;
- public override void AddRune (Rune rune)
+ public override void AddRune (Rune rune)
{
if (Clip.Contains (ccol, crow)) {
if (needMove) {
Curses.move (crow, ccol);
needMove = false;
}
- Curses.addch ((int)(uint)rune);
+ Curses.addch ((int)(uint)MakePrintable(rune));
} else
needMove = true;
if (sync)
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
index 19196397c..f1c52c40d 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
@@ -90,6 +90,7 @@ namespace Terminal.Gui {
///
public override void AddRune (Rune rune)
{
+ rune = MakePrintable (rune);
if (Clip.Contains (ccol, crow)) {
if (needMove) {
//MockConsole.CursorLeft = ccol;
diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
index 91a39b3bf..c176d8fd2 100644
--- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
@@ -70,6 +70,7 @@ namespace Terminal.Gui {
public override void AddRune (Rune rune)
{
+ rune = MakePrintable (rune);
if (Clip.Contains (ccol, crow)) {
if (needMove) {
//Console.CursorLeft = ccol;
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
index 6397967e0..3618a849f 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
@@ -1126,6 +1126,7 @@ namespace Terminal.Gui {
public override void AddRune (Rune rune)
{
+ rune = MakePrintable (rune);
var position = crow * Cols + ccol;
if (Clip.Contains (ccol, crow)) {
diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs
index 77f61f1e2..dc709cd70 100644
--- a/Terminal.Gui/Core/ConsoleDriver.cs
+++ b/Terminal.Gui/Core/ConsoleDriver.cs
@@ -1,4 +1,4 @@
-//
+//
// ConsoleDriver.cs: Definition for the Console Driver API
//
// Authors:
@@ -558,6 +558,28 @@ namespace Terminal.Gui {
/// Rune to add.
public abstract void AddRune (Rune rune);
///
+ /// Ensures a Rune is not a control character and can be displayed by translating characters below 0x20
+ /// to equivalent, printable, Unicode chars.
+ ///
+ /// Rune to translate
+ ///
+ public static Rune MakePrintable (Rune c)
+ {
+ if (c <= 0x1F) {
+ // ASCII (C0) control characters.
+ return new Rune (c + 0x2400);
+ } else if (c >= 0x80 && c <= 0x9F) {
+ // C1 control characters (https://www.aivosto.com/articles/control-characters.html#c1)
+ return new Rune (0x25a1); // U+25A1, WHITE SQUARE, □:
+ } else if (Rune.ColumnWidth (c) > 1) {
+ // BUGBUG: Until we figure out how to fix #41. Note this still doesn't help when
+ // an Emoji or other char doesn't represent it's width correctly
+ return new Rune (0x25a1); // U+25A1, WHITE SQUARE, □:
+ } else {
+ return c;
+ }
+ }
+ ///
/// Adds the specified
///
/// String.
diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs
index 3e2aaaaf1..b9e475338 100644
--- a/Terminal.Gui/Views/Button.cs
+++ b/Terminal.Gui/Views/Button.cs
@@ -166,14 +166,6 @@ namespace Terminal.Gui {
else
shown_text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
- shown_text = shown_text
- .Replace ("\f", "\u21a1") // U+21A1 ↡ DOWNWARDS TWO HEADED ARROW
- .Replace ("\n", "\u240a") // U+240A (SYMBOL FOR LINE FEED, ␊)
- .Replace ("\r", "\u240d") // U+240D (SYMBOL FOR CARRIAGE RETURN, ␍)
- .Replace ("\t", "\u2409") // U+2409 ␉ SYMBOL FOR HORIZONTAL TABULATION
- .Replace ("\v", "\u240b") // U+240B ␋ SYMBOL FOR VERTICAL TABULATION
- .TrimSpace ();
-
shown_text = GetTextFromHotKey (shown_text, '_', out hot_pos, out hot_key);
SetNeedsDisplay ();
diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap.cs
index ca4b5303d..a875c4658 100644
--- a/UICatalog/Scenarios/CharacterMap.cs
+++ b/UICatalog/Scenarios/CharacterMap.cs
@@ -37,6 +37,9 @@ namespace UICatalog {
}
var radioItems = new (ustring radioLabel, int start, int end) [] {
+ CreateRadio("ASCII Control Characterss", 0x00, 0x1F),
+ CreateRadio("C0 Control Characters", 0x80, 0x9f),
+ CreateRadio("Hangul Jamo", 0x1100, 0x11ff), // This is where wide chars tend to start
CreateRadio("Currency Symbols", 0x20A0, 0x20CF),
CreateRadio("Letterlike Symbols", 0x2100, 0x214F),
CreateRadio("Arrows", 0x2190, 0x21ff),
@@ -106,14 +109,14 @@ namespace UICatalog {
#if true
private void CharMap_DrawContent (Rect viewport)
{
- Rune ReplaceNonPrintables (Rune c)
- {
- if (c < 0x20) {
- return new Rune (c + 0x2400); // U+25A1 □ WHITE SQUARE
- } else {
- return c;
- }
- }
+ //Rune ReplaceNonPrintables (Rune c)
+ //{
+ // if (c < 0x20) {
+ // return new Rune (c + 0x2400); // U+25A1 □ WHITE SQUARE
+ // } else {
+ // return c;
+ // }
+ //}
for (int header = 0; header < 16; header++) {
Move (viewport.X + RowHeaderWidth + (header * 2), 0);
@@ -125,10 +128,12 @@ namespace UICatalog {
var rowLabel = $"U+{val / 16:x4}x";
Move (0, y + 1);
Driver.AddStr (rowLabel);
+ var prevColWasWide = false;
for (int col = 0; col < 16; col++) {
- Move (viewport.X + RowHeaderWidth + (col * 2), 0 + y + 1);
- Driver.AddRune (' ');
- Driver.AddRune (ReplaceNonPrintables (new Rune (((uint)((uint)(-viewport.Y + row) * 16 + col)))));
+ var rune = new Rune ((uint)((uint)(-viewport.Y + row) * 16 + col));
+ Move (viewport.X + RowHeaderWidth + (col * 2) + (prevColWasWide ? 0 : 1), 0 + y + 1);
+ Driver.AddRune (rune);
+ //prevColWasWide = Rune.ColumnWidth(rune) > 1;
}
}
}