Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions Examples/InlineColorPicker/Program.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,68 @@
// Inline ColorPicker — demonstrates using RunnableWrapper<ColorPicker, Color?> in inline mode.
//
// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command
// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output,
// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike.
//
// Renders a ColorPicker inline in the terminal (primary buffer) without dialog buttons.
// If the user accepts (double-click), the selected color name is written to stdout.
// If the user cancels (Esc), nothing is output and exit code is 1.
//
// Usage:
// dotnet run --project Examples/InlineColorPicker
// dotnet run --project Examples/InlineColorPicker -- --initial "#FF0000"
// dotnet run --project Examples/InlineColorPicker -- --initial Red
// $color = dotnet run --project Examples/InlineColorPicker # capture in shell

using Terminal.Gui.App;
using Terminal.Gui.Drawing;
using Terminal.Gui.ViewBase;
using Terminal.Gui.Views;

// Parse command-line arguments
string? initialValue = null;

for (var i = 0; i < args.Length; i++)
{
if (args [i] is "--initial" or "-i")
{
if (i + 1 < args.Length)
{
initialValue = args [++i];
}
else
{
Console.Error.WriteLine ("Error: --initial requires a color value (e.g., \"#FF0000\" or \"Red\").");

return 1;
}
}
}

// Enable inline mode before Init
Application.AppModel = AppModel.Inline;

IApplication app = Application.Create ().Init ();

// Wrap ColorPicker in a RunnableWrapper — no dialog buttons, just the picker.
// ColorPicker raises Command.Accept on double-click.
RunnableWrapper<ColorPicker, Color?> wrapper = new ()
{
Title = "Select a Color (Double-click to accept, Esc to cancel)",
ResultExtractor = cp => cp.Value
};
RunnableWrapper<ColorPicker, Color?> wrapper = new () { Title = "Select a Color (Double-click to accept, Esc to cancel)", ResultExtractor = cp => cp.Value };

// Enable color name display
wrapper.GetWrappedView ().Style.ShowColorName = true;
wrapper.GetWrappedView ().ApplyStyleChanges ();

// Apply initial value via IValue.TrySetValueFromString if provided
if (initialValue is { })
{
if (!((IValue)wrapper.GetWrappedView ()).TrySetValueFromString (initialValue))
{
Console.Error.WriteLine ($"Error: '{initialValue}' is not a valid color (use e.g., \"#FF0000\" or \"Red\").");
app.Dispose ();

return 1;
}
}

// Run inline — blocks until user accepts or cancels
app.Run (wrapper);
Expand All @@ -39,9 +75,7 @@
{
StandardColorsNameResolver resolver = new ();

string output = resolver.TryNameColor (selectedColor, out string? name)
? name
: selectedColor.ToString ();
string output = resolver.TryNameColor (selectedColor, out string? name) ? name : selectedColor.ToString ();

Console.WriteLine (output);

Expand Down
98 changes: 59 additions & 39 deletions Examples/InlineSelect/Program.cs
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
// InlineSelect — demonstrates using RunnableWrapper<OptionSelector, int?> in inline mode.
//
// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command
// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output,
// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike.
//
// Renders an OptionSelector inline in the terminal with options from the command line.
// Supports horizontal or vertical orientation via --horizontal / --vertical flags.
// Hot keys are auto-assigned from option text.
// Supports --timeout <seconds> to auto-cancel via CancellationToken (demonstrates RunAsync).
// Supports --initial <index> to pre-select an option via IValue.TrySetValueFromString.
//
// Usage:
// dotnet run --project Examples/InlineSelect -- Apple Banana Cherry
// dotnet run --project Examples/InlineSelect -- --horizontal Red Green Blue Yellow
// dotnet run --project Examples/InlineSelect -- --vertical One Two Three
// dotnet run --project Examples/InlineSelect -- --timeout 10 Apple Banana Cherry
// dotnet run --project Examples/InlineSelect -- --initial 1 Apple Banana Cherry

using Terminal.Gui.App;
using Terminal.Gui.Drawing;
using Terminal.Gui.ViewBase;
using Terminal.Gui.Views;
using Timeout = System.Threading.Timeout;

// Parse command-line arguments
Orientation orientation = Orientation.Vertical;
List<string> options = [];
int? timeoutSeconds = null;
string? initialValue = null;

for (int i = 0; i < args.Length; i++)
for (var i = 0; i < args.Length; i++)
{
string arg = args [i];

if (arg is "--horizontal" or "-h")
{
orientation = Orientation.Horizontal;
}
else if (arg is "--vertical" or "-v")
switch (arg)
{
orientation = Orientation.Vertical;
}
else if (arg is "--timeout" or "-t")
{
if (i + 1 < args.Length && int.TryParse (args [i + 1], out int seconds))
{
case "--horizontal" or "-h": orientation = Orientation.Horizontal; break;

case "--vertical" or "-v": orientation = Orientation.Vertical; break;

case "--timeout" or "-t" when i + 1 < args.Length && int.TryParse (args [i + 1], out int seconds):
timeoutSeconds = seconds;
i++; // skip the next arg (the number)
}
else
{

break;

case "--timeout" or "-t":
Console.Error.WriteLine ("Error: --timeout requires a number of seconds.");

return 1;
}
}
else
{
options.Add (arg);

case "--initial" or "-i" when i + 1 < args.Length: initialValue = args [++i]; break;

case "--initial" or "-i":
Console.Error.WriteLine ("Error: --initial requires an index value.");

return 1;

default: options.Add (arg); break;
}
}

Expand All @@ -66,12 +74,7 @@
IApplication app = Application.Create ().Init ();

// Build the OptionSelector with command-line options
OptionSelector selector = new ()
{
Labels = options,
Orientation = orientation,
AssignHotKeys = true
};
OptionSelector selector = new () { Labels = options, Orientation = orientation, AssignHotKeys = true };

// Wrap in RunnableWrapper — auto-extracts Value via IValue<int?>
RunnableWrapper<OptionSelector, int?> wrapper = new (selector)
Expand All @@ -83,6 +86,25 @@
BorderStyle = LineStyle.Rounded
};

// Apply initial value if provided — match by label (case-insensitive) or by numeric index
if (initialValue is { })
{
// First try matching a label
int matchIndex = options.FindIndex (o => string.Equals (o, initialValue, StringComparison.OrdinalIgnoreCase));

if (matchIndex >= 0)
{
selector.Value = matchIndex;
}
else if (!((IValue)selector).TrySetValueFromString (initialValue))
{
Console.Error.WriteLine ($"Error: '{initialValue}' does not match any option and is not a valid index.");
app.Dispose ();

return 1;
}
}

