mirror of https://github.com/adamdruppe/arsd.git
minigui getting more usable on linux
This commit is contained in:
parent
fc1cfc1f8a
commit
f0ac35c83b
376
minigui.d
376
minigui.d
|
@ -507,31 +507,36 @@ version(win32_widgets) {
|
||||||
int HookedWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) nothrow {
|
int HookedWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) nothrow {
|
||||||
//import std.stdio; try { writeln(iMessage); } catch(Exception e) {};
|
//import std.stdio; try { writeln(iMessage); } catch(Exception e) {};
|
||||||
if(auto te = hWnd in Widget.nativeMapping) {
|
if(auto te = hWnd in Widget.nativeMapping) {
|
||||||
if(iMessage == WM_SETFOCUS) {
|
try {
|
||||||
auto lol = *te;
|
if(iMessage == WM_SETFOCUS) {
|
||||||
while(lol !is null && lol.implicitlyCreated)
|
auto lol = *te;
|
||||||
lol = lol.parent;
|
while(lol !is null && lol.implicitlyCreated)
|
||||||
(*te).parentWindow.focusedWidget = lol;
|
lol = lol.parent;
|
||||||
}
|
lol.focus();
|
||||||
|
//(*te).parentWindow.focusedWidget = lol;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(iMessage == WM_CTLCOLORBTN || iMessage == WM_CTLCOLORSTATIC) {
|
if(iMessage == WM_CTLCOLORBTN || iMessage == WM_CTLCOLORSTATIC) {
|
||||||
SetBkMode(cast(HDC) wParam, TRANSPARENT);
|
SetBkMode(cast(HDC) wParam, TRANSPARENT);
|
||||||
return cast(typeof(return))
|
return cast(typeof(return))
|
||||||
//GetStockObject(NULL_BRUSH);
|
//GetStockObject(NULL_BRUSH);
|
||||||
// this is the window background color...
|
// this is the window background color...
|
||||||
GetSysColorBrush(COLOR_3DFACE);
|
GetSysColorBrush(COLOR_3DFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto pos = getChildPositionRelativeToParentOrigin(*te);
|
auto pos = getChildPositionRelativeToParentOrigin(*te);
|
||||||
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 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
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
assert(0, e.toString());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -649,6 +654,10 @@ class Widget {
|
||||||
parent.addChild(this);
|
parent.addChild(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFocused() {
|
||||||
|
return parentWindow && parentWindow.focusedWidget is this;
|
||||||
|
}
|
||||||
|
|
||||||
bool showing = true;
|
bool showing = true;
|
||||||
void show() { showing = true; redraw(); }
|
void show() { showing = true; redraw(); }
|
||||||
void hide() { showing = false; }
|
void hide() { showing = false; }
|
||||||
|
@ -695,6 +704,31 @@ class Widget {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void focus() {
|
||||||
|
assert(parentWindow !is null);
|
||||||
|
if(parentWindow.focusedWidget is this)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(parentWindow.focusedWidget) {
|
||||||
|
// FIXME: more details here? like from and to
|
||||||
|
auto evt = new Event("blur", parentWindow.focusedWidget);
|
||||||
|
parentWindow.focusedWidget = null;
|
||||||
|
evt.sendDirectly();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
version(win32_widgets) {
|
||||||
|
if(this.hwnd !is null)
|
||||||
|
SetFocus(this.hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
parentWindow.focusedWidget = this;
|
||||||
|
auto evt = new Event("focus", this);
|
||||||
|
evt.sendDirectly();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void attachedToWindow(Window w) {}
|
void attachedToWindow(Window w) {}
|
||||||
void addedTo(Widget w) {}
|
void addedTo(Widget w) {}
|
||||||
|
|
||||||
|
@ -783,6 +817,9 @@ class Widget {
|
||||||
if(!showing) return;
|
if(!showing) return;
|
||||||
|
|
||||||
assert(parentWindow !is null);
|
assert(parentWindow !is null);
|
||||||
|
if(parentWindow.win.closed())
|
||||||
|
return;
|
||||||
|
|
||||||
auto ugh = this.parent;
|
auto ugh = this.parent;
|
||||||
int lox, loy;
|
int lox, loy;
|
||||||
while(ugh) {
|
while(ugh) {
|
||||||
|
@ -872,7 +909,7 @@ class Window : Widget {
|
||||||
this(int width = 500, int height = 500, string title = null) {
|
this(int width = 500, int height = 500, string title = null) {
|
||||||
super(null);
|
super(null);
|
||||||
|
|
||||||
win = new SimpleWindow(width, height, title, OpenGlOptions.no, Resizability.allowResizing);
|
win = new SimpleWindow(width, height, title, OpenGlOptions.no, Resizability.allowResizing, WindowTypes.normal, WindowFlags.dontAutoShow);
|
||||||
this.width = win.width;
|
this.width = win.width;
|
||||||
this.height = win.height;
|
this.height = win.height;
|
||||||
this.parentWindow = this;
|
this.parentWindow = this;
|
||||||
|
@ -885,6 +922,15 @@ class Window : Widget {
|
||||||
redraw();
|
redraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
win.onFocusChange = (bool getting) {
|
||||||
|
if(this.focusedWidget) {
|
||||||
|
auto evt = new Event(getting ? "focus" : "blur", this.focusedWidget);
|
||||||
|
evt.sendDirectly();
|
||||||
|
}
|
||||||
|
auto evt = new Event(getting ? "focus" : "blur", this);
|
||||||
|
evt.sendDirectly();
|
||||||
|
};
|
||||||
|
|
||||||
win.setEventHandlers(
|
win.setEventHandlers(
|
||||||
(MouseEvent e) {
|
(MouseEvent e) {
|
||||||
dispatchMouseEvent(e);
|
dispatchMouseEvent(e);
|
||||||
|
@ -968,12 +1014,15 @@ class Window : Widget {
|
||||||
|
|
||||||
if(recipient !is null) {
|
if(recipient !is null) {
|
||||||
// import std.stdio; writeln(typeid(recipient));
|
// import std.stdio; writeln(typeid(recipient));
|
||||||
|
recipient.focus();
|
||||||
|
/*
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
if(recipient.hwnd !is null)
|
if(recipient.hwnd !is null)
|
||||||
SetFocus(recipient.hwnd);
|
SetFocus(recipient.hwnd);
|
||||||
} else {
|
} else {
|
||||||
focusedWidget = recipient;
|
focusedWidget = recipient;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
skipNextChar = true;
|
skipNextChar = true;
|
||||||
}
|
}
|
||||||
|
@ -1117,6 +1166,7 @@ class Window : Widget {
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
recomputeChildLayout();
|
recomputeChildLayout();
|
||||||
|
win.show();
|
||||||
redraw();
|
redraw();
|
||||||
win.eventLoop(0);
|
win.eventLoop(0);
|
||||||
}
|
}
|
||||||
|
@ -1821,6 +1871,7 @@ class MouseActivatedWidget : Widget {
|
||||||
|
|
||||||
addEventListener("mouseleave", delegate (Widget _this, Event ev) {
|
addEventListener("mouseleave", delegate (Widget _this, Event ev) {
|
||||||
isHovering = false;
|
isHovering = false;
|
||||||
|
isDepressed = false;
|
||||||
redraw();
|
redraw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1834,9 +1885,34 @@ class MouseActivatedWidget : Widget {
|
||||||
redraw();
|
redraw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defaultEventHandlers["focus"] = delegate (Widget _this, Event ev) {
|
||||||
|
_this.redraw();
|
||||||
|
};
|
||||||
|
defaultEventHandlers["blur"] = delegate (Widget _this, Event ev) {
|
||||||
|
isDepressed = false;
|
||||||
|
isHovering = false;
|
||||||
|
_this.redraw();
|
||||||
|
};
|
||||||
|
defaultEventHandlers["keydown"] = delegate (Widget _this, Event ev) {
|
||||||
|
if(ev.key == Key.Space || ev.key == Key.Enter || ev.key == Key.PadEnter) {
|
||||||
|
isDepressed = true;
|
||||||
|
_this.redraw();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
defaultEventHandlers["keyup"] = delegate (Widget _this, Event ev) {
|
||||||
|
if(!isDepressed)
|
||||||
|
return;
|
||||||
|
isDepressed = false;
|
||||||
|
_this.redraw();
|
||||||
|
|
||||||
|
auto event = new Event("triggered", this);
|
||||||
|
event.sendDirectly();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
defaultEventHandlers["click"] = (Widget w, Event ev) {
|
defaultEventHandlers["click"] = (Widget w, Event ev) {
|
||||||
auto event = new Event("triggered", this);
|
auto event = new Event("triggered", this);
|
||||||
event.dispatch();
|
event.sendDirectly();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2012,17 +2088,24 @@ class Button : MouseActivatedWidget {
|
||||||
painter.drawRectangle(Point(0, 0), width, height);
|
painter.drawRectangle(Point(0, 0), width, height);
|
||||||
|
|
||||||
|
|
||||||
painter.outlineColor = (isHovering && isDepressed) ? Color(128, 128, 128) : Color.white;
|
painter.outlineColor = (isDepressed) ? Color(128, 128, 128) : Color.white;
|
||||||
painter.drawLine(Point(0, 0), Point(width, 0));
|
painter.drawLine(Point(0, 0), Point(width, 0));
|
||||||
painter.drawLine(Point(0, 0), Point(0, height - 1));
|
painter.drawLine(Point(0, 0), Point(0, height - 1));
|
||||||
|
|
||||||
painter.outlineColor = (isHovering && isDepressed) ? Color.white : Color(128, 128, 128);
|
painter.outlineColor = (isDepressed) ? Color.white : Color(128, 128, 128);
|
||||||
painter.drawLine(Point(width - 1, 1), Point(width - 1, height - 1));
|
painter.drawLine(Point(width - 1, 1), Point(width - 1, height - 1));
|
||||||
painter.drawLine(Point(1, height - 1), Point(width - 1, height - 1));
|
painter.drawLine(Point(1, height - 1), Point(width - 1, height - 1));
|
||||||
|
|
||||||
|
|
||||||
painter.outlineColor = Color.black;
|
painter.outlineColor = Color.black;
|
||||||
painter.drawText(Point(0, 0), label, Point(width, height), TextAlignment.Center | TextAlignment.VerticalCenter);
|
painter.drawText(Point(0, 0), label, Point(width, height), TextAlignment.Center | TextAlignment.VerticalCenter);
|
||||||
|
|
||||||
|
if(isFocused()) {
|
||||||
|
painter.fillColor = Color.transparent;
|
||||||
|
painter.outlineColor = Color.black;
|
||||||
|
painter.drawRectangle(Point(2, 2), width - 4, height - 4);
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2073,141 +2156,15 @@ class TextLabel : Widget {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
/// Contains the implementation of text editing
|
||||||
class LineEdit : Widget {
|
abstract class EditableTextWidget : Widget {
|
||||||
version(win32_widgets)
|
|
||||||
this(Widget parent = null) {
|
this(Widget parent = null) {
|
||||||
super(parent);
|
super(parent);
|
||||||
parentWindow = parent.parentWindow;
|
|
||||||
createWin32Window(this, "edit", "",
|
|
||||||
0, WS_EX_CLIENTEDGE);//|WS_HSCROLL|ES_AUTOHSCROLL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this(Widget parent = null) {
|
|
||||||
super(parent);
|
|
||||||
|
|
||||||
this.paint = (ScreenPainter painter) {
|
|
||||||
painter.fillColor = Color.white;
|
|
||||||
painter.drawRectangle(Point(0, 0), width, height);
|
|
||||||
|
|
||||||
painter.outlineColor = Color.black;
|
|
||||||
painter.drawText(Point(4, 4), content, Point(width - 4, height - 4));
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultEventHandlers["click"] = delegate (Widget _this, Event ev) {
|
|
||||||
this.focus();
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultEventHandlers["char"] = delegate (Widget _this, Event ev) {
|
|
||||||
content = content() ~ cast(char) ev.character;
|
|
||||||
redraw();
|
|
||||||
};
|
|
||||||
|
|
||||||
static if(UsingSimpledisplayX11)
|
|
||||||
cursor = XCreateFontCursor(XDisplayConnection.get(), 152 /* XC_xterm, a text input thingy */);
|
|
||||||
//super();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int minHeight() { return Window.lineHeight + 0; } // the +0 is to leave room for the padding
|
||||||
string _content;
|
override int maxHeight() { return Window.lineHeight + 0; }
|
||||||
@property string content() {
|
|
||||||
version(win32_widgets) {
|
|
||||||
char[4096] buffer;
|
|
||||||
|
|
||||||
// FIXME: GetWindowTextW
|
|
||||||
// FIXME: GetWindowTextLength
|
|
||||||
auto l = GetWindowTextA(hwnd, buffer.ptr, buffer.length - 1);
|
|
||||||
if(l >= 0)
|
|
||||||
_content = buffer[0 .. l].idup;
|
|
||||||
}
|
|
||||||
return _content;
|
|
||||||
}
|
|
||||||
@property void content(string s) {
|
|
||||||
_content = s;
|
|
||||||
version(win32_widgets)
|
|
||||||
SetWindowTextA(hwnd, toStringzInternal(s));
|
|
||||||
else
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void focus() {
|
|
||||||
assert(parentWindow !is null);
|
|
||||||
parentWindow.focusedWidget = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
override int minHeight() { return Window.lineHeight; }
|
|
||||||
override int maxHeight() { return Window.lineHeight; }
|
|
||||||
override int widthStretchiness() { return 3; }
|
override int widthStretchiness() { return 3; }
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
class TextEdit : Widget {
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
mixin ExperimentalTextComponent;
|
|
||||||
|
|
||||||
override int minHeight() { return Window.lineHeight; }
|
|
||||||
override int heightStretchiness() { return 3; }
|
|
||||||
override int widthStretchiness() { return 3; }
|
|
||||||
|
|
||||||
version(win32_widgets)
|
|
||||||
this(Widget parent = null) {
|
|
||||||
super(parent);
|
|
||||||
parentWindow = parent.parentWindow;
|
|
||||||
createWin32Window(this, "edit", "",
|
|
||||||
0|WS_VSCROLL|WS_HSCROLL|ES_MULTILINE|ES_WANTRETURN|ES_AUTOHSCROLL|ES_AUTOVSCROLL, WS_EX_CLIENTEDGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this(Widget parent = null) {
|
|
||||||
super(parent);
|
|
||||||
|
|
||||||
textLayout = new TextLayout(Rectangle(0, 0, width, height));
|
|
||||||
|
|
||||||
this.paint = (ScreenPainter painter) {
|
|
||||||
painter.fillColor = Color.white;
|
|
||||||
painter.drawRectangle(Point(0, 0), width, height);
|
|
||||||
|
|
||||||
textLayout.boundingBox = Rectangle(4, 4, width - 8, height - 8);
|
|
||||||
|
|
||||||
painter.outlineColor = Color.black;
|
|
||||||
// painter.drawText(Point(4, 4), content, Point(width - 4, height - 4));
|
|
||||||
|
|
||||||
textLayout.drawInto(painter);
|
|
||||||
};
|
|
||||||
|
|
||||||
caratTimer = new Timer(500, {
|
|
||||||
if(!parentWindow.win.closed && parentWindow.focusedWidget is this) {
|
|
||||||
auto painter = this.draw();
|
|
||||||
painter.pen = Pen(Color.white, 1);
|
|
||||||
painter.rasterOp = RasterOp.xor;
|
|
||||||
if(lastClick.element) {
|
|
||||||
painter.drawLine(
|
|
||||||
Point(lastClick.element.xOfIndex(lastClick.offset + 1), lastClick.element.boundingBox.top),
|
|
||||||
Point(lastClick.element.xOfIndex(lastClick.offset + 1), lastClick.element.boundingBox.bottom)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
painter.drawLine(
|
|
||||||
Point(4, 4),
|
|
||||||
Point(4, 10)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
defaultEventHandlers["click"] = delegate (Widget _this, Event ev) {
|
|
||||||
this.focus();
|
|
||||||
lastClick = textLayout.identify(ev.clientX, ev.clientY);
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultEventHandlers["char"] = delegate (Widget _this, Event ev) {
|
|
||||||
textLayout.addText("" ~ cast(char) ev.character); // FIXME
|
|
||||||
redraw();
|
|
||||||
};
|
|
||||||
|
|
||||||
static if(UsingSimpledisplayX11)
|
|
||||||
cursor = XCreateFontCursor(XDisplayConnection.get(), 152 /* XC_xterm, a text input thingy */);
|
|
||||||
//super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@property string content() {
|
@property string content() {
|
||||||
version(win32_widgets) {
|
version(win32_widgets) {
|
||||||
|
@ -2233,17 +2190,110 @@ class TextEdit : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void focus() {
|
version(win32_widgets) { /* will do it with Windows calls in the classes */ }
|
||||||
assert(parentWindow !is null);
|
else {
|
||||||
parentWindow.focusedWidget = this;
|
// FIXME
|
||||||
}
|
mixin ExperimentalTextComponent;
|
||||||
|
|
||||||
version(win32_widgets) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Timer caratTimer;
|
Timer caratTimer;
|
||||||
TextLayout textLayout;
|
TextLayout textLayout;
|
||||||
TextIdentifyResult lastClick;
|
TextIdentifyResult lastClick;
|
||||||
|
|
||||||
|
void setupCustomTextEditing() {
|
||||||
|
textLayout = new TextLayout(Rectangle(0, 0, width, height));
|
||||||
|
|
||||||
|
this.paint = (ScreenPainter painter) {
|
||||||
|
if(parentWindow.win.closed) return;
|
||||||
|
painter.fillColor = Color.white;
|
||||||
|
painter.drawRectangle(Point(0, 0), width, height);
|
||||||
|
|
||||||
|
textLayout.boundingBox = Rectangle(4, 0, width - 8, height - 0);
|
||||||
|
|
||||||
|
painter.outlineColor = Color.black;
|
||||||
|
// painter.drawText(Point(4, 4), content, Point(width - 4, height - 4));
|
||||||
|
|
||||||
|
textLayout.caratShowingOnScreen = false;
|
||||||
|
|
||||||
|
textLayout.drawInto(painter, !parentWindow.win.closed && parentWindow.focusedWidget is this);
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultEventHandlers["click"] = delegate (Widget _this, Event ev) {
|
||||||
|
if(parentWindow.win.closed) return;
|
||||||
|
this.focus();
|
||||||
|
textLayout.moveCaratToPixelCoordinates(ev.clientX, ev.clientY);
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultEventHandlers["focus"] = delegate (Widget _this, Event ev) {
|
||||||
|
if(parentWindow.win.closed) return;
|
||||||
|
auto painter = this.draw();
|
||||||
|
textLayout.drawCarat(painter);
|
||||||
|
|
||||||
|
if(caratTimer) {
|
||||||
|
caratTimer.destroy();
|
||||||
|
caratTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
caratTimer = new Timer(500, {
|
||||||
|
if(parentWindow.win.closed) {
|
||||||
|
caratTimer.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(parentWindow.focusedWidget is this) {
|
||||||
|
auto painter = this.draw();
|
||||||
|
textLayout.drawCarat(painter);
|
||||||
|
} else if(textLayout.caratShowingOnScreen) {
|
||||||
|
auto painter = this.draw();
|
||||||
|
textLayout.eraseCarat(painter);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
defaultEventHandlers["blur"] = delegate (Widget _this, Event ev) {
|
||||||
|
if(parentWindow.win.closed) return;
|
||||||
|
auto painter = this.draw();
|
||||||
|
textLayout.eraseCarat(painter);
|
||||||
|
if(caratTimer) {
|
||||||
|
caratTimer.destroy();
|
||||||
|
caratTimer = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultEventHandlers["char"] = delegate (Widget _this, Event ev) {
|
||||||
|
textLayout.addText("" ~ cast(char) ev.character); // FIXME
|
||||||
|
redraw();
|
||||||
|
};
|
||||||
|
|
||||||
|
static if(UsingSimpledisplayX11)
|
||||||
|
cursor = XCreateFontCursor(XDisplayConnection.get(), 152 /* XC_xterm, a text input thingy */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
class LineEdit : EditableTextWidget {
|
||||||
|
this(Widget parent = null) {
|
||||||
|
super(parent);
|
||||||
|
version(win32_widgets) {
|
||||||
|
parentWindow = parent.parentWindow;
|
||||||
|
createWin32Window(this, "edit", "",
|
||||||
|
0, WS_EX_CLIENTEDGE);//|WS_HSCROLL|ES_AUTOHSCROLL);
|
||||||
|
} else {
|
||||||
|
setupCustomTextEditing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
class TextEdit : EditableTextWidget {
|
||||||
|
this(Widget parent = null) {
|
||||||
|
super(parent);
|
||||||
|
version(win32_widgets) {
|
||||||
|
parentWindow = parent.parentWindow;
|
||||||
|
createWin32Window(this, "edit", "",
|
||||||
|
0|WS_VSCROLL|WS_HSCROLL|ES_MULTILINE|ES_WANTRETURN|ES_AUTOHSCROLL|ES_AUTOVSCROLL, WS_EX_CLIENTEDGE);
|
||||||
|
} else {
|
||||||
|
setupCustomTextEditing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2265,12 +2315,14 @@ class MessageBox : Window {
|
||||||
auto button = new Button("OK", this);
|
auto button = new Button("OK", this);
|
||||||
button. x = this.width / 2 - button.width / 2;
|
button. x = this.width / 2 - button.width / 2;
|
||||||
button.y = height - (button.height + 10);
|
button.y = height - (button.height + 10);
|
||||||
button.addEventListener(EventType.click, () {
|
button.addEventListener(EventType.triggered, () {
|
||||||
close();
|
close();
|
||||||
});
|
});
|
||||||
|
|
||||||
button.registerMovement();
|
button.registerMovement();
|
||||||
|
button.focus();
|
||||||
|
|
||||||
|
win.show();
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
121
simpledisplay.d
121
simpledisplay.d
|
@ -75,7 +75,6 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Jump_list:
|
Jump_list:
|
||||||
|
|
||||||
Don't worry, you don't have to read this whole documentation file!
|
Don't worry, you don't have to read this whole documentation file!
|
||||||
|
@ -365,6 +364,50 @@
|
||||||
|
|
||||||
minigui still needs a lot of work to be finished at this time, but it already offers a number of useful classes.
|
minigui still needs a lot of work to be finished at this time, but it already offers a number of useful classes.
|
||||||
|
|
||||||
|
$(H2 Platform-specific tips and tricks)
|
||||||
|
|
||||||
|
Windows_tips:
|
||||||
|
|
||||||
|
You can add icons or manifest files to your exe using a resource file.
|
||||||
|
|
||||||
|
To create a Windows .ico file, use the gimp or something. I'll write a helper
|
||||||
|
program later.
|
||||||
|
|
||||||
|
Create `yourapp.rc`:
|
||||||
|
|
||||||
|
```rc
|
||||||
|
1 ICON filename.ico
|
||||||
|
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "YourApp.exe.manifest"
|
||||||
|
```
|
||||||
|
|
||||||
|
And `yourapp.exe.manifest`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity
|
||||||
|
version="1.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
name="CompanyName.ProductName.YourApplication"
|
||||||
|
type="win32"
|
||||||
|
/>
|
||||||
|
<description>Your application description here.</description>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
$(H2 $(ID developer-notes) Developer notes)
|
$(H2 $(ID developer-notes) Developer notes)
|
||||||
|
|
||||||
I don't have a Mac, so that code isn't maintained. I would like to have a Cocoa
|
I don't have a Mac, so that code isn't maintained. I would like to have a Cocoa
|
||||||
|
@ -404,7 +447,7 @@
|
||||||
I live in the eastern United States, so I will most likely not be around at night in
|
I live in the eastern United States, so I will most likely not be around at night in
|
||||||
that US east timezone.
|
that US east timezone.
|
||||||
|
|
||||||
License: Copyright Adam D. Ruppe, 2011-2016. Released under the Boost Software License.
|
License: Copyright Adam D. Ruppe, 2011-2017. Released under the Boost Software License.
|
||||||
|
|
||||||
Building documentation: You may wish to use the `arsd.ddoc` file from my github with
|
Building documentation: You may wish to use the `arsd.ddoc` file from my github with
|
||||||
building the documentation for simpledisplay yourself. It will give it a bit more style.
|
building the documentation for simpledisplay yourself. It will give it a bit more style.
|
||||||
|
@ -3901,7 +3944,10 @@ void displayImage(Image image, SimpleWindow win = null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The 2D drawing proxy.
|
The 2D drawing proxy. You acquire one of these with [SimpleWindow.draw] rather
|
||||||
|
than constructing it directly. Then, it is reference counted so you can pass it
|
||||||
|
at around and when the last ref goes out of scope, the buffered drawing activities
|
||||||
|
are all carried out.
|
||||||
|
|
||||||
|
|
||||||
Most functions use the outlineColor instead of taking a color themselves.
|
Most functions use the outlineColor instead of taking a color themselves.
|
||||||
|
@ -3911,6 +3957,8 @@ void displayImage(Image image, SimpleWindow win = null) {
|
||||||
struct ScreenPainter {
|
struct ScreenPainter {
|
||||||
SimpleWindow window;
|
SimpleWindow window;
|
||||||
this(SimpleWindow window, NativeWindowHandle handle) {
|
this(SimpleWindow window, NativeWindowHandle handle) {
|
||||||
|
if(window.closed)
|
||||||
|
throw new Exception("cannot draw on a closed window");
|
||||||
this.window = window;
|
this.window = window;
|
||||||
if(window.activeScreenPainter !is null) {
|
if(window.activeScreenPainter !is null) {
|
||||||
impl = window.activeScreenPainter;
|
impl = window.activeScreenPainter;
|
||||||
|
@ -3936,8 +3984,6 @@ struct ScreenPainter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @disable this(this) { } // compiler bug? the linker is bitching about it beind defined twice
|
|
||||||
|
|
||||||
this(this) {
|
this(this) {
|
||||||
impl.referenceCount++;
|
impl.referenceCount++;
|
||||||
//writeln("refcount ++ ", impl.referenceCount);
|
//writeln("refcount ++ ", impl.referenceCount);
|
||||||
|
@ -6115,7 +6161,7 @@ version(X11) {
|
||||||
auto h = y2 - y;
|
auto h = y2 - y;
|
||||||
if(textHeight < h) {
|
if(textHeight < h) {
|
||||||
cy += (h - textHeight) / 2;
|
cy += (h - textHeight) / 2;
|
||||||
cy -= lineHeight / 4;
|
//cy -= lineHeight / 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10419,6 +10465,7 @@ mixin template ExperimentalTextComponent() {
|
||||||
|
|
||||||
ie.text = arg[lastLineIndex .. $];
|
ie.text = arg[lastLineIndex .. $];
|
||||||
blocks[$-1].parts ~= ie;
|
blocks[$-1].parts ~= ie;
|
||||||
|
carat = Carat(this, &(blocks[$-1].parts[$-1]), ie.text.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10449,7 +10496,13 @@ mixin template ExperimentalTextComponent() {
|
||||||
return TextIdentifyResult(null, 0);
|
return TextIdentifyResult(null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawInto(ScreenPainter painter) {
|
void moveCaratToPixelCoordinates(int x, int y) {
|
||||||
|
auto result = identify(x, y);
|
||||||
|
carat.inlineElement = result.element;
|
||||||
|
carat.offset = result.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawInto(ScreenPainter painter, bool focused = false) {
|
||||||
auto pos = Point(boundingBox.left, boundingBox.top);
|
auto pos = Point(boundingBox.left, boundingBox.top);
|
||||||
|
|
||||||
int lastHeight;
|
int lastHeight;
|
||||||
|
@ -10488,6 +10541,60 @@ mixin template ExperimentalTextComponent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(focused) {
|
||||||
|
highlightSelection(painter);
|
||||||
|
drawCarat(painter);
|
||||||
|
} else {
|
||||||
|
eraseCarat(painter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void highlightSelection(ScreenPainter painter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int caratLastDrawnX, caratLastDrawnY1, caratLastDrawnY2;
|
||||||
|
bool caratShowingOnScreen = false;
|
||||||
|
void drawCarat(ScreenPainter painter) {
|
||||||
|
int x, y1, y2;
|
||||||
|
if(carat.inlineElement is null) {
|
||||||
|
x = boundingBox.left;
|
||||||
|
y1 = boundingBox.top + 2;
|
||||||
|
y2 = boundingBox.bottom - 2;
|
||||||
|
} else {
|
||||||
|
x = carat.inlineElement.xOfIndex(carat.offset + 1);
|
||||||
|
y1 = carat.inlineElement.boundingBox.top + 2;
|
||||||
|
y2 = carat.inlineElement.boundingBox.bottom - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(caratShowingOnScreen && (x != caratLastDrawnX || y1 != caratLastDrawnY1 || y2 != caratLastDrawnY2))
|
||||||
|
eraseCarat(painter);
|
||||||
|
|
||||||
|
painter.pen = Pen(Color.white, 1);
|
||||||
|
painter.rasterOp = RasterOp.xor;
|
||||||
|
painter.drawLine(
|
||||||
|
Point(x, y1),
|
||||||
|
Point(x, y2)
|
||||||
|
);
|
||||||
|
caratShowingOnScreen = !caratShowingOnScreen;
|
||||||
|
|
||||||
|
if(caratShowingOnScreen) {
|
||||||
|
caratLastDrawnX = x;
|
||||||
|
caratLastDrawnY1 = y1;
|
||||||
|
caratLastDrawnY2 = y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eraseCarat(ScreenPainter painter) {
|
||||||
|
if(!caratShowingOnScreen) return;
|
||||||
|
painter.pen = Pen(Color.white, 1);
|
||||||
|
painter.rasterOp = RasterOp.xor;
|
||||||
|
painter.drawLine(
|
||||||
|
Point(caratLastDrawnX, caratLastDrawnY1),
|
||||||
|
Point(caratLastDrawnX, caratLastDrawnY2)
|
||||||
|
);
|
||||||
|
|
||||||
|
caratShowingOnScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Carat movement api
|
/// Carat movement api
|
||||||
|
|
Loading…
Reference in New Issue