Notepad.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. using System.IO;
  2. using Terminal.Gui;
  3. namespace UICatalog.Scenarios {
  4. [ScenarioMetadata (Name: "Notepad", Description: "Multi-tab text editor uising the TabView control.")]
  5. [ScenarioCategory ("Controls"), ScenarioCategory ("TabView")]
  6. public class Notepad : Scenario {
  7. TabView tabView;
  8. private int numbeOfNewTabs = 1;
  9. // Don't create a Window, just return the top-level view
  10. public override void Init (ColorScheme colorScheme)
  11. {
  12. Application.Init ();
  13. Application.Top.ColorScheme = Colors.Base;
  14. }
  15. public override void Setup ()
  16. {
  17. var menu = new MenuBar (new MenuBarItem [] {
  18. new MenuBarItem ("_File", new MenuItem [] {
  19. new MenuItem ("_New", "", () => New()),
  20. new MenuItem ("_Open", "", () => Open()),
  21. new MenuItem ("_Save", "", () => Save()),
  22. new MenuItem ("Save _As", "", () => SaveAs()),
  23. new MenuItem ("_Close", "", () => Close()),
  24. new MenuItem ("_Quit", "", () => Quit()),
  25. })
  26. });
  27. Application.Top.Add (menu);
  28. tabView = new TabView () {
  29. X = 0,
  30. Y = 1,
  31. Width = Dim.Fill (),
  32. Height = Dim.Fill (1),
  33. };
  34. tabView.TabClicked += TabView_TabClicked;
  35. tabView.Style.ShowBorder = true;
  36. tabView.ApplyStyleChanges ();
  37. Application.Top.Add (tabView);
  38. var lenStatusItem = new StatusItem (Key.CharMask, "Len: ", null);
  39. var statusBar = new StatusBar (new StatusItem [] {
  40. new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
  41. // These shortcut keys don't seem to work correctly in linux
  42. //new StatusItem(Key.CtrlMask | Key.N, "~^O~ Open", () => Open()),
  43. //new StatusItem(Key.CtrlMask | Key.N, "~^N~ New", () => New()),
  44. new StatusItem(Key.CtrlMask | Key.S, "~^S~ Save", () => Save()),
  45. new StatusItem(Key.CtrlMask | Key.W, "~^W~ Close", () => Close()),
  46. lenStatusItem,
  47. });
  48. tabView.SelectedTabChanged += (s, e) => lenStatusItem.Title = $"Len:{(e.NewTab?.View?.Text?.Length ?? 0)}";
  49. Application.Top.Add (statusBar);
  50. New ();
  51. }
  52. private void TabView_TabClicked (object sender, TabView.TabMouseEventArgs e)
  53. {
  54. var contextMenu = new ContextMenu (e.MouseEvent.X + 1, e.MouseEvent.Y + 1,
  55. new MenuBarItem (new MenuItem [] {
  56. new MenuItem ($"Save", "", () => Save(e.Tab)),
  57. new MenuItem ($"Close", "", () => Close(e.Tab)),
  58. })
  59. );
  60. contextMenu.Show ();
  61. e.MouseEvent.Handled = true;
  62. }
  63. private void New ()
  64. {
  65. Open ("", null, $"new {numbeOfNewTabs++}");
  66. }
  67. private void Close ()
  68. {
  69. Close (tabView.SelectedTab);
  70. }
  71. private void Close (TabView.Tab tabToClose)
  72. {
  73. var tab = tabToClose as OpenedFile;
  74. if (tab == null) {
  75. return;
  76. }
  77. if (tab.UnsavedChanges) {
  78. int result = MessageBox.Query ("Save Changes", $"Save changes to {tab.Text.ToString ().TrimEnd ('*')}", "Yes", "No", "Cancel");
  79. if (result == -1 || result == 2) {
  80. // user cancelled
  81. return;
  82. }
  83. if (result == 0) {
  84. tab.Save ();
  85. }
  86. }
  87. // close and dispose the tab
  88. tabView.RemoveTab (tab);
  89. tab.View.Dispose ();
  90. }
  91. private void Open ()
  92. {
  93. var open = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = true };
  94. Application.Run (open);
  95. if (!open.Canceled) {
  96. foreach (var path in open.FilePaths) {
  97. if (string.IsNullOrEmpty (path) || !File.Exists (path)) {
  98. return;
  99. }
  100. Open (File.ReadAllText (path), new FileInfo (path), Path.GetFileName (path));
  101. }
  102. }
  103. }
  104. /// <summary>
  105. /// Creates a new tab with initial text
  106. /// </summary>
  107. /// <param name="initialText"></param>
  108. /// <param name="fileInfo">File that was read or null if a new blank document</param>
  109. private void Open (string initialText, FileInfo fileInfo, string tabName)
  110. {
  111. var textView = new TextView () {
  112. X = 0,
  113. Y = 0,
  114. Width = Dim.Fill (),
  115. Height = Dim.Fill (),
  116. Text = initialText
  117. };
  118. var tab = new OpenedFile (tabName, fileInfo, textView);
  119. tabView.AddTab (tab, true);
  120. // when user makes changes rename tab to indicate unsaved
  121. textView.KeyUp += (k) => {
  122. // if current text doesn't match saved text
  123. var areDiff = tab.UnsavedChanges;
  124. if (areDiff) {
  125. if (!tab.Text.ToString ().EndsWith ('*')) {
  126. tab.Text = tab.Text.ToString () + '*';
  127. tabView.SetNeedsDisplay ();
  128. }
  129. } else {
  130. if (tab.Text.ToString ().EndsWith ('*')) {
  131. tab.Text = tab.Text.ToString ().TrimEnd ('*');
  132. tabView.SetNeedsDisplay ();
  133. }
  134. }
  135. };
  136. }
  137. public void Save()
  138. {
  139. Save (tabView.SelectedTab);
  140. }
  141. public void Save (TabView.Tab tabToSave )
  142. {
  143. var tab = tabToSave as OpenedFile;
  144. if (tab == null) {
  145. return;
  146. }
  147. if (tab.File == null) {
  148. SaveAs ();
  149. }
  150. tab.Save ();
  151. tabView.SetNeedsDisplay ();
  152. }
  153. public bool SaveAs ()
  154. {
  155. var tab = tabView.SelectedTab as OpenedFile;
  156. if (tab == null) {
  157. return false;
  158. }
  159. var fd = new SaveDialog ();
  160. Application.Run (fd);
  161. if (string.IsNullOrWhiteSpace (fd.FilePath?.ToString ())) {
  162. return false;
  163. }
  164. tab.File = new FileInfo (fd.FilePath.ToString ());
  165. tab.Text = fd.FileName.ToString ();
  166. tab.Save ();
  167. return true;
  168. }
  169. private class OpenedFile : TabView.Tab {
  170. public FileInfo File { get; set; }
  171. /// <summary>
  172. /// The text of the tab the last time it was saved
  173. /// </summary>
  174. /// <value></value>
  175. public string SavedText { get; set; }
  176. public bool UnsavedChanges => !string.Equals (SavedText, View.Text.ToString ());
  177. public OpenedFile (string name, FileInfo file, TextView control) : base (name, control)
  178. {
  179. File = file;
  180. SavedText = control.Text.ToString ();
  181. }
  182. internal void Save ()
  183. {
  184. var newText = View.Text.ToString ();
  185. System.IO.File.WriteAllText (File.FullName, newText);
  186. SavedText = newText;
  187. Text = Text.ToString ().TrimEnd ('*');
  188. }
  189. }
  190. private void Quit ()
  191. {
  192. Application.RequestStop ();
  193. }
  194. }
  195. }