// Run with optional timeout via RunAsync + CancellationToken
if (timeoutSeconds.HasValue)
{
Expand All @@ -93,22 +115,20 @@
DateTime startTime = DateTime.UtcNow;
int totalMs = timeoutSeconds.Value * 1000;

using Timer progressTimer = new (
_ => app.Invoke (
_ =>
{
int elapsedMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
int percent = Math.Min (elapsedMs * 100 / totalMs, 100);
app.Driver?.ProgressIndicator?.SetValue (percent);
}),
null,
0,
250);
await using Timer progressTimer = new (_ => app.Invoke (_ =>
{
var elapsedMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
int percent = Math.Min (elapsedMs * 100 / totalMs, 100);
app.Driver?.ProgressIndicator?.SetValue (percent);
}),
null,
0,
250);

await app.RunAsync (wrapper, cts.Token);

// Clear the progress indicator when done
progressTimer.Change (System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
progressTimer.Change (Timeout.Infinite, Timeout.Infinite);
app.Driver?.ProgressIndicator?.Clear ();
}
else
Expand All @@ -121,7 +141,7 @@

app.Dispose ();

if (result is { } selectedIndex && selectedIndex >= 0 && selectedIndex < options.Count)
if (result is { } selectedIndex and >= 0 && selectedIndex < options.Count)
{
Console.WriteLine (options [selectedIndex]);

Expand Down
61 changes: 59 additions & 2 deletions Examples/PromptExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// Example demonstrating the Prompt API for getting typed input from users
// NOTE: See https://github.com/gui-cs/clet that turns every Terminal.Gui View into a CLI command
// NOTE: — typed inputs, a real file picker, a Markdown viewer — with consistent JSON output,
// NOTE: predictable exit codes, and full keyboard/mouse support. Works for humans and AI agents alike.

using Terminal.Gui.App;
using Terminal.Gui.Configuration;
Expand All @@ -8,6 +11,7 @@
using Terminal.Gui.ViewBase;
using Terminal.Gui.Views;
using Color = Terminal.Gui.Drawing.Color;

// ReSharper disable AccessToDisposedClosure

ConfigurationManager.Enable (ConfigLocations.All);
Expand All @@ -19,7 +23,18 @@
mainWindow.Text = "This example demonstrates various uses of the Prompt API.\nPress the buttons to try different prompt types.\nPress Esc to quit.";
mainWindow.TextAlignment = Alignment.Center;

int buttonY = 0;
// Initial Value TextField — entered text is applied to prompt views via IValue.TrySetValueFromString
TextField initialValueField = new ()
{
Title = "Initial _Value (TrySetValueFromString)",
X = 0,
Y = 0,
Width = Dim.Fill (),
BorderStyle = LineStyle.Dotted
};
mainWindow.Add (initialValueField);

var buttonY = 2;

// Example 1: TextField with string result using auto-Text extraction
Button textFieldButton = new () { Title = "TextField (Auto-Text)", X = Pos.Center (), Y = buttonY++ };
Expand All @@ -31,6 +46,12 @@
prompt.Title = textFieldButton.Title;
prompt.GetWrappedView ().Width = 40;
prompt.GetWrappedView ().Text = "Default name";

if (!string.IsNullOrEmpty (initialValueField.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField.Text);
}
});

MessageBox.Query (app, textFieldButton.Title, result is { } ? $"You entered: {result}" : "Canceled", Strings.btnOk);
Expand All @@ -51,6 +72,13 @@
"Some text\nis nice.";
prompt.GetWrappedView ().Width = Dim.Fill (0, 40);
prompt.GetWrappedView ().Height = Dim.Fill (0, 8);

if (!string.IsNullOrEmpty (initialValueField.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField
.Text);
}
});

MessageBox.Query (app, textViewButton.Title, result is { } ? $"You entered: {result}" : "Canceled", Strings.btnOk);
Expand All @@ -68,6 +96,12 @@
{
prompt.Title = "Select a Date";
prompt.GetWrappedView ().Value = DateTime.Now;

if (!string.IsNullOrEmpty (initialValueField.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField.Text);
}
});

if (result is { } selectedDate)
Expand All @@ -88,7 +122,16 @@
colorPickerButton.Accepting += (_, _) =>
{
Color? result = mainWindow.Prompt<ColorPicker, Color?> (input: null,
beginInitHandler: prompt => { prompt.Title = "Pick a Color"; });
beginInitHandler: prompt =>
{
prompt.Title = "Pick a Color";

if (!string.IsNullOrEmpty (initialValueField.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField.Text);
}
});

if (result is { } selectedColor)
{
Expand All @@ -111,6 +154,12 @@
{
prompt.Title = "Pick a Color (as text)";
prompt.GetWrappedView ().SelectedColor = Color.Red;

if (!string.IsNullOrEmpty (initialValueField.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField.Text);
}
});

MessageBox.Query (app, colorTextButton.Title, result is { } ? $"Color as text: {result}" : "Canceled", Strings.btnOk);
Expand Down Expand Up @@ -178,6 +227,14 @@
beginInitHandler: prompt =>
{
prompt.Title = "Choose Selector Styles";

if (!string.IsNullOrEmpty (initialValueField
.Text))
{
((IValue)prompt.GetWrappedView ())
.TrySetValueFromString (initialValueField
.Text);
}
});

if (result is { } styles)
Expand Down
Loading
Loading