Browse Source

More work on file dialog

Miguel de Icaza 7 years ago
parent
commit
31ae05af42
2 changed files with 102 additions and 18 deletions
  1. 1 1
      Example/demo.cs
  2. 101 17
      Terminal.Gui/Dialogs/FileDialog.cs

+ 1 - 1
Example/demo.cs

@@ -211,7 +211,7 @@ static class Demo {
 		Application.Init ();
 		var top = Application.Top;
 		var tframe = top.Frame;
-		//Open ();
+		Open ();
 #if true
 		var win = new Window ("Hello") {
 			X = 0,

+ 101 - 17
Terminal.Gui/Dialogs/FileDialog.cs

@@ -23,11 +23,14 @@ namespace Terminal.Gui {
 	internal class DirListView : View {
 		int top, selected;
 		DirectoryInfo dirInfo;
-		List<(string,bool)> infos;
+		List<(string,bool,bool)> infos;
+		internal bool canChooseFiles = true;
+		internal bool canChooseDirectories = false;
+		internal bool allowsMultipleSelection = false;
 
 		public DirListView ()
 		{
-			infos = new List<(string,bool)> ();
+			infos = new List<(string,bool,bool)> ();
 			CanFocus = true;
 		}
 
@@ -43,14 +46,14 @@ namespace Terminal.Gui {
 			return false;
 		}
 
-		void Reload ()
+		internal void Reload ()
 		{
 			dirInfo = new DirectoryInfo (directory.ToString ());
 			infos = (from x in dirInfo.GetFileSystemInfos ()
 			         where IsAllowed (x)
 			         orderby (!x.Attributes.HasFlag (FileAttributes.Directory)) + x.Name
-			         select (x.Name, x.Attributes.HasFlag (FileAttributes.Directory))).ToList ();
-			infos.Insert (0, ("..", true));
+			         select (x.Name, x.Attributes.HasFlag (FileAttributes.Directory), false)).ToList ();
+			infos.Insert (0, ("..", true, false));
 			top = 0;
 			selected = 0;
 			SetNeedsDisplay ();
@@ -78,7 +81,7 @@ namespace Terminal.Gui {
 			var width = f.Width;
 			var ustr = ustring.Make (str);
 
-			Move (2, line);
+			Move (allowsMultipleSelection ? 3 : 2, line);
 			int byteLen = ustr.Length;
 			int used = 0;
 			for (int i = 0; i < byteLen;) {
@@ -121,6 +124,10 @@ namespace Terminal.Gui {
 				var fi = infos [item];
 
 				Driver.AddRune (isSelected ? '>' : ' ');
+
+				if (allowsMultipleSelection)
+					Driver.AddRune (fi.Item3 ? '*' : ' ');
+				
 				if (fi.Item2)
 					Driver.AddRune ('/');
 				else
@@ -134,8 +141,10 @@ namespace Terminal.Gui {
 
 		void SelectionChanged ()
 		{
-			if (SelectedChanged != null)
-				SelectedChanged (infos [selected]);
+			if (SelectedChanged != null) {
+				var sel = infos [selected];
+				SelectedChanged ((sel.Item1, sel.Item2));
+			}
 		}
 
 		public override bool ProcessKey (KeyEvent keyEvent)
@@ -201,6 +210,19 @@ namespace Terminal.Gui {
 					SetNeedsDisplay ();
 				}
 				return true;
+
+			case Key.Space:
+			case Key.ControlT: 
+				if (allowsMultipleSelection) {
+					if ((canChooseFiles && infos [selected].Item2 == false) ||
+					    (canChooseDirectories && infos [selected].Item2 &&
+					     infos [selected].Item1 != "..")){
+						infos [selected] = (infos [selected].Item1, infos [selected].Item2, !infos [selected].Item3);
+						SelectionChanged ();
+						SetNeedsDisplay ();
+					}
+				}
+				return true;
 			}
 			return base.ProcessKey (keyEvent);
 		}
@@ -214,13 +236,42 @@ namespace Terminal.Gui {
 			}
 		}
 
+		public string MakePath (string relativePath)
+		{
+			return Path.GetFullPath (Path.Combine (Directory.ToString (), relativePath));
+		}
+
+		public IReadOnlyList<string> FilePaths {
+			get {
+				if (allowsMultipleSelection) {
+					var res = new List<string> ();
+					foreach (var item in infos)
+						if (item.Item3)
+							res.Add (MakePath (item.Item1));
+					return res;
+				} else {
+					if (infos [selected].Item2) {
+						if (canChooseDirectories)
+							return new List<string> () { MakePath (infos [selected].Item1) };
+						return Array.Empty<string> ();
+					} else {
+						if (canChooseFiles) 
+							return new List<string> () { MakePath (infos [selected].Item1) };
+						return Array.Empty<string> ();
+					}
+				}
+			}
+		}
 	}
 
+	/// <summary>
+	/// Base class for the OpenDialog and the SaveDialog
+	/// </summary>
 	public class FileDialog : Dialog {
 		Button prompt, cancel;
 		Label nameFieldLabel, message, dirLabel;
 		TextField dirEntry, nameEntry;
-		DirListView dirListView;
+		internal DirListView dirListView;
 
 		public FileDialog (ustring title, ustring prompt, ustring nameFieldLabel, ustring message) : base (title, Driver.Cols - 20, Driver.Rows - 5, null)
 		{
@@ -358,6 +409,19 @@ namespace Terminal.Gui {
 		}
 	}
 
+	/// <summary>
+	/// The Open Dialog provides an interactive dialog box for users to select files or directories.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// The open dialog can be used to select files for opening, it can be configured to allow
+	/// multiple items to be selected (based on the AllowsMultipleSelection) variable and
+	/// you can control whether this should allow files or directories to be selected.
+	/// </para>
+	/// <para>
+	/// To select more than one file, users can use the spacebar, or control-t.
+	/// </para>
+	/// </remarks>
 	public class OpenDialog : FileDialog {
 		public OpenDialog (ustring title, ustring message) : base (title, prompt: "Open", nameFieldLabel: "Open", message: message)
 		{
@@ -366,25 +430,45 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> can choose files.
 		/// </summary>
-		/// <value><c>true</c> if can choose files; otherwise, <c>false</c>.</value>
-		public bool CanChooseFiles { get; set; }
+		/// <value><c>true</c> if can choose files; otherwise, <c>false</c>.  Defaults to <c>true</c></value>
+		public bool CanChooseFiles {
+			get => dirListView.canChooseFiles;
+			set {
+				dirListView.canChooseDirectories = value;
+				dirListView.Reload ();
+			}
+		}
 
 		/// <summary>
 		/// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> can choose directories.
 		/// </summary>
-		/// <value><c>true</c> if can choose directories; otherwise, <c>false</c>.</value>
-		public bool CanChooseDirectories { get; set; }
+		/// <value><c>true</c> if can choose directories; otherwise, <c>false</c> defaults to <c>false</c>.</value>
+		public bool CanChooseDirectories {
+			get => dirListView.canChooseDirectories;
+			set {
+				dirListView.canChooseDirectories = value;
+				dirListView.Reload ();
+			}
+		}
 
 		/// <summary>
 		/// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.OpenDialog"/> allows multiple selection.
 		/// </summary>
-		/// <value><c>true</c> if allows multiple selection; otherwise, <c>false</c>.</value>
-		public bool AllowsMultipleSelection { get; set; }
+		/// <value><c>true</c> if allows multiple selection; otherwise, <c>false</c>, defaults to false.</value>
+		public bool AllowsMultipleSelection {
+			get => dirListView.allowsMultipleSelection;
+			set {
+				dirListView.allowsMultipleSelection = value;
+				dirListView.Reload ();
+			}
+		}
 
 		/// <summary>
-		/// Gets the file paths selected
+		/// Returns the selected files, or an empty list if nothing has been selected
 		/// </summary>
 		/// <value>The file paths.</value>
-		public IReadOnlyList<ustring> FilePaths { get; }
+		public IReadOnlyList<string> FilePaths {
+			get => dirListView.FilePaths;
+		}
 	}
 }