Hey folks, my pure Nim CSS Grid layout engine has reached an alpha "MVP" status! It implements roughly 70-80% of the CSS Grid spec. I just finished getting the initial auto-placement algorithm working and wanted to share the progress.
The code is here: https://github.com/elcritch/fidget/blob/devel/src/fidget/grids.nim
If you're new to (modern) CSS Grid, Adobe has a great write-up on the benefits of a CSS Grid layout.
The module currently works with my fork of Fidget (elcritch/fidget), but is written to be separable into its own package. It's part of my efforts to make Fidgetty be able to provide a nice suite of re-usable widgets built on top of Fidget.
I'll likely split CSS Grid into it's own nimble package at some point since CSS Grid provides a fairly handy general UI layout system. I could see it being useful for TUI's or ImGUI, etc. If folks are interested in that, feel free to ping me on Discord.
The non-orange boxes are automatically placed and overflow into the second row once the top one is full:
Beware the * auto-placement* support is currently very minimal but should be flushed out soon.
Here's what a clone of the "Constraints" section in the main Fidget demo looks like (code is below):
This example is intentionally verbose. It's also possible to use numbers instead, but using names makes it easier to edit.
proc drawMain() =
frame "autoLayout":
# setup frame for css grid
font "IBM Plex Sans", 16, 400, 16, hLeft, vCenter
box 10'pw, 10'ph, 80'pw, 80'ph
fill "#FFFFFF"
# Setup columns using inline syntax
gridTemplateColumns ["left"] 30'ui ["outer-left"] 2'fr ["middle-left"] 3'fr ["center-left"] 100'ui \
["center-right"] 3'fr ["middle-right"] 2'fr ["outer-right"] 30'ui ["right"]
# Setup rows using a command-style syntax (one per row)
gridTemplateRows:
["top"] 30'ui
["outer-top"] 2'fr
["middle-top"] 3'fr
["center-top"] 100'ui
["center-bottom"] 3'fr
["middle-bottom"] 2'fr
["outer-bottom"] 30'ui
["bottom"]
rectangle "TR":
gridColumn "right" // "outer-right"
gridRow "top" // "outer-top"
fill "#70BDCF"
rectangle "TL":
gridColumn "left" // "outer-left"
gridRow "top" // "outer-top"
fill "#70BDCF"
rectangle "BR":
gridColumn "right" // "outer-right"
gridRow "bottom" // "outer-bottom"
fill "#70BDCF"
rectangle "BL":
gridColumn "left" // "outer-left"
gridRow "bottom" // "outer-bottom"
fill "#70BDCF"
rectangle "Center":
gridColumn "center-left" // "center-right"
gridRow "center-top" // "center-bottom"
fill "#FFFFFF", 0.50
rectangle "Scale":
gridColumn "middle-left" // "middle-right"
gridRow "middle-top" // "middle-bottom"
fill "#FFFFFF", 0.25
rectangle "LRTB":
gridColumn "outer-left" // "outer-right"
gridRow "outer-top" // "outer-bottom"
fill "#70BDCF"
Thanks! @treeform I'll admit I was sorta hoping you would like it. :)
Using it worked pretty well in the demo choosenimapp app I made. The upfront complexity is a bit higher but it was much easier to adjust a grid upfront than trying to merge multiple concepts together like columns/rows/springs/etc to make a grid, IMHO.
Just being able to setup a header and add rows 3-6 were buttons and then add a large text area below was a sinch. I wonder if Figma supports CSS Grid? Hmmm, that'd be cool.
I split this out into it's own package! It's not explicitly Fidget related. Though Fidgetty is it's primary use case for me. I kinda wanna play with it for TUI's too. :)
https://github.com/elcritch/cssgrid
Anyone interested in hacking on this with me?! It's nerdy but also easy to pick off a small bit and implement it. I'd like to use pixie to draw images for testing, etc which would make it a bit more fun to see.
Also I've already refactored the code a bit and fixed a few issues with the syntax, and added a few more features. Though I'm a bit intimidated by all the options https://yoksel.github.io/grid-cheatsheet/ -- but things like minmax support are important for usage with real UI's. That requires being able to plumb in minimum-content-size support. That's gonna be interesting, though maybe not too bad.
Always happy to hear your progress, man.
You're really providing practical options for the community. For example, for a gui app I wrote I had to switch to another language, and that's a bummer.
What I'm trying to say is that there's a real need, especially for those who create tools and simple apps for others - like a volunteer group they're working with, etc.
So thank you. I also think your vision is very accurate. make a gui straightforward to write, and try to find elegant ways to support the custom more flexible options (still keeping it manageable).
Though I'm a bit intimidated by all the options
Don't be intimidated, advance with a courageous heart :-)
but seriously, in terms of a roadmap, my thoughts are that to get a practical result, we only need the basics of all the gui elements (or even just the common ones at first). Afterwards see that things are consistent and implement the missing ones. At that point, probably other users will help to finish the missing controls, while you provided the general vision.
Design, then baby steps, ensure the design, then all the way to a tested feature complete product. And version 1 is enough, time to rest :-)
Thanks for the kind words! Hopefully css-grid turns out to be useful for others too.
Don't be intimidated, advance with a courageous heart :-)
haha, that's great. Yes I've been plodding along in little bits. I'm partly using this to reinforce in myself that consistent small efforts do add up over time. ;)
but seriously, in terms of a roadmap, my thoughts are that to get a practical result, we only need the basics of all the gui elements (or even just the common ones at first).
Great part is that's largely there. It's currently usable. Though it's missing the minmax and auto bits you can still create usable layouts with it. The auto-flow and auto-insert are largely working. There's lots of optimizations and cleanup, but overall it's pretty handy so far.
Oddly, I haven't found any other non-browser engine implementations of CSS grid. I was hoping to compare my code. Though writing it in Nim has been a breeze compared to the standard C++ for these things.
PS: sadly I have very little time, to get into this and contribute, though I would've loved to work together.
Always feel free to do a PR or just report and issue. Having people use it and give feedback is pretty helpful!
Oddly, I haven't found any other non-browser engine implementations of CSS grid
Will McGugan (author of rich Python library for rich terminal output) is currently building a CSS parser and render for his work-in-progress TUI library Textual. Not sure if he got to CSS grid yet but I guess at a certain point he will. It is very nice to follow along his progress on Twitter: https://twitter.com/willmcgugan/status/1565094757449302016?s=21&t=PbFpWl-zP9982jeoaH7Lbg
(Incidentally I would love for something like rich in Nim)
That's really cool! That demo uses table-rows / table-columns which look like renamed css grid items.
A basic TUI demo could probably put together with css-grid and say illwill fairly quickly IMHO. With CSS grid you essentially get vertical and horizontal layouts as well.
A css parser does seem sorta handy for Fidgetty themes. Even a subset would make UI styling easier.
cssgrid now supports basic auto-flow working with either rows or columns. Auto-flow is how items that don't have a set position get positioned. In the examples below you can see two large blocks are fixed at the 1//2 column and the 5//6 column (darker blue). Then non-fixed nodes are flowed around the fixed ones. I've started using pixie to draw images in the tests.
Unfortunately css-grid "dense" mode currently isn't supported, but wouldn't be too hard to implement in the future. Another limitation currently is that mixed sized non-fixed nodes aren't handled -- yet it's next on the list.
auto-flow-column:
auto-flow-row: