From 40fbab4e1f98a0d84948df8ebb8052ed4dc524c0 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Tue, 4 Aug 2015 20:49:07 -0400 Subject: [PATCH] web.d updates --- dom.d | 7 ++- exception.d | 2 +- gamehelpers.d | 6 ++- jsvar.d | 6 +-- minigui.d | 31 +++++++++++ simpledisplay.d | 11 ++++ terminal.d | 139 ++++++++++++++++++++++++++++++++++++++++++++++++ web.d | 6 +-- 8 files changed, 198 insertions(+), 10 deletions(-) diff --git a/dom.d b/dom.d index 50a160b..d8ebec8 100644 --- a/dom.d +++ b/dom.d @@ -14,9 +14,11 @@ and adding spaces is easier than using LT macros everywhere. - BTW: this file depends on arsd.characterencodings, so help it - correctly read files from the internet. You should be able to + BTW: this file optionally depends on arsd.characterencodings, to + help it correctly read files from the internet. You should be able to get characterencodings.d from the same place you got this file. + + If you want it to stand alone, just always use the `parseUtf8` function. */ module arsd.dom; @@ -38,6 +40,7 @@ bool isConvenientAttribute(string name) { "src", "content", "pattern", "placeholder", "required", "alt", "rel", + "method", "action", "enctype" ]; foreach(l; list) if(name == l) return true; diff --git a/exception.d b/exception.d index fd2e51f..85adb54 100644 --- a/exception.d +++ b/exception.d @@ -271,7 +271,7 @@ version(exception_2_example) { alias enforce = enforceBase!ExceptionBase; import core.stdc.stdio; - //auto fp = enforce!fopen("nofile.txt".ptr, "rb".ptr); + auto fp = enforce!fopen("nofile.txt".ptr, "rb".ptr); // construct, passing it error details as data, not strings. diff --git a/gamehelpers.d b/gamehelpers.d index ecccc67..ef4e751 100644 --- a/gamehelpers.d +++ b/gamehelpers.d @@ -68,8 +68,12 @@ final class OpenGlTexture { // For easy 2d drawing of it void draw(Point where, int width = 0, int height = 0, float rotation = 0.0, Color bg = Color.white) { + draw(where.x, where.y, width, height, rotation, bg); + } + + void draw(float x, float y, int width = 0, int height = 0, float rotation = 0.0, Color bg = Color.white) { glPushMatrix(); - glTranslatef(where.x, where.y, 0); + glTranslatef(x, y, 0); glRotatef(rotation, 0,0, 1); if(width == 0) diff --git a/jsvar.d b/jsvar.d index 86fa1bd..7d8e0a0 100644 --- a/jsvar.d +++ b/jsvar.d @@ -904,8 +904,7 @@ struct var { return this.opEquals(var(t)); } - - public bool opEquals(T:var)(T t) { + public bool opEquals(T:var)(T t) const { // FIXME: should this be == or === ? if(this._type != t._type) return false; @@ -1127,7 +1126,8 @@ struct var { } else if(_type == Type.Object) { // objects might overload opIndex var* n = new var(); - *n = this["opIndex"](idx); + if("opIndex" in this) + *n = this["opIndex"](idx); return *n; } version(jsvar_throw) diff --git a/minigui.d b/minigui.d index dc11793..1cfd20d 100644 --- a/minigui.d +++ b/minigui.d @@ -6,6 +6,37 @@ module arsd.minigui; /* + + The main goals of minigui.d are to: + 1) Provide basic widgets that just work in a lightweight lib. + I basically want things comparable to a plain HTML form, + plus the easy and obvious things you expect from Windows + apps like a menu. + 2) Use native things when possible for best functionality with + least library weight. + 3) Give building blocks to provide easy extension for your + custom widgets, or hooking into additional native widgets + I didn't wrap. + 4) Provide interfaces for easy interaction between third + party minigui extensions. (event model, perhaps + signals/slots, drop-in ease of use bits.) + 5) Zero non-system dependencies, including Phobos as much as + I reasonably can. It must only import arsd.color and + my simpledisplay.d. If you need more, it will have to be + an extension module. + 6) An easy layout system that generally works. + + A stretch goal is to make it easy to make gui forms with code, + some kind of resource file (xml?) and even a wysiwyg designer. + + Another stretch goal is to make it easy to hook data into the gui, + including from reflection. So like auto-generate a form from a + function signature or struct definition, or show a list from an + array that automatically updates as the array is changed. Then, + your program focuses on the data more than the gui interaction. + + + STILL NEEDED: * combo box. (this is diff than select because you can free-form edit too. more like a lineedit with autoselect) * slider diff --git a/simpledisplay.d b/simpledisplay.d index 2d079f2..a229b66 100644 --- a/simpledisplay.d +++ b/simpledisplay.d @@ -2457,6 +2457,7 @@ version(Windows) { HWND hwnd; int oldWidth; int oldHeight; + bool inSizeMove; // the extern(Windows) wndproc should just forward to this int windowProcedure(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) { @@ -2476,6 +2477,12 @@ version(Windows) { case WM_SIZE: width = LOWORD(lParam); height = HIWORD(lParam); + + // I want to avoid tearing in the windows (my code is inefficient + // so this is a hack around that) so while sizing, we don't trigger, + // but we do want to trigger on events like mazimize. + if(!inSizeMove) + goto size_changed; break; // I don't like the tearing I get when redrawing on WM_SIZE // (I know there's other ways to fix that but I don't like that behavior anyway) @@ -2483,12 +2490,16 @@ version(Windows) { case 0x0231: /* WM_ENTERSIZEMOVE */ oldWidth = this.width; oldHeight = this.height; + inSizeMove = true; break; case 0x0232: /* WM_EXITSIZEMOVE */ + inSizeMove = false; // nothing relevant changed, don't bother redrawing if(oldWidth == width && oldHeight == height) break; + size_changed: + // note: OpenGL windows don't use a backing bmp, so no need to change them // if resizability is anything other than allowResizing, it is meant to either stretch the one image or just do nothing if(openglMode == OpenGlOptions.no && resizability == Resizablity.allowResizing) { diff --git a/terminal.d b/terminal.d index 4c42fe2..ea3ac91 100644 --- a/terminal.d +++ b/terminal.d @@ -3104,6 +3104,145 @@ version(Windows) { extern(Windows) HRESULT SHGetFolderPathA(HWND, int, HANDLE, DWORD, LPSTR); } + + + + +/* Like getting a line, printing a lot of lines is kinda important too, so I'm including + that widget here too. */ + + +struct ScrollbackBuffer { + struct LineComponent { + string text; + int color = Color.DEFAULT; + int background = Color.DEFAULT; + void delegate() onclick; + } + + struct Line { + LineComponent[] components; + int length() { + int l = 0; + foreach(c; components) + l += c.text.length; + return l; + } + } + + // FIXME: limit scrollback lines.length + + Line[] lines; + string name; + + int scrollbackPosition; + + void drawInto(Terminal* terminal, in int x, in int y, in int width, in int height) { + if(lines.length == 0) + return; + + /* We need to figure out how much is going to fit + in a first pass, so we can figure out where to + start drawing */ + + int remaining = height + scrollbackPosition; + int start = lines.length; + int howMany = 0; + + // we'll work backwards to figure out how much will fit... + // this will give accurate per-line things even with changing width and wrapping + // while being generally efficient - we usually want to show the end of the list + // anyway; actually using the scrollback is a bit of an exceptional case. + foreach_reverse(line; lines) { + int written = 0; + foreach(component; line.components) { + auto towrite = component.text; + written += towrite.length; + while(written > width) { + written -= width; + remaining--; + if(remaining <= 0) + break; + } + } + + remaining--; + + + start--; + howMany++; + if(remaining <= 0) + break; + } + + // second pass: actually draw it + int linePos = remaining; + + foreach(idx, line; lines[start .. start + howMany]) { + int written = 0; + + terminal.moveTo(x, y + ((linePos >= 0) ? linePos : 0)); + foreach(component; line.components) { + terminal.color(component.color, component.background); + auto towrite = component.text; + while(linePos < 0 && width < towrite.length) { + towrite = towrite[width .. $]; + linePos++; + } + terminal.write(towrite); + written += towrite.length; + while(written > width) { + written -= width; + linePos++; + if(linePos >= height) + break; + } + } + + if(written < width) + foreach(i; written .. width) + terminal.write(" "); + + linePos++; + + if(linePos >= height) + break; + } + + foreach(i; linePos .. height) { + if(i >= 0 && i < height) { + terminal.moveTo(x, y + i); + foreach(w; 0 .. width) + terminal.write(" "); + } + } + } + + void addLine(string line) { + lines ~= Line([LineComponent(line)]); + } + + void scrollUp(int lines = 1) { + scrollbackPosition += lines; + if(scrollbackPosition >= this.lines.length) + scrollbackPosition = this.lines.length - 1; + } + + void scrollDown(int lines = 1) { + scrollbackPosition -= lines; + if(scrollbackPosition < 0) + scrollbackPosition = 0; + } + + // does scrolling via wheel and keyboard and also clicks on content + void handleEvent() { + } +} + + + + + /* // more efficient scrolling diff --git a/web.d b/web.d index 7d907f2..fc4e002 100644 --- a/web.d +++ b/web.d @@ -1843,12 +1843,12 @@ Form createAutomaticForm(Document document, string action, in Parameter[] parame input.name = param.name; input.innerText = param.value; - input.rows = "7"; + input.attrs.rows = "7"; auto idx = type.indexOf("-"); if(idx != -1) { idx++; - input.rows = type[idx .. $]; + input.attrs.rows = type[idx .. $]; } } else { input = Element.make("input"); @@ -4021,7 +4021,7 @@ void translateQsa(Document document, Cgi cgi, string logicalScriptName = null) { string[][string] vars; foreach(k, v; cgi.getArray) vars[k] = cast(string[]) v; - foreach(k, v; decodeVariablesSingle(a.qsa)) { + foreach(k, v; decodeVariablesSingle(a.attrs.qsa)) { if(k in cgi.get && cgi.get[k] == v) matches++; possibilities++;