mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
@@ -1,4 +1,5 @@
|
||||
#nullable enable
|
||||
|
||||
namespace UICatalog.Scenarios;
|
||||
|
||||
[ScenarioMetadata ("Notepad", "Multi-tab text editor using the TabView control.")]
|
||||
@@ -16,41 +17,65 @@ public class Notepad : Scenario
|
||||
{
|
||||
Application.Init ();
|
||||
|
||||
Toplevel top = new ();
|
||||
|
||||
var menu = new MenuBar
|
||||
Window top = new ()
|
||||
{
|
||||
Menus =
|
||||
[
|
||||
new (
|
||||
"_File",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_New",
|
||||
"",
|
||||
() => New (),
|
||||
null,
|
||||
null,
|
||||
KeyCode.N
|
||||
| KeyCode.CtrlMask
|
||||
| KeyCode.AltMask
|
||||
),
|
||||
new ("_Open", "", Open),
|
||||
new ("_Save", "", Save),
|
||||
new ("Save _As", "", () => SaveAs ()),
|
||||
new ("_Close", "", Close),
|
||||
new ("_Quit", "", Quit)
|
||||
}
|
||||
),
|
||||
new (
|
||||
"_About",
|
||||
"",
|
||||
() => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
|
||||
)
|
||||
]
|
||||
BorderStyle = LineStyle.None,
|
||||
};
|
||||
top.Add (menu);
|
||||
|
||||
// MenuBar
|
||||
MenuBar menu = new ();
|
||||
|
||||
menu.Add (
|
||||
new MenuBarItem (
|
||||
"_File",
|
||||
[
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_New",
|
||||
Key = Key.N.WithCtrl.WithAlt,
|
||||
Action = New
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_Open",
|
||||
Action = Open
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_Save",
|
||||
Action = Save
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Title = "Save _As",
|
||||
Action = () => SaveAs ()
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_Close",
|
||||
Action = Close
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_Quit",
|
||||
Action = Quit
|
||||
}
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
menu.Add (
|
||||
new MenuBarItem (
|
||||
"_About",
|
||||
[
|
||||
new MenuItem
|
||||
{
|
||||
Title = "_About",
|
||||
Action = () => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
|
||||
}
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
_tabView = CreateNewTabView ();
|
||||
|
||||
@@ -58,27 +83,28 @@ public class Notepad : Scenario
|
||||
_tabView.ApplyStyleChanges ();
|
||||
|
||||
_tabView.X = 0;
|
||||
_tabView.Y = 1;
|
||||
_tabView.Y = Pos.Bottom (menu);
|
||||
_tabView.Width = Dim.Fill ();
|
||||
_tabView.Height = Dim.Fill (1);
|
||||
|
||||
top.Add (_tabView);
|
||||
LenShortcut = new (Key.Empty, "Len: ", null);
|
||||
|
||||
var statusBar = new StatusBar (
|
||||
[
|
||||
new (Application.QuitKey, "Quit", Quit),
|
||||
new (Key.F2, "Open", Open),
|
||||
new (Key.F1, "New", New),
|
||||
new (Key.F3, "Save", Save),
|
||||
new (Key.F6, "Close", Close),
|
||||
LenShortcut
|
||||
]
|
||||
)
|
||||
// StatusBar
|
||||
StatusBar statusBar = new (
|
||||
[
|
||||
new (Application.QuitKey, "Quit", Quit),
|
||||
new (Key.F2, "Open", Open),
|
||||
new (Key.F1, "New", New),
|
||||
new (Key.F3, "Save", Save),
|
||||
new (Key.F6, "Close", Close),
|
||||
LenShortcut
|
||||
]
|
||||
)
|
||||
{
|
||||
AlignmentModes = AlignmentModes.IgnoreFirstOrLast
|
||||
};
|
||||
top.Add (statusBar);
|
||||
|
||||
top.Add (menu, _tabView, statusBar);
|
||||
|
||||
_focusedTabView = _tabView;
|
||||
_tabView.SelectedTabChanged += TabView_SelectedTabChanged;
|
||||
@@ -87,55 +113,52 @@ public class Notepad : Scenario
|
||||
top.Ready += (s, e) =>
|
||||
{
|
||||
New ();
|
||||
LenShortcut.Title = $"Len:{_focusedTabView.Text?.Length ?? 0}";
|
||||
LenShortcut.Title = $"Len:{_focusedTabView?.Text?.Length ?? 0}";
|
||||
};
|
||||
|
||||
Application.Run (top);
|
||||
top.Dispose ();
|
||||
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
public void Save () { Save (_focusedTabView!, _focusedTabView!.SelectedTab!); }
|
||||
public void Save ()
|
||||
{
|
||||
if (_focusedTabView?.SelectedTab is { })
|
||||
{
|
||||
Save (_focusedTabView, _focusedTabView.SelectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save (TabView tabViewToSave, Tab tabToSave)
|
||||
{
|
||||
var tab = tabToSave as OpenedFile;
|
||||
|
||||
if (tab == null)
|
||||
if (tabToSave is not OpenedFile tab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab.File == null)
|
||||
if (tab.File is null)
|
||||
{
|
||||
SaveAs ();
|
||||
}
|
||||
else
|
||||
{
|
||||
tab.Save ();
|
||||
}
|
||||
|
||||
tab.Save ();
|
||||
tabViewToSave.SetNeedsDraw ();
|
||||
}
|
||||
|
||||
public bool SaveAs ()
|
||||
{
|
||||
var tab = _focusedTabView!.SelectedTab as OpenedFile;
|
||||
|
||||
if (tab == null)
|
||||
if (_focusedTabView?.SelectedTab is not OpenedFile tab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fd = new SaveDialog ();
|
||||
SaveDialog fd = new ();
|
||||
Application.Run (fd);
|
||||
|
||||
if (string.IsNullOrWhiteSpace (fd.Path))
|
||||
{
|
||||
fd.Dispose ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fd.Canceled)
|
||||
if (string.IsNullOrWhiteSpace (fd.Path) || fd.Canceled)
|
||||
{
|
||||
fd.Dispose ();
|
||||
|
||||
@@ -151,13 +174,17 @@ public class Notepad : Scenario
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Close () { Close (_focusedTabView!, _focusedTabView!.SelectedTab!); }
|
||||
private void Close ()
|
||||
{
|
||||
if (_focusedTabView?.SelectedTab is { })
|
||||
{
|
||||
Close (_focusedTabView, _focusedTabView.SelectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
private void Close (TabView tv, Tab tabToClose)
|
||||
{
|
||||
var tab = tabToClose as OpenedFile;
|
||||
|
||||
if (tab == null)
|
||||
if (tabToClose is not OpenedFile tab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -182,7 +209,7 @@ public class Notepad : Scenario
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
if (tab.File == null)
|
||||
if (tab.File is null)
|
||||
{
|
||||
SaveAs ();
|
||||
}
|
||||
@@ -207,7 +234,7 @@ public class Notepad : Scenario
|
||||
|
||||
private TabView CreateNewTabView ()
|
||||
{
|
||||
var tv = new TabView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
|
||||
TabView tv = new () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
|
||||
|
||||
tv.TabClicked += TabView_TabClicked;
|
||||
tv.SelectedTabChanged += TabView_SelectedTabChanged;
|
||||
@@ -220,7 +247,7 @@ public class Notepad : Scenario
|
||||
|
||||
private void Open ()
|
||||
{
|
||||
var open = new OpenDialog { Title = "Open", AllowsMultipleSelection = true };
|
||||
OpenDialog open = new () { Title = "Open", AllowsMultipleSelection = true };
|
||||
|
||||
Application.Run (open);
|
||||
|
||||
@@ -246,21 +273,29 @@ public class Notepad : Scenario
|
||||
/// <summary>Creates a new tab with initial text</summary>
|
||||
/// <param name="fileInfo">File that was read or null if a new blank document</param>
|
||||
/// <param name="tabName"></param>
|
||||
private void Open (FileInfo fileInfo, string tabName)
|
||||
private void Open (FileInfo? fileInfo, string tabName)
|
||||
{
|
||||
var tab = new OpenedFile (this) { DisplayText = tabName, File = fileInfo };
|
||||
if (_focusedTabView is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OpenedFile tab = new (this) { DisplayText = tabName, File = fileInfo };
|
||||
tab.View = tab.CreateTextView (fileInfo);
|
||||
tab.SavedText = tab.View.Text;
|
||||
tab.RegisterTextViewEvents (_focusedTabView!);
|
||||
tab.RegisterTextViewEvents (_focusedTabView);
|
||||
|
||||
_focusedTabView!.AddTab (tab, true);
|
||||
_focusedTabView.AddTab (tab, true);
|
||||
}
|
||||
|
||||
private void Quit () { Application.RequestStop (); }
|
||||
|
||||
private void TabView_SelectedTabChanged (object? sender, TabChangedEventArgs e)
|
||||
{
|
||||
LenShortcut!.Title = $"Len:{e.NewTab?.View?.Text?.Length ?? 0}";
|
||||
if (LenShortcut is { })
|
||||
{
|
||||
LenShortcut.Title = $"Len:{e.NewTab?.View?.Text?.Length ?? 0}";
|
||||
}
|
||||
|
||||
e.NewTab?.View?.SetFocus ();
|
||||
}
|
||||
@@ -275,30 +310,33 @@ public class Notepad : Scenario
|
||||
|
||||
View [] items;
|
||||
|
||||
if (e.Tab == null)
|
||||
if (e.Tab is null)
|
||||
{
|
||||
items = [new MenuItemv2 ("Open", "", Open)];
|
||||
items = [new MenuItem { Title = "Open", Action = Open }];
|
||||
}
|
||||
else
|
||||
{
|
||||
var tv = (TabView)sender!;
|
||||
var t = (OpenedFile)e.Tab;
|
||||
|
||||
items =
|
||||
[
|
||||
new MenuItemv2 ("Save", "", () => Save (_focusedTabView!, e.Tab)),
|
||||
new MenuItemv2 ("Close", "", () => Close (tv, e.Tab))
|
||||
new MenuItem { Title = "Save", Action = () => Save (_focusedTabView!, e.Tab) },
|
||||
new MenuItem { Title = "Close", Action = () => Close (tv, e.Tab) }
|
||||
];
|
||||
|
||||
PopoverMenu? contextMenu = new (items);
|
||||
|
||||
// Registering with the PopoverManager will ensure that the context menu is closed when the view is no longer focused
|
||||
// and the context menu is disposed when it is closed.
|
||||
tv.App!.Popover?.Register (contextMenu);
|
||||
contextMenu?.MakeVisible (e.MouseEvent.ScreenPosition);
|
||||
|
||||
e.MouseEvent.Handled = true;
|
||||
}
|
||||
|
||||
PopoverMenu contextMenu = new (items);
|
||||
|
||||
// Registering with the PopoverManager will ensure that the context menu is closed when the view is no longer focused
|
||||
// and the context menu is disposed when it is closed.
|
||||
if (sender is TabView tabView && tabView.App?.Popover is { })
|
||||
{
|
||||
tabView.App.Popover.Register (contextMenu);
|
||||
}
|
||||
|
||||
contextMenu.MakeVisible (e.MouseEvent.ScreenPosition);
|
||||
|
||||
e.MouseEvent.Handled = true;
|
||||
}
|
||||
|
||||
private class OpenedFile (Notepad notepad) : Tab
|
||||
@@ -307,8 +345,8 @@ public class Notepad : Scenario
|
||||
|
||||
public OpenedFile CloneTo (TabView other)
|
||||
{
|
||||
var newTab = new OpenedFile (_notepad) { DisplayText = base.Text, File = File };
|
||||
newTab.View = newTab.CreateTextView (newTab.File!);
|
||||
OpenedFile newTab = new (_notepad) { DisplayText = Text, File = File };
|
||||
newTab.View = newTab.CreateTextView (newTab.File);
|
||||
newTab.SavedText = newTab.View.Text;
|
||||
newTab.RegisterTextViewEvents (other);
|
||||
other.AddTab (newTab, true);
|
||||
@@ -340,7 +378,10 @@ public class Notepad : Scenario
|
||||
|
||||
public void RegisterTextViewEvents (TabView parent)
|
||||
{
|
||||
var textView = (TextView)View!;
|
||||
if (View is not TextView textView)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// when user makes changes rename tab to indicate unsaved
|
||||
textView.ContentsChanged += (s, k) =>
|
||||
@@ -363,25 +404,27 @@ public class Notepad : Scenario
|
||||
}
|
||||
}
|
||||
|
||||
_notepad.LenShortcut!.Title = $"Len:{textView.Text.Length}";
|
||||
if (_notepad.LenShortcut is { })
|
||||
{
|
||||
_notepad.LenShortcut.Title = $"Len:{textView.Text.Length}";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>The text of the tab the last time it was saved</summary>
|
||||
/// <value></value>
|
||||
public string? SavedText { get; set; }
|
||||
|
||||
public bool UnsavedChanges => !string.Equals (SavedText, View!.Text);
|
||||
public bool UnsavedChanges => View is { } && !string.Equals (SavedText, View.Text);
|
||||
|
||||
internal void Save ()
|
||||
{
|
||||
string newText = View!.Text;
|
||||
|
||||
if (File is null || string.IsNullOrWhiteSpace (File.FullName))
|
||||
if (View is null || File is null || string.IsNullOrWhiteSpace (File.FullName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string newText = View.Text;
|
||||
|
||||
System.IO.File.WriteAllText (File.FullName, newText);
|
||||
SavedText = newText;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user