فهرست منبع

FileDialog work

miguel 7 سال پیش
والد
کامیت
6c3fa389a6
3فایلهای تغییر یافته به همراه174 افزوده شده و 58 حذف شده
  1. 1 1
      Example/demo.cs
  2. 172 56
      Terminal.Gui/Dialogs/FileDialog.cs
  3. 1 1
      Terminal.Gui/Views/TextField.cs

+ 1 - 1
Example/demo.cs

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

+ 172 - 56
Terminal.Gui/Dialogs/FileDialog.cs

@@ -1,6 +1,17 @@
 // 
 // FileDialog.cs: File system dialogs for open and save
 //
+// TODO:
+//   * Raise event on file selected
+//   * Add directory selector
+//   * Update file name on cursor changes
+//   * Figure out why Ok/Cancel buttons do not work
+//   * Implement subclasses
+//   * Figure out why message text does not show
+//   * Remove the extra space when message does not show
+//   * Use a line separator to show the file listing, so we can use same colors as the rest
+//   * Implement support for the subclass properties.
+//   * Add mouse support
 
 using System;
 using System.Collections.Generic;
@@ -10,72 +21,94 @@ using System.Linq;
 
 namespace Terminal.Gui {
 	internal class DirListView : View {
-		int topFile, currentFile;
+		int top, selected;
 		DirectoryInfo dirInfo;
-		List<FileSystemInfo> infos;
+		List<(string,bool)> infos;
 
 		public DirListView ()
 		{
-			infos = new List<FileSystemInfo> ();
+			infos = new List<(string,bool)> ();
 			CanFocus = true;
 		}
 
+		bool IsAllowed (FileSystemInfo fsi)
+		{
+			if (fsi.Attributes.HasFlag (FileAttributes.Directory))
+			    return true;
+			if (allowedFileTypes == null)
+				return true;
+			foreach (var ft in allowedFileTypes)
+				if (fsi.Name.EndsWith (ft))
+					return true;
+			return false;
+		}
+
 		void Reload ()
 		{
-			dirInfo = new DirectoryInfo (directory);
-			infos = (from x in dirInfo.GetFileSystemInfos () orderby (!x.Attributes.HasFlag (FileAttributes.Directory)) + x.Name select x).ToList ();
-			topFile = 0;
-			currentFile = 0;
+			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));
+			top = 0;
+			selected = 0;
 			SetNeedsDisplay ();
 		}
 
-		string directory;
-		public string Directory {
+		ustring directory;
+		public ustring Directory {
 			get => directory;
 			set {
-				if (directory != value)
+				if (directory == value)
 					return;
-				
 				directory = value;
 				Reload ();
 			}
 		}
 
-		public override void Redraw (Rect region)
+		public override void PositionCursor ()
 		{
-			Driver.SetAttribute (ColorScheme.Focus);
-			var g = Frame;
-
-			for (int y = 0; y < g.Height; y++) {
-				Move (0, y);
-				for (int x = 0; x < g.Width; x++) {
-					Rune r;
-					switch (x % 3) {
-					case 0:
-						r = '.';
-						break;
-					case 1:
-						r = 'o';
-						break;
-					default:
-						r = 'O';
-						break;
-					}
-					Driver.AddRune (r);
-				}
+			Move (0, selected - top);
+		}
+
+		void DrawString (int line, string str)
+		{
+			var f = Frame;
+			var width = f.Width;
+			var ustr = ustring.Make (str);
+
+			Move (2, line);
+			int byteLen = ustr.Length;
+			int used = 0;
+			for (int i = 0; i < byteLen;) {
+				(var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
+				var count = Rune.ColumnWidth (rune);
+				if (used + count >= width)
+					break;
+				Driver.AddRune (rune);
+				used += count;
+				i += size;
 			}
-			return;
+			for (; used < width; used++) {
+				Driver.AddRune (' ');
+			}			
+		}
+
+		public override void Redraw (Rect region)
+		{
 			var current = ColorScheme.Focus;
 			Driver.SetAttribute (current);
 			Move (0, 0);
 			var f = Frame;
-			var item = topFile;
+			var item = top;
 			bool focused = HasFocus;
 			var width = region.Width;
 
-			bool isSelected = false;
 			for (int row = 0; row < f.Height; row++, item++) {
-				var newcolor = focused ? (isSelected ? ColorScheme.Focus : ColorScheme.Normal) : ColorScheme.Normal;
+				bool isSelected = item == selected;
+				Move (0, row);
+				var newcolor = focused ? (isSelected ? ColorScheme.HotNormal : ColorScheme.Focus) : ColorScheme.Focus;
 				if (newcolor != current) {
 					Driver.SetAttribute (newcolor);
 					current = newcolor;
@@ -86,23 +119,101 @@ namespace Terminal.Gui {
 					continue;
 				}
 				var fi = infos [item];
-				var ustr = ustring.Make (fi.Name);
-				int byteLen = ustr.Length;
-				int used = 0;
-				for (int i = 0; i < byteLen;) {
-					(var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
-					var count = Rune.ColumnWidth (rune);
-					if (used + count >= width)
-						break;
-					Driver.AddRune (rune);
-					used += count;
-					i += size;
-				}
-				for (; used < width; used++) {
+
+				Driver.AddRune (isSelected ? '>' : ' ');
+				if (fi.Item2)
+					Driver.AddRune ('/');
+				else
 					Driver.AddRune (' ');
+				DrawString (row, fi.Item1);
+			}
+		}
+
+		public Action<(string,bool)> SelectedChanged;
+		public Action<ustring> DirectoryChanged;
+
+		void SelectionChanged ()
+		{
+			if (SelectedChanged != null)
+				SelectedChanged (infos [selected]);
+		}
+
+		public override bool ProcessKey (KeyEvent keyEvent)
+		{
+			switch (keyEvent.Key) {
+			case Key.CursorUp:
+			case Key.ControlP:
+				if (selected > 0) {
+					selected--;
+					if (selected < top)
+						top = selected;
+					SelectionChanged ();
+					SetNeedsDisplay ();
+				}
+				return true;
+
+			case Key.CursorDown:
+			case Key.ControlN:
+				if (selected + 1 < infos.Count) {
+					selected++;
+					if (selected >= top + Frame.Height)
+						top++;
+					SelectionChanged ();
+					SetNeedsDisplay ();
+				}
+				return true;
+
+			case Key.ControlV:
+			case Key.PageDown:
+				var n = (selected + Frame.Height);
+				if (n > infos.Count)
+					n = infos.Count - 1;
+				if (n != selected) {
+					selected = n;
+					if (infos.Count >= Frame.Height)
+						top = selected;
+					else
+						top = 0;
+					SelectionChanged ();
+
+					SetNeedsDisplay ();
+				}
+				return true;
+
+			case Key.Enter:
+				if (infos [selected].Item2) {
+					Directory = Path.GetFullPath (Path.Combine (Path.GetFullPath (Directory.ToString ()), infos [selected].Item1));
+					if (DirectoryChanged != null)
+						DirectoryChanged (Directory);
+				} else {
+					// File Selected
 				}
+				return true;
+
+			case Key.PageUp:
+				n = (selected - Frame.Height);
+				if (n < 0)
+					n = 0;
+				if (n != selected) {
+					selected = n;
+					top = selected;
+					SelectionChanged ();
+					SetNeedsDisplay ();
+				}
+				return true;
+			}
+			return base.ProcessKey (keyEvent);
+		}
+
+		string [] allowedFileTypes;
+		public string [] AllowedFileTypes {
+			get => allowedFileTypes;
+			set {
+				allowedFileTypes = value;
+				Reload ();
 			}
 		}
+
 	}
 
 	public class FileDialog : Dialog {
@@ -111,42 +222,43 @@ namespace Terminal.Gui {
 		TextField dirEntry, nameEntry;
 		DirListView dirListView;
 
-		public FileDialog (ustring title, ustring prompt, ustring nameFieldLabel, ustring message) : base (title, Driver.Cols - 20, Driver.Rows - 6, null)
+		public FileDialog (ustring title, ustring prompt, ustring nameFieldLabel, ustring message) : base (title, Driver.Cols - 20, Driver.Rows - 5, null)
 		{
 			this.message = new Label (Rect.Empty, "MESSAGE" + message);
 			var msgLines = Label.MeasureLines (message, Driver.Cols - 20);
 
 			dirLabel = new Label ("Directory: ") {
-				X = 2,
+				X = 1,
 				Y = 1 + msgLines
 			};
 
 			dirEntry = new TextField ("") {
-				X = 12,
+				X = 11,
 				Y = 1 + msgLines,
 				Width = Dim.Fill () - 1
 			};
 			Add (dirLabel, dirEntry);
 
 			this.nameFieldLabel = new Label (nameFieldLabel) {
-				X = 2,
+				X = 1,
 				Y = 3 + msgLines,
 			};
 			nameEntry = new TextField ("") {
-				X = 2 + nameFieldLabel.RuneCount + 1,
+				X = 1 + nameFieldLabel.RuneCount + 1,
 				Y = 3 + msgLines,
 				Width = Dim.Fill () - 1
 			};
 			Add (this.nameFieldLabel, nameEntry);
 
 			dirListView = new DirListView () {
-				X = 2,
+				X = 1,
 				Y = 3 + msgLines + 2,
 				Width = Dim.Fill (),
 				Height = Dim.Fill (),
 				Directory = "."	
 			};
 			Add (dirListView);
+			dirListView.DirectoryChanged = (dir) => dirEntry.Text = dir;
 
 			this.cancel = new Button ("Cancel");
 			AddButton (cancel);
@@ -208,6 +320,7 @@ namespace Terminal.Gui {
 			get => dirEntry.Text;
 			set {
 				dirEntry.Text = value;
+				dirListView.Directory = value;
 			}
 		}
 
@@ -215,7 +328,10 @@ namespace Terminal.Gui {
 		/// The array of filename extensions allowed, or null if all file extensions are allowed.
 		/// </summary>
 		/// <value>The allowed file types.</value>
-		public ustring [] AllowedFileTypes { get; set; }
+		public string [] AllowedFileTypes {
+			get => dirListView.AllowedFileTypes;
+			set => dirListView.AllowedFileTypes = value;
+		}
 
 
 		/// <summary>

+ 1 - 1
Terminal.Gui/Views/TextField.cs

@@ -246,7 +246,7 @@ namespace Terminal.Gui {
 
 			default:
 				// Ignore other control characters.
-				if (kb.Key < Key.Space || kb.Key > Key.CharMask)
+					if (kb.Key < Key.Space || kb.Key > Key.CharMask)
 					return false;
 
 				var kbstr = ustring.Make ((uint)kb.Key);