using System.IO;
using Terminal.Gui;
namespace UICatalog.Scenarios {
[ScenarioMetadata (Name: "Notepad", Description: "Multi-tab text editor uising the TabView control.")]
[ScenarioCategory ("Controls"), ScenarioCategory ("TabView")]
public class Notepad : Scenario {
TabView tabView;
private int numbeOfNewTabs = 1;
// Don't create a Window, just return the top-level view
public override void Init (ColorScheme colorScheme)
{
Application.Init ();
Application.Top.ColorScheme = Colors.Base;
}
public override void Setup ()
{
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_New", "", () => New()),
new MenuItem ("_Open", "", () => Open()),
new MenuItem ("_Save", "", () => Save()),
new MenuItem ("Save _As", "", () => SaveAs()),
new MenuItem ("_Close", "", () => Close()),
new MenuItem ("_Quit", "", () => Quit()),
})
});
Application.Top.Add (menu);
tabView = new TabView () {
X = 0,
Y = 1,
Width = Dim.Fill (),
Height = Dim.Fill (1),
};
tabView.TabClicked += TabView_TabClicked;
tabView.Style.ShowBorder = true;
tabView.ApplyStyleChanges ();
Application.Top.Add (tabView);
var lenStatusItem = new StatusItem (Key.CharMask, "Len: ", null);
var statusBar = new StatusBar (new StatusItem [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
// These shortcut keys don't seem to work correctly in linux
//new StatusItem(Key.CtrlMask | Key.N, "~^O~ Open", () => Open()),
//new StatusItem(Key.CtrlMask | Key.N, "~^N~ New", () => New()),
new StatusItem(Key.CtrlMask | Key.S, "~^S~ Save", () => Save()),
new StatusItem(Key.CtrlMask | Key.W, "~^W~ Close", () => Close()),
lenStatusItem,
});
tabView.SelectedTabChanged += (s, e) => lenStatusItem.Title = $"Len:{(e.NewTab?.View?.Text?.Length ?? 0)}";
Application.Top.Add (statusBar);
New ();
}
private void TabView_TabClicked (object sender, TabView.TabMouseEventArgs e)
{
// we are only interested in right clicks
if(!e.MouseEvent.Flags.HasFlag(MouseFlags.Button3Clicked)) {
return;
}
MenuBarItem items;
if (e.Tab == null) {
items = new MenuBarItem (new MenuItem [] {
new MenuItem ($"Open", "", () => Open()),
});
} else {
items = new MenuBarItem (new MenuItem [] {
new MenuItem ($"Save", "", () => Save(e.Tab)),
new MenuItem ($"Close", "", () => Close(e.Tab)),
});
}
var contextMenu = new ContextMenu (e.MouseEvent.X + 1, e.MouseEvent.Y + 1, items);
contextMenu.Show ();
e.MouseEvent.Handled = true;
}
private void New ()
{
Open ("", null, $"new {numbeOfNewTabs++}");
}
private void Close ()
{
Close (tabView.SelectedTab);
}
private void Close (TabView.Tab tabToClose)
{
var tab = tabToClose as OpenedFile;
if (tab == null) {
return;
}
if (tab.UnsavedChanges) {
int result = MessageBox.Query ("Save Changes", $"Save changes to {tab.Text.ToString ().TrimEnd ('*')}", "Yes", "No", "Cancel");
if (result == -1 || result == 2) {
// user cancelled
return;
}
if (result == 0) {
tab.Save ();
}
}
// close and dispose the tab
tabView.RemoveTab (tab);
tab.View.Dispose ();
}
private void Open ()
{
var open = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = true };
Application.Run (open);
if (!open.Canceled) {
foreach (var path in open.FilePaths) {
if (string.IsNullOrEmpty (path) || !File.Exists (path)) {
return;
}
Open (File.ReadAllText (path), new FileInfo (path), Path.GetFileName (path));
}
}
}
///
/// Creates a new tab with initial text
///
///
/// File that was read or null if a new blank document
private void Open (string initialText, FileInfo fileInfo, string tabName)
{
var textView = new TextView () {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
Text = initialText
};
var tab = new OpenedFile (tabName, fileInfo, textView);
tabView.AddTab (tab, true);
// when user makes changes rename tab to indicate unsaved
textView.KeyUp += (k) => {
// if current text doesn't match saved text
var areDiff = tab.UnsavedChanges;
if (areDiff) {
if (!tab.Text.ToString ().EndsWith ('*')) {
tab.Text = tab.Text.ToString () + '*';
tabView.SetNeedsDisplay ();
}
} else {
if (tab.Text.ToString ().EndsWith ('*')) {
tab.Text = tab.Text.ToString ().TrimEnd ('*');
tabView.SetNeedsDisplay ();
}
}
};
}
public void Save ()
{
Save (tabView.SelectedTab);
}
public void Save (TabView.Tab tabToSave)
{
var tab = tabToSave as OpenedFile;
if (tab == null) {
return;
}
if (tab.File == null) {
SaveAs ();
}
tab.Save ();
tabView.SetNeedsDisplay ();
}
public bool SaveAs ()
{
var tab = tabView.SelectedTab as OpenedFile;
if (tab == null) {
return false;
}
var fd = new SaveDialog ();
Application.Run (fd);
if (string.IsNullOrWhiteSpace (fd.FilePath?.ToString ())) {
return false;
}
tab.File = new FileInfo (fd.FilePath.ToString ());
tab.Text = fd.FileName.ToString ();
tab.Save ();
return true;
}
private class OpenedFile : TabView.Tab {
public FileInfo File { get; set; }
///
/// The text of the tab the last time it was saved
///
///
public string SavedText { get; set; }
public bool UnsavedChanges => !string.Equals (SavedText, View.Text.ToString ());
public OpenedFile (string name, FileInfo file, TextView control) : base (name, control)
{
File = file;
SavedText = control.Text.ToString ();
}
internal void Save ()
{
var newText = View.Text.ToString ();
System.IO.File.WriteAllText (File.FullName, newText);
SavedText = newText;
Text = Text.ToString ().TrimEnd ('*');
}
}
private void Quit ()
{
Application.RequestStop ();
}
}
}