FileDialog.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. //
  2. // FileDialog.cs: File system dialogs for open and save
  3. //
  4. using System;
  5. using System.Collections.Generic;
  6. using NStack;
  7. using System.IO;
  8. using System.Linq;
  9. namespace Terminal.Gui {
  10. internal class DirListView : View {
  11. int topFile, currentFile;
  12. DirectoryInfo dirInfo;
  13. List<FileSystemInfo> infos;
  14. public DirListView ()
  15. {
  16. infos = new List<FileSystemInfo> ();
  17. CanFocus = true;
  18. }
  19. void Reload ()
  20. {
  21. dirInfo = new DirectoryInfo (directory);
  22. infos = (from x in dirInfo.GetFileSystemInfos () orderby (!x.Attributes.HasFlag (FileAttributes.Directory)) + x.Name select x).ToList ();
  23. topFile = 0;
  24. currentFile = 0;
  25. SetNeedsDisplay ();
  26. }
  27. string directory;
  28. public string Directory {
  29. get => directory;
  30. set {
  31. if (directory != value)
  32. return;
  33. directory = value;
  34. Reload ();
  35. }
  36. }
  37. public override void Redraw (Rect region)
  38. {
  39. Driver.SetAttribute (ColorScheme.Focus);
  40. var g = Frame;
  41. for (int y = 0; y < g.Height; y++) {
  42. Move (0, y);
  43. for (int x = 0; x < g.Width; x++) {
  44. Rune r;
  45. switch (x % 3) {
  46. case 0:
  47. r = '.';
  48. break;
  49. case 1:
  50. r = 'o';
  51. break;
  52. default:
  53. r = 'O';
  54. break;
  55. }
  56. Driver.AddRune (r);
  57. }
  58. }
  59. return;
  60. var current = ColorScheme.Focus;
  61. Driver.SetAttribute (current);
  62. Move (0, 0);
  63. var f = Frame;
  64. var item = topFile;
  65. bool focused = HasFocus;
  66. var width = region.Width;
  67. bool isSelected = false;
  68. for (int row = 0; row < f.Height; row++, item++) {
  69. var newcolor = focused ? (isSelected ? ColorScheme.Focus : ColorScheme.Normal) : ColorScheme.Normal;
  70. if (newcolor != current) {
  71. Driver.SetAttribute (newcolor);
  72. current = newcolor;
  73. }
  74. if (item >= infos.Count) {
  75. for (int c = 0; c < f.Width; c++)
  76. Driver.AddRune (' ');
  77. continue;
  78. }
  79. var fi = infos [item];
  80. var ustr = ustring.Make (fi.Name);
  81. int byteLen = ustr.Length;
  82. int used = 0;
  83. for (int i = 0; i < byteLen;) {
  84. (var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
  85. var count = Rune.ColumnWidth (rune);
  86. if (used + count >= width)
  87. break;
  88. Driver.AddRune (rune);
  89. used += count;
  90. i += size;
  91. }
  92. for (; used < width; used++) {
  93. Driver.AddRune (' ');
  94. }
  95. }
  96. }
  97. }
  98. public class FileDialog : Dialog {
  99. Button prompt, cancel;
  100. Label nameFieldLabel, message, dirLabel;
  101. TextField dirEntry, nameEntry;
  102. DirListView dirListView;
  103. public FileDialog (ustring title, ustring prompt, ustring nameFieldLabel, ustring message) : base (title, Driver.Cols - 20, Driver.Rows - 6, null)
  104. {
  105. this.message = new Label (Rect.Empty, "MESSAGE" + message);
  106. var msgLines = Label.MeasureLines (message, Driver.Cols - 20);
  107. dirLabel = new Label ("Directory: ") {
  108. X = 2,
  109. Y = 1 + msgLines
  110. };
  111. dirEntry = new TextField ("") {
  112. X = 12,
  113. Y = 1 + msgLines,
  114. Width = Dim.Fill () - 1
  115. };
  116. Add (dirLabel, dirEntry);
  117. this.nameFieldLabel = new Label (nameFieldLabel) {
  118. X = 2,
  119. Y = 3 + msgLines,
  120. };
  121. nameEntry = new TextField ("") {
  122. X = 2 + nameFieldLabel.RuneCount + 1,
  123. Y = 3 + msgLines,
  124. Width = Dim.Fill () - 1
  125. };
  126. Add (this.nameFieldLabel, nameEntry);
  127. dirListView = new DirListView () {
  128. X = 2,
  129. Y = 3 + msgLines + 2,
  130. Width = Dim.Fill (),
  131. Height = Dim.Fill (),
  132. Directory = "."
  133. };
  134. Add (dirListView);
  135. this.cancel = new Button ("Cancel");
  136. AddButton (cancel);
  137. this.prompt = new Button (prompt);
  138. AddButton (this.prompt);
  139. }
  140. /// <summary>
  141. /// Gets or sets the prompt label for the button displayed to the user
  142. /// </summary>
  143. /// <value>The prompt.</value>
  144. public ustring Prompt {
  145. get => prompt.Text;
  146. set {
  147. prompt.Text = value;
  148. }
  149. }
  150. /// <summary>
  151. /// Gets or sets the name field label.
  152. /// </summary>
  153. /// <value>The name field label.</value>
  154. public ustring NameFieldLabel {
  155. get => nameFieldLabel.Text;
  156. set {
  157. nameFieldLabel.Text = value;
  158. }
  159. }
  160. /// <summary>
  161. /// Gets or sets the message displayed to the user, defaults to nothing
  162. /// </summary>
  163. /// <value>The message.</value>
  164. public ustring Message {
  165. get => message.Text;
  166. set {
  167. message.Text = value;
  168. }
  169. }
  170. /// <summary>
  171. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.FileDialog"/> can create directories.
  172. /// </summary>
  173. /// <value><c>true</c> if can create directories; otherwise, <c>false</c>.</value>
  174. public bool CanCreateDirectories { get; set; }
  175. /// <summary>
  176. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.FileDialog"/> is extension hidden.
  177. /// </summary>
  178. /// <value><c>true</c> if is extension hidden; otherwise, <c>false</c>.</value>
  179. public bool IsExtensionHidden { get; set; }
  180. /// <summary>
  181. /// Gets or sets the directory path for this panel
  182. /// </summary>
  183. /// <value>The directory path.</value>
  184. public ustring DirectoryPath {
  185. get => dirEntry.Text;
  186. set {
  187. dirEntry.Text = value;
  188. }
  189. }
  190. /// <summary>
  191. /// The array of filename extensions allowed, or null if all file extensions are allowed.
  192. /// </summary>
  193. /// <value>The allowed file types.</value>
  194. public ustring [] AllowedFileTypes { get; set; }
  195. /// <summary>
  196. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.FileDialog"/> allows the file to be saved with a different extension
  197. /// </summary>
  198. /// <value><c>true</c> if allows other file types; otherwise, <c>false</c>.</value>
  199. public bool AllowsOtherFileTypes { get; set; }
  200. /// <summary>
  201. /// The File path that is currently shown on the panel
  202. /// </summary>
  203. /// <value>The absolute file path for the file path entered.</value>
  204. public ustring FilePath {
  205. get => nameEntry.Text;
  206. set {
  207. nameEntry.Text = value;
  208. }
  209. }
  210. }
  211. public class SaveDialog : FileDialog {
  212. public SaveDialog (ustring title, ustring message) : base (title, prompt: "Save", nameFieldLabel: "Save as:", message: message)
  213. {
  214. }
  215. }
  216. public class OpenDialog : FileDialog {
  217. public OpenDialog (ustring title, ustring message) : base (title, prompt: "Open", nameFieldLabel: "Open", message: message)
  218. {
  219. }
  220. /// <summary>
  221. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> can choose files.
  222. /// </summary>
  223. /// <value><c>true</c> if can choose files; otherwise, <c>false</c>.</value>
  224. public bool CanChooseFiles { get; set; }
  225. /// <summary>
  226. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> can choose directories.
  227. /// </summary>
  228. /// <value><c>true</c> if can choose directories; otherwise, <c>false</c>.</value>
  229. public bool CanChooseDirectories { get; set; }
  230. /// <summary>
  231. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> allows multiple selection.
  232. /// </summary>
  233. /// <value><c>true</c> if allows multiple selection; otherwise, <c>false</c>.</value>
  234. public bool AllowsMultipleSelection { get; set; }
  235. /// <summary>
  236. /// Gets the file paths selected
  237. /// </summary>
  238. /// <value>The file paths.</value>
  239. public IReadOnlyList<ustring> FilePaths { get; }
  240. }
  241. }