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 {
|
||||
//import std.stdio; try { writeln(iMessage); } catch(Exception e) {};
|
||||
if(auto te = hWnd in Widget.nativeMapping) {
|
||||
if(iMessage == WM_SETFOCUS) {
|
||||
auto lol = *te;
|
||||
while(lol !is null && lol.implicitlyCreated)
|
||||
lol = lol.parent;
|
||||
(*te).parentWindow.focusedWidget = lol;
|
||||
}
|
||||
try {
|
||||
if(iMessage == WM_SETFOCUS) {
|
||||
auto lol = *te;
|
||||
while(lol !is null && lol.implicitlyCreated)
|
||||
lol = lol.parent;
|
||||
lol.focus();
|
||||
//(*te).parentWindow.focusedWidget = lol;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(iMessage == WM_CTLCOLORBTN || iMessage == WM_CTLCOLORSTATIC) {
|
||||
SetBkMode(cast(HDC) wParam, TRANSPARENT);
|
||||
return cast(typeof(return))
|
||||
//GetStockObject(NULL_BRUSH);
|
||||
// this is the window background color...
|
||||
GetSysColorBrush(COLOR_3DFACE);
|
||||
}
|
||||
if(iMessage == WM_CTLCOLORBTN || iMessage == WM_CTLCOLORSTATIC) {
|
||||
SetBkMode(cast(HDC) wParam, TRANSPARENT);
|
||||
return cast(typeof(return))
|
||||
//GetStockObject(NULL_BRUSH);
|
||||
// this is the window background color...
|
||||
GetSysColorBrush(COLOR_3DFACE);
|
||||
}
|
||||
|
||||
|
||||
auto pos = getChildPositionRelativeToParentOrigin(*te);
|
||||
lastDefaultPrevented = false;
|
||||
// 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)
|
||||
return CallWindowProcW((*te).originalWindowProcedure, hWnd, iMessage, wParam, lParam);
|
||||
else {
|
||||
// it was something we recognized, should only call the window procedure if the default was not prevented
|
||||
auto pos = getChildPositionRelativeToParentOrigin(*te);
|
||||
lastDefaultPrevented = false;
|
||||
// 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)
|
||||
return CallWindowProcW((*te).originalWindowProcedure, hWnd, iMessage, wParam, lParam);
|
||||
else {
|
||||
// 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;
|
||||
}
|
||||
|
@ -649,6 +654,10 @@ class Widget {
|
|||
parent.addChild(this);
|
||||
}
|
||||
|
||||
bool isFocused() {
|
||||
return parentWindow && parentWindow.focusedWidget is this;
|
||||
}
|
||||
|
||||
bool showing = true;
|
||||
void show() { showing = true; redraw(); }
|
||||
void hide() { showing = false; }
|
||||
|
@ -695,6 +704,31 @@ class Widget {
|
|||
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 addedTo(Widget w) {}
|
||||
|
||||
|
@ -783,6 +817,9 @@ class Widget {
|
|||
if(!showing) return;
|
||||
|
||||
assert(parentWindow !is null);
|
||||
if(parentWindow.win.closed())
|
||||
return;
|
||||
|
||||
auto ugh = this.parent;
|
||||
int lox, loy;
|
||||
while(ugh) {
|
||||
|
@ -872,7 +909,7 @@ class Window : Widget {
|
|||
this(int width = 500, int height = 500, string title = 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.height = win.height;
|
||||
this.parentWindow = this;
|
||||
|
@ -885,6 +922,15 @@ class Window : Widget {
|
|||
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(
|
||||
(MouseEvent e) {
|
||||
dispatchMouseEvent(e);
|
||||
|
@ -968,12 +1014,15 @@ class Window : Widget {
|
|||
|
||||
if(recipient !is null) {
|
||||
// import std.stdio; writeln(typeid(recipient));
|
||||
recipient.focus();
|
||||
/*
|
||||
version(win32_widgets) {
|
||||
if(recipient.hwnd !is null)
|
||||
SetFocus(recipient.hwnd);
|
||||
} else {
|
||||
focusedWidget = recipient;
|
||||
}
|
||||
*/
|
||||
|
||||
skipNextChar = true;
|
||||
}
|
||||
|
@ -1117,6 +1166,7 @@ class Window : Widget {
|
|||
|
||||
void loop() {
|
||||
recomputeChildLayout();
|
||||
win.show();
|
||||
redraw();
|
||||
win.eventLoop(0);
|
||||
}
|
||||
|
@ -1821,6 +1871,7 @@ class MouseActivatedWidget : Widget {
|
|||
|
||||
addEventListener("mouseleave", delegate (Widget _this, Event ev) {
|
||||
isHovering = false;
|
||||
isDepressed = false;
|
||||
redraw();
|
||||
});
|
||||
|
||||
|
@ -1834,9 +1885,34 @@ class MouseActivatedWidget : Widget {
|
|||
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) {
|
||||
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.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(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(1, height - 1), Point(width - 1, height - 1));
|
||||
|
||||
|
||||
painter.outlineColor = Color.black;
|
||||
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 {
|
|||
|
||||
}
|
||||
|
||||
///
|
||||
class LineEdit : Widget {
|
||||
version(win32_widgets)
|
||||
/// Contains the implementation of text editing
|
||||
abstract class EditableTextWidget : Widget {
|
||||
this(Widget parent = null) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
string _content;
|
||||
@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 minHeight() { return Window.lineHeight + 0; } // the +0 is to leave room for the padding
|
||||
override int maxHeight() { return Window.lineHeight + 0; }
|
||||
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() {
|
||||
version(win32_widgets) {
|
||||
|
@ -2233,17 +2190,110 @@ class TextEdit : Widget {
|
|||
}
|
||||
}
|
||||
|
||||
void focus() {
|
||||
assert(parentWindow !is null);
|
||||
parentWindow.focusedWidget = this;
|
||||
}
|
||||
version(win32_widgets) { /* will do it with Windows calls in the classes */ }
|
||||
else {
|
||||
// FIXME
|
||||
mixin ExperimentalTextComponent;
|
||||
|
||||
version(win32_widgets) {
|
||||
|
||||
} else {
|
||||
Timer caratTimer;
|
||||
TextLayout textLayout;
|
||||
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);
|
||||
button. x = this.width / 2 - button.width / 2;
|
||||
button.y = height - (button.height + 10);
|
||||
button.addEventListener(EventType.click, () {
|
||||
button.addEventListener(EventType.triggered, () {
|
||||
close();
|
||||
});
|
||||
|
||||
button.registerMovement();
|
||||
button.focus();
|
||||
|
||||
win.show();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
|
121
simpledisplay.d
121
simpledisplay.d
|
@ -75,7 +75,6 @@
|
|||
)
|
||||
|
||||
|
||||
|
||||
Jump_list:
|
||||
|
||||
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.
|
||||
|
||||
$(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)
|
||||
|
||||
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
|
||||
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 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.
|
||||
|
@ -3911,6 +3957,8 @@ void displayImage(Image image, SimpleWindow win = null) {
|
|||
struct ScreenPainter {
|
||||
SimpleWindow window;
|
||||
this(SimpleWindow window, NativeWindowHandle handle) {
|
||||
if(window.closed)
|
||||
throw new Exception("cannot draw on a closed window");
|
||||
this.window = window;
|
||||
if(window.activeScreenPainter !is null) {
|
||||
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) {
|
||||
impl.referenceCount++;
|
||||
//writeln("refcount ++ ", impl.referenceCount);
|
||||
|
@ -6115,7 +6161,7 @@ version(X11) {
|
|||
auto h = y2 - y;
|
||||
if(textHeight < h) {
|
||||
cy += (h - textHeight) / 2;
|
||||
cy -= lineHeight / 4;
|
||||
//cy -= lineHeight / 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10419,6 +10465,7 @@ mixin template ExperimentalTextComponent() {
|
|||
|
||||
ie.text = arg[lastLineIndex .. $];
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue