From 67ff73e84af4d59cb34507c9d98421cf75dffc12 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 7 Dec 2015 16:10:48 +0300 Subject: [PATCH] file dialog improvements --- src/dlangui/core/stdaction.d | 2 + src/dlangui/dialogs/filedlg.d | 147 +++++++++++++++++++++++++++++++++- src/dlangui/widgets/styles.d | 4 +- views/res/i18n/std_en.ini | 1 + views/res/i18n/std_ru.ini | 1 + 5 files changed, 150 insertions(+), 5 deletions(-) diff --git a/src/dlangui/core/stdaction.d b/src/dlangui/core/stdaction.d index 6e769fa0..600647e3 100644 --- a/src/dlangui/core/stdaction.d +++ b/src/dlangui/core/stdaction.d @@ -35,6 +35,7 @@ enum StandardAction : int { DiscardAll, OpenUrl, Apply, + OpenDirectory, } const Action ACTION_OK = new Action(StandardAction.Ok, "ACTION_OK"c, "dialog-ok"); @@ -47,6 +48,7 @@ const Action ACTION_ABORT = new Action(StandardAction.Abort, "ACTION_ABORT"c); const Action ACTION_RETRY = new Action(StandardAction.Retry, "ACTION_RETRY"c); const Action ACTION_IGNORE = new Action(StandardAction.Ignore, "ACTION_IGNORE"c); const Action ACTION_OPEN = new Action(StandardAction.Open, "ACTION_OPEN"c); +const Action ACTION_OPEN_DIRECTORY = new Action(StandardAction.OpenDirectory, "ACTION_OPEN_DIRECTORY"c); const Action ACTION_SAVE = new Action(StandardAction.Save, "ACTION_SAVE"c); const Action ACTION_SAVE_ALL = new Action(StandardAction.SaveAll, "ACTION_SAVE_ALL"c); const Action ACTION_DISCARD_CHANGES = new Action(StandardAction.DiscardChanges, "ACTION_DISCARD_CHANGES"c); diff --git a/src/dlangui/dialogs/filedlg.d b/src/dlangui/dialogs/filedlg.d index 1e25ce1e..9982f3c0 100644 --- a/src/dlangui/dialogs/filedlg.d +++ b/src/dlangui/dialogs/filedlg.d @@ -42,6 +42,8 @@ private import std.algorithm; private import std.file; private import std.path; private import std.utf; +private import std.string; +private import std.array; private import std.conv : to; private import std.array : split; @@ -52,10 +54,13 @@ enum FileDialogFlag : uint { FileMustExist = 0x100, /// ask before saving to existing ConfirmOverwrite = 0x200, + /// select directory, not file + SelectDirectory = 0x400, /// flags for Open dialog Open = FileMustExist, /// flags for Save dialog Save = ConfirmOverwrite, + } /// filetype filter entry for FileDialog @@ -97,7 +102,9 @@ class FileDialog : Dialog, CustomGridCellAdapter { super(caption, parent, fileDialogFlags | (SHOW_FILE_DIALOG_IN_POPUP ? DialogFlag.Popup : 0)); _isOpenDialog = !(_flags & FileDialogFlag.ConfirmOverwrite); if (action is null) { - if (_isOpenDialog) + if (fileDialogFlags & FileDialogFlag.SelectDirectory) + action = ACTION_OPEN_DIRECTORY.clone(); + else if (_isOpenDialog) action = ACTION_OPEN.clone(); else action = ACTION_SAVE.clone(); @@ -133,6 +140,22 @@ class FileDialog : Dialog, CustomGridCellAdapter { _filterIndex = index; } + @property string path() { + return _path; + } + + @property void path(string s) { + _path = s; + } + + @property string filename() { + return _filename; + } + + @property void filename(string s) { + _filename = s; + } + /// return currently selected filter value - array of patterns like ["*.txt", "*.rtf"] @property string[] selectedFilter() { if (_filterIndex >= 0 && _filterIndex < _filters.length) @@ -338,11 +361,15 @@ class FileDialog : Dialog, CustomGridCellAdapter { _edPath.layoutWidth(FILL_PARENT); _edPath.layoutWeight = 0; _edPath.onPathSelectionListener = &onPathSelected; - HorizontalLayout fnlayout = new HorizontalLayout(); fnlayout.layoutWidth(FILL_PARENT); _edFilename = new EditLine("filename"); _edFilename.layoutWidth(FILL_PARENT); + if (_flags & FileDialogFlag.SelectDirectory) { + _edFilename.visibility = Visibility.Invisible; + } + + //_edFilename.layoutWeight = 0; fnlayout.addChild(_edFilename); if (_filters.length) { @@ -389,7 +416,10 @@ class FileDialog : Dialog, CustomGridCellAdapter { onItemSelected(row); }; - openDirectory(currentDir, null); + if (_path.empty) { + _path = currentDir; + } + openDirectory(_path, _filename); _fileList.layoutHeight = FILL_PARENT; } @@ -665,3 +695,114 @@ class FilePathPanel : FrameLayout { return _path; } } + +class FileNameEditLine : HorizontalLayout { + protected EditLine _edFileName; + protected Button _btn; + protected string[string] _filetypeIcons; + protected dstring _caption = "Open File"d; + protected uint _fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist; + protected FileFilterEntry[] _filters; + protected int _filterIndex; + + /// Modified state change listener (e.g. content has been saved, or first time modified after save) + Signal!ModifiedStateListener modifiedStateChange; + /// editor content is changed + Signal!EditableContentChangeListener contentChange; + + this(string ID = null) { + super(ID); + _edFileName = new EditLine("edFileName"); + _edFileName.minWidth(200); + _btn = new Button("btnFile", "..."d); + _btn.click = delegate(Widget src) { + FileDialog dlg = new FileDialog(UIString(_caption), window, null, _fileDialogFlags); + foreach(key, value; _filetypeIcons) + dlg.filetypeIcons[key] = value; + dlg.filters = _filters; + dlg.dialogResult = delegate(Dialog dlg, const Action result) { + if (result.id == ACTION_OPEN.id) { + _edFileName.text = toUTF32(result.stringParam); + if (contentChange.assigned) + contentChange(_edFileName.content); + } + }; + string path = toUTF8(_edFileName.text); + if (!path.empty) { + if (exists(path) && isFile(path)) { + dlg.path = dirName(path); + dlg.filename = baseName(path); + } else if (exists(path) && isDir(path)) { + dlg.path = path; + } + } + dlg.show(); + return true; + }; + _edFileName.contentChange = delegate(EditableContent content) { + if (contentChange.assigned) + contentChange(content); + }; + _edFileName.modifiedStateChange = delegate(Widget src, bool modified) { + if (modifiedStateChange.assigned) + modifiedStateChange(src, modified); + }; + addChild(_edFileName); + addChild(_btn); + } + + @property uint fileDialogFlags() { return _fileDialogFlags; } + @property void fileDialogFlags(uint f) { _fileDialogFlags = f; } + + @property dstring caption() { return _caption; } + @property void caption(dstring s) { _caption = s; } + + /// returns widget content text (override to support this) + override @property dstring text() { return _edFileName.text; } + /// sets widget content text (override to support this) + override @property Widget text(dstring s) { _edFileName.text = s; return this; } + /// sets widget content text (override to support this) + override @property Widget text(UIString s) { _edFileName.text = s.value; return this; } + + /// mapping of file extension to icon resource name, e.g. ".txt": "text-plain" + @property ref string[string] filetypeIcons() { return _filetypeIcons; } + + /// filter list for file type filter combo box + @property FileFilterEntry[] filters() { + return _filters; + } + + /// filter list for file type filter combo box + @property void filters(FileFilterEntry[] values) { + _filters = values; + } + + /// add new filter entry + void addFilter(FileFilterEntry value) { + _filters ~= value; + } + + /// filter index + @property int filterIndex() { + return _filterIndex; + } + + /// filter index + @property void filterIndex(int index) { + _filterIndex = index; + } + + @property bool readOnly() { return _edFileName.readOnly; } + @property void readOnly(bool f) { _edFileName.readOnly = f; } + +} + +class DirEditLine : FileNameEditLine { + this(string ID = null) { + super(ID); + _fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist | FileDialogFlag.SelectDirectory; + } +} + +import dlangui.widgets.metadata; +mixin(registerWidgets!(FileNameEditLine, DirEditLine)()); diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d index d4ae98fd..04609b39 100644 --- a/src/dlangui/widgets/styles.d +++ b/src/dlangui/widgets/styles.d @@ -1215,9 +1215,9 @@ FontFamily decodeFontFamily(string s) { /// decode layout dimension (FILL_PARENT, WRAP_CONTENT, or just size) int decodeLayoutDimension(string s) { - if (s.equal("FILL_PARENT")) + if (s.equal("FILL_PARENT") || s.equal("fill")) return FILL_PARENT; - if (s.equal("WRAP_CONTENT")) + if (s.equal("WRAP_CONTENT") || s.equal("wrap")) return WRAP_CONTENT; return decodeDimension(s); } diff --git a/views/res/i18n/std_en.ini b/views/res/i18n/std_en.ini index e9bc09f8..7aeb2940 100644 --- a/views/res/i18n/std_en.ini +++ b/views/res/i18n/std_en.ini @@ -10,6 +10,7 @@ ACTION_ABORT=Abort ACTION_RETRY=Retry ACTION_IGNORE=Ignore ACTION_OPEN=Open +ACTION_OPEN_DIRECTORY=Select Directory ACTION_SAVE=Save ACTION_SAVE_ALL=Save All ACTION_DISCARD_CHANGES=Discard diff --git a/views/res/i18n/std_ru.ini b/views/res/i18n/std_ru.ini index 51eb80a2..76a4ccb8 100644 --- a/views/res/i18n/std_ru.ini +++ b/views/res/i18n/std_ru.ini @@ -9,4 +9,5 @@ ACTION_ABORT=Прервать ACTION_RETRY=Повтор ACTION_IGNORE=Игнорировать ACTION_OPEN=Открыть +ACTION_OPEN_DIRECTORY=Выбрать папку ACTION_SAVE=Сохранить