It’s been 3 weeks since the last update, but rest assured that those weeks have not been wasted. In fact, I have worked on QTX every single day in from afternoon to bedtime. The changes and fixes in this update are in their hundreds. I will only list those that are of immediate interest for users to know about.
Please be advised that this update is very much work in progress, meaning that if you experience any issues then please report those issues so I can get them fixed. The ZIndex support especially is borderline experimental, since it’s one of those absolutely bizarre aspects of HTML that makes no sense from an architecture point of view.
To underline: This update contains no new .exe file, purely RTL changes! It is the same exefile as was in the last update (I have to do the RTL changes before I go in and make changes to the exe). For those of you that are waiting for IDE fixes, sit tight, they will be out very soon.
Partial changelog
- Completely overhauled the theme.css file so it takes height for mobile platforms, make sure you copy this into your existing projects! Also replace the old default.theme.css in the themes folder with the new one!
- SetLeft, SetTop, SetWidth and SetHeight optimized
- MoveTo, SetSize, SetBounds, BoundsRect adjusted to call the above methods when doing changes, rather than ad-hoc setting the values
- GetClientRect fixed, it now uses GetClientWidth() and GetClientHeight() which adjusts for the any border-padding and margins
- Added support for Shadow DOM, calling TQTXWidget.AttachShadow() creates a shadow-dom on an element, which can be accessed via the property ShadowRoot: TQTXWidget, or direct access to the shadow handle via ShadowHandle
- Introduced the concept of “Synchronized widgets”. By setting the Synchronized: boolean property on a widget inside the constructor callback, the widget will wait until all it’s children are created and in the DOM (as well as itself) before invoking ObjectReady(). This is important for widgets that wrap external JS frameworks, or that needs to be 100% sure that the widget is indeed “ready” before it’s manipulated further.
- Added a new CreateOptions flag, wmSynchronized, which developers can set if they dont want to set the Synchronized property. The function GetCreateOptions() can be overriden and you can add the wmSynchronized flag to the result (datatype is a set)
- Introduced stacking-context functions to TQTXWidget: GetStackContextFor() and an overloaded version that also takes a filter parameter. This will return an array of each child element on a widget, sorted by their element-index. This can be used to determine how widgets are overlapping
- Optimized BringToFront() and SendToBack(), there was no need for the RemoveChild() call prior to re-insert or re-append of the element
- Implemented Tooltips (!) This is now in the unit qtx.dom.tooltip.pas
- Expanded TQTXWidget with a Hint property, as well as a ShowHint property
- TQTXDomApplication makes a reference to TQTXTooltipManager, which brings in that part of the RTL automatically. You will need to reference qtx.dom.tooltip.pas in your units if you wish to access the tooltip system directly
- Added a InstallWindowClass() method to TQTXToolTipManager, you can use this to install your own tooltip widget if you want to style it differently
- Changed the “body” proxy component property for TQTXDOMApplication from a component, to a full blown widget. If you want to create widgets directly on the HTML body, you can use this as a parent. Changing this to a TQTXWidget also means you can easily access things like background, styles, check the width and height etc.
- Added a new FormContainer: TQTXWidget property to TQTXDOMApplication, this is a proxy widget that will always represent the container where forms are housed. Different application models represents forms differently, and will have different layout rules for forms. This property simplifies access to the “viewport”, regardless of application model.
- Added Touch delegates, these delegates can be found in qtx.dom.events.touch.pas (Please note that you dont need to use these unless you explicitly need multi-touch support. Instead use the pointer-events and check the pointerType property to know if a user is operating with a mouse, pen or touch, and then implement your handling code thereafter).
- Added the Touch delegates to the widgets in the RTL, these now show up the “add delegate” dialog for the form-designer
- Added touch helper functions to TQTXDOMApplication, as well as the partial TQTXWidget class in various units
- The qtx.dom.widgets.pas unit was getting rather big. Exported things like borders into it’s own unit (qtx.dom.border.pas)
- To speed up widget creation, borders and font objects are now created “on demand”, meaning they are created when you first reference them. No point wasting CPU time creating a background object when it’s not used
- Refactored TQTXToolbar so that it supports vertical layout (!)
- Rewrote the CSS for the toolbar so it takes height for both horizontal and vertical orientation
- Added support for ZOrder! Exposing the property ZOrder to TQTXWidget. ZOrder under HTML is a bit strange, since elements initially follow their elementIndex (a new widget is always topmost since it’s appended to the parent, and thus ends up at the end of the child collection). ZOrder overrides this, which to be frank is quite confusing for Delphi developers (myself included). Default value is “auto”, which in QTX means -1. So if no zindex has been assigned to a widget, it will return -1, which simply means “automatic”.
- Implemented ZOrder functions which simplifies sorting and working with ZIndex: GetZOrderHighestFrom(), GetZOrderBoundsFor(), GetZOrderStackFor(). These are used by the RTL to deal with ZOrder.
- Re-implemented (experimental) BringToFront() and SendToBack() so they now use ZIndex rather than elementIndex. Please note that this is experimental at this point. I have tested this with the various example apps and it works fine, but there are bounds to be edge-cases where you might have to call BringToFront() in order to remap the zindex of child widgets. Consider this work in progress! You can turn this off by disabling the $IFDEF in qtx.dom.pas, EXP_ZINDEX
- Added a new InstallViewPort() method to TQTXDisplay, so that an application model can use a different TQTXViewport class if needed
- Disabled older system to detect resize, which caused excessive calls to Invalidate() and Moved(). If you need automatic Resize() and Moved() calls, simply activate the ResizeObserver or MoveObserver, by calling their Observe() methods. When writing widgets you would call ResizeObserver.Observe() in ObjectReady(). This will then listen for mutation events in the DOM and call Resize() automatically whenever your widget has it’s size changed. The MoveObserver works the exact same way.
- Expanded TQTXDisplay with methods that performs the layout, StdLayout(). TQTXDisplay will organize it’s children vertically, subtracting the height of any widgets you might have created there directly, and resize the viewport to cover the reminder. By isolating this logic in it’s own procedure, different TQTXViewport than the default class (see InstallViewPort() above) can perform changes to the default layout regime if needed.
- Implemented a new widget, TQTXDOMIFrame, which creates an IFrame element. Please note that this widget still needs work. When finished it will also expose a message channel for communication between “apps” or third party websites.
- TQTXWindowElement, the baseclass for all TQTXWindow parts, now inherits from TQTXSyncWidgetContainer
- TQTXWindow is now synchronized, since that works better when hosting external websites as the content
- Added a new Window type, TQTXFrameWindow, which contains a TQTXDOMIFrame widget
- Implemented a new application model, this is still being worked on, but you can find it in the test project “Windowing app”, which is ultimately the desktop project I have been showing lately. This project also has an Amiga webassembly emulator — make sure you open this project in the browser, as miniblink does not support WASM.
- .. And much, much more!
I could literally continue for at least 2 more A4 pages of changes and fixes, but the above list represents the biggest changes to the RTL so far.
What to look out for?
Since I have disabled the old resize system, which ultimately tied into BeginUpdate(), EndUpdate() and logging of changes between those two methods, some of your existing projects might be affected by this. The solution is to activate the ResizeObserver object in your widget ( a simple ResizeObserver.Observe(); will do).
The ZIndex change is quite huge, in that our codebase has so far only dealt with ElementIndex (creation index) with regards to BringToFront() and SendToBack(). But so far I have not seen any dire consequences for this change. If your project is affected, you can turn off the ZOrder support by disabling the EXP_ZINDEX $IFDEF on top of the qtx.dom.widgets.pas unit.
I have completely overhauled the theme.css file so it takes height for mobile platforms, make sure you copy this into your existing projects! Also replace the old default.theme.css in the themes folder with the new one!
Download
You can download the RTL update from www.patreon.com/quartexNow as usual!