FileDialog work

This commit is contained in:
miguel
2018-05-05 14:09:21 -04:00
parent 64dcc3ca0c
commit 6c3fa389a6
3 changed files with 175 additions and 59 deletions

View File

@@ -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,

View File

@@ -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 PositionCursor ()
{
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;
}
for (; used < width; used++) {
Driver.AddRune (' ');
}
}
public override void Redraw (Rect region)
{
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);
}
}
return;
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>

View File

@@ -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);