Friday, November 22, 2013

UI Layout using Constraints

My last post about stdgui was over 5 months ago.  Although family life has been busy I have not been entirely idle.

I have concluded that the existing GUI frameworks don't meet the goals of stdgui.  The project will proceed.

However, a few months ago I sat down with my prototype "SnapLayout" layout system and attempted to layout a simple example.  I was surprised at how much mental effort it required.  Granted, it had been awhile since working with SnaypLayout and I was probably a bit tired but I got the same feeling of tedium I've had in the past trying to mix-n-match layout managers to get the desired look.  SnapLayout is perhaps only marginally better than the status-quo.  I want a true advancement.


I started pondering: what if we could specify exactly how widgets align to each other with some sort of declarative syntax.  I came up with something like this:

---
 lblTemplate
|lstTemplate
|btnShowBanner|
---

CenterV: lblTemplate lstTemplate
Top: lstTemplate txtMessage

lblMessage txtMessage|
lblColor selColor
lblSpeed rdoSlow
rdoNorm
rdoFast
chkReverse

Right: lblMessage lblColor lblSpeed
Left: txtMessage selColor rdo* chkReverse
FillH: txtMessage

lstTemplate fraPreview|
btnShowBanner

fraPreview {
 |lblPreview
}

Here's the idea.  A block such as:
---
 lblTemplate
|lstTemplate
|btnShowBanner|
---

means:
  • the top of lblTemplate aligns to the parent window top edge (---).
  • the top of lstTemplate aligns to the bottom of lblTemplate
  • the left of lstTemplate aligns to the parent window left edge
  • the top of btnShowBanner aligns to the bottom of lstTemplate
  • the left and right edge of btnShowBanner aligns to the parent window left and right edge, respectively.

I call this an "implicit block".  I think it's a pretty concise expression of intent and fairly intuitive for programmers who read left-to-right and top-to-bottom.

Next we have explicit constraints such as:

Right: lblMessage lblColor lblSpeed

which means: align the right edges of lblMessage, lblColor and lblSpeed.  Explicit constraints are used to express that which cannot be expressed in an implicit block.


The only thing I don't like is having to give a name to every widget.

With this concept in mind I started trying to design an algorithm to render such layouts. After a few fruitless weeks with pen and paper I had to give up.  I was out of my depth.

Thankfully, some lucky online searching pointed me in the right direction.  Such problems are known as Linear programming and algorithms have already been developed for solving systems of linear equations of the type found in user interfaces.  Specifically the Cassowary Constraint Solving Toolkit.

Here I thought I was exploring revolutionary territory.  Not so!  Apparently there have been a wide number constraint-based UI layout tools over the past few decades.  My question is, why didn't they take off?  Why don't we see them in popular toolkits?  Perhaps it's finally starting to take hold because in 2011, Apple integrated Cassowary into their interface builder (see AutoLayout).  Also a new python-based framework called enaml uses Cassowary.

With Cassowary in my toolchest I've begun prototyping a layout system based upon the above syntax.  So far I have the parser working (thanks to Lemon) and I'm able to isolate all the distinct lines which widgets align to.


No comments:

Post a Comment