mirror of https://github.com/buggins/dlangui.git
FileDialog fixes
This commit is contained in:
parent
570b7f0c92
commit
7fc0e7eee9
|
@ -64,7 +64,7 @@
|
|||
<doXGeneration>1</doXGeneration>
|
||||
<xfilename>$(IntDir)\$(TargetName).json</xfilename>
|
||||
<debuglevel>0</debuglevel>
|
||||
<debugids />
|
||||
<debugids>DebugFocus</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>USE_SDL USE_OPENGL</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
|
|
|
@ -293,8 +293,8 @@ extern (C) int UIAppMain(string[] args) {
|
|||
UIString caption;
|
||||
caption = "Open Text File"d;
|
||||
FileDialog dlg = new FileDialog(caption, window, null);
|
||||
dlg.onDialogResult = delegate(Dialog dlg, Action result) {
|
||||
Log.d("FileDialog.onDialogResult");
|
||||
dlg.onDialogResult = delegate(Dialog dlg, const Action result) {
|
||||
Log.d("FileDialog.onDialogResult: ", result, " param=", result.stringParam);
|
||||
};
|
||||
dlg.show();
|
||||
return true;
|
||||
|
|
|
@ -66,7 +66,7 @@ class Action {
|
|||
/// optional object parameter
|
||||
protected Object _objectParam;
|
||||
/// returns optional string parameter
|
||||
@property string stringParam() {
|
||||
@property string stringParam() const {
|
||||
return _stringParam;
|
||||
}
|
||||
/// sets optional string parameter
|
||||
|
@ -107,6 +107,10 @@ class Action {
|
|||
}
|
||||
/// deep copy
|
||||
@property Action clone() immutable { return new Action(this); }
|
||||
/// deep copy
|
||||
@property Action clone() const { return new Action(cast(immutable)this); }
|
||||
/// deep copy
|
||||
@property Action clone() { return new Action(cast(immutable)this); }
|
||||
/// create action only with ID
|
||||
this(int id) {
|
||||
_id = id;
|
||||
|
@ -185,6 +189,10 @@ class Action {
|
|||
_iconId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
override string toString() const {
|
||||
return "Action(" ~ to!string(_id) ~ ")";
|
||||
}
|
||||
}
|
||||
|
||||
/// Map of Accelerator to Action
|
||||
|
|
|
@ -34,7 +34,7 @@ enum DialogFlag : uint {
|
|||
}
|
||||
|
||||
interface DialogResultHandler {
|
||||
public void onDialogResult(Dialog dlg, Action result);
|
||||
public void onDialogResult(Dialog dlg, const Action result);
|
||||
}
|
||||
|
||||
/// base for all dialogs
|
||||
|
@ -88,8 +88,11 @@ class Dialog : VerticalLayout {
|
|||
return this;
|
||||
}
|
||||
|
||||
protected const(Action) [] _buttonActions;
|
||||
|
||||
/// create panel with buttons based on list of actions
|
||||
Widget createButtonsPanel(const Action[] actions, int defaultActionIndex, int splitBeforeIndex) {
|
||||
Widget createButtonsPanel(const(Action) [] actions, int defaultActionIndex, int splitBeforeIndex) {
|
||||
_buttonActions = actions;
|
||||
LinearLayout res = new HorizontalLayout("buttons");
|
||||
res.layoutWidth(FILL_PARENT);
|
||||
res.layoutWeight = 0;
|
||||
|
@ -97,18 +100,26 @@ class Dialog : VerticalLayout {
|
|||
if (splitBeforeIndex == i)
|
||||
res.addChild(new HSpacer());
|
||||
const Action a = actions[i];
|
||||
string id = "btn" ~ to!string(a.id);
|
||||
string id = "btn" ~ to!string(a.id);
|
||||
ImageTextButton btn = new ImageTextButton(id, a.iconId, a.label);
|
||||
if (defaultActionIndex == i)
|
||||
btn.setState(State.Default);
|
||||
btn.onClickListener = delegate(Widget source) {
|
||||
return handleAction(a);
|
||||
};
|
||||
btn.action = a.clone();
|
||||
res.addChild(btn);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Custom handling of actions
|
||||
override bool handleAction(const Action action) {
|
||||
foreach(const Action a; _buttonActions)
|
||||
if (a.id == action.id) {
|
||||
close(action);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// override to implement creation of dialog controls
|
||||
void init() {
|
||||
}
|
||||
|
@ -121,7 +132,7 @@ class Dialog : VerticalLayout {
|
|||
|
||||
If action is null, no result dispatching will occur.
|
||||
*/
|
||||
void close(Action action) {
|
||||
void close(const Action action) {
|
||||
if (action) {
|
||||
if (onDialogResult.assigned)
|
||||
onDialogResult(this, action);
|
||||
|
@ -144,5 +155,11 @@ class Dialog : VerticalLayout {
|
|||
_window.windowIcon = drawableCache.getImage(_icon);
|
||||
_window.mainWidget = this;
|
||||
_window.show();
|
||||
onShow();
|
||||
}
|
||||
|
||||
/// called after window with dialog is shown
|
||||
void onShow() {
|
||||
// override to do something useful
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import dlangui.widgets.editors;
|
|||
import dlangui.platforms.common.platform;
|
||||
import dlangui.dialogs.dialog;
|
||||
|
||||
private import std.algorithm;
|
||||
private import std.file;
|
||||
private import std.path;
|
||||
private import std.utf;
|
||||
|
@ -70,8 +71,17 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
protected DirEntry[] _entries;
|
||||
protected bool _isRoot;
|
||||
|
||||
protected bool _isOpenDialog;
|
||||
|
||||
this(UIString caption, Window parent, Action action = null, uint fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist) {
|
||||
super(caption, parent, fileDialogFlags);
|
||||
_isOpenDialog = !(_flags & FileDialogFlag.ConfirmOverwrite);
|
||||
if (action is null) {
|
||||
if (_isOpenDialog)
|
||||
action = ACTION_OPEN.clone();
|
||||
else
|
||||
action = ACTION_SAVE.clone();
|
||||
}
|
||||
_action = action;
|
||||
}
|
||||
|
||||
|
@ -82,7 +92,11 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
_fileList.fillColumnWidth(1);
|
||||
}
|
||||
|
||||
protected bool openDirectory(string dir) {
|
||||
protected bool upLevel() {
|
||||
return openDirectory(buildNormalizedPath(_path, ".."), _path);
|
||||
}
|
||||
|
||||
protected bool openDirectory(string dir, string selectedItemPath) {
|
||||
dir = buildNormalizedPath(dir);
|
||||
Log.d("FileDialog.openDirectory(", dir, ")");
|
||||
_fileList.rows = 0;
|
||||
|
@ -93,7 +107,10 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
_isRoot = isRoot(dir);
|
||||
_edPath.text = toUTF32(_path);
|
||||
_fileList.rows = cast(int)_entries.length;
|
||||
int selectionIndex = -1;
|
||||
for (int i = 0; i < _entries.length; i++) {
|
||||
if (_entries[i].name.equal(selectedItemPath))
|
||||
selectionIndex = i;
|
||||
string fname = baseName(_entries[i].name);
|
||||
string sz;
|
||||
string date;
|
||||
|
@ -111,9 +128,23 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
}
|
||||
_fileList.autoFitColumnWidths();
|
||||
_fileList.fillColumnWidth(1);
|
||||
if (selectionIndex >= 0)
|
||||
_fileList.selectCell(1, selectionIndex + 1, true);
|
||||
else if (_entries.length > 0)
|
||||
_fileList.selectCell(1, 1, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
override bool onKeyEvent(KeyEvent event) {
|
||||
if (event.action == KeyAction.KeyDown) {
|
||||
if (event.keyCode == KeyCode.BACK && event.flags == 0) {
|
||||
upLevel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// return true for custom drawn cell
|
||||
override bool isCustomCell(int col, int row) {
|
||||
if (col == 0 && row >= 0)
|
||||
|
@ -150,8 +181,9 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
protected Widget createRootsList() {
|
||||
protected ListWidget createRootsList() {
|
||||
ListWidget res = new ListWidget("ROOTS_LIST");
|
||||
res.styleId = "EDIT_BOX";
|
||||
WidgetListAdapter adapter = new WidgetListAdapter();
|
||||
foreach(ref RootEntry root; _roots) {
|
||||
ImageTextButton btn = new ImageTextButton(null, root.icon, root.label);
|
||||
|
@ -161,28 +193,61 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
adapter.widgets.add(btn);
|
||||
}
|
||||
res.ownAdapter = adapter;
|
||||
res.layoutWidth = WRAP_CONTENT;
|
||||
res.layoutHeight = FILL_PARENT;
|
||||
res.layoutWidth(WRAP_CONTENT).layoutHeight(FILL_PARENT).layoutWeight(0);
|
||||
res.onItemClickListener = delegate(Widget source, int itemIndex) {
|
||||
openDirectory(_roots[itemIndex].path);
|
||||
openDirectory(_roots[itemIndex].path, null);
|
||||
return true;
|
||||
};
|
||||
res.focusable = true;
|
||||
debug Log.d("root lisk styleId=", res.styleId);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// file list item activated (double clicked or Enter key pressed)
|
||||
protected void onItemActivated(int index) {
|
||||
DirEntry e = _entries[index];
|
||||
if (e.isDir) {
|
||||
openDirectory(e.name);
|
||||
openDirectory(e.name, _path);
|
||||
} else if (e.isFile) {
|
||||
string fname = e.name;
|
||||
Action result = ACTION_OPEN.clone();
|
||||
Action result = _action;
|
||||
result.stringParam = fname;
|
||||
close(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// file list item selected
|
||||
protected void onItemSelected(int index) {
|
||||
DirEntry e = _entries[index];
|
||||
if (e.isDir) {
|
||||
_edFilename.text = ""d;
|
||||
_filename = "";
|
||||
} else if (e.isFile) {
|
||||
string fname = e.name;
|
||||
_edFilename.text = toUTF32(baseName(fname));
|
||||
_filename = fname;
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom handling of actions
|
||||
override bool handleAction(const Action action) {
|
||||
if (action.id == StandardAction.Cancel) {
|
||||
super.handleAction(action);
|
||||
return true;
|
||||
}
|
||||
if (action.id == StandardAction.Open || action.id == StandardAction.Save) {
|
||||
if (_filename.length > 0) {
|
||||
Action result = _action;
|
||||
result.stringParam = _filename;
|
||||
close(result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.handleAction(action);
|
||||
}
|
||||
|
||||
|
||||
/// override to implement creation of dialog controls
|
||||
override void init() {
|
||||
_roots = getRootPaths;
|
||||
|
@ -211,7 +276,7 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
_edPath.layoutWidth(FILL_PARENT);
|
||||
_edPath.layoutWeight = 0;
|
||||
|
||||
_edFilename = new EditLine("path");
|
||||
_edFilename = new EditLine("filename");
|
||||
_edFilename.layoutWidth(FILL_PARENT);
|
||||
_edFilename.layoutWeight = 0;
|
||||
|
||||
|
@ -230,16 +295,22 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
|
||||
|
||||
addChild(content);
|
||||
addChild(createButtonsPanel([ACTION_OPEN, ACTION_CANCEL], 0, 0));
|
||||
addChild(createButtonsPanel([cast(immutable)_action, ACTION_CANCEL], 0, 0));
|
||||
|
||||
_fileList.customCellAdapter = this;
|
||||
_fileList.onCellActivated = delegate(GridWidgetBase source, int col, int row) {
|
||||
onItemActivated(row);
|
||||
};
|
||||
_fileList.onCellSelected = delegate(GridWidgetBase source, int col, int row) {
|
||||
onItemSelected(row);
|
||||
};
|
||||
|
||||
openDirectory(currentDir);
|
||||
openDirectory(currentDir, null);
|
||||
_fileList.layoutHeight = FILL_PARENT;
|
||||
|
||||
_fileList.setFocus();
|
||||
}
|
||||
|
||||
override void onShow() {
|
||||
_fileList.setFocus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -311,8 +311,11 @@ class Window {
|
|||
if (focus.onKeyEvent(event))
|
||||
return true; // processed by focused widget
|
||||
}
|
||||
if (_mainWidget)
|
||||
return dispatchKeyEvent(_mainWidget, event) || res;
|
||||
if (_mainWidget) {
|
||||
if (dispatchKeyEvent(_mainWidget, event))
|
||||
return res;
|
||||
return _mainWidget.onKeyEvent(event) || res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -431,7 +434,7 @@ class Window {
|
|||
}
|
||||
|
||||
/// dispatch action to main widget
|
||||
bool dispatchAction(Action action) {
|
||||
bool dispatchAction(const Action action) {
|
||||
Widget focus = focusedWidget;
|
||||
// first, offer action to focused widget
|
||||
if (focus && focus.handleAction(action))
|
||||
|
|
|
@ -191,6 +191,7 @@ class ImageWidget : Widget {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// button with image only
|
||||
class ImageButton : ImageWidget {
|
||||
this(string ID = null, string drawableId = null) {
|
||||
|
@ -201,6 +202,8 @@ class ImageButton : ImageWidget {
|
|||
focusable = true;
|
||||
trackHover = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// button with image and text
|
||||
|
|
|
@ -200,6 +200,8 @@ enum GridActions : int {
|
|||
DocumentEnd,
|
||||
/// move cursor to the end of document with selection
|
||||
SelectDocumentEnd,
|
||||
/// Enter key pressed on cell
|
||||
ActivateCell,
|
||||
}
|
||||
|
||||
/// Adapter for custom drawing of some cells in grid widgets
|
||||
|
@ -610,7 +612,7 @@ class GridWidgetBase : ScrollWidgetBase {
|
|||
if (makeVisible)
|
||||
makeCellVisible(_col, _row);
|
||||
if (onCellSelected.assigned)
|
||||
onCellSelected(this, _col, _row);
|
||||
onCellSelected(this, _col - _headerCols, _row - _headerRows);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -799,6 +801,12 @@ class GridWidgetBase : ScrollWidgetBase {
|
|||
}
|
||||
|
||||
switch (actionId) {
|
||||
case GridActions.ActivateCell:
|
||||
if (onCellActivated.assigned) {
|
||||
onCellActivated(this, col, row);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case GridActions.ScrollLeft:
|
||||
scrollBy(-1, 0);
|
||||
return true;
|
||||
|
@ -1103,6 +1111,7 @@ class GridWidgetBase : ScrollWidgetBase {
|
|||
new Action(GridActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control),
|
||||
new Action(GridActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control),
|
||||
new Action(GridActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
|
||||
new Action(GridActions.ActivateCell, KeyCode.RETURN, 0),
|
||||
]);
|
||||
focusable = true;
|
||||
}
|
||||
|
|
|
@ -780,7 +780,7 @@ class ListWidget : WidgetGroup, OnScrollHandler {
|
|||
// TODO
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return super.onKeyEvent(event);
|
||||
//if (_selectedItemIndex != -1 && event.action == KeyAction.KeyUp && (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) {
|
||||
// itemClicked(_selectedItemIndex);
|
||||
// return true;
|
||||
|
|
|
@ -596,6 +596,13 @@ class Widget {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected Action _action;
|
||||
/// action to emit on click
|
||||
@property Action action() { return _action; }
|
||||
/// action to emit on click
|
||||
@property void action(Action action) { _action = action; }
|
||||
|
||||
|
||||
protected bool _focusGroup;
|
||||
/*****************************************
|
||||
* When focus group is set for some parent widget, focus from one of containing widgets can be moved using keyboard only to one of other widgets containing in it and cannot bypass bounds of focusGroup.
|
||||
|
@ -668,6 +675,9 @@ class Widget {
|
|||
}
|
||||
return obj1.rect.left < obj2.rect.left;
|
||||
}
|
||||
override string toString() {
|
||||
return widget.id;
|
||||
}
|
||||
}
|
||||
|
||||
private void findFocusableChildren(ref TabOrderInfo[] results, Rect clipRect) {
|
||||
|
@ -727,6 +737,7 @@ class Widget {
|
|||
break;
|
||||
}
|
||||
}
|
||||
debug(DebugFocus) Log.d("findNextFocusWidget myIndex=", myIndex, " of focusables: ", focusables);
|
||||
if (myIndex == -1)
|
||||
return null; // not found myself
|
||||
if (focusables.length == 1)
|
||||
|
@ -876,7 +887,11 @@ class Widget {
|
|||
|
||||
// called to process click and notify listeners
|
||||
protected bool handleClick() {
|
||||
bool res = onClickListener(this);
|
||||
bool res = false;
|
||||
if (onClickListener.assigned)
|
||||
res = onClickListener(this);
|
||||
else if (_action)
|
||||
res = handleAction(_action);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue