FileDialog - path segments

This commit is contained in:
Vadim Lopatin 2015-01-05 17:47:35 +03:00
parent 0b073321a2
commit 5fdf4ad935
3 changed files with 134 additions and 13 deletions

View File

@ -33,6 +33,7 @@ import dlangui.widgets.popup;
import dlangui.widgets.layouts; import dlangui.widgets.layouts;
import dlangui.widgets.grid; import dlangui.widgets.grid;
import dlangui.widgets.editors; import dlangui.widgets.editors;
import dlangui.widgets.menu;
import dlangui.platforms.common.platform; import dlangui.platforms.common.platform;
import dlangui.dialogs.dialog; import dlangui.dialogs.dialog;
@ -57,7 +58,7 @@ enum FileDialogFlag : uint {
/// File open / save dialog /// File open / save dialog
class FileDialog : Dialog, CustomGridCellAdapter { class FileDialog : Dialog, CustomGridCellAdapter {
protected EditLine _edPath; protected FilePathPanel _edPath;
protected EditLine _edFilename; protected EditLine _edFilename;
protected StringGridWidget _fileList; protected StringGridWidget _fileList;
//protected StringGridWidget places; //protected StringGridWidget places;
@ -105,7 +106,7 @@ class FileDialog : Dialog, CustomGridCellAdapter {
return false; return false;
_path = dir; _path = dir;
_isRoot = isRoot(dir); _isRoot = isRoot(dir);
_edPath.text = toUTF32(_path); _edPath.path = _path; //toUTF32(_path);
_fileList.rows = cast(int)_entries.length; _fileList.rows = cast(int)_entries.length;
int selectionIndex = -1; int selectionIndex = -1;
for (int i = 0; i < _entries.length; i++) { for (int i = 0; i < _entries.length; i++) {
@ -247,6 +248,10 @@ class FileDialog : Dialog, CustomGridCellAdapter {
return super.handleAction(action); return super.handleAction(action);
} }
bool onPathSelected(string path) {
//
return openDirectory(path, null);
}
/// override to implement creation of dialog controls /// override to implement creation of dialog controls
override void init() { override void init() {
@ -272,9 +277,10 @@ class FileDialog : Dialog, CustomGridCellAdapter {
content.addChild(leftPanel); content.addChild(leftPanel);
content.addChild(rightPanel); content.addChild(rightPanel);
_edPath = new EditLine("path"); _edPath = new FilePathPanel("path");
_edPath.layoutWidth(FILL_PARENT); _edPath.layoutWidth(FILL_PARENT);
_edPath.layoutWeight = 0; _edPath.layoutWeight = 0;
_edPath.onPathSelectionListener = &onPathSelected;
_edFilename = new EditLine("filename"); _edFilename = new EditLine("filename");
_edFilename.layoutWidth(FILL_PARENT); _edFilename.layoutWidth(FILL_PARENT);
@ -326,14 +332,22 @@ class FilePathPanelItem : HorizontalLayout {
Listener!OnPathSelectionHandler onPathSelectionListener; Listener!OnPathSelectionHandler onPathSelectionListener;
this(string path) { this(string path) {
super(null); super(null);
styleId = "LIST_ITEM";
_path = path; _path = path;
string fname = baseName(path); string fname = isRoot(path) ? path : baseName(path);
_text = new TextWidget(null, toUTF32(fname)); _text = new TextWidget(null, toUTF32(fname));
_text.styleId = "BUTTON_TRANSPARENT";
_text.clickable = true; _text.clickable = true;
_text.onClickListener = &onTextClick; _text.onClickListener = &onTextClick;
//_text.backgroundColor = 0xC0FFFF;
_text.state = State.Parent;
_button = new ImageButton(null, "scrollbar_btn_right"); _button = new ImageButton(null, "scrollbar_btn_right");
_button.styleId = "BUTTON_TRANSPARENT";
_button.focusable = false; _button.focusable = false;
_button.onClickListener = &onButtonClick; _button.onClickListener = &onButtonClick;
//_button.backgroundColor = 0xC0FFC0;
_button.state = State.Parent;
trackHover(true);
addChild(_text); addChild(_text);
addChild(_button); addChild(_button);
margins(Rect(2,0,2,0)); margins(Rect(2,0,2,0));
@ -344,15 +358,48 @@ class FilePathPanelItem : HorizontalLayout {
return false; return false;
} }
private bool onButtonClick(Widget src) { private bool onButtonClick(Widget src) {
// TODO: show popup menu with subdirs // show popup menu with subdirs
string[] filters;
DirEntry[] entries;
if (!listDirectory(_path, true, false, false, filters, entries))
return false;
if (entries.length == 0)
return false;
MenuItem dirs = new MenuItem();
int itemId = 25000;
foreach(ref DirEntry e; entries) {
string fullPath = e.name;
string d = baseName(fullPath);
Action a = new Action(itemId++, toUTF32(d));
MenuItem item = new MenuItem(a);
item.onMenuItemClick = delegate(MenuItem item) {
if (onPathSelectionListener.assigned)
return onPathSelectionListener(fullPath);
return false;
};
dirs.add(item);
}
PopupMenu menuWidget = new PopupMenu(dirs);
PopupWidget popup = window.showPopup(menuWidget, this, PopupAlign.Below);
popup.flags = PopupFlags.CloseOnClickOutside;
return true; return true;
} }
} }
/// Panel with buttons - path segments - for fast navigation to subdirs.
class FilePathPanelButtons : WidgetGroup { class FilePathPanelButtons : WidgetGroup {
protected string _path; protected string _path;
Listener!OnPathSelectionHandler onPathSelectionListener;
bool onPathSelected(string path) {
if (onPathSelectionListener.assigned) {
return onPathSelectionListener(path);
}
return false;
}
this(string ID = null) { this(string ID = null) {
super(ID); super(ID);
layoutWidth = FILL_PARENT;
clickable = true;
} }
void init(string path) { void init(string path) {
_path = path; _path = path;
@ -360,8 +407,9 @@ class FilePathPanelButtons : WidgetGroup {
string itemPath = path; string itemPath = path;
for (;;) { for (;;) {
FilePathPanelItem item = new FilePathPanelItem(itemPath); FilePathPanelItem item = new FilePathPanelItem(itemPath);
item.onPathSelectionListener = &onPathSelected;
addChild(item); addChild(item);
if (isRoot(path)) { if (isRoot(itemPath)) {
break; break;
} }
itemPath = parentDir(itemPath); itemPath = parentDir(itemPath);
@ -378,7 +426,10 @@ class FilePathPanelButtons : WidgetGroup {
pwidth -= m.left + m.right + p.left + p.right; pwidth -= m.left + m.right + p.left + p.right;
if (parentHeight != SIZE_UNSPECIFIED) if (parentHeight != SIZE_UNSPECIFIED)
pheight -= m.top + m.bottom + p.top + p.bottom; pheight -= m.top + m.bottom + p.top + p.bottom;
int reservedForEmptySpace = parentWidth / 16; int reservedForEmptySpace = parentWidth / 20;
if (reservedForEmptySpace > 40)
reservedForEmptySpace = 40;
Point sz; Point sz;
sz.x += reservedForEmptySpace; sz.x += reservedForEmptySpace;
// measure children // measure children
@ -410,7 +461,9 @@ class FilePathPanelButtons : WidgetGroup {
applyMargins(rc); applyMargins(rc);
applyPadding(rc); applyPadding(rc);
int reservedForEmptySpace = rc.width / 16; int reservedForEmptySpace = rc.width / 20;
if (reservedForEmptySpace > 40)
reservedForEmptySpace = 40;
int maxw = rc.width - reservedForEmptySpace; int maxw = rc.width - reservedForEmptySpace;
int totalw = 0; int totalw = 0;
int visibleItems = 0; int visibleItems = 0;
@ -437,33 +490,90 @@ class FilePathPanelButtons : WidgetGroup {
int w = item.measuredWidth; int w = item.measuredWidth;
if (i == visibleItems - 1 && w > maxw) if (i == visibleItems - 1 && w > maxw)
w = maxw; w = maxw;
rc.right = rc.left + w; itemRect.right = itemRect.left + w;
item.layout(rc); item.layout(itemRect);
rc.left += w; itemRect.left += w;
} }
} }
/// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible)
return;
super.onDraw(buf);
Rect rc = _pos;
applyMargins(rc);
applyPadding(rc);
auto saver = ClipRectSaver(buf, rc);
for (int i = 0; i < _children.count; i++) {
Widget item = _children.get(i);
if (item.visibility != Visibility.Visible)
continue;
item.onDraw(buf);
}
}
}
interface PathSelectedHandler {
bool onPathSelected(string path);
} }
class FilePathPanel : FrameLayout { class FilePathPanel : FrameLayout {
Listener!OnPathSelectionHandler onPathSelectionListener;
static const ID_SEGMENTS = "SEGMENTS"; static const ID_SEGMENTS = "SEGMENTS";
static const ID_EDITOR = "ED_PATH"; static const ID_EDITOR = "ED_PATH";
protected FilePathPanelButtons _segments; protected FilePathPanelButtons _segments;
protected EditLine _edPath; protected EditLine _edPath;
protected string _path; protected string _path;
Signal!PathSelectedHandler pathListener;
this(string ID = null) { this(string ID = null) {
super(ID); super(ID);
_segments = new FilePathPanelButtons(ID_SEGMENTS); _segments = new FilePathPanelButtons(ID_SEGMENTS);
_edPath = new EditLine(ID_EDITOR); _edPath = new EditLine(ID_EDITOR);
_edPath.layoutWidth = FILL_PARENT;
_edPath.editorActionListener = &onEditorAction;
_edPath.onFocusChangeListener = &onEditorFocusChanged;
_segments.onClickListener = &onSegmentsClickOutside;
_segments.onPathSelectionListener = &onPathSelected;
addChild(_segments); addChild(_segments);
addChild(_edPath); addChild(_edPath);
showChild(ID_SEGMENTS);
} }
protected bool onEditorFocusChanged(Widget source, bool focused) {
if (!focused) {
_edPath.text = toUTF32(_path);
showChild(ID_SEGMENTS);
}
return true;
}
protected bool onPathSelected(string path) {
if (onPathSelectionListener.assigned) {
if (exists(path))
return onPathSelectionListener(path);
}
return false;
}
bool onSegmentsClickOutside(Widget w) {
// switch to editor
showChild(ID_EDITOR);
_edPath.setFocus();
return true;
}
bool onEditorAction(const Action action) {
if (action.id == EditorActions.InsertNewLine) {
string fn = buildNormalizedPath(toUTF8(_edPath.text));
if (exists(fn) && isDir(fn))
return onPathSelected(fn);
}
return false;
}
@property void path(string value) { @property void path(string value) {
_segments.init(value); _segments.init(value);
_edPath.text = toUTF32(value); _edPath.text = toUTF32(value);
_path = path; _path = path;
showChild(ID_SEGMENTS);
} }
@property string path() { @property string path() {
return _path; return _path;

View File

@ -1708,10 +1708,15 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
} }
interface EditorActionHandler {
bool onEditorAction(const Action action);
}
/// single line editor /// single line editor
class EditLine : EditWidgetBase { class EditLine : EditWidgetBase {
Signal!EditorActionHandler editorActionListener;
/// empty parameter list constructor - for usage by factory /// empty parameter list constructor - for usage by factory
this() { this() {
this(null); this(null);
@ -1797,6 +1802,12 @@ class EditLine : EditWidgetBase {
override protected bool handleAction(const Action a) { override protected bool handleAction(const Action a) {
switch (a.id) { switch (a.id) {
case EditorActions.InsertNewLine:
case EditorActions.PrependNewLine:
if (editorActionListener.assigned) {
return editorActionListener(a);
}
break;
case EditorActions.Up: case EditorActions.Up:
break; break;
case EditorActions.Down: case EditorActions.Down: