Notepad.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. // we are only interested in right clicks
  55. if(!e.MouseEvent.Flags.HasFlag(MouseFlags.Button3Clicked)) {
  56. return;
  57. }
  58. MenuBarItem items;
  59. if (e.Tab == null) {
  60. items = new MenuBarItem (new MenuItem [] {
  61. new MenuItem ($"Open", "", () => Open()),
  62. });
  63. } else {
  64. items = new MenuBarItem (new MenuItem [] {
  65. new MenuItem ($"Save", "", () => Save(e.Tab)),
  66. new MenuItem ($"Close", "", () => Close(e.Tab)),
  67. });
  68. }
  69. var contextMenu = new ContextMenu (e.MouseEvent.X + 1, e.MouseEvent.Y + 1, items);
  70. contextMenu.Show ();
  71. e.MouseEvent.Handled = true;
  72. }
  73. private void New ()
  74. {
  75. Open ("", null, $"new {numbeOfNewTabs++}");
  76. }
  77. private void Close ()
  78. {
  79. Close (tabView.SelectedTab);
  80. }
  81. private void Close (TabView.Tab tabToClose)
  82. {
  83. var tab = tabToClose as OpenedFile;
  84. if (tab == null) {
  85. return;
  86. }
  87. if (tab.UnsavedChanges) {
  88. int result = MessageBox.Query ("Save Changes", $"Save changes to {tab.Text.ToString ().TrimEnd ('*')}", "Yes", "No", "Cancel");
  89. if (result == -1 || result == 2) {
  90. // user cancelled
  91. return;
  92. }
  93. if (result == 0) {
  94. tab.Save ();
  95. }
  96. }
  97. // close and dispose the tab
  98. tabView.RemoveTab (tab);
  99. tab.View.Dispose ();
  100. }
  101. private void Open ()
  102. {
  103. var open = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = true };
  104. Application.Run (open);
  105. if (!open.Canceled) {
  106. foreach (var path in open.FilePaths) {
  107. if (string.IsNullOrEmpty (path) || !File.Exists (path)) {
  108. return;
  109. }
  110. Open (File.ReadAllText (path), new FileInfo (path), Path.GetFileName (path));
  111. }
  112. }
  113. }
  114. /// <summary>
  115. /// Creates a new tab with initial text
  116. /// </summary>
  117. /// <param name="initialText"></param>
  118. /// <param name="fileInfo">File that was read or null if a new blank document</param>
  119. private void Open (string initialText, FileInfo fileInfo, string tabName)
  120. {
  121. var textView = new TextView () {
  122. X = 0,
  123. Y = 0,
  124. Width = Dim.Fill (),
  125. Height = Dim.Fill (),
  126. Text = initialText
  127. };
  128. var tab = new OpenedFile (tabName, fileInfo, textView);
  129. tabView.AddTab (tab, true);
  130. // when user makes changes rename tab to indicate unsaved
  131. textView.KeyUp += (k) => {
  132. // if current text doesn't match saved text
  133. var areDiff = tab.UnsavedChanges;
  134. if (areDiff) {
  135. if (!tab.Text.ToString ().EndsWith ('*')) {
  136. tab.Text = tab.Text.ToString () + '*';
  137. tabView.SetNeedsDisplay ();
  138. }
  139. } else {
  140. if (tab.Text.ToString ().EndsWith ('*')) {
  141. tab.Text = tab.Text.ToString ().TrimEnd ('*');
  142. tabView.SetNeedsDisplay ();
  143. }
  144. }
  145. };
  146. }
  147. public void Save ()
  148. {
  149. Save (tabView.SelectedTab);
  150. }
  151. public void Save (TabView.Tab tabToSave)
  152. {
  153. var tab = tabToSave as OpenedFile;
  154. if (tab == null) {
  155. return;
  156. }
  157. if (tab.File == null) {
  158. SaveAs ();
  159. }
  160. tab.Save ();
  161. tabView.SetNeedsDisplay ();
  162. }
  163. public bool SaveAs ()
  164. {
  165. var tab = tabView.SelectedTab as OpenedFile;
  166. if (tab == null) {
  167. return false;
  168. }
  169. var fd = new SaveDialog ();
  170. Application.Run (fd);
  171. if (string.IsNullOrWhiteSpace (fd.FilePath?.ToString ())) {
  172. return false;
  173. }
  174. tab.File = new FileInfo (fd.FilePath.ToString ());
  175. tab.Text = fd.FileName.ToString ();
  176. tab.Save ();
  177. return true;
  178. }
  179. private class OpenedFile : TabView.Tab {
  180. public FileInfo File { get; set; }
  181. /// <summary>
  182. /// The text of the tab the last time it was saved
  183. /// </summary>
  184. /// <value></value>
  185. public string SavedText { get; set; }
  186. public bool UnsavedChanges => !string.Equals (SavedText, View.Text.ToString ());
  187. public OpenedFile (string name, FileInfo file, TextView control) : base (name, control)
  188. {
  189. File = file;
  190. SavedText = control.Text.ToString ();
  191. }
  192. internal void Save ()
  193. {
  194. var newText = View.Text.ToString ();
  195. System.IO.File.WriteAllText (File.FullName, newText);
  196. SavedText = newText;
  197. Text = Text.ToString ().TrimEnd ('*');
  198. }
  199. }
  200. private void Quit ()
  201. {
  202. Application.RequestStop ();
  203. }
  204. }
  205. }