These are a couple modules I've put together to deal with some of my layout needs.
The "base" module allows one to query the various coordinates of display objects (left, center, top, etc.). Furthermore, it allows you to place objects according to those properties, or relative to other objects (align object on left to x; put object at bottom-right of content; put object 1 to right of object 2, plus some displacement; etc.).
Where these routines accept number arguments, you can also pass in strings like "5%", "-1.7%", etc. In the case of "5%", this would mean, for x or y, 5% of the way across the screen or, for width or height, 5% of the screen wide or tall, respectively.
The layout DSL module builds on the above, but adds some (VERY basic) mini-languages on top. My own use cases have primarily been allowing these as arguments when constructing custom widgets.
As a proof of concept, I also allow these to be added as extended properties of display objects, so one can then do stuff like 'object.x = "40%"', 'object.left = object2.center_x', or 'object.right = "from_right_align -3%"'. I still haven't put this to use myself, but it's there.
Some of my own uses, since it will take forever to write examples...
Calling a constructor that uses the DSL behind the scenes: example 1
Under the hood, where it first assigns the dimensions: example 2
And the position: example 3
(Sometimes the width or height comes into play when calculating position, so I resolve those first.)
Relative widgets: example 4
(The anchor assignment is actually unnecessary now, but preceded these modules.)
Using percentage-based dimensions: example 5
More DSL commands: example 6
Known issues / gotchas
There's a bit of inconsistency depending upon whether your object is a group or not. In all my use cases, local and content coordinates have been the same, but obviously it's not even remotely out of the ordinary to have groups not at (0, 0).
A corollary of that is that computing objects relative to one another won't be reliable if the objects are in separate groups, if one or both are off (0, 0).
(Those last two probably aren't that hard to fix.)
layout.PutAtFirstHit() isn't ready yet, thus the lack of docs. It's supposed to try a bunch of options and choose the first one it accepts, but as is I haven't found it to be powerful enough. I'll either split it up to do x and y separately, or add a bunch of options. Anyhow, at that point, it probably belongs in the DSL module instead.
The ProcessWidgetParams() is probably not what it should be, and the docs really only describe what I've come up with so far. I've only had a couple widgets to try it on, and it hasn't been put through its paces, so it only reflects that.
These are neither pretty nor exciting, but here are the current docs, generated for the project these came from: