Hacker News new | past | comments | ask | show | jobs | submit login
Declarative GUI with constraints-based layout engine for Python (github.com/nucleic)
120 points by ducktective on Sept 11, 2022 | hide | past | favorite | 37 comments



I find constraints-based layout superior to boxing. First, it is truly declarative way of what you (and a user) want to see. Boxes and tables are just parasitic invisible guides which force you to re-hierarchy everything after additional requirements, or to slap new things around because a layout is too fragile to patch in a minute. I’ve seen frontend guys designing cool grids only to stumble upon them later and trying to avoid re-debugging all the scrolls, unintended protrusions and pixel imperfections. And it wasn’t even a quick job in the first place. And even if you like guides, why not define them via constraints without any physical hierarchy?

Second, since it is just a set of equations, it allows to create higher-level design languages like “a remark below that input, same width and x” or automagic “every element has right-margin of min:20px to the edge”, which allows any dynamically created row to function without poisoning all elements with specifically located paddings/margins/etc. Tables and boxing always forces you to think in terms of their clumsy and situational size request/allocation process, which is usually too complex to reason about without an experiment.

That said, I have yet to see a constraints library which is powerful enough to do all the modern ui yadda yadda.


As a contrary view, I find most forms of automatic layout tedious and error prone. For the vast majority of interfaces, a fairly rigid absolute layout of all components typically works with less computation of the client machine. Yes, you have to do some computation on laying out the components. And you have to set what you are planning on supporting. But the rube Goldberg machine that is most web automated layouts is a literal tar pit.


I think there is a sweet spot between automatically laid out elements on a fixed sized canvas. Responsive design is the root of all evil, and we would have a lot less headaches with something like hypercard, where modularity and responsiveness happens at a functionality level, i.e. more screen estate? -just show more cards.


I suspect that automation at construction time is also generally positive. Basically, have a tool that will lay everything out, but then leave it in such a way that you can manually move things around. And once things are "built", have them be fairly locked in to what was chosen at construction.

This would move web design to be a lot more like many other design tasks. Even if something parametric goes into designing type faces, as an example, on build, that is all gone.


Also, this is what designers do anyway. Nobody draws a full-screen sketch and expects a css guy to infer all other form factors. We literally have source materials for all widths. If designers just left their designs in an (x,y) format and sent it to a constraint programmer with notes on what expands/wraps where, it would be a very natural job continuation. But instead they re-cipher these results into a grid-boxed-media-query pepe silvia form which entangles everything beyond all repair.


It is an amusing clash of trying to make semantic markup that is both describing the interface and describing the data in the document at the same time. And generally gets everyone yelling/focusing on different parts.


Nucleic also makes Kiwi one of the fastest Cassowary Constraint implementations. It is very useful for implementing custom GUIs as it can make building internal component layouts and general layout systems fairly straightforward and it’s very performant.

I highly encourage taking a look at it and it has also been ported to a wide range of language.

I’m using Nim kiwi with my own GUI library now. I’ll have to take a peak at how enaml is using kiwi for its layouts.

https://kiwisolver.readthedocs.io/en/latest/

https://github.com/alexbirkett/kiwi-java

https://github.com/PongoEngine/jasper

https://github.com/yglukhov/kiwi


I looked at the first Employee example in Nucleic but didn't see anything that struck me. Actually I didn't see a way to adjust layout at all. What am I missing? Without reading the paper, what is Cassowary Constraints solving for? I'd guess a bin packing implementing, which could be handy for graph networks come to think of it.

Personally I've been writing a CSS Grid implementation because I find the "Grid" (aka Table) to provide most of what I want: https://github.com/elcritch/cssgrid/blob/main/tests/tlayout....

Though I was running into issues when trying to add `min/max/minmax` functions with fracs, as they end up creating a constraints equation. It seems CSS Grid just gives up if you specify anything that'd require a constraint solver. At least on Chrome & Safari. Fair enough but I figure I'll add at least a 1-pass try for doing `minmax(1fr, 100px)` type of things.


I had tried to use Kiwi a while back - is it a part of Cassowary solvers that they have such a small number of constraint types? I ended up having to use Z3 because I wanted by boxes have subtraction and division constraints. Was it possible with Kiwi?


Commenting with my own experience of more than one decade of UI building (web, desktop app) using various stacks and frameworks: Sure, this looks cool, but there is nothing fundamentally new about it -- people have come up with various design tools like this, maybe not as clean-looking as this one, but the idea has been around for a while. And all these "low-code" frameworks cannot escape one problem -- as soon as you need advanced features, more flexibility or certain customization, you will find that this kind of framework has little to no support for those use cases. You can either wait for such support, try to implement that yourself, or just use the original libraries to build everything, and the answer is often the last one. This is a all-or-nothing question and I have seen it too many times. People often avoid such UI building tools for this reason.


This seems to be active, but I’m curious as to how small the apps can be given the Qt dependency (and the usual penchant for packaging a small Python runtime on cross-platform installs).

Also, what kind of licensing would these apps be under?


As I always do when yet another UI option comes along, I went looking for a hierarchical "tree" view widget in the documentation. Could not find it.


I look for a sortable, filterable, selectable table.

Like anything coming close to AntD’s table tells me that it’s serious business.


What are the implications, good or bad, of such absence?


It's often a bad implication.

The reason is that Treeview is where a lot of "rubber meets the road". It scrolls. It has icons that likely change state. It has active widgets. It may have a LOT of widgets and be a good test of performance. It has text and all of the idiocy that entails. It may or may not have selection. It has a connection to backing data.

So, you get a nice microcosm of how you should plumb together the components of the UI toolkit if you look at the Treeview implementation.

However, I would like to provide the contrarian position, as well. I find that far too many people use Treeview as a substitute for actual design. I often find that the TreeView really should be something else--a config file, a table interface (table interfaces are really underused in GUI design given how many of your users are wedded to Excel for business things), etc. Everything doesn't need to be pointy-clicky and often throwing things out improves your GUI.

Treeviews tend to be the laziest of options--and, as we all know, programmers are very lazy.


Not the parent, but a tree view is convenient for an app that has a lot of settings. For instance you can take a dictionary of settings and create a tree view with the same structure. If a setting gets added later, you don't need to rearrange the GUI, it rearranges itself.

I've seen this kind of GUI in programs that manage complicated hardware such as scientific instrumentation.


Interesting, it looks like a new implementation of https://en.wikipedia.org/wiki/Naked_objects from back in 2002 era.


It's not quite a new implementation, since the initial version of enaml was implemented almost a decade ago, and was partly inspired by an earlier toolkit called Traits/TraitsUI - https://github.com/enthought/traitsui.


Back around 2002 or so, I used to use PythonCard for in-house tools. PythonCard was a kind of a cross between HyperCard and Visual Basic and used wxWidgets for the UI elements. It was really excellent software.


What's the distinctive part that made PythonCard useful?


The simplicity of it. No programming was needed to create the UI. It used a dialog editor like the one from Visual Basic. It was pretty fun to use.

You just had to drag-and-drop a control on the form. Handling events was just as easy. In the dialog editor you could association a standard event (like mouse or keyboard events) with a python function.

If you really wanted to, you could edit the event code because it was all just dictionaries, but you didn't need to.


Is there anything similar for generating html/react UI’s ?


You can contain your native react creations in electron if you really don't want to go the native GUI kits route.

For all the shit that Electron gets, it is reliably cross-platform with relatively little effort.


I have looked extensively and unfortunately haven’t been able to find anything of the kind. Closest you would get is the Flutter framework which supports web. But that’s not Python.


You can use python with Electron ... with all that Electron implies.


There's a web toolkit for enaml. https://github.com/codelv/enaml-web


This is really cool. I was playing around with a similar concept myself a few years ago (trying to build something React-esque, but for Python GUIs). It was way over my head then though, so I've never got anything more than a proof of concept working.

Check out the cool / weird DSL though!

https://github.com/notpushkin/pyrract


I was just thinking we used traits and enaml quite a lot in the scientific Python community and didn't realize that's what this was pointing to.

As far as using it goes... It was alright. Very very fast to set something up, but has the usual "many things are now easy, but some things are now impossible" problem that many other frameworks introduce.


Feel like the constraints-based layout is not the right design of constraints. I don't know if there is any research on type based (constraints) layout. How to type flex layout in composable way, could use some vector (matrix), and knapsack kind of algorithm. A child component spec should have some layout constraints to conform.


I have been very excited about constraint-based layout for about 20 years, after seeing a demo of an music app at a conference in Bordeaux. It used the original Cassowary implementation.

Last year, I finally got a chance to try things out, using Kiwi via C++.

The results, frankly, were underwhelming, at least for my purposes. It seemed that for most of what I wanted to be able to do, a "table" layout was more appropriate and provided more than enough flexibility. Creating layouts that do not in some sense use columns and rows is not unheard of, but it's rare.


Yeah, I were obsessed a long time ago. It doesn't have to be automatic. Start from what we have in css, there's media query. Looking good on desktop/laptop/mobile seems like special case. So generally we might look for semantic that scales e.g. ratio, open height, open width, .. idk I don't figure it out yet, it's like a greenfield area where previous solution doesn't look like revolutionary.


Traditional desktop ui idiom implies enough space for all controls to fit. Frameworks could include similar width-breakpoint sets of constraints, or e.g. a type of H:a|-|b constraint which could transform into V:a|-|b plus H:parent|-|b when parent is too narrow, essentially wrapping an element.

But they usually don’t. It doesn’t mean that constraint-based layout lacks flexibility. Only specific engines do, but so do specific table engines. It’s easy to forget that css also sucked for 20 years straight, and still does, if you dig an inch deeper than usual. E.g. grid is cool, but did anyone try to page-break it in media print? Can we baseline—align divs & inputs that are not direct children of a flexbox? Not to mention internalized bugs like when your grid gets a parasite scroll when its scrollable child has large padding specified in particular units.

All that said, I think the best toolkit is the one which contains all of the tools and not only a subset.


I'll echo this. It sounds compelling to make a constraint based layout, but often you are just as well off with a very simple grid. And not a whole lot of components in a page.


Looks cool. One overall criticism for GUI libraries though (not just this one):

They really need to make a GUI library with a default style that just makes it look really good. Instead I see defaults that are terrible across 99% of all gui libraries.

imgui is the exception here, but the defaults for imgui are very stylized.


Qt 5 (which this seems to be based on) is getting quite old now.


It's based on qtpy [1][2], which supports both Qt5 and Qt6 with pyqt5, pyqt6, pyside2 and pyside6.

[1] https://enaml.readthedocs.io/en/latest/get_started/installat... [2] https://github.com/spyder-ide/qtpy


Why no HTML? Web is so big nowadays if it could render to HTML the platform coverage will be parallel to none.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: