I've been pecking away on Fidgets. It's a widget library built on top of Fidget and has been split out into a new repo. However it does rely on my fork of Fidget for the foreseeable future.
That said I've been working on settling a core set of APIs and features:
There's still a few outstanding changes I want to make:
A demo can be found at fidgets/tests/testDemo.nim.
Time for a sample:
the name fidget VS fidgets is a bit confusing
agree, what about fidget*ing*?
Fiddling with Fidget's Fidgets. The name is fine.
What you've made looks good. Time to explore.
Great effort, I would suggest the nim maintainers to take this as official UI lib and support eh developers and the original dev also who set the the core libs to make this happen. make it a true cross platform UI library for nim. For theming either you create a new set of theme style that could better fit as across platform or use ex. Material Design theme as main theme till theme support will be better.
I prefer to have agreements with the original developer and merge it to save the name.
For theming either you create a new set of theme style that could better fit as across platform or use ex. Material Design theme as main theme till theme support will be better.
I'm open to people helping with themes. I just did the bare minimum.
I prefer to have agreements with the original developer and merge it to save the name.
Possibly, though they have separate purposes. I'd like to merge my changes or work on getting the required API changes into Fidget. The widget API and standard widgets are separate from the core rendering library and would tend to evolve at different pace from Fidget.
Thanks, those are good points and on my mind. The logic started getting hard to follow in longer callback sections. Using the : command syntax the eye doesn't have any context between actions or UI descriptions.
I sorta like the proc click() = since it makes that distinction a bit clearer. Making a declarative DSL for UIs is tricky since you're inherently mixing multiple abstractions at once. :-)
I think figuring out things like how do you describe layout vs logic in a clean valid declarative Nim syntax is more important than the engine in some ways. Apple's SwiftUI is declarative too and has been interesting to follow as they've struggled to build it out.
That said the Fidget model is to build the graph and render it every time, but only when an event triggers a render. It's like immediate mode but more efficient since you only re-render on events unlike in ImGui.
The Fidgetty DSL is built on top that model to try and create re-usable and customizable "widgets". I can create useful apps with it now! However I have a bit of writers block because there's a few parts that are nagging me..
The main remaining issues are:
Handling mouse events sort of needs to be done in a tree model after computing the layout to best handle cases like overlapping nodes. That'd be a breaking change to the Fidget model though. I'm partly there however by using callbacks for Fidgetty onClick handlers instead of templates.
The other big one is the same thing Owlkettle had with the Button {.add_left.} where you want to do grid style layouts and say "this widget should be left" without cluttering up the widget's own api. I dislike the HTML/CSS model where you have to wrap your actual UI elements in <box class="flow-left"><my-actual-item>... or whatever. I sort of ended up with that in the Theme(warningPalette()): section. Particularly it's annoying to have to indent/un-indent a whole block just to change the color. I'd like the DSL to be more like:
@withTheme = warningPalette()
Checkbox(label = fmt"Click {self.myCheck}"):
checked: self.myCheck
There is an auto-layout constraint engine in Fidget, however it's difficult to use without a UI tool to build it for you. However I don't use Figma. I'm mostly interested in automated layouts.
This is indeed ancient wisdom. That Delphi stuff sounds very similar to the Xmt Layout widget in the X11/Motif world of the mid-90s (which used "attach" terms rather than "anchor"). Both are actually pretty closely related to how TeX does stretchable space/alignment layout. While it helps to know pixels/be able to intervene at the "ground level" (much like assembly code), it should never have been a dominant specification paradigm. Dots-per-inch variation increases have made pixels less & less the relevant coordinate (though TeX already was dealing with 1200 DPI magazine & 50 DPI dot matrix outputs in the 1970s).
I blame the popularity of Visual BASIC user-experience during a time when DPI variation on video displays was particularly narrow for diluting this wisdom. VB may have improved by now (??), but I have definitely seen little apps in the past couple years that decidedly require low DPI to be well conceived.
The wrinkles I imagine i18n adding are just measurement accuracy of fancier glyphs and/or fonts lying about their metrics more often (possibly real concerns, but not fundamental to the approach, and probably a problem with any other approach..).
I finally figured out a clean way to re-work how Fidget handles events! Even better the user API doesn't change any so my fork require re-writing basic Fidget code. It also keeps the imperative code simplicity.
The model used is that events are captured by a node based on its screenBox (mouse overlap) and it's listens events. The node which captures an event is now determined before node logic is called. This simplifies logic as nodes now only need to check if an event was flagged in their own events field.
The semantics are a bit different but resolve lots of little annoying issues. In particular events now work with clipContent by properly masking events based on clipped parents. This was a real issue with the previous raw-event setup which required lots of work-arounds to handle pop-ups and menus correctly. Now events and popups mostly just work.
Usage differences from upstream Fidget and/or previous changes I'd made in my Fidget fork:
Its implemented in a new compute pass called computeEvents for those curious.
If anyone tries it and finds bugs, please file an issue.
Thanks! I was a bit unsure how worth it would be given how well gtk4 performs. But gtk4 really builds on the OO widget setups which make it difficult to build custom feeling UIs IMHO. Particularly building dynamic GUIs seem interesting to me so I decided to finish trying to fix the remaining issues that keep me from feeling this is "ready".
Glad I did! The event refactor worked way better than I expected.
Now I'm working on a CSS Grid layout mechanism! An HN post about how Figma uses CSS grid in their own tooling inspired me. I'd used flexbox stuff via css frameworks before and it was a pain. However, raw CSS Grid seems pretty nice. In some ways it feels like the best of the old school Pascal and QT 'spring' layouts with somewhat more modern layout interface.
Here's a basic CSS Grid example from csstricks:
The core logic is done, now I'm just plumbing it into Fidget's layout engine.
And CSS grid is now available in Fidgetty's version of Fidget. Who needs HTML?!
Simplified code for the example:
frame "css grid area":
# setup frame for css grid
box 0, 0, 80'pw, 80'ph
fill "#FFFFFF"
# Setup CSS Grid Template
layout lmGrid
gridTemplateColumns ["first"] 40'ui ["second", "line2"] 50'ui ["line3"] auto \
["col4-start"] 50'ui ["five"] 40'ui ["end"]
gridTemplateRows ["row1-start"] 25'perc ["row1-end"] 100'ui ["third-line"] auto ["last-line"]
rectangle "css grid item":
# Setup CSS Grid Template
# note I'm working on sugar for these
columnStart 2.mkIndex
columnEnd "five".mkIndex
rowStart "row1-start".mkIndex
rowEnd 3.mkIndex
fill rgba(245, 129, 49, 123).to(Color)
# ...
Note the basics are mostly working. Some syntax sugar needs to be added. Bug reports are welcome! I've never used raw CSS grid in html myself. ;)
The core notion behind CSS grid are grid lines. Items on the grid set their layout by selecting start & stop grid lines in column & row directions. This can be done either using indexes or optional names. Grid lines are set based on order and then track widths to create tracks (e.g. columns/rows).
Fraction units (fr) are important to CSS grid and make it easier than other grid systems. fr units are based on fractions. All fractions per direction are summed to create the denominator, so gridTemplateColumns 1'fr 1'fr 1'fr would be close to 33%. However fr units first take into account any fixed (pixel or ui) widths. This simplifies a lot of challenges with grid layouts based on percentages mixed with fixed sizes. For example a fixed padding of 1'em (1 font size) around an item is trivial using gridTemplateColumns 1'em 1'fr 1'em.
See the CSS Tricks tutorial on css grids (first example, top right) for more details. The example above is taken from the top-right of that tutorial.
I landed on CSS Grid because of the combination line-start/line-stop's and fraction units (fr) make it easy to define complicated grids. Many things like constraints are implicitly set. Many web devs should also feel familiar with it too, which vibes well with Fidget's story in my mind.
The implementation largely it tries to follow CSS Grid, but I'm not planning to follow the entire spec. Unless people want to pay me oodles of money to do so. :P Also some differences may be due to how Fidget/Fidgetty works or for performance reasons.
Note that there are still some items left to add like the span attribute on the Grid Item locations. A few of the more advanced shortcuts haven't been created yet. The syntax sugars is handled by macros currently to match CSS syntax more closely. This could be changed but appears ok.