From 6e4e2966ca31fcc4497c4f3d1a82a5889636908f Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Fri, 13 Sep 2024 22:02:07 -0400 Subject: [PATCH] some browser jam stuff --- dom.d | 41 +++++++++++++++++++++++++---- minigui.d | 71 +++++++++++++++++++++++++++++++++++++++++++++++--- textlayouter.d | 21 +++++++++++++++ 3 files changed, 125 insertions(+), 8 deletions(-) diff --git a/dom.d b/dom.d index e18401d..81ef4f7 100644 --- a/dom.d +++ b/dom.d @@ -3078,7 +3078,7 @@ class Element : DomParent { /* done */ - _computedStyle = new CssStyle(null, style); // gives at least something to work with + _computedStyle = computedStyleFactory(this); } return _computedStyle; } @@ -7640,6 +7640,24 @@ Element[] removeDuplicates(Element[] input) { // done with CSS selector handling +/++ + This delegate is called if you call [Element.computedStyle] to attach an object to the element + that holds stylesheet information. You can rebind it to something else to return a subclass + if you want to hold more per-element extension data than the normal computed style object holds + (e.g. layout info as well). + + The default is `return new CssStyle(null, element.style);` + + History: + Added September 13, 2024 (dub v11.6) ++/ +CssStyle function(Element e) computedStyleFactory = &defaultComputedStyleFactory; + +/// ditto +CssStyle defaultComputedStyleFactory(Element e) { + return new CssStyle(null, e.style); // gives at least something to work with +} + // FIXME: use the better parser from html.d /// This is probably not useful to you unless you're writing a browser or something like that. @@ -7726,7 +7744,7 @@ class CssStyle { if(value is null) return getValue(name); else - return setValue(name, value, 0x02000000 /* inline specificity */); + return setValue(name, value, Specificity(0x02000000) /* inline specificity */); } /// takes dash style name @@ -8709,11 +8727,13 @@ void fillForm(T)(Form form, T obj, string name) { History: Added March 25, 2022 (dub v10.8) + + The `stripLeadingAndTrailing` argument was added September 13, 2024 (dub v11.6). +/ -string normalizeWhitespace(string text) { +string normalizeWhitespace(string text, bool stripLeadingAndTrailing = true) { string ret; ret.reserve(text.length); - bool lastWasWhite = true; + bool lastWasWhite = stripLeadingAndTrailing; foreach(char ch; text) { if(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') { if(lastWasWhite) @@ -8727,12 +8747,23 @@ string normalizeWhitespace(string text) { ret ~= ch; } - return ret.stripRight; + if(stripLeadingAndTrailing) + return ret.stripRight; + else { + /+ + if(lastWasWhite && (ret.length == 0 || ret[$-1] != ' ')) + ret ~= ' '; + +/ + return ret; + } } unittest { assert(normalizeWhitespace(" foo ") == "foo"); assert(normalizeWhitespace(" f\n \t oo ") == "f oo"); + assert(normalizeWhitespace(" foo ", false) == " foo "); + assert(normalizeWhitespace(" foo ", false) == " foo "); + assert(normalizeWhitespace("\nfoo", false) == " foo"); } unittest { diff --git a/minigui.d b/minigui.d index eff15ac..f66a86c 100644 --- a/minigui.d +++ b/minigui.d @@ -1560,11 +1560,23 @@ class Widget : ReflectableProperties { +/ final @property inout(Window) parentWindow() inout @nogc nothrow pure { return _parentWindow; } private @property void parentWindow(Window parent) { + auto old = _parentWindow; _parentWindow = parent; + newParentWindow(old, _parentWindow); foreach(child; children) child.parentWindow = parent; // please note that this is recursive } + /++ + Called when the widget has been added to or remove from a parent window. + + Note that either oldParent and/or newParent may be null any time this is called. + + History: + Added September 13, 2024 + +/ + protected void newParentWindow(Window oldParent, Window newParent) {} + /++ Returns the list of the widget's children. @@ -12093,6 +12105,7 @@ class TextDisplayHelper : Widget { with(l.selection()) { if(!isEmpty()) { getPrimarySelection(parentWindow.win, (in char[] txt) { + // import std.stdio; writeln("txt: ", txt, " sel: ", getContentString); if(txt.length) { preservedPrimaryText = txt.idup; // writeln(preservedPrimaryText); @@ -12425,6 +12438,8 @@ class TextDisplayHelper : Widget { parentWindow.win.getPrimarySelection((txt) { doStateCheckpoint(); + // import arsd.core; writeln(txt);writeln(l.selection.getContentString);writeln(preservedPrimaryText); + if(txt == l.selection.getContentString && preservedPrimaryText.length) l.selection.replaceContent(preservedPrimaryText); else @@ -12910,7 +12925,10 @@ abstract class EditableTextWidget : EditableTextWidgetParent { this.tabStop = false; smw.tabStop = false; tdh = textDisplayHelperFactory(textLayout, smw); + } + override void newParentWindow(Window old, Window n) { + if(n is null) return; this.parentWindow.addEventListener((scope DpiChangedEvent dce) { if(textLayout) { if(auto style = cast(TextDisplayHelper.MyTextStyle) textLayout.defaultStyle()) { @@ -13453,6 +13471,9 @@ abstract class GenericListViewWidget : Widget { private ScrollMessageWidget smw; private GenericListViewWidgetInner inner; + /++ + + +/ abstract GenericListViewItem itemFactory(Widget parent); // in device-dependent pixels /++ @@ -13508,9 +13529,7 @@ abstract class GenericListViewWidget : Widget { private GenericListViewItem[] items; } -/++ - -+/ +/// ditto abstract class GenericListViewItem : Widget { /++ +/ @@ -13544,6 +13563,52 @@ abstract class GenericListViewItem : Widget { } } +/// +unittest { + import arsd.minigui; + + import std.conv; + + void main() { + auto mw = new MainWindow(); + + static class MyListViewItem : GenericListViewItem { + this(Widget parent) { + super(parent); + + label = new TextLabel("unloaded", TextAlignment.Left, this); + button = new Button("Click", this); + + button.addEventListener("triggered", (){ + messageBox(text("clicked ", currentIndexLoaded())); + }); + } + override void showItem(int idx) { + label.label = "Item " ~ to!string(idx); + } + + TextLabel label; + Button button; + } + + auto widget = new class GenericListViewWidget { + this() { + super(mw); + } + override GenericListViewItem itemFactory(Widget parent) { + return new MyListViewItem(parent); + } + override Size itemSize() { + return Size(0, scaleWithDpi(80)); + } + }; + + widget.setItemCount(5000); + + mw.loop(); + } +} + private class GenericListViewWidgetInner : Widget { this(GenericListViewWidget glvw, ScrollMessageWidget smw) { super(smw); diff --git a/textlayouter.d b/textlayouter.d index d85bb51..f424da7 100644 --- a/textlayouter.d +++ b/textlayouter.d @@ -1212,6 +1212,8 @@ class TextLayouter { Starts from the given selection and moves in the direction to find next. Returns true if found. + + NOT IMPLEMENTED use a selection instead +/ FindResult find(int selectionId, in const(char)[] text, bool direction, bool wraparound) { return FindResult.NotFound; @@ -1756,6 +1758,25 @@ class TextLayouter { return idx; } + /++ + + History: + Added September 13, 2024 + +/ + const(TextStyle) styleAtPoint(Point p) { + TextStyle s; + getInternalSegments(delegate bool(size_t segmentIndex, scope ref Segment segment) { + if(segment.boundingBox.contains(p)) { + s = stylePalette[segment.styleInformationIndex]; + return false; + } + + return true; + }, Rectangle(p, Size(1, 1))); + + return s; + } + private StyleHandle getInsertionStyleAt(int offset) { assert(offset >= 0 && offset < text.length); /+