Terminal
Ein Terminal wie in PuTTY oder Windows Terminal: Zellraster mit Farben (ANSI, 256, RGB), Merkmalen, breiten Zeichen und Rückblick, ein blinkender Cursor, Auswahl (Doppelklick: Wort, Dreifachklick: Zeile, Alt+Ziehen: Rechteck), Kopieren und Einfügen. Die Steuerfolgen deutet die Anwendung; hier antwortet eine kleine Kommandozeile: „hilfe“, „farben“, „breit“, „leer“.


KXAML
TerminalSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
xmlns:x="https://ui.kuonen.org/kxaml/x"
x:Class="Kuonen.UI.Galerie.Seiten.TerminalVorfuehrung"
Spacing="8">
<StackPanel Orientation="Horizontal" Spacing="8">
<ComboBox x:Name="Bedienung" MinWidth="120" />
<CheckBox x:Name="Hell" Content="Hell" />
</StackPanel>
<TerminalView x:Name="Terminal" Height="320" />
</StackPanel>TerminalSeite.kxaml.cs
using Kuonen.UI;
namespace Kuonen.UI.Galerie.Seiten;
public sealed partial class TerminalSeite
{
protected override Func<UIElement>? KxamlFabrik => () => new TerminalVorfuehrung();
}
/// <summary>KXAML-Fassung der Seite Terminal: der Aufbau steht in TerminalSeite.kxaml, hier das Verhalten.</summary>
public sealed partial class TerminalVorfuehrung
{
public TerminalVorfuehrung()
{
InitializeComponent();
TerminalSeite.Verdrahte(Terminal, Bedienung, Hell);
}
}C#
TerminalSeite.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;
namespace Kuonen.UI.Galerie.Seiten;
/// <summary>Galerie-Seite: das Terminal (<see cref="TerminalView"/>) mit einer kleinen eingebauten Kommandozeile statt einer echten Gegenstelle.</summary>
public sealed partial class TerminalSeite : GalerieSeite
{
public override string Titel => "Terminal";
public override string Beschreibung =>
"Ein Terminal wie in PuTTY oder Windows Terminal: Zellraster mit Farben (ANSI, 256, RGB), Merkmalen, breiten Zeichen und Rückblick, ein blinkender "
+ "Cursor, Auswahl (Doppelklick: Wort, Dreifachklick: Zeile, Alt+Ziehen: Rechteck), Kopieren und Einfügen. Die Steuerfolgen deutet die Anwendung; "
+ "hier antwortet eine kleine Kommandozeile: „hilfe“, „farben“, „breit“, „leer“.";
public override string Stichworte =>
"TerminalView Terminal Konsole Console Shell PuTTY xterm VT100 ANSI SSH Telnet Emulator Rückblick Scrollback Cursor Auswahl Kopieren Einfügen";
public override string Datei => nameof(TerminalSeite);
/// <summary>Die Eingabeaufforderung der kleinen Kommandozeile.</summary>
public const string Aufforderung = "kuonen> ";
internal static readonly string[] Bedienungen = ["Modern", "PuTTY", "xterm"];
/// <summary>Das Verhalten beider Fassungen: Bedienung und Schema wählen, die Kommandozeile antwortet auf die Eingaben.</summary>
internal static void Verdrahte(TerminalView terminal, ComboBox bedienung, CheckBox hell)
{
var puffer = terminal.Puffer;
var zeile = new System.Text.StringBuilder();
Begruesse(puffer);
bedienung.ItemsSource = Bedienungen;
bedienung.SelectedIndex = 0;
bedienung.SelectionChanged += (_, _) => terminal.Bedienung = (TerminalBedienung)Math.Max(0, bedienung.SelectedIndex);
hell.Checked += (_, _) => terminal.Farbschema = TerminalFarbschema.Hell;
hell.Unchecked += (_, _) => terminal.Farbschema = TerminalFarbschema.Dunkel;
terminal.Senden += eingabe =>
{
using var _ = puffer.Aendern();
foreach (var rune in eingabe.EnumerateRunes())
{
if (rune.Value == '\r')
{
puffer.Schreibe("\r\n");
Fuehre(puffer, zeile.ToString().Trim());
zeile.Clear();
puffer.Schreibe(Aufforderung);
}
else if (rune.Value is 0x7F or '\b')
{
if (zeile.Length == 0) continue;
zeile.Length -= char.IsLowSurrogate(zeile[^1]) ? 2 : 1;
puffer.Schreibe("\b \b");
}
else if (rune.Value >= ' ' && !System.Text.Rune.IsControl(rune))
{
zeile.Append(rune.ToString());
puffer.SchreibeZeichen(rune.Value);
}
}
};
}
private static void Begruesse(TerminalPuffer puffer)
{
puffer.Vordergrund = TerminalFarbe.Palette(10);
puffer.Merkmale = TerminalMerkmal.Fett;
puffer.Schreibe("Kuonen.UI Terminal\r\n");
puffer.Merkmale = TerminalMerkmal.Keine;
puffer.Vordergrund = TerminalFarbe.Vorgabe;
puffer.Schreibe("Tippen Sie „hilfe“ und Enter.\r\n" + Aufforderung);
}
internal static void Fuehre(TerminalPuffer puffer, string befehl)
{
switch (befehl)
{
case "":
break;
case "hilfe":
puffer.Schreibe("farben die 16 ANSI-Farben, Würfel und Graustufen\r\nbreit breite und kombinierende Zeichen\r\nleer Bildschirm leeren\r\n");
break;
case "farben":
for (int i = 0; i < 16; i++)
{
puffer.Hintergrund = TerminalFarbe.Palette(i);
puffer.Schreibe(" ");
}
puffer.Hintergrund = TerminalFarbe.Vorgabe;
puffer.Schreibe("\r\n");
for (int i = 16; i < 256; i += 6)
{
puffer.Hintergrund = TerminalFarbe.Palette(i);
puffer.Schreibe(" ");
}
puffer.Hintergrund = TerminalFarbe.Vorgabe;
puffer.Schreibe("\r\n");
foreach (var (merkmal, name) in new[] { (TerminalMerkmal.Fett, "fett"), (TerminalMerkmal.Kursiv, "kursiv"), (TerminalMerkmal.Unterstrichen, "unterstrichen"),
(TerminalMerkmal.Durchgestrichen, "durchgestrichen"), (TerminalMerkmal.Umgekehrt, "umgekehrt"), (TerminalMerkmal.Blinkend, "blinkend") })
{
puffer.Merkmale = merkmal;
puffer.Schreibe(name);
puffer.Merkmale = TerminalMerkmal.Keine;
puffer.Schreibe(" ");
}
puffer.Schreibe("\r\n");
break;
case "breit":
puffer.Schreibe("中文 日本語 한국어 😀 é ü\r\n");
break;
case "leer":
puffer.LoescheZeilenBereich();
puffer.SetzeCursor(0, 0);
break;
default:
puffer.Vordergrund = TerminalFarbe.Palette(9);
puffer.Schreibe($"Unbekannt: {befehl}\r\n");
puffer.Vordergrund = TerminalFarbe.Vorgabe;
break;
}
}
public override UIElement Baue()
{
var terminal = new TerminalView { Height = 320 };
var bedienung = new ComboBox { MinWidth = 120 };
var hell = new CheckBox { Content = "Hell" };
Verdrahte(terminal, bedienung, hell);
var leiste = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, Children = { bedienung, hell } };
return new StackPanel { Spacing = 8, Children = { leiste, terminal } };
}
}