mirror of https://github.com/adamdruppe/arsd.git
basic file chooser dialog
This commit is contained in:
parent
06577dee6f
commit
86fb5ba6ee
228
minigui.d
228
minigui.d
|
@ -52,6 +52,12 @@
|
||||||
`<input type="checkbox">` = [Checkbox]
|
`<input type="checkbox">` = [Checkbox]
|
||||||
`<input type="radio">` = [Radiobox]
|
`<input type="radio">` = [Radiobox]
|
||||||
`<button>` = [Button]
|
`<button>` = [Button]
|
||||||
|
|
||||||
|
|
||||||
|
Stretchiness:
|
||||||
|
The default is 4. You can use larger numbers for things that should
|
||||||
|
consume a lot of space, and lower numbers for ones that are better at
|
||||||
|
smaller sizes.
|
||||||
+/
|
+/
|
||||||
module arsd.minigui;
|
module arsd.minigui;
|
||||||
|
|
||||||
|
@ -183,13 +189,13 @@ abstract class ComboboxBase : Widget {
|
||||||
|
|
||||||
version(win32_widgets)
|
version(win32_widgets)
|
||||||
override void handleWmCommand(ushort cmd, ushort id) {
|
override void handleWmCommand(ushort cmd, ushort id) {
|
||||||
selection = SendMessageA(hwnd, 327 /* CB_GETCURSEL */, 0, 0);
|
selection = cast(int) SendMessageA(hwnd, 327 /* CB_GETCURSEL */, 0, 0);
|
||||||
auto event = new Event(EventType.change, this);
|
auto event = new Event(EventType.change, this);
|
||||||
event.dispatch();
|
event.dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
override int minHeight() { return Window.lineHeight * 4 / 3; }
|
override int minHeight() { return Window.lineHeight + 4; }
|
||||||
override int maxHeight() { return Window.lineHeight * 4 / 3; }
|
override int maxHeight() { return Window.lineHeight + 4; }
|
||||||
|
|
||||||
version(custom_widgets) {
|
version(custom_widgets) {
|
||||||
SimpleWindow dropDown;
|
SimpleWindow dropDown;
|
||||||
|
@ -374,7 +380,7 @@ class ComboBox : ComboboxBase {
|
||||||
|
|
||||||
override int minHeight() { return Window.lineHeight * 3; }
|
override int minHeight() { return Window.lineHeight * 3; }
|
||||||
override int maxHeight() { return int.max; }
|
override int maxHeight() { return int.max; }
|
||||||
override int heightStretchiness() { return 2; }
|
override int heightStretchiness() { return 5; }
|
||||||
|
|
||||||
version(custom_widgets) {
|
version(custom_widgets) {
|
||||||
LineEdit lineEdit;
|
LineEdit lineEdit;
|
||||||
|
@ -391,7 +397,7 @@ class ComboBox : ComboboxBase {
|
||||||
|
|
||||||
+/
|
+/
|
||||||
version(custom_widgets)
|
version(custom_widgets)
|
||||||
class ListWidget : Widget {
|
class ListWidget : ScrollableWidget {
|
||||||
|
|
||||||
static struct Option {
|
static struct Option {
|
||||||
string label;
|
string label;
|
||||||
|
@ -445,8 +451,21 @@ class ListWidget : Widget {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addOption(string text) {
|
||||||
|
options ~= Option(text);
|
||||||
|
setContentSize(width, cast(int) (options.length * Window.lineHeight));
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
options = null;
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
Option[] options;
|
Option[] options;
|
||||||
bool multiSelect;
|
bool multiSelect;
|
||||||
|
|
||||||
|
override int heightStretchiness() { return 6; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -693,8 +712,8 @@ mixin template LayoutInfo() {
|
||||||
}
|
}
|
||||||
int maxWidth() { return int.max; }
|
int maxWidth() { return int.max; }
|
||||||
int maxHeight() { return int.max; }
|
int maxHeight() { return int.max; }
|
||||||
int widthStretchiness() { return 1; }
|
int widthStretchiness() { return 4; }
|
||||||
int heightStretchiness() { return 1; }
|
int heightStretchiness() { return 4; }
|
||||||
|
|
||||||
int marginLeft() { return 0; }
|
int marginLeft() { return 0; }
|
||||||
int marginRight() { return 0; }
|
int marginRight() { return 0; }
|
||||||
|
@ -845,20 +864,6 @@ void recomputeChildLayout(string relevantMeasure)(Widget parent) {
|
||||||
|
|
||||||
int mymax(int a, int b) { return a > b ? a : b; }
|
int mymax(int a, int b) { return a > b ? a : b; }
|
||||||
|
|
||||||
/+
|
|
||||||
mixin template StyleInfo(string windowType) {
|
|
||||||
version(win32_theming)
|
|
||||||
HTHEME theme;
|
|
||||||
/* ok we need to:
|
|
||||||
open theme
|
|
||||||
close theme (when it is all done)
|
|
||||||
draw background
|
|
||||||
get font
|
|
||||||
respond to theme changed messages
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
+/
|
|
||||||
|
|
||||||
// OK so we need to make getting at the native window stuff possible in simpledisplay.d
|
// OK so we need to make getting at the native window stuff possible in simpledisplay.d
|
||||||
// and here, it must be integrable with the layout, the event system, and not be painted over.
|
// and here, it must be integrable with the layout, the event system, and not be painted over.
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
|
@ -890,7 +895,7 @@ version(win32_widgets) {
|
||||||
lastDefaultPrevented = false;
|
lastDefaultPrevented = false;
|
||||||
// try {import std.stdio; writeln(typeid(*te)); } catch(Exception e) {}
|
// try {import std.stdio; writeln(typeid(*te)); } catch(Exception e) {}
|
||||||
if(SimpleWindow.triggerEvents(hWnd, iMessage, wParam, lParam, pos[0], pos[1], (*te).parentWindow.win) || !lastDefaultPrevented)
|
if(SimpleWindow.triggerEvents(hWnd, iMessage, wParam, lParam, pos[0], pos[1], (*te).parentWindow.win) || !lastDefaultPrevented)
|
||||||
return CallWindowProcW((*te).originalWindowProcedure, hWnd, iMessage, wParam, lParam);
|
return cast(int) CallWindowProcW((*te).originalWindowProcedure, hWnd, iMessage, wParam, lParam);
|
||||||
else {
|
else {
|
||||||
// it was something we recognized, should only call the window procedure if the default was not prevented
|
// it was something we recognized, should only call the window procedure if the default was not prevented
|
||||||
}
|
}
|
||||||
|
@ -1882,6 +1887,16 @@ class HorizontalLayout : Layout {
|
||||||
return largest + margins;
|
return largest + margins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int heightStretchiness() {
|
||||||
|
int max;
|
||||||
|
foreach(child; children) {
|
||||||
|
auto c = child.heightStretchiness;
|
||||||
|
if(c > max)
|
||||||
|
c = max;
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/++
|
/++
|
||||||
|
@ -2473,15 +2488,16 @@ class ToolBar : Widget {
|
||||||
SendMessageA(hwnd, TB_BUTTONSTRUCTSIZE, cast(WPARAM)TBBUTTON.sizeof, 0);
|
SendMessageA(hwnd, TB_BUTTONSTRUCTSIZE, cast(WPARAM)TBBUTTON.sizeof, 0);
|
||||||
SendMessageA(hwnd, TB_ADDBUTTONSA, cast(WPARAM) buttons.length, cast(LPARAM)buttons.ptr);
|
SendMessageA(hwnd, TB_ADDBUTTONSA, cast(WPARAM) buttons.length, cast(LPARAM)buttons.ptr);
|
||||||
|
|
||||||
/* this seems to make it a vertical toolbar on windows xp... don't actually want that
|
|
||||||
SIZE size;
|
SIZE size;
|
||||||
SendMessageA(hwnd, TB_GETIDEALSIZE, true, cast(LPARAM) &size);
|
import core.sys.windows.commctrl;
|
||||||
idealHeight = size.cy;
|
SendMessageA(hwnd, TB_GETMAXSIZE, 0, cast(LPARAM) &size);
|
||||||
*/
|
idealHeight = size.cy + 4; // the plus 4 is a hack
|
||||||
|
|
||||||
|
/*
|
||||||
RECT rect;
|
RECT rect;
|
||||||
GetWindowRect(hwnd, &rect);
|
GetWindowRect(hwnd, &rect);
|
||||||
idealHeight = rect.bottom - rect.top + 10; // the +10 is a hack since the size right now doesn't look right on a real Windows XP box
|
idealHeight = rect.bottom - rect.top + 10; // the +10 is a hack since the size right now doesn't look right on a real Windows XP box
|
||||||
|
*/
|
||||||
|
|
||||||
assert(idealHeight);
|
assert(idealHeight);
|
||||||
} else version(custom_widgets) {
|
} else version(custom_widgets) {
|
||||||
|
@ -2932,7 +2948,13 @@ class Fieldset : Widget {
|
||||||
}
|
}
|
||||||
|
|
||||||
override int minHeight() {
|
override int minHeight() {
|
||||||
return super.minHeight() + Window.lineHeight + 4;
|
auto m = paddingTop() + paddingBottom();
|
||||||
|
foreach(child; children) {
|
||||||
|
m += child.minHeight();
|
||||||
|
m += child.marginBottom();
|
||||||
|
m += child.marginTop();
|
||||||
|
}
|
||||||
|
return m + 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3342,6 +3364,9 @@ class Button : MouseActivatedWidget {
|
||||||
Color hoverBgColor;
|
Color hoverBgColor;
|
||||||
Color depressedBgColor;
|
Color depressedBgColor;
|
||||||
|
|
||||||
|
override int heightStretchiness() { return 3; }
|
||||||
|
override int widthStretchiness() { return 3; }
|
||||||
|
|
||||||
version(win32_widgets)
|
version(win32_widgets)
|
||||||
override void handleWmCommand(ushort cmd, ushort id) {
|
override void handleWmCommand(ushort cmd, ushort id) {
|
||||||
auto event = new Event("triggered", this);
|
auto event = new Event("triggered", this);
|
||||||
|
@ -3397,7 +3422,7 @@ class Button : MouseActivatedWidget {
|
||||||
}
|
}
|
||||||
else static assert(false);
|
else static assert(false);
|
||||||
|
|
||||||
override int minHeight() { return Window.lineHeight; }
|
override int minHeight() { return Window.lineHeight + 4; }
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ArrowDirection {
|
enum ArrowDirection {
|
||||||
|
@ -3516,7 +3541,7 @@ abstract class EditableTextWidget : ScrollableWidget {
|
||||||
|
|
||||||
override int minWidth() { return 16; }
|
override int minWidth() { return 16; }
|
||||||
override int minHeight() { return Window.lineHeight + 0; } // the +0 is to leave room for the padding
|
override int minHeight() { return Window.lineHeight + 0; } // the +0 is to leave room for the padding
|
||||||
override int widthStretchiness() { return 3; }
|
override int widthStretchiness() { return 7; }
|
||||||
|
|
||||||
@property string content() {
|
@property string content() {
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
|
@ -3678,6 +3703,10 @@ abstract class EditableTextWidget : ScrollableWidget {
|
||||||
|
|
||||||
///
|
///
|
||||||
class LineEdit : EditableTextWidget {
|
class LineEdit : EditableTextWidget {
|
||||||
|
// FIXME: hack
|
||||||
|
override bool showingVerticalScroll() { return false; }
|
||||||
|
override bool showingHorizontalScroll() { return false; }
|
||||||
|
|
||||||
this(Widget parent = null) {
|
this(Widget parent = null) {
|
||||||
super(parent);
|
super(parent);
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
|
@ -3708,7 +3737,7 @@ class TextEdit : EditableTextWidget {
|
||||||
} else static assert(false);
|
} else static assert(false);
|
||||||
}
|
}
|
||||||
override int maxHeight() { return int.max; }
|
override int maxHeight() { return int.max; }
|
||||||
override int heightStretchiness() { return 4; }
|
override int heightStretchiness() { return 7; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3994,40 +4023,6 @@ WidgetAtPointResponse widgetAtPoint(Widget starting, int x, int y) {
|
||||||
return WidgetAtPointResponse(starting, x, y);
|
return WidgetAtPointResponse(starting, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
version(win32_theming) {
|
|
||||||
import std.c.windows.windows;
|
|
||||||
|
|
||||||
alias HANDLE HTHEME;
|
|
||||||
|
|
||||||
// Since dmd doesn't offer uxtheme.lib, I'll load the dll at runtime instead
|
|
||||||
HMODULE uxtheme;
|
|
||||||
static this() {
|
|
||||||
uxtheme = LoadLibraryA("uxtheme.dll");
|
|
||||||
if(uxtheme) {
|
|
||||||
DrawThemeBackground = cast(typeof(DrawThemeBackground)) GetProcAddress(uxtheme, "DrawThemeBackground");
|
|
||||||
OpenThemeData = cast(typeof(OpenThemeData)) GetProcAddress(uxtheme, "OpenThemeData");
|
|
||||||
CloseThemeData = cast(typeof(CloseThemeData)) GetProcAddress(uxtheme, "CloseThemeData");
|
|
||||||
GetThemeSysColorBrush = cast(typeof(GetThemeSysColorBrush)) GetProcAddress(uxtheme, "CloseThemeData");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// everything from here is just win32 headers copy pasta
|
|
||||||
private:
|
|
||||||
extern(Windows):
|
|
||||||
|
|
||||||
HRESULT function(HTHEME, HDC, int, int, in RECT*, in RECT*) DrawThemeBackground;
|
|
||||||
HTHEME function(HWND, LPCWSTR) OpenThemeData;
|
|
||||||
HRESULT function(HTHEME) CloseThemeData;
|
|
||||||
HBRUSH function(HTHEME, int) GetThemeSysColorBrush;
|
|
||||||
|
|
||||||
HMODULE LoadLibraryA(LPCSTR);
|
|
||||||
BOOL FreeLibrary(HMODULE);
|
|
||||||
FARPROC GetProcAddress(HMODULE, LPCSTR);
|
|
||||||
// pragma(lib, "uxtheme");
|
|
||||||
|
|
||||||
BOOL GetClassInfoA(HINSTANCE, LPCSTR, WNDCLASS*);
|
|
||||||
}
|
|
||||||
|
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
import core.sys.windows.windows;
|
import core.sys.windows.windows;
|
||||||
import gdi = core.sys.windows.wingdi;
|
import gdi = core.sys.windows.wingdi;
|
||||||
|
@ -4291,6 +4286,111 @@ enum GenericIcons : ushort {
|
||||||
Print,
|
Print,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getOpenFileName(
|
||||||
|
void delegate(string) onOK = null,
|
||||||
|
string prefilledName = null,
|
||||||
|
string[] filters = null,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
version(win32_widgets) {
|
||||||
|
/*
|
||||||
|
Ofn.lStructSize = sizeof(OPENFILENAME);
|
||||||
|
Ofn.hwndOwner = hWnd;
|
||||||
|
Ofn.lpstrFilter = szFilter;
|
||||||
|
Ofn.lpstrFile= szFile;
|
||||||
|
Ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile);
|
||||||
|
Ofn.lpstrFileTitle = szFileTitle;
|
||||||
|
Ofn.nMaxFileTitle = sizeof(szFileTitle);
|
||||||
|
Ofn.lpstrInitialDir = (LPSTR)NULL;
|
||||||
|
Ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
|
||||||
|
Ofn.lpstrTitle = szTitle;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
wchar[1024] file = 0;
|
||||||
|
OPENFILENAME ofn;
|
||||||
|
ofn.lStructSize = ofn.sizeof;
|
||||||
|
ofn.lpstrFile = file.ptr;
|
||||||
|
ofn.nMaxFile = file.length;
|
||||||
|
GetOpenFileName(&ofn);
|
||||||
|
} else version(custom_widgets) {
|
||||||
|
auto picker = new FilePicker();
|
||||||
|
picker.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version(custom_widgets)
|
||||||
|
class FilePicker : Dialog {
|
||||||
|
this(Window owner = null) {
|
||||||
|
//import std.file;
|
||||||
|
super(300, 200, "Choose File..."); // owner);
|
||||||
|
|
||||||
|
auto listWidget = new ListWidget(this);
|
||||||
|
|
||||||
|
auto lineEdit = new LineEdit(this);
|
||||||
|
lineEdit.focus();
|
||||||
|
lineEdit.addEventListener("char", (Event event) {
|
||||||
|
if(event.character == '\t' || event.character == '\n')
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
listWidget.addEventListener(EventType.change, () {
|
||||||
|
foreach(o; listWidget.options)
|
||||||
|
if(o.selected)
|
||||||
|
lineEdit.content = o.label;
|
||||||
|
});
|
||||||
|
|
||||||
|
lineEdit.addEventListener(EventType.keydown, (Event event) {
|
||||||
|
if(event.key == Key.Tab) {
|
||||||
|
import std.file; // FIXME: so slow building :(
|
||||||
|
listWidget.clear();
|
||||||
|
|
||||||
|
string commonPrefix;
|
||||||
|
auto cnt = lineEdit.content;
|
||||||
|
if(cnt.length >= 2 && cnt[0 ..2] == "./")
|
||||||
|
cnt = cnt[2 .. $];
|
||||||
|
foreach(string name; dirEntries(".", cnt ~ "*", SpanMode.shallow)) {
|
||||||
|
listWidget.addOption(name);
|
||||||
|
if(commonPrefix is null)
|
||||||
|
commonPrefix = name;
|
||||||
|
else {
|
||||||
|
foreach(idx, char i; name) {
|
||||||
|
if(idx >= commonPrefix.length || i != commonPrefix[idx]) {
|
||||||
|
commonPrefix = commonPrefix[0 .. idx];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineEdit.content = commonPrefix;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto hl = new HorizontalLayout(this);
|
||||||
|
auto cancelButton = new Button("Cancel", hl);
|
||||||
|
auto okButton = new Button("OK", hl);
|
||||||
|
|
||||||
|
recomputeChildLayout(); // FIXME hack
|
||||||
|
|
||||||
|
cancelButton.addEventListener(EventType.triggered, &Cancel);
|
||||||
|
okButton.addEventListener(EventType.triggered, &OK);
|
||||||
|
|
||||||
|
this.addEventListener("keydown", (Event event) {
|
||||||
|
if(event.key == Key.Enter)
|
||||||
|
OK();
|
||||||
|
if(event.key == Key.Escape)
|
||||||
|
Cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override void OK() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775947%28v=vs.85%29.aspx#check_boxes
|
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775947%28v=vs.85%29.aspx#check_boxes
|
||||||
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633574%28v=vs.85%29.aspx
|
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633574%28v=vs.85%29.aspx
|
||||||
|
|
|
@ -151,7 +151,7 @@ class ColorPickerDialog : Dialog {
|
||||||
this.addEventListener("keydown", (Event event) {
|
this.addEventListener("keydown", (Event event) {
|
||||||
if(event.key == Key.Enter)
|
if(event.key == Key.Enter)
|
||||||
OK();
|
OK();
|
||||||
if(event.character == Key.Escape)
|
if(event.key == Key.Escape)
|
||||||
Cancel();
|
Cancel();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue