mirror of https://github.com/adamdruppe/arsd.git
font api in sdpy
This commit is contained in:
parent
45e4fc98ec
commit
df9c912bd9
4
color.d
4
color.d
|
@ -1256,6 +1256,10 @@ struct Point {
|
|||
Point opBinary(string op)(Point rhs) {
|
||||
return Point(mixin("x" ~ op ~ "rhs.x"), mixin("y" ~ op ~ "rhs.y"));
|
||||
}
|
||||
|
||||
Point opBinary(string op)(int rhs) {
|
||||
return Point(mixin("x" ~ op ~ "rhs"), mixin("y" ~ op ~ "rhs"));
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
|
270
minigui.d
270
minigui.d
|
@ -1,5 +1,18 @@
|
|||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775498%28v=vs.85%29.aspx
|
||||
|
||||
/*
|
||||
TODO:
|
||||
|
||||
scrolling
|
||||
event cleanup
|
||||
ScreenPainter dtor stuff. clipping api.
|
||||
Windows radio button sizing and theme text selection
|
||||
tooltips.
|
||||
api improvements
|
||||
|
||||
margins are kinda broken, they don't collapse like they should. at least.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
1(15:19:48) NotSpooky: Menus, text entry, label, notebook, box, frame, file dialogs and layout (this one is very useful because I can draw lines between its child widgets
|
||||
|
@ -123,6 +136,27 @@ abstract class ComboboxBase : Widget {
|
|||
else version(custom_widgets)
|
||||
this(Widget parent = null) {
|
||||
super(parent);
|
||||
|
||||
addEventListener("keydown", (Event event) {
|
||||
if(event.key == Key.Up) {
|
||||
if(selection > -1) { // -1 means select blank
|
||||
selection--;
|
||||
auto t = new Event("change", this);
|
||||
t.dispatch();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
if(event.key == Key.Down) {
|
||||
if(selection + 1 < options.length) {
|
||||
selection++;
|
||||
auto t = new Event("change", this);
|
||||
t.dispatch();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
else static assert(false);
|
||||
|
||||
|
@ -139,12 +173,15 @@ abstract class ComboboxBase : Widget {
|
|||
selection = idx;
|
||||
version(win32_widgets)
|
||||
SendMessageA(hwnd, 334 /*CB_SETCURSEL*/, idx, 0);
|
||||
|
||||
auto t = new Event("change", this);
|
||||
t.dispatch();
|
||||
}
|
||||
|
||||
version(win32_widgets)
|
||||
override void handleWmCommand(ushort cmd, ushort id) {
|
||||
selection = SendMessageA(hwnd, 327 /* CB_GETCURSEL */, 0, 0);
|
||||
auto event = new Event("changed", this);
|
||||
auto event = new Event("change", this);
|
||||
event.dispatch();
|
||||
}
|
||||
|
||||
|
@ -177,12 +214,12 @@ abstract class ComboboxBase : Widget {
|
|||
|
||||
dropDown.setEventHandlers(
|
||||
(MouseEvent event) {
|
||||
if(event.type == MouseEventType.buttonPressed) {
|
||||
if(event.type == MouseEventType.buttonReleased) {
|
||||
auto element = (event.y - 4) / Window.lineHeight;
|
||||
if(element >= 0 && element <= options.length) {
|
||||
selection = element;
|
||||
|
||||
auto t = new Event("changed", this);
|
||||
auto t = new Event("change", this);
|
||||
t.dispatch();
|
||||
}
|
||||
dropDown.close();
|
||||
|
@ -211,12 +248,36 @@ class DropDownSelection : ComboboxBase {
|
|||
draw3dFrame(this, painter, FrameStyle.risen);
|
||||
painter.outlineColor = Color.black;
|
||||
painter.drawText(Point(4, 4), selection == -1 ? "" : options[selection]);
|
||||
painter.drawLine(Point(width - 4 - 8, 4), Point(width - 4 - 2, height - 2));
|
||||
painter.drawLine(Point(width - 2, 4), Point(width - 4 - 2, height - 2));
|
||||
|
||||
painter.outlineColor = Color.black;
|
||||
painter.fillColor = Color.black;
|
||||
Point[3] triangle;
|
||||
enum padding = 6;
|
||||
enum paddingV = 8;
|
||||
enum triangleWidth = 10;
|
||||
triangle[0] = Point(width - padding - triangleWidth, paddingV);
|
||||
triangle[1] = Point(width - padding - triangleWidth / 2, height - paddingV);
|
||||
triangle[2] = Point(width - padding - 0, paddingV);
|
||||
painter.drawPolygon(triangle[]);
|
||||
|
||||
if(isFocused()) {
|
||||
painter.fillColor = Color.transparent;
|
||||
painter.pen = Pen(Color.black, 1, Pen.Style.Dashed);
|
||||
painter.drawRectangle(Point(2, 2), width - 4, height - 4);
|
||||
painter.pen = Pen(Color.black, 1, Pen.Style.Solid);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
addEventListener("changed", &this.redraw);
|
||||
addEventListener("click", &this.popup);
|
||||
addEventListener("focus", &this.redraw);
|
||||
addEventListener("blur", &this.redraw);
|
||||
addEventListener("change", &this.redraw);
|
||||
addEventListener("mousedown", () { this.focus(); this.popup(); });
|
||||
addEventListener("keydown", (Event event) {
|
||||
if(event.key == Key.Space)
|
||||
popup();
|
||||
});
|
||||
} else static assert(false);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +294,8 @@ class FreeEntrySelection : ComboboxBase {
|
|||
super(parent);
|
||||
auto hl = new HorizontalLayout(this);
|
||||
lineEdit = new LineEdit(hl);
|
||||
lineEdit.content = selection == -1 ? "" : options[selection];
|
||||
|
||||
tabStop = false;
|
||||
|
||||
auto btn = new class Button {
|
||||
this() {
|
||||
|
@ -243,9 +305,11 @@ class FreeEntrySelection : ComboboxBase {
|
|||
return 16;
|
||||
}
|
||||
};
|
||||
//btn.addDirectEventListener("focus", &lineEdit.focus);
|
||||
btn.addEventListener("triggered", &this.popup);
|
||||
addEventListener("changed", {
|
||||
lineEdit.content = selection == -1 ? "" : options[selection];
|
||||
addEventListener("change", {
|
||||
lineEdit.content = (selection == -1 ? "" : options[selection]);
|
||||
lineEdit.focus();
|
||||
redraw();
|
||||
});
|
||||
}
|
||||
|
@ -278,6 +342,30 @@ class ComboBox : ComboboxBase {
|
|||
}
|
||||
lineEdit.content = c;
|
||||
});
|
||||
|
||||
listWidget.tabStop = false;
|
||||
this.tabStop = false;
|
||||
listWidget.addEventListener("focus", &lineEdit.focus);
|
||||
this.addEventListener("focus", &lineEdit.focus);
|
||||
|
||||
addDirectEventListener("change", {
|
||||
listWidget.setSelection(selection);
|
||||
if(selection != -1)
|
||||
lineEdit.content = options[selection];
|
||||
lineEdit.focus();
|
||||
redraw();
|
||||
});
|
||||
|
||||
listWidget.addDirectEventListener("change", {
|
||||
int set = -1;
|
||||
foreach(idx, opt; listWidget.options)
|
||||
if(opt.selected) {
|
||||
set = cast(int) idx;
|
||||
break;
|
||||
}
|
||||
if(set != selection)
|
||||
this.setSelection(set);
|
||||
});
|
||||
} else static assert(false);
|
||||
}
|
||||
|
||||
|
@ -307,21 +395,28 @@ class ListWidget : Widget {
|
|||
bool selected;
|
||||
}
|
||||
|
||||
void setSelection(int y) {
|
||||
if(!multiSelect)
|
||||
foreach(ref opt; options)
|
||||
opt.selected = false;
|
||||
if(y >= 0 && y < options.length)
|
||||
options[y].selected = !options[y].selected;
|
||||
|
||||
auto evt = new Event("change", this);
|
||||
evt.dispatch();
|
||||
|
||||
redraw();
|
||||
|
||||
}
|
||||
|
||||
this(Widget parent = null) {
|
||||
super(parent);
|
||||
|
||||
defaultEventHandlers["click"] = delegate(Widget _this, Event event) {
|
||||
this.focus();
|
||||
auto y = (event.clientY - 4) / Window.lineHeight;
|
||||
if(y >= 0 && y < options.length) {
|
||||
if(!multiSelect)
|
||||
foreach(ref opt; options)
|
||||
opt.selected = false;
|
||||
options[y].selected = !options[y].selected;
|
||||
|
||||
auto evt = new Event("change", this);
|
||||
evt.dispatch();
|
||||
|
||||
redraw();
|
||||
setSelection(y);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -588,6 +683,7 @@ mixin template LayoutInfo() {
|
|||
foreach(child; children) {
|
||||
sum += child.minHeight();
|
||||
sum += child.marginTop();
|
||||
sum += child.marginBottom();
|
||||
}
|
||||
|
||||
return sum;
|
||||
|
@ -806,6 +902,19 @@ version(win32_widgets) {
|
|||
|
||||
assert(p.hwnd !is null);
|
||||
|
||||
|
||||
static HFONT font;
|
||||
if(font is null) {
|
||||
NONCLIENTMETRICS params;
|
||||
params.cbSize = params.sizeof;
|
||||
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, params.sizeof, ¶ms, 0)) {
|
||||
font = CreateFontIndirect(¶ms.lfMessageFont);
|
||||
}
|
||||
}
|
||||
|
||||
if(font)
|
||||
SendMessage(p.hwnd, WM_SETFONT, cast(uint) font, true);
|
||||
|
||||
Widget.nativeMapping[p.hwnd] = p;
|
||||
|
||||
p.originalWindowProcedure = cast(WNDPROC) SetWindowLong(p.hwnd, GWL_WNDPROC, cast(LONG) &HookedWndProc);
|
||||
|
@ -993,7 +1102,7 @@ class Widget {
|
|||
|
||||
parentWindow.focusedWidget = this;
|
||||
auto evt = new Event("focus", this);
|
||||
evt.sendDirectly();
|
||||
evt.dispatch();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1206,10 +1315,10 @@ class Window : Widget {
|
|||
win.onFocusChange = (bool getting) {
|
||||
if(this.focusedWidget) {
|
||||
auto evt = new Event(getting ? "focus" : "blur", this.focusedWidget);
|
||||
evt.sendDirectly();
|
||||
evt.dispatch();
|
||||
}
|
||||
auto evt = new Event(getting ? "focus" : "blur", this);
|
||||
evt.sendDirectly();
|
||||
evt.dispatch();
|
||||
};
|
||||
|
||||
win.setEventHandlers(
|
||||
|
@ -1606,8 +1715,8 @@ class ToolBar : Widget {
|
|||
override int minHeight() { return idealHeight; }
|
||||
override int maxHeight() { return idealHeight; }
|
||||
} else version(custom_widgets) {
|
||||
override int minHeight() { return Window.lineHeight * 3/2; }
|
||||
override int maxHeight() { return Window.lineHeight * 3/2; }
|
||||
override int minHeight() { return 32; }// Window.lineHeight * 3/2; }
|
||||
override int maxHeight() { return 32; } //Window.lineHeight * 3/2; }
|
||||
} else static assert(false);
|
||||
override int heightStretchiness() { return 0; }
|
||||
|
||||
|
@ -1685,7 +1794,61 @@ class ToolButton : Button {
|
|||
this.draw3dFrame(painter, isDepressed ? FrameStyle.sunk : FrameStyle.risen, currentButtonColor);
|
||||
|
||||
painter.outlineColor = Color.black;
|
||||
painter.drawText(Point(0, 0), action.label, Point(width, height), TextAlignment.Center | TextAlignment.VerticalCenter);
|
||||
|
||||
enum iconSize = 32;
|
||||
enum multiplier = iconSize / 16;
|
||||
switch(action.iconId) {
|
||||
case GenericIcons.New:
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawPolygon(
|
||||
Point(3, 2) * multiplier, Point(3, 13) * multiplier, Point(12, 13) * multiplier, Point(12, 6) * multiplier,
|
||||
Point(8, 2) * multiplier, Point(8, 6) * multiplier, Point(12, 6) * multiplier, Point(8, 2) * multiplier
|
||||
);
|
||||
break;
|
||||
case GenericIcons.Save:
|
||||
painter.fillColor = Color.black;
|
||||
painter.drawRectangle(Point(2, 2) * multiplier, Point(13, 13) * multiplier);
|
||||
|
||||
painter.fillColor = Color.white;
|
||||
painter.outlineColor = Color.white;
|
||||
painter.drawRectangle(Point(6, 3) * multiplier, Point(9, 5) * multiplier);
|
||||
painter.drawRectangle(Point(5, 9) * multiplier, Point(10, 12) * multiplier);
|
||||
break;
|
||||
case GenericIcons.Open:
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawPolygon(
|
||||
Point(2, 4) * multiplier, Point(2, 12) * multiplier, Point(13, 12) * multiplier, Point(13, 3) * multiplier,
|
||||
Point(9, 3) * multiplier, Point(9, 4) * multiplier, Point(2, 4) * multiplier);
|
||||
painter.drawLine(Point(3, 6) * multiplier, Point(9, 6) * multiplier);
|
||||
painter.drawLine(Point(9, 7) * multiplier, Point(13, 7) * multiplier);
|
||||
break;
|
||||
case GenericIcons.Copy:
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawRectangle(Point(3, 2) * multiplier, Point(9, 10) * multiplier);
|
||||
painter.drawRectangle(Point(6, 5) * multiplier, Point(12, 13) * multiplier);
|
||||
break;
|
||||
case GenericIcons.Cut:
|
||||
painter.fillColor = Color.transparent;
|
||||
painter.drawLine(Point(3, 2) * multiplier, Point(10, 9) * multiplier);
|
||||
painter.drawLine(Point(4, 9) * multiplier, Point(11, 2) * multiplier);
|
||||
painter.drawRectangle(Point(3, 9) * multiplier, Point(5, 13) * multiplier);
|
||||
painter.drawRectangle(Point(9, 9) * multiplier, Point(11, 12) * multiplier);
|
||||
break;
|
||||
case GenericIcons.Paste:
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawRectangle(Point(2, 3) * multiplier, Point(11, 11) * multiplier);
|
||||
painter.drawRectangle(Point(6, 8) * multiplier, Point(13, 13) * multiplier);
|
||||
painter.drawLine(Point(6, 2) * multiplier, Point(4, 5) * multiplier);
|
||||
painter.drawLine(Point(7, 2) * multiplier, Point(9, 5) * multiplier);
|
||||
painter.fillColor = Color.black;
|
||||
painter.drawRectangle(Point(4, 5) * multiplier, Point(9, 6) * multiplier);
|
||||
break;
|
||||
case GenericIcons.Help:
|
||||
painter.drawText(Point(0, 0), "?", Point(width, height), TextAlignment.Center | TextAlignment.VerticalCenter);
|
||||
break;
|
||||
default:
|
||||
painter.drawText(Point(0, 0), action.label, Point(width, height), TextAlignment.Center | TextAlignment.VerticalCenter);
|
||||
}
|
||||
};
|
||||
}
|
||||
else static assert(false);
|
||||
|
@ -1693,7 +1856,10 @@ class ToolButton : Button {
|
|||
|
||||
Action action;
|
||||
|
||||
override int maxWidth() { return 40; }
|
||||
override int maxWidth() { return 32; }
|
||||
override int minWidth() { return 32; }
|
||||
override int maxHeight() { return 32; }
|
||||
override int minHeight() { return 32; }
|
||||
}
|
||||
|
||||
|
||||
|
@ -1854,7 +2020,7 @@ class StatusBar : Widget {
|
|||
assert(idealHeight);
|
||||
} else version(custom_widgets) {
|
||||
this.paint = (ScreenPainter painter) {
|
||||
this.draw3dFrame(painter, FrameStyle.risen);
|
||||
this.draw3dFrame(painter, FrameStyle.sunk);
|
||||
int cpos = 0;
|
||||
int remainingLength = this.width;
|
||||
foreach(idx, part; this.partsArray) {
|
||||
|
@ -2287,9 +2453,15 @@ else static assert(false);
|
|||
///
|
||||
class Checkbox : MouseActivatedWidget {
|
||||
|
||||
override int maxHeight() { return 16; }
|
||||
override int minHeight() { return 16; }
|
||||
mixin Margin!"4";
|
||||
version(win32_widgets) {
|
||||
override int maxHeight() { return 16; }
|
||||
override int minHeight() { return 16; }
|
||||
} else version(custom_widgets) {
|
||||
override int maxHeight() { return Window.lineHeight; }
|
||||
override int minHeight() { return Window.lineHeight; }
|
||||
} else static assert(0);
|
||||
|
||||
override int marginLeft() { return 4; }
|
||||
|
||||
version(win32_widgets)
|
||||
this(string label, Widget parent = null) {
|
||||
|
@ -2315,21 +2487,23 @@ class Checkbox : MouseActivatedWidget {
|
|||
}
|
||||
|
||||
|
||||
enum buttonSize = 16;
|
||||
|
||||
painter.outlineColor = Color.black;
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawRectangle(Point(2, 2), height - 2, height - 2);
|
||||
painter.drawRectangle(Point(2, 2), buttonSize - 2, buttonSize - 2);
|
||||
|
||||
if(isChecked) {
|
||||
painter.pen = Pen(Color.black, 2);
|
||||
// I'm using height so the checkbox is square
|
||||
painter.drawLine(Point(6, 6), Point(height - 4, height - 4));
|
||||
painter.drawLine(Point(height-4, 6), Point(6, height - 4));
|
||||
enum padding = 5;
|
||||
painter.drawLine(Point(padding, padding), Point(buttonSize - (padding-2), buttonSize - (padding-2)));
|
||||
painter.drawLine(Point(buttonSize-(padding-2), padding), Point(padding, buttonSize - (padding-2)));
|
||||
|
||||
painter.pen = Pen(Color.black, 1);
|
||||
}
|
||||
|
||||
painter.drawText(Point(height + 4, 0), label, Point(width, height), TextAlignment.Left | TextAlignment.VerticalCenter);
|
||||
painter.drawText(Point(buttonSize + 4, 0), label, Point(width, height), TextAlignment.Left | TextAlignment.VerticalCenter);
|
||||
};
|
||||
|
||||
defaultEventHandlers["triggered"] = delegate (Widget _this, Event ev) {
|
||||
|
@ -2355,8 +2529,16 @@ class VerticalSpacer : Widget {
|
|||
|
||||
///
|
||||
class Radiobox : MouseActivatedWidget {
|
||||
override int maxHeight() { return 16; }
|
||||
override int minHeight() { return 16; }
|
||||
|
||||
version(win32_widgets) {
|
||||
override int maxHeight() { return 16; }
|
||||
override int minHeight() { return 16; }
|
||||
} else version(custom_widgets) {
|
||||
override int maxHeight() { return Window.lineHeight; }
|
||||
override int minHeight() { return Window.lineHeight; }
|
||||
} else static assert(0);
|
||||
|
||||
override int marginLeft() { return 4; }
|
||||
|
||||
version(win32_widgets)
|
||||
this(string label, Widget parent = null) {
|
||||
|
@ -2382,18 +2564,19 @@ class Radiobox : MouseActivatedWidget {
|
|||
|
||||
painter.pen = Pen(Color.black, 1, Pen.Style.Solid);
|
||||
|
||||
enum buttonSize = 16;
|
||||
|
||||
painter.outlineColor = Color.black;
|
||||
painter.fillColor = Color.white;
|
||||
painter.drawEllipse(Point(2, 2), Point(height - 2, height - 2));
|
||||
|
||||
painter.drawEllipse(Point(2, 2), Point(buttonSize - 2, buttonSize - 2));
|
||||
if(isChecked) {
|
||||
painter.outlineColor = Color.black;
|
||||
painter.fillColor = Color.black;
|
||||
// I'm using height so the checkbox is square
|
||||
painter.drawEllipse(Point(5, 5), Point(height - 5, height - 5));
|
||||
painter.drawEllipse(Point(5, 5), Point(buttonSize - 5, buttonSize - 5));
|
||||
}
|
||||
|
||||
painter.drawText(Point(height + 4, 0), label, Point(width, height), TextAlignment.Left | TextAlignment.VerticalCenter);
|
||||
painter.drawText(Point(buttonSize + 4, 0), label, Point(width, height), TextAlignment.Left | TextAlignment.VerticalCenter);
|
||||
};
|
||||
|
||||
defaultEventHandlers["triggered"] = delegate (Widget _this, Event ev) {
|
||||
|
@ -2771,6 +2954,13 @@ mixin template EventStuff() {
|
|||
EventHandler[][string] capturingEventHandlers;
|
||||
EventHandler[string] defaultEventHandlers;
|
||||
|
||||
void addDirectEventListener(string event, void delegate() handler, bool useCapture = false) {
|
||||
addEventListener(event, (Widget, Event e) {
|
||||
if(e.srcElement is this)
|
||||
handler();
|
||||
}, useCapture);
|
||||
}
|
||||
|
||||
void addEventListener(string event, void delegate() handler, bool useCapture = false) {
|
||||
addEventListener(event, (Widget, Event) { handler(); }, useCapture);
|
||||
}
|
||||
|
|
198
simpledisplay.d
198
simpledisplay.d
|
@ -3990,6 +3990,122 @@ void displayImage(Image image, SimpleWindow win = null) {
|
|||
}
|
||||
}
|
||||
|
||||
enum FontWeight : int {
|
||||
dontcare = 0,
|
||||
thin = 100,
|
||||
extralight = 200,
|
||||
light = 300,
|
||||
regular = 400,
|
||||
medium = 500,
|
||||
semibold = 600,
|
||||
bold = 700,
|
||||
extrabold = 800,
|
||||
heavy = 900
|
||||
}
|
||||
|
||||
/++
|
||||
Represents a font loaded off the operating system or the X server.
|
||||
|
||||
|
||||
While the api here is unified cross platform, the fonts are not necessarily
|
||||
available, even across machines of the same platform, so be sure to always check
|
||||
for null (using [isNull]) and have a fallback plan.
|
||||
|
||||
When you have a font you like, use [ScreenPainter.setFont] to load it for drawing.
|
||||
|
||||
Worst case, a null font will automatically fall back to the default font loaded
|
||||
for your system.
|
||||
+/
|
||||
class OperatingSystemFont {
|
||||
|
||||
version(X11) {
|
||||
XFontStruct* font;
|
||||
XFontSet fontset;
|
||||
} else version(Windows) {
|
||||
HFONT font;
|
||||
} else static assert(0);
|
||||
|
||||
///
|
||||
this(string name, int size = 0, FontWeight weight = FontWeight.dontcare, bool italic = false) {
|
||||
load(name, size, weight, italic);
|
||||
}
|
||||
|
||||
///
|
||||
bool load(string name, int size = 0, FontWeight weight = FontWeight.dontcare, bool italic = false) {
|
||||
unload();
|
||||
version(X11) {
|
||||
string weightstr;
|
||||
with(FontWeight)
|
||||
final switch(weight) {
|
||||
case dontcare: weightstr = "*"; break;
|
||||
case thin: weightstr = "extralight"; break;
|
||||
case extralight: weightstr = "extralight"; break;
|
||||
case light: weightstr = "light"; break;
|
||||
case regular: weightstr = "regular"; break;
|
||||
case medium: weightstr = "medium"; break;
|
||||
case semibold: weightstr = "demibold"; break;
|
||||
case bold: weightstr = "bold"; break;
|
||||
case extrabold: weightstr = "demibold"; break;
|
||||
case heavy: weightstr = "black"; break;
|
||||
}
|
||||
string sizestr;
|
||||
if(size == 0)
|
||||
sizestr = "*";
|
||||
else
|
||||
sizestr = "" ~ cast(char)(size / 10 + '0') ~ cast(char)(size % 10 + '0');
|
||||
auto xfontstr = "-*-"~name~"-"~weightstr~"-"~(italic ? "i" : "r")~"-*-*-"~sizestr~"-*-*-*-*-*-*-*";
|
||||
|
||||
//import std.stdio; writeln(xfontstr);
|
||||
|
||||
auto display = XDisplayConnection.get;
|
||||
|
||||
font = XLoadQueryFont(display, xfontstr.ptr);
|
||||
if(font is null)
|
||||
return false;
|
||||
|
||||
char** lol;
|
||||
int lol2;
|
||||
char* lol3;
|
||||
fontset = XCreateFontSet(display, xfontstr.ptr, &lol, &lol2, &lol3);
|
||||
} else version(Windows) {
|
||||
WCharzBuffer buffer = WCharzBuffer(name);
|
||||
font = CreateFont(size, 0, 0, 0, cast(int) weight, italic, 0, 0, 0, 0, 0, 0, 0, buffer.ptr);
|
||||
} else static assert(0);
|
||||
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
///
|
||||
void unload() {
|
||||
if(isNull())
|
||||
return;
|
||||
|
||||
version(X11) {
|
||||
auto display = XDisplayConnection.get;
|
||||
|
||||
if(font)
|
||||
XFreeFont(display, font);
|
||||
if(fontset)
|
||||
XFreeFontSet(display, fontset);
|
||||
|
||||
font = null;
|
||||
fontset = null;
|
||||
} else version(Windows) {
|
||||
DeleteObject(font);
|
||||
font = null;
|
||||
} else static assert(0);
|
||||
}
|
||||
|
||||
///
|
||||
bool isNull() {
|
||||
return font is null;
|
||||
}
|
||||
|
||||
~this() {
|
||||
unload();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
|
@ -4036,6 +4152,11 @@ struct ScreenPainter {
|
|||
//writeln("refcount ++ ", impl.referenceCount);
|
||||
}
|
||||
|
||||
///
|
||||
void setFont(OperatingSystemFont font) {
|
||||
impl.setFont(font);
|
||||
}
|
||||
|
||||
///
|
||||
int fontHeight() {
|
||||
return impl.fontHeight();
|
||||
|
@ -4200,6 +4321,13 @@ struct ScreenPainter {
|
|||
impl.drawRectangle(upperLeft.x, upperLeft.y, width, height);
|
||||
}
|
||||
|
||||
void drawRectangle(Point upperLeft, Point lowerRightInclusive) {
|
||||
transform(upperLeft);
|
||||
transform(lowerRightInclusive);
|
||||
impl.drawRectangle(upperLeft.x, upperLeft.y,
|
||||
lowerRightInclusive.x - upperLeft.x + 1, lowerRightInclusive.y - upperLeft.y + 1);
|
||||
}
|
||||
|
||||
/// Arguments are the points of the bounding rectangle
|
||||
void drawEllipse(Point upperLeft, Point lowerRight) {
|
||||
transform(upperLeft);
|
||||
|
@ -4215,11 +4343,16 @@ struct ScreenPainter {
|
|||
|
||||
/// .
|
||||
void drawPolygon(Point[] vertexes) {
|
||||
foreach(vertex; vertexes)
|
||||
foreach(ref vertex; vertexes)
|
||||
transform(vertex);
|
||||
impl.drawPolygon(vertexes);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
void drawPolygon(Point[] vertexes...) {
|
||||
drawPolygon(vertexes);
|
||||
}
|
||||
|
||||
|
||||
// and do a draw/fill in a single call maybe. Windows can do it... but X can't, though it could do two calls.
|
||||
|
||||
|
@ -5030,6 +5163,31 @@ version(Windows) {
|
|||
|
||||
// X doesn't draw a text background, so neither should we
|
||||
SetBkMode(hdc, TRANSPARENT);
|
||||
|
||||
|
||||
static bool triedDefaultGuiFont = false;
|
||||
if(!triedDefaultGuiFont) {
|
||||
NONCLIENTMETRICS params;
|
||||
params.cbSize = params.sizeof;
|
||||
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, params.sizeof, ¶ms, 0)) {
|
||||
defaultGuiFont = CreateFontIndirect(¶ms.lfMessageFont);
|
||||
}
|
||||
triedDefaultGuiFont = true;
|
||||
}
|
||||
|
||||
if(defaultGuiFont) {
|
||||
SelectObject(hdc, defaultGuiFont);
|
||||
// DeleteObject(defaultGuiFont);
|
||||
}
|
||||
}
|
||||
|
||||
static HFONT defaultGuiFont;
|
||||
|
||||
void setFont(OperatingSystemFont font) {
|
||||
if(font && font.font)
|
||||
SelectObject(hdc, font.font);
|
||||
else if(defaultGuiFont)
|
||||
SelectObject(hdc, defaultGuiFont);
|
||||
}
|
||||
|
||||
// just because we can on Windows...
|
||||
|
@ -6009,9 +6167,13 @@ version(X11) {
|
|||
// FIXME: should the gc be static too so it isn't recreated every time draw is called?
|
||||
GC gc;
|
||||
|
||||
__gshared XFontStruct* font;
|
||||
__gshared bool fontAttempted;
|
||||
__gshared XFontSet fontset;
|
||||
|
||||
__gshared XFontStruct* defaultfont;
|
||||
__gshared XFontSet defaultfontset;
|
||||
|
||||
XFontStruct* font;
|
||||
XFontSet fontset;
|
||||
|
||||
void create(NativeWindowHandle window) {
|
||||
this.display = XDisplayConnection.get();
|
||||
|
@ -6039,13 +6201,31 @@ version(X11) {
|
|||
fontset = XCreateFontSet(display, xfontstr.ptr, &lol, &lol2, &lol3);
|
||||
|
||||
fontAttempted = true;
|
||||
|
||||
defaultfont = font;
|
||||
defaultfontset = fontset;
|
||||
}
|
||||
|
||||
font = defaultfont;
|
||||
fontset = defaultfontset;
|
||||
|
||||
if(font) {
|
||||
XSetFont(display, gc, font.fid);
|
||||
}
|
||||
}
|
||||
|
||||
void setFont(OperatingSystemFont font) {
|
||||
if(font && font.font) {
|
||||
this.font = font.font;
|
||||
this.fontset = font.fontset;
|
||||
XSetFont(display, gc, font.font.fid);
|
||||
} else {
|
||||
this.font = defaultfont;
|
||||
this.fontset = defaultfontset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
auto buffer = this.window.impl.buffer;
|
||||
|
||||
|
@ -6311,8 +6491,12 @@ version(X11) {
|
|||
}
|
||||
|
||||
void drawPolygon(Point[] vertexes) {
|
||||
XPoint[16] pointsBuffer;
|
||||
XPoint[] points;
|
||||
points.length = vertexes.length;
|
||||
if(vertexes.length <= pointsBuffer.length)
|
||||
points = pointsBuffer[0 .. vertexes.length];
|
||||
else
|
||||
points.length = vertexes.length;
|
||||
|
||||
foreach(i, p; vertexes) {
|
||||
points[i].x = cast(short) p.x;
|
||||
|
@ -10837,6 +11021,7 @@ mixin template ExperimentalTextComponent() {
|
|||
Point(x, y1),
|
||||
Point(x, y2)
|
||||
);
|
||||
painter.rasterOp = RasterOp.normal;
|
||||
caratShowingOnScreen = !caratShowingOnScreen;
|
||||
|
||||
if(caratShowingOnScreen) {
|
||||
|
@ -10856,12 +11041,14 @@ mixin template ExperimentalTextComponent() {
|
|||
);
|
||||
|
||||
caratShowingOnScreen = false;
|
||||
painter.rasterOp = RasterOp.normal;
|
||||
}
|
||||
|
||||
/// Carat movement api
|
||||
/// These should give the user a logical result based on what they see on screen...
|
||||
/// thus they locate predominately by *pixels* not char index. (These will generally coincide with monospace fonts tho!)
|
||||
void moveUp(ref Carat carat) {
|
||||
if(carat.inlineElement is null) return;
|
||||
auto x = carat.inlineElement.xOfIndex(carat.offset);
|
||||
auto y = carat.inlineElement.boundingBox.top + 2;
|
||||
|
||||
|
@ -10875,6 +11062,7 @@ mixin template ExperimentalTextComponent() {
|
|||
}
|
||||
}
|
||||
void moveDown(ref Carat carat) {
|
||||
if(carat.inlineElement is null) return;
|
||||
auto x = carat.inlineElement.xOfIndex(carat.offset);
|
||||
auto y = carat.inlineElement.boundingBox.bottom - 2;
|
||||
|
||||
|
@ -10914,6 +11102,7 @@ mixin template ExperimentalTextComponent() {
|
|||
}
|
||||
}
|
||||
void moveHome(ref Carat carat) {
|
||||
if(carat.inlineElement is null) return;
|
||||
auto x = 0;
|
||||
auto y = carat.inlineElement.boundingBox.top + 2;
|
||||
|
||||
|
@ -10925,6 +11114,7 @@ mixin template ExperimentalTextComponent() {
|
|||
}
|
||||
}
|
||||
void moveEnd(ref Carat carat) {
|
||||
if(carat.inlineElement is null) return;
|
||||
auto x = int.max;
|
||||
auto y = carat.inlineElement.boundingBox.top + 2;
|
||||
|
||||
|
|
Loading…
Reference in New Issue