matrix 2023-05-11

I have a renewed interest in connecting isolated matrices together. Is it as simple as setting :parent and :kids appropriately? I would like to be able to do something like: (with an imaginary fx-render-with that also takes a parent in the args)

(mx/container
 {} {:name :root
     :access :granted}
 (m/NovelStrangeWidget
  .fooBar m/Baz.buzz
  .child (fx/fx-render-with me ctx
                       (fx/text (str (mget (fasc :root) :access))))))

> So the problem would not be arranging the parentage to support fasc -- we can easily work this out -- but rather the timing of a nested model being brought to life, and all its formulas being kicked off. Ah, gotcha. Really like the idea of making deftag generate functions and the sugaring macro. Perfect for what I'm after. Thanks! 🙂

Yeah, user defined deftag is what I'm currently using. Actually, there might be a way to make my original use-case not need the sugar macro after all.

Presuming nothing will break if the one "widget" wrapped is actually a composite of several widgets.

Got totally bogged down with a stupid mistake today. 😞 I'll try the streamer tmrw.

No worries, and thanks!

Wait...would you rather see (fx/ (m/ (fx/ (fasc )))) first? btw, I am thinking about converting these to GitHub issues if they get interesting, as in if the precise functional requirements turn out to need non-obvious definition.

Streamer slightly preferred personally, but truth be told I'm happy either way :D. Thanks again for making such a fantastic library! I'm very happy with the results. Blog post slowly but surely in the works for f/mx.

Thx! I have a streamer surprise I am about to share. I'll give you a sneak preview once I push. Might not be the ultimate solution, but it involves no changes to MX. A blog post would really help. No one wants to go first! When it comes down to the chicken-egg question on f/mx, the answer will be "Ben". You get to choose if you want to be the egg or the chicken. I see a big future for Flutter, and I see CLJD to replacing CLJS in the CLJ universe. We could be in a good place. More on the streamer in a sec,

Just pushed, Key element: https://github.com/kennytilton/flutter-mx/blob/2a0fe34629200b2f252656b1d6909d01dd704be6/src/tiltontec/example/x020_reactive_stream.cljd#L62 The story is, I remembered we have a cFn capability, which really should be cF->cI, meaning it starts out as a formula then behaves as an input. The original use was to be able to have an input cell that was initialized from surrounding MX info. Kinda in the spirit of an OO constructor initializing the new instance in interesting ways. Anyway, I realized the pattern of an async cell feeding an input cell could be expressed as a cFn, as I did in this push. The bad news is the need to wrap the cell value as {:stream ...} or {:msg ...}, and forever deal with that when reading/setting. OTOH, any time we can do X without Y, such as when Y is a macro and X is a function, that's a pretty compelling story. OTOH again, the change to MX is pretty simple. If it was a profound change I would go with cFn, but.... What do you think? Now I am wondering if I can use types or ^meta instead of {:stream/:msg} 🤔

Actually, I can lose the artificial map. In the morning. 🛏️

🎉 1

> ...now me is the layout-builder... Cool, so the trick is to use as-dart-callbackinstead of ->CBAsIs ? > OTOH, it would be weird for deeply nested builder objects to be reaching out all over the Matrix. Hmm, does this mean it might be a bad idea to do this frequently as I'm currently doing?

Yep. a-d-c wraps CBasis, btw. "Hmm, does this mean it might be a bad idea to do this frequently as I'm currently doing?" Nah, go for it. I am just getting boring in my old age. I am forgetting Tilton's Law: "Don't restrict a tool's use gratuitously. We never know what users will think of, especially with good tools."

Haha okay :P. If you ever write a book of Tilton's Laws, I'm interested in ordering a copy 🙂 .

children-stateless now kids->prop-stateless ya?

Err, seems not.

I have to look, but real quick, the name kids->prop... means the proxy/family children are being provided to a property of the Dart widget, that property not being .children

Ah, yes, the recent NavigationRail .destinations. In children-whatever, the proxy :kids become the children. Flutter has an infinite variety in this regard, let me know if we need a new one.

Oh, okay, so I need to specify the prop to children in the deftag

(fx/deftag tiltontec.flutter-mx.factory/children-stateless special-widget fm/SpecialWidget)

So ^ (what I used to have, no longer exists) becomes: (fx/deftag tiltontec.flutter-mx.factory/kids->prop-stateless special-widget fm/SpecialWidget :children)

Oh, you are trying to use deftag for a homebrew widget. But your own widget will never need the first map, which is reserved for the Dart constructor. I need a use case!!!! 🙂

Oh that sounds interesting, but I'm using it for a third-party dart widget. Specifically flutter_map's FlutterMap. (Which is actually stateful, I later discovered)

Oh, sorry, forgot my own syntax.

Okay, seems it's not quite right just yet. Compiles, and then flutter dies:

You rock! 🤘

Launching flutter run
Launching lib/main.dart on Linux in debug mode...
Building Linux application...
ERROR: lib/cljd-out/pbvm/ui/home.dart:4921:12: Error: The method 'call' isn't defined for the class 'PersistentHashMap<dynamic, dynamic>'.
ERROR:  - 'PersistentHashMap' is from 'package:pbvm/cljd-out/cljd/core.dart' ('lib/cljd-out/cljd/core.dart').
ERROR: Try correcting the name to the name of an existing method, or defining a method named 'call'.
ERROR: return $180(ExpandedScrollingColumn: (lcoc_core.mapv.$_invoke$2((lcoc_core.partial.$_invoke$2(lcotfm_core.fx_render, ctx$6, )), lcotm_api.mkids(me$8, ), )), );
ERROR:            ^
ERROR: Target kernel_snapshot failed: Exception
Exception: Build process failed
💀 Flutter sub-process exited with 1

Is it passing the f/mx widget as-is to children?

I'm lost. What deftag did we settle on? Looking at FlutterMap. ps. No, f/mx widgets should not be passed to Dart ever.

Sorry, I didn't explain very well at all. :P Issue I'm having is that after upgrading to the latest mx sha for (with-par ,,,) the deftag I had used broke because children-stateless no longer exists in factory.cljd So this broke: (fx/deftag tiltontec.flutter-mx.factory/children-stateless special-widget fm/SpecialWidget) and I'm trying to figure out what I need to replace it with.

I tried to replace it with (another widget example) (fx/deftag tiltontec.flutter-mx.factory/kids->prop-stateless expanded-scrolling-column fl/ExpandedScrollingColumn :children) which is what I just tried that compiled but didn't run.

I deleted children-stateless?! brb.. ps. You are on the latest SHA? I was going to warn you about. Nothing functional, but serious reorg of low-level stuff.

Oh, well actually you did warn me, but I didn't guess it was completely dysfunctional :P

pps. didn't you decide thst widget is stateful? \

One of them is, but expanded-scrolling-column is not.

OK, sorry, I did delete children-stateless once I had a working kids->prop. I could bring children-stateless back to ease the migration.

OK, gimme a sec.

Not sure if anyone else is using it yet, but since it is part of the public api I'd highly recommend keeping them as a shell macros that redirect to kids->props-state* just in case :)

Just me getting up to speed on open source. 🙂 No idea how I was so blind on that. I have indeed heard of the word "deprecated". Almost done with the recovery.

👍🏻 1
😂 1

Oh, that happens in open-source projects all the time! Thankfully much less so in the Clojure community.

Should I care if I see a bunch of these now?

flutter: .... - :render-sees-not-mref?-passing-thru - SizedBox(height: 20.0)

Oh, wow, you grabbed the new wet paint version. 🙀 No, that message is fine. It means a SizedBox is not an f/mx proxy, so we just pass it along to Dart for rendering.

👍🏻 1

Did the excerpt I offered work OK in a vanilla CLJD app?

Excerpt of layout-builder excerpt? Yes.

I meant the ten-liner above. I thought you could just try that in a non-f/mx setting.

btw, I was working on x05-fab when this surfaced. I think I left the throw there commented out for easy follow-up.

> I meant the ten-liner above. Hmm, I don't see a non f/mx 10 liner? (blinks...) maybe I've been staring at the screen for to long... I'm using the layout-builder as a regular and frequent widget, but am I correct in thinking it's not really a first-class f/mx widget? IE. the builder prop isn't assigned as the :kids, and might have issues with with certain traversals and garbage collection?

OMG I am crossing threads!!!!! n.m. I thought I was chatting with Christophe.

Glad I'm not the only one to do that :P

Wow, not sure what magic you've been crafting, but the "wet-paint" mx is much faster!

Interesting. And that latest SHA disables the "quiesce" mechanism, so not sure what else it could be. Is this your own app that is faster, or an example or two? I did find that some sloppy formula coding was killing a couple of examples.

Dart 3, maybe?

I was running Dart 3 yesterday, so I don't think so. I was running a really old MX sha before, maybe it was something do to with that? Or maybe my computer just needed a reboot. :P

My own app.

I suspect there is a lot of room for improvement in f/mx internals. I am thinking of hiring the CLJD lads for a code review of the f/mx internals at some point.

Nice! (Maybe as a side-effect they'll see how much fun f/mx is 🙂 )

Heh-heh, you read my mind. I was going to pay them to execute a couple of CodeLabs in f/mx, give us a couple more examples and maybe get them hooked.

👍🏻 1

Hmm, yet-another layout-builder hiccup: I keep getting these:

The following assertion was thrown building LayoutBuilder:
setState() or markNeedsBuild() called during build.
This app_frameReifyirmorq$2 widget cannot be marked as needing to build because the framework is
already in the process of building widgets. A widget can be marked as needing to be built during the
build phase only if one of its ancestors is currently building. This exception is allowed because
the framework builds parent widgets before children, which means a dirty descendant will always be
built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
  app_frameReifyirmorq$2-[GlobalKey#2af10]
The widget which was currently being built when the offending call was made was:
  LayoutBuilder

I used to see that. I remember it passing painlessy, such as it turning out to be just a restart thing. Hang on. Is this new since the newest f/mx, or is this an old problem?

This is the "wet-paint" sha you gave me in the other thread, so pretty recent.

I'll see if I can get you a minimal reproducible tomorrow.

Currently, I'm probably not helping. This is the macro I'm using all over the place:

(defn ^:macro-support container-sees-layout*
  [args matrix body]
   `(fx/layout-builder
     {:builder (fx/as-dart-callback [~(symbol "ctx") ^m/BoxConstraints ~(symbol "box-constraint")]
                                    (mx/with-par ~(symbol "me")
                                      (let [^m/BoxConstraints ~(symbol "w-box-constraints") ^m/BoxConstraints
                                            (if (> 9999 (.-maxWidth ^m/BoxConstraints ~(symbol "box-constraint")))
                                              ~(symbol "box-constraint")
                                              (pbvm.utils.fmx/get-prop-up ~(symbol "me") :w-box-constraints))

                                            ^m/BoxConstraints ~(symbol "h-box-constraints") ^m/BoxConstraints
                                            (if (> 9999 (.-maxHeight ^m/BoxConstraints ~(symbol "box-constraint")))
                                              ~(symbol "box-constraint")
                                              (pbvm.utils.fmx/get-prop-up ~(symbol "me") :w-box-constraints))]

                                        (let [^m/BoxConstraint ~(symbol "min-h") (.-minHeight ~(symbol "h-box-constraints"))
                                              ^m/BoxConstraint ~(symbol "max-h") (.-maxHeight ~(symbol "h-box-constraints"))
                                              ^m/BoxConstraint ~(symbol "min-w") (.-minWidth ~(symbol "w-box-constraints"))
                                              ^m/BoxConstraint ~(symbol "max-w") (.-maxWidth ~(symbol "w-box-constraints"))]
                                          (fx/fx-render ~(symbol "ctx")
                                                        (fx/container
                                                         ~args
                                                         ~(merge matrix
                                                                 `{:h-box-constraints ^m/BoxConstraints ~(symbol "h-box-constraints")
                                                                   :w-box-constraints ^m/BoxConstraints ~(symbol "w-box-constraints")
                                                                   :min-h ^m/BoxConstraint ~(symbol "min-h")
                                                                   :max-h ^m/BoxConstraint ~(symbol "max-h")
                                                                   :min-w ^m/BoxConstraint ~(symbol "min-w")
                                                                   :max-w ^m/BoxConstraint ~(symbol "max-w")})
                                                         ~body))))))}))
All I wanted to do was get the max-h and max-w available without blowing everything up in a scroll view 😂

Awesome. Thx for the trouble. I would like to tackle it. Getting back to your work, would you be Ok for while on the old paint? I am pretty happy with the code re-org, and with dealing with resource scavenging, but I am slogging thru a bug in TodoMVC where the code crashes left on encountering a model or cell that has already been (logically) scavenged. Only a few bugs, mostly because of clumsy specification of formulas -- not including reactive mget's in a cF, no idea what got into me -- which caused massive over-scavenging. There's one for the Matrix Style Guide. Anyway, let me know if you want to revert and if I can then branch the pre-wet into an always backwards-compatible maintenance branch.

Our messages crossed, sorry. Re your macro, that's fine, I'll look at it in a sec. But egad! 🤣 Seriously, is there no opportunity for that old Common Lisp trick: create a conventional function named call-with-<macro-name> ? Anyway... Mind you, I mentioned that I think I have spotted an easy way around the heavy macrology in w/mx, such that they all can be functions. Should help with app size/memory use.

Way cool. 😎 Great work!

Just got side-tracked into worrying (at long last) about resource leaks, so focused now on cancelling subscriptions, which led to belated enabling of the "quiesce" mechanism for when widgets get dropped, which led to fussing over protocol inheritance... fun stuff, but another day's hacking before I look at a stream cell. 🕐

Oh cool sounds like maybe I'll stop getting copious "multiple widgets used the same global key" errors :D

Hey, talk to me when you have issues! 🙂 f/mx is still growing out of its POC stage and someone using it in anger is a great way to accelerate that. Looks like the only place I mess with a key is in the todo demo:

(defn todo-list-item [todo]
  (fx/dismissible
    {:key         (m/ValueKey. (td-stg-id todo))
     ....}...))
Do we need a default GlobalKey on widgets? Anyway, glad to help out on anything like this!

Haha okay. :P It wasn't particularly high on my priority list to fix since everything still worked. I presumed it was related to hot-reload. > Do we need a default GlobalKey on widgets? Actually it only shows up when I add a global key to a widget. (It's how they say to programmatically open the side-drawer widget). I was guessing hot-reload or life-cycle issue.

OK. I am here if needed.

This comes at an interesting time, because I happen to be contemplating a new approach to f/mx lifecycle when it comes to spawning children. I will come back to this. But first: I am trying to remember where we left the idea of non-FX widgets having FX children. ISTR it not working, but I will check the Slack history. If I understand the use case, m/NovelStrangeWidget will be a newly defined, pure CLJD widget. So something f/mx has not wrapped, obviously. Option #1: f/mx users wrap novel widgets themselves. That should be pretty trivial. Otherwise, I see a potential lifecycle issue: will (fx/fx/render-with...) get called at the wrong time? So the problem would not be arranging the parentage to support fasc -- we can easily work this out -- but rather the timing of a nested model being brought to life, and all its formulas being kicked off. I am starting to really like Option #1, as I type. It might just be:

(deftag tiltontec.flutter-mx.factory/k1-child-stateless
 novel-strange-widget m/NovelStrangeWidget)
Kebab-case not required, that would be up to the f/mx user. Anyway, user-wrapping would avoid any issues, because NovelStrangeWidget becomes just another native CLJD widget, and the deftag would handle converting it to f/mx nature. Then no lifecycle issues, because we would have an all-f/mx solution. Or perhaps we can wrap on the fly, which would look sth like this:
(mx/container
 {} {:name :root
     :access :granted}
 (fx/as-fmx-widget
   (m/NovelStrangeWidget
    {.fooBar m/Baz.buzz}
    (fx/text (str (mget (fasc :root) :access))))))
But I would recommend first wrapping m/NovelStrangeWidget, which should work easily, and then mulling the possibility of a fx/as-fmx-widget in-line macro as a second, sugaring elaboration. The more I think on it, the more I suspect fx/fx-render-with me will have lifecycle issues, but I will stare at this today. As for the change I mentioned earlier, I am starting to think deftag can generate named functions instead of macros. These functions would be factories, returning functions to be invoked with a single parameter, the parent. So the kids of an f/mx widget would be functions to produce f/mx children, and we just have to modify the handling of any value of any property, :kids or some delegate property, to see if it is some, say, FXFactory and, if so, call it with me as the parent. BUT! This might not change anything about the original question. 🙂 It just strikes me as ballpark-ish similar. Let me know if you want to try Option #1.

So where have we landed on this? Sounds like you have it sorted out, but maybe not? That use of a Future to trigger a re-render seems like sth it would be nice to eliminate, if possible. Is that still in the mix?

So after pounding away at this on several different angles, and trying really, really hard to to it the "proper" flutter way, I got somewhat close to the layout we're after. Aaand.... it's slow, broken, and ugly :P Seems my crazy macro combined with the power of f/mx is significantly better/faster than the native flutter solution 🤷🏻‍♂️ 🤣 I'd much prefer to ditch the Future, still looking for a way to do that. AddPostFrameCallback didn't seem to work, so I've probably not yet figured out the right way to call it. I was hoping it was simply a matter of checking mounted before calling setState, but I see you've already got that covered. :) Hopefully I can narrow what part of the app is triggering a change higher up the tree. The callstack says plenty, but not much relevent to my problem :P

Sure, old paint should be no problem. I'm just using with-par and layout-builder, both of which are easy to patch :).

Trying to make reproducible, first hiccup is quickly evident:

(def nested-layo (fx/layout-builder
                  {:builder (fx/as-dart-callback [ctx box-constraint]
                                                 (fx/fx-render ctx
                                                               (mx/with-par me
                                                                 (fx/text
                                                                  {:style (cF (p/TextStyle
                                                                               .color (mget me :font-color)
                                                                               .fontSize (mget me :font-size)))}
                                                                  {:font-size  (* 0.1 (mget (fasc :first) :font-size))
                                                                   :font-color (cF (mget (fasc :scaffo) :scaff-color))}
                                                                  (str "Fontsize " (/ (int (* 10 (mget (fasc :first) :font-size))) 10))))))}))
(defn make-app []
  (let [title "Layout Builder Dynamic Text Size"]
    (fx/material-app {:title title}
                     (fx/scaffold
                      {:appBar (fx/app-bar {:title (fx/text title)})}
                      {:name        :scaffo
                       :scaff-color m.Colors/red}
                      (fx/center
                       (fx/layout-builder
                        {:builder (fx/as-dart-callback [ctx box-constraint]
                                                       (fx/fx-render ctx
                                        ; now we can play in f/mx world....
                                                                     (mx/with-par me
                                                                       (fx/column
                                                                        (fx/text
                                                                         {:style (cF (p/TextStyle
                                                                                      .color (mget me :font-color)
                                                                                      .fontSize (mget me :font-size)))}
                                                                         {:name :first
                                                                          :font-size  (* 0.1 (.-maxHeight ^m/BoxConstraints box-constraint))
                                                                          :font-color (cF (cond
                                                                                            (> (mget me :font-size) 50)
                                                                                            (mget (fasc :scaffo) :scaff-color) ;; m.Colors/red
                                                                                            :else m.Colors/cyan))}
                                                                         (str "Fontsize " (/ (int (* 10 (mget me :font-size))) 10)))
                                                                        nested-layo))))}))))))
The me in nested-layo is nil.

Mm, that's actually not quite accurate. The nil is the result of (fasc :first).

New idea after seeing link above is to create a custom widget based on layoutbuilder so that we can get first class mx support and maybe even stuff the constraints directly onto me

👀 1

While we are at it, I am about to push a new f/mx that can clean up resources when mx widgets are dropped, such as when a to-do gets deleted, or a delegate gets replaced by a new delegate. Seems fine with the half dozen examples in f/mx, but next up is testing with the full sandbox. Then I can give this a try, see why (fasc :first) comes up empty.

Ah, already pushed: cfd19f51a25138960b462109794297182b4fb0a1

👍🏻 1

Am I correct in thinking that layout-builder as-is currently is not a first-class f/mx-widget? (IE. :kids not assigned, no automatic removal of unused children, etc.)

👀 1
1

This is a draft I've been working on to make it first class, but as is probably obvious I'm in a little over my head :P

👀 1

Wowzers, I've cross-polluted a few threads around here - sorry about that.

Whew! I thought my excess drinking had me seeing triple. 🍻

😆 1

I'm having a very hard time reproducing that mark_needs_build error 😮‍💨

"obvious I'm in a little over my head" Welcome to the club! I am writing code to write code in a library I do not know. I just beat these things into submission through trial and error, then head for the liquor cabinet. 🥃

😆 1

Aha, I figured out a repro! The working working version of nested-layo cheats by using a dart future to fire after the build phase finishes. Maybe they have some sort of queueNeedsBuild? Somehow I doubt it :P.

Woahboy, I just found out that all this song and dance I've been doing to get layout-builder to bend to my will, and lo and behold, the m/FittedBox widget does exactly what I need - scale font according to available space. 🤦🏻‍♂️ laughcry

That's what I get for trying to hard to work with what I know and not hard enough to learn what I don't :P

Well turns out that wasn't the only thing I was using it for, for this design I need to specify a fractionallySizedBox not of the possible space (Ie. listView -> unlimited), but of the visible space.

What about defining new deftags using a widget built with f/mx? The current app I'm working on has a custom theme that is difficult to build with regular flutter widgets (Or at least, with the ones I'm actually know how to use), so I've been using that expose-layout helper extensively. Off to try that now with expose-layout so I can de-fragment my apps now shattered matrix-tree...

looks at deftag. ---> sees:

`(~'~factory ~@(when ~param-property
                        [~param-property]) ~'~fx-class ~fx-props# ~mx-props# ~@children#)
👀 👀 👀

^ Footprints of a lisp legend 😁

Not sure I follow: "What about defining new deftags using a widget built with f/mx?". Possibly irrelevant: What I do is define functions that return a stock widget. Those functions can take any parameters I like.

And then deftag your defn?

> Not sure I follow: .... I was thinking of the layout-builder helper I had bulit, but come to think of it, it really does make much more sense to start with native flutter widget and wrap, instead of round trip from fx -> fx-render -> deftag like I was thinking :P. Must be time for my nap.

Well, deftag per se exists to support (generator [flutter-arg-map [mx-arg-map]*] & kids])* , then just expands to, say, (generator {} {} ~@kids) if arg maps are not specified. When I create a CLJD function, I might have arbitrary syntax. Happy napping! 😴

ps. Might push the shiny new f/mx shortly so I can convert the starter and sampler. Don't grab that SHA yet! 🤯

👍🏻 1

Ah, so what I'm after is a defn based on generator. Now I know where to look after my nap. Thanks!

Or the kids-for-builder factory is probably pretty close from the looks sounds of it. Nope.

I may be a little in over my head here. Even after my nap :P.

What I'm after is wrapping this:

(m/LayoutBuilder
  .builder
  (fn [context constraints]
    fx-kids-go-here)))
In such a way that the matrix family is not broken.

I'm guessing we'll need reify, perhaps close to this factory:

(defmacro k1-home-stateful [fx-class fx-props mx-props & [home]]
  (let []
    ;(assert (not (contains? fx-props :home)) "k1-home-stateful passed :home param in FX props, but expects :home as first child")
    ;(assert (not (contains? mx-props :home)) "k1-home-stateful sees :home in MX props, but expects :home as first child")
    `(tiltontec.flutter-mx.factory/make-fx (new tiltontec.flutter-mx.factory/FXDartWidget)
       ~fx-props
       (assoc ~mx-props
         :fx-class (quote ~fx-class)
         :fx-gen (fn [me ctx]
                   (reify :extends (m/StatefulWidget
                                     .key (tiltontec.flutter-mx.core/fx-resolve me ctx
                                            (tiltontec.matrix.api/mget? me :key)))
                     (~'createState [_#]
                       (reify :extends w/State
                         (^void ~'initState [this]
                           ;(.initState ~'^super this)
                           (tiltontec.flutter-mx.factory/record-fx$state me this)
                           (when-let [init (tiltontec.matrix.api/mget? me :initState)]
                             ;; this is where widgets can build controllers who vsync
                             (init this me)))
                         (~'build [_# ctx]
                           (let [bod# (tiltontec.flutter-mx.core/fx-resolve :kid1 me ctx
                                        (first (tiltontec.matrix.api/mkids me)))]
                             (with-flutter-ref
                               (~fx-class
                                 .home bod#
                                 ~@(let [kvs (for [[k# _#] fx-props]
                                               [(symbol (str "." (name k#))) ;;k#
                                                `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                   (tiltontec.matrix.api/mget me ~k#))])]
                                     (apply concat kvs)))))))))))
       (tiltontec.matrix.api/cFkids ~home))))

Perhaps the cljd version of this dart code:

class MyLayoutBuilder extends LayoutBuilder {
  @override
  Widget builder(BuildContext context, BoxConstraints constraints) {
    return Container(
      width: constraints.maxWidth / 2,
      height: constraints.maxHeight / 2,
      color: Colors.blue,
    );
  }
}

And maybe expose the constraints similar to how you exposed the flutter ref

Maybe something close to this?:

(defmacro k1-layout-builder [fx-class fx-props mx-props & [child]]
  (let []
    `(tiltontec.flutter-mx.factory/make-fx
      (new tiltontec.flutter-mx.factory/FXDartWidget)
      ~fx-props
      (assoc ~mx-props
             :fx-class (quote ~fx-class)
             :fx-gen (fn [me ctx]
                       (reify :extends (m/LayoutBuilder
                                           .key (tiltontec.flutter-mx.core/fx-resolve me ctx
                                                                                      (tiltontec.matrix.api/mget? me :key)))
                         (~'builder [ctx constraints]
                          (let [bod# (tiltontec.flutter-mx.core/fx-resolve :kid1 me ctx
                                                                           (first (tiltontec.matrix.api/mkids me)))]
                            (with-flutter-ref
                              (~fx-class
                               ~@(let [kvs (for [[k# _#] fx-props]
                                             [(symbol (str "." (name k#))) ;;k#
                                              `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                     (tiltontec.matrix.api/mget me ~k#))])]
                                   (apply concat kvs)))))))))
                                           (tiltontec.matrix.api/cFkids ~child))))

👀 1

(Currently doesn't do anything with bod#, and I imagine returning cFkids to builder kills it) ((And bod# might be a mis-nomer now that it's not for a widget with a .body param))

(Also doesn't expose the constraints yet)

Did you see?:

(deftag tiltontec.flutter-mx.factory/childless-stateless layout-builder w/LayoutBuilder)
I use that in f/mx itself:
tiltontec.example.x029_layout_builder
Does that not work for your use case?

That is what I've been using, and it displays fine, but (unless I'm mistaken, that would be nice) it has the nested fx-render woe of being isolated from the rest of the matrix family.

I'll go try again, maybe I messed up something else :)

OK, I forgot the context. This is the use case with an fx widget under non-fx?

Or at least, this is the most recent use-case :)

That example survived my md-quiesce overhaul. 🙂 Are you looking to connect the rendered widget with the outer me? I might have a separate macro for that. Checking...

Does indeed break with this modification of example x029

Says mget passed nil. (`me` is nil).

Yep! I had made this mad macro:

(defn ^:macro-support container-sees-layout*
  [args matrix body]
   `(fx/layout-builder
     {:builder (fx/in-my-context [~(symbol "me") _]
                                 (fx/->CBAsIs
                                  (fn [~(symbol "ctx") ^m/BoxConstraints ~(symbol "box-constraint")]
                                    (let [^m/BoxConstraint ~(symbol "min-h") (.-minHeight ^m/BoxConstraints ~(symbol "box-constraint"))
                                          ^m/BoxConstraint ~(symbol "max-h") (.-maxHeight ^m/BoxConstraints ~(symbol "box-constraint"))
                                          ^m/BoxConstraint ~(symbol "min-w") (.-minWidth ^m/BoxConstraints ~(symbol "box-constraint"))
                                          ^m/BoxConstraint ~(symbol "max-w") (.-maxWidth ^m/BoxConstraints ~(symbol "box-constraint"))]
                                      (fx/fx-render ~(symbol "ctx")
                                                    (fx/container
                                                     ~args
                                                     ~(merge matrix
                                                             `{:min-h ^m/BoxConstraint ~(symbol "min-h")
                                                               :max-h ^m/BoxConstraint ~(symbol "max-h")
                                                               :min-w ^m/BoxConstraint ~(symbol "min-w")
                                                               :max-w ^m/BoxConstraint ~(symbol "max-w")
                                                               :parent ~(symbol "me")})
                                                     ~body))))))}))

(defmacro container-sees-layout
  ([body] (container-sees-layout* {} {} body))
  ([args body] (container-sees-layout* args {} body))
  ([args matrix body] (container-sees-layout* args matrix body)))
but seems to not always work as expected.

I am looking at this code:

(defmacro with-ctx+as-is [[me ctx] callback-fn]
  `(tiltontec.flutter-mx.core/in-my-context [~me ~ctx]
     (tiltontec.flutter-mx.core/->CBAsIs
       ~callback-fn)))

(defmacro as-dart-callback [[& cb-params] & body]
  `(tiltontec.flutter-mx.core/with-ctx+as-is [~'me ~'ctx]
     (fn [~@cb-params]
       (tiltontec.cell.base/with-mx-isolation
         ~@body))))

Intriguingly, it is used with the animated-builder fx widget, Check out expanding-action-button in the x05-fab example.

OK, in x029 I added a print:

(defn make-app []
  (let [title "Layout Builder Dynamic Text Size"]
    (fx/material-app {:title title}
      (fx/scaffold
        {:appBar (fx/app-bar {:title (fx/text title)})}
        (fx/center
          (fx/layout-builder
            {:builder (fx/->CBAsIs
                        (fn [ctx box-constraint]
                          (dp :layo-builder-sees-me (minfo me))
...snip...
It logs:
flutter: :DPR> :layo-builder-sees-me [:minfo :fxc m/Center :mxtype Instance of 'FXDartWidget' :anon]
I will investigate why me is not the layout-builder, possibly tmrw cuz I am dragging, 😴

Cool, now me is the layout-builder:

(defn make-app []
  (let [title "Layout Builder Dynamic Text Size"]
    (fx/material-app {:title title}
      (fx/scaffold
        {:appBar (fx/app-bar {:title (fx/text title)})}
        (fx/center
          (fx/layout-builder
            {:builder (as-dart-callback [ctx box-constraint]
                        (dp :layo-builder-sees-me (minfo me))
                        (fx/fx-render ctx
                          ; now we can play in f/mx world....
                          (fx/text
                            {:style (cF (p/TextStyle
                                          .color (mget me :font-color)
                                          .fontSize (mget me :font-size)))}
                            {:font-size  (* 0.1 (.-maxHeight ^m/BoxConstraints box-constraint))
                             :font-color (cF (cond
                                               (> (mget me :font-size) 50) m.Colors/red
                                               :else m.Colors/cyan))}
                            (str "Fontsize " (/ (int (* 10 (mget me :font-size))) 10)))))}))))))
Log:
flutter: :DPR> :layo-builder-sees-me [:minfo :fxc w/LayoutBuilder :mxtype Instance of 'FXDartWidget' :anon]
Time for 🍾 ? I wonder if we should add (with-par me.... Might scale better, otherwise deeply nested widgets cannot blithely fasc. OTOH, it would be weird for deeply nested builder objects to be reaching out all over the Matrix. I imagine the builder fn at its top level handling interfacing with the surroundings. But I generally do not like limiting capability, so a with-par might me in order. You have been suggesting that, right?

This also works:

(defn make-app []
  (let [title "Layout Builder Dynamic Text Size"]
    (fx/material-app {:title title}
      (fx/scaffold
        {:appBar (fx/app-bar {:title (fx/text title)})}
        {:name :scaffo
         :scaff-color m.Colors/red}
        (fx/center
          (fx/layout-builder
            {:builder (as-dart-callback [ctx box-constraint]
                        (dp :layo-builder-sees-me (minfo me))
                        (fx/fx-render ctx
                          ; now we can play in f/mx world....
                          (with-par me
                            (fx/text
                              {:style (cF (p/TextStyle
                                            .color (mget me :font-color)
                                            .fontSize (mget me :font-size)))}
                              {:font-size  (* 0.1 (.-maxHeight ^m/BoxConstraints box-constraint))
                               :font-color (cF (cond
                                                 (> (mget me :font-size) 50)
                                                 (mget (fasc :scaffo) :scaff-color) ;; m.Colors/red ;; nb <=======================
                                                 :else m.Colors/cyan))}
                              (str "Fontsize " (/ (int (* 10 (mget me :font-size))) 10))))))}))))))
Now this is not fx->dart->fx, but that should be manageable. 🤞

🎉 1

Say, @hiskennyness, in which cases tiltontec.cell.core should be used instead of tiltontec.matrix.api?

Only if I missed something! Hmm...ISTR a possible edge case that could not be lifted into the api. Are you seeing sth specific?

FYI, I have not assiduously revisited all my examples/demos to convert to the api, and they will still work because I did my best to keep things backwards compatible. I see the code I shared yesterday is largely unconverted. Lemme look at the original I copied over. Brb...

Looks like I converted todo/core.cljs and lost interest. Do you need the rest converted? In the meantime I will refresh my memory on the few things that could not be APIed.

No no, I did it myself 🙂

Looks like the defmultis are the only things I could not refactor, hence me giving them their own ns, to make that problem more transparent (as in, why the hell didn't kenny lift that?) 🙂 :

[tiltontec.cell.poly :refer [watch watch-by-type]]