matrix

Benjamin C 2023-05-20T00:52:40.971099Z

Would it be trival to bind ctx to me in some way in f/mx? Imaginary usage:

(-> m/MediaQuery (.of (fx/my-ctx me) .-size .-width)

kennytilton 2023-05-20T01:11:23.312379Z

Research required! ðŸĪĢ Specifically, is context sth that can reliably be cached and then used at some arbitrarily later time? Or is it a dynamic value without object identity? Over here, research has been deferred until I see a use case where ctc needs to be pulled from some cache.

kennytilton 2023-05-24T11:29:54.681889Z

defs evaluate just once, FYI. So the only difference is the laziness.

kennytilton 2023-05-21T11:31:51.108839Z

Haha, I thought the latest was not working until I saw the values for the text widgets -- it's an MX inspector! Aside: I changed ~(symbol ".builder") to .builder and it seems fine. So is this solution too specific in what it does to be called with-layout? I am thinking different usages will want to do different things with the box constraints. Can this be generalized with a new :builder-watch property that will be invoked on each builder call? Or are you thinking you just want to make f/mx generally extensible by folks who want to author their own factory macros? That would be fine for power users, but I like the idea of a generic :builder-watch for an in-between solution that keeps the built child as kid-1 but supports build-watching. ðŸĪ”

kennytilton 2023-05-21T13:36:37.792119Z

I am seeing over here -- and I may have screwed sth up, or not have the latest -- I am seeing that rotating the sim loses track of the :max-w. btw, did you mean the two magicals to be nested one under the other? The make-app I have has them both with the column as the parent. I recall you mentioning nesting.

kennytilton 2023-05-20T10:38:05.990019Z

I saw that early on and my reaction was, well, MX models never change parent, ie they never change location, so maybe we can grab the context and cache it. Indeed, we did for a while, in a meta property fx$ctx or sth. But then I saw we could always get the required context with a suitably tagged callback that says in effect, "I will tell you the value for this property if you call me back with the build context." So I decided to play it safe and heed the "do not cache" warning, even tho it did not seem to apply. That said, perhaps there is a Flutter use case that requires a widget to be un-/re-mounted, because it has to be some place different but be the identical widget. I see no harm in stashing the context, so I think we can make that change and see if it breaks. Your thoughts, @zenflowapp? ps. Yes, this is definitely what I call a speed bump. Good metaphor, because we literally must slow down and think at a crawl, very carefully picking the right spot and right callback wrapper. We might have too many of the latter, btw. 🙂 My thinking is that, as we code more and more app stuff in anger, we might settle on just a few, and then give them better names. 🙂

kennytilton 2023-05-20T11:19:05.909059Z

Btw, nice confluence: quiesce is still broken, and I keep wondering if it is because an old Dart widget is lurking about somewhere swallowing mouse events. The mention of "unmount" has me thinking if md-quiesce needs to do more work to properly snuff a widget. ðŸĪ”

Benjamin C 2023-05-20T16:12:12.965599Z

Hmm, I'd be happy to experiment with it! Seems my app has plenty of things to trigger weird flutter edge-cases, might be a good testing ground :P

Benjamin C 2023-05-20T16:13:49.727419Z

I'd imagine as long as our cached context is updated on the new builds, the only remaining danger would be the case where you try to use the context and the widget is unmounted. So if we can handle that, I imagine we're golden.

kennytilton 2023-05-20T16:40:11.573649Z

I think you nailed it on the head: we get the ctx with every build, so the only problem will be if we need the ctx before then. I have a ctx cacher working OK, just need to test on more examples then away we go. (In a few hours if all goes well.)

🎉 1
Benjamin C 2023-05-20T16:44:03.454309Z

> so the only problem will be if we need the ctx before then Before build - would that include during build? IE. in a layout-builder?

Benjamin C 2023-05-20T16:44:53.988519Z

Worst case scenario we revert to in-my-context when needed :)

kennytilton 2023-05-20T18:28:38.549979Z

"Before build - would that include during build? IE. in a layout-builder?" Dunno, just speculating. We are passed the ctx in the build call, and I am caching it first thing, so if we do not see a :fx$ctx we must be "before" any build. ðŸĪ· Possible use case: Not sure if it is still there, but at one point I tried using one of my ctx macros in a formula for a custom state cell -- which ran before we had ctx. I think. 🙂 It might have been the where a standard widget factory did not use fx-resolve, and those have been converted. My original thinking was that only cells for Dart/Flutter, the first map, would ever need context, but I was goofing around trying to grab some Flutter info in a custom temp cell. The values for the d/F constructors would only be sought during builds, so that seemed safe. Let's see where the new approach comes up short and address it if/then. Gonna test some more and maybe push sth in a few.

👍ðŸŧ 1
kennytilton 2023-05-20T18:33:23.031909Z

Btw, the builders I see in my examples all get passed a ctx -- did you have one that did not? Flutter certainly has a wide variety of patterns for things.

Benjamin C 2023-05-20T18:39:25.355749Z

Oh, right.. No I haven't yet. I'm still tinkering with trying to get a custom layout-builder widget that I can use first-class with mx (fxx/magic-layout (fx/some-child-widget {:height (/ (:fl$max-h @me) 2)}))

kennytilton 2023-05-20T18:51:01.716529Z

Not sure I follow, but often this MX stuff works only because things are in formulas that will not run straight away, and all these with-ctx-whatever macros double down on that by yielding functions that will be called from within build functions, where ctx is avaliable. Maybe we need a new macro? 🙂

Benjamin C 2023-05-20T18:59:35.745589Z

> Not sure I follow Your probably not missing too much, this is me imagining I can somehow or another bypass all my flutter-not-wanting-to-be-responsive-the-way-I-want-it-to woes (read: probably wishful thinking, or if I'm lucky, a new macro) :P.

kennytilton 2023-05-20T19:12:54.618899Z

OK, keep me posted, I will dive in early if needed, no need to go crazy on anything before asking. Still lots of polishing ot go, and I have not even looked at performance yet. ctx realease candidate is in SHA e789cd4f4bb0447f840a02f9d5543787a84b5158 on the "todo" branch, which has been pushed. The examples in f/mx work, gonna try the sampler next. Relevant code:

;;; --- ctx tracking ----------------------

(defn record-fx$ctx [me ctx]
  (mx/rmap-meta-set! [:fx$ctx me] ctx))

(defn ctx-check [fx-class me ctx]
  (cond
    (nil? (fx-ctx me))
    (do
      ;(dp :ctx-check-NIL (str "<<" fx-class ">> NIL so adopting build ctx: <" ctx))
      (record-fx$ctx me ctx))

    (= ctx (fx-ctx me))
    (dpx :ctx-check-OK! (str "<<" fx-class ">>  both ctx: <" ctx ">"))

    :else (do
            (dp :ctx-match-fail-being-corrected (str "<<" fx-class ">> adopting build ctx: <" ctx "> not= cache: <" (fx-ctx me) ">"))
            (record-fx$ctx me ctx))))

(defn fx-ctx [me]
  (:fx$ctx (meta me)))
ctx-check gets called just inside the build calls. Needs a better name actually -- it now caches the ctx, but yells if it already knows a ctx and is passed a different one. Call fx-ctx to retrieve the ctx where otherwise not available (and be ready for nil 🙂 in case we missed sth). If you have your own build, the ones I did look like this:
(~'build [_# ctx]
    (tiltontec.flutter-mx.factory/ctx-check (quote ~fx-class) me ctx)
       (with-flutter-ref...
Testing the sandbox examples next.

Benjamin C 2023-05-20T19:14:19.745279Z

Sweet, thanks!

Benjamin C 2023-05-20T19:19:53.364939Z

I'll try to organize list my scattered thoughts: â€Ē flutter provides through layout builder maxH/W properties of parent that I want to use to size the child â€Ē this is only available during layout (part of build) time â€Ē because of infinite constraints of things like scrollviews and others, I want to "inherit" the last maxH/W that isn't infinite â€Ē my "dream" api would be something like (fx/parent-capture-max-size-and-attach-to-me (fx/a-child-that-technically-is-wrapped-in--as-dart-callback--and-passed-to-bulider {:height (/ (mget?-like-that-returns-first-found-prop-asc :bc$max-h) 2)}))

Benjamin C 2023-05-20T19:26:46.303509Z

Last bit made more readable:

(defn first-fm-up-with-prop [me prop]
  (mx/fm-navig #(not (nil? (mx/mget? % prop))) me :me? false? :up? true :inside? false))

(defn get-prop-up [me prop]
  (when-let [first-parent-with-prop (first-fm-up-with-prop me prop)]
    (mget first-parent-with-prop prop)))

(fx/parent-capture-max-size-from-layoutBuilder-and-attach-to-me
 (fx/a-child-that-technically-is-wrapped-in--as-dart-callback--and-passed-to-bulider
  {:height (/ (get-prop-up :bc$max-h) 2)}))

kennytilton 2023-05-20T19:26:51.772329Z

"...first-found-prop-asc"!!! I have been contemplating such a beast!! Sure would simplify the coding, and further scandalize the string static crowd!

kennytilton 2023-05-20T19:30:02.813699Z

What if an ascendant fas the prop :bc$max-h but the value is nil? Do you want to give up there, or keep ascending until a second ascendant has the prop and a value?

Benjamin C 2023-05-20T19:30:46.683669Z

Oh, sounds like a good variant/flag to have!

Benjamin C 2023-05-20T19:31:55.516359Z

In the layout use-case I'm after the first "something" but in general, is well, general :)

kennytilton 2023-05-20T19:32:50.642609Z

To test if me has prop, just a simple clj contains? is what mget? uses:

(contains? @me prop)

1
kennytilton 2023-05-20T19:33:51.720639Z

Prolly should be encapsulated in md-has-prop? or sth.

👍ðŸŧ 1
Benjamin C 2023-05-20T19:35:35.861109Z

As far as this bit goes:

(fx/parent-capture-max-size-from-layoutBuilder-and-attach-to-me
 (fx/a-child-that-technically-is-wrapped-in--as-dart-callback--and-passed-to-bulider
What do you think? Am I dreaming something unrealistic?

Benjamin C 2023-05-20T19:38:25.844859Z

(not necessarily wrapped in as-dart-callback I suppose, what I mean is that it's treated as any other mx widget in the sense of kids/me/parent being handled)

kennytilton 2023-05-20T19:38:41.334199Z

Sorry, I did not grasp that. But one good thing about having MX widgets wrapping dart widgets is we can get away with a lot.

kennytilton 2023-05-20T19:39:24.389359Z

Can we take an existing example with a builder and make things more concrete?

Benjamin C 2023-05-20T19:40:15.264959Z

I've been trying, but not being all that versed in matrix intenals I get a little lost :P Here is a commented excerpt:

kennytilton 2023-05-20T19:42:23.225189Z

Not seeing the excerpt. What was the example we just did where I used as-dart-callback to make the buillding widget visible to the built?

Benjamin C 2023-05-20T19:43:34.325659Z

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))))))}))))))

🙏 1
kennytilton 2023-05-20T19:43:59.572299Z

Ah, ok, it was x029-layout-builder. I never copied that to the sandbox.

Benjamin C 2023-05-20T19:44:17.604299Z

Sorry, modding excerpt, almost ready

kennytilton 2023-05-20T19:45:14.528169Z

np I am working thru all the sandbox examples, looking good so far.

👍ðŸŧ 1
Benjamin C 2023-05-20T19:58:28.226459Z

Alright, untested, probably all kinds of wrong and broken, maybe-close code:

(defmacro kid->layout-builder [fx-class fx-props mx-props & 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/StatelessWidget)
                                                            (~'build [_# ctx]
                                                             (with-flutter-ref
                                                               (~fx-class
                                                                ~(symbol ".builder")
                                                                (fx/-as-dart-callback [_# constraints]
                                                                 (fx/fx-render ctx (tiltontec.matrix.api/cFkids ~@child)))
                                                                ~@(let [kvs (for [[k# _#] fx-props]
                                                                              [(symbol (str "." (name k#)))
                                                                               `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                      (tiltontec.matrix.api/mget me ~k#))])]
                                                                    (apply concat kvs))))))))))
Add in a bit from my old macro, (can be be simplifed a lot, sorry for the noise), and attach to me's meta instead of dircetly into the matrix, and I think it might work
`(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")))
                                                ^m/BoxConstraints ~(symbol "box-constraint")
                                                ^m/BoxConstraints (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))))))

👀 1
Benjamin C 2023-05-20T19:59:59.979379Z

Okay, definitely broken, just a moment.... Oh nvm, back to just probably :P

😀 1
Benjamin C 2023-05-20T20:10:24.581589Z

I'm really not so great with decoding flutter errors, but I think this means I have to type something different?

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building make_appReifyirmorq$2(dirty, state:
make_appReify2we0cb$2#2ed24):
Class 'Symbol' has no instance method '$_invoke$4' with matching arguments.
Receiver: Instance of 'Symbol'
Tried calling: $_invoke$4(LayoutBuilder, null, null, Instance of 'Atom')
Found: $_invoke$4(dynamic, dynamic, dynamic, dynamic) => dynamic

Benjamin C 2023-05-20T20:11:30.435599Z

Or probably more likely, I need to quote/unquote differently ðŸĪ·ðŸŧ‍♂ïļ

kennytilton 2023-05-20T20:15:00.224199Z

Actually, I was wondering about your use of symbol

Benjamin C 2023-05-20T20:15:22.358479Z

Ah, yep, that can change methinks

kennytilton 2023-05-20T20:16:05.751909Z

eg, cannot ~(symbol "me") just be me?

Benjamin C 2023-05-20T20:17:03.330399Z

Oh, your looking at the second part -- yeah, you can ignore the all the symbol bits.

kennytilton 2023-05-20T20:17:20.075719Z

Did I start that? 🙂 Lemme look around....

Benjamin C 2023-05-20T20:17:21.825029Z

Part of the clutter that I plan to clean

Benjamin C 2023-05-20T20:18:13.487129Z

For now I'm just trying to get the first part working, without actually doing anything with layoutbuilders constraints

Benjamin C 2023-05-20T20:21:50.371929Z

Hmm, looking at kids->prop-stateless as an example, maybe we don't need the reify bit

kennytilton 2023-05-20T20:22:37.785239Z

btw, are you working in a clone of f/mx proper? Or are you working your macrology into your own sources? I am thinking it would help if I could pull in the code you are working on. This stuff is so dense I really need to compile/run to think about it.

kennytilton 2023-05-20T20:26:25.310619Z

So going back to your original "scattered thoughts", do I understand to want the parent of the built widgets to track the max values passed as constraints, such that they are available to the built widgets?

Benjamin C 2023-05-20T20:26:43.150329Z

The latter, but should be copy/pastable into f/mx: this into factory:

(defmacro kid->layout-builder [fx-class fx-props mx-props & 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]
                                                          (with-flutter-ref
                                                            (~fx-class
                                                             ~(symbol ".builder")
                                                             (fx/-as-dart-callback [_# constraints]
                                                                                   (fx/fx-render ctx (tiltontec.matrix.api/cFkids ~@child)))
                                                             ~@(let [kvs (for [[k# _#] fx-props]
                                                                           [(symbol (str "." (name k#)))
                                                                            `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                   (tiltontec.matrix.api/mget me ~k#))])]
                                                                 (apply concat kvs))))))))
and this into core:
(fx/deftag `kid->prop-layout-builder magical-layout m/LayoutBuilder) ;; <-- different name of course :P

kennytilton 2023-05-20T20:29:02.629229Z

Wait, why "diff name of course"? I like magical-layout! 🙂

kennytilton 2023-05-20T20:31:10.478119Z

And then the actual make-app?

Benjamin C 2023-05-20T20:32:12.588739Z

> do I understand to want the parent of the built widgets to track the max values passed as constraints, such that they are available to the built widgets? Yes, and if the max value is infinite, use that of the next magical-layout up. Haha, well, I guess there may not really be a short name that describes it well :P, (yet at least).

Benjamin C 2023-05-20T20:32:22.952449Z

Oh right, just a sec.

kennytilton 2023-05-20T20:34:34.836229Z

Nested layout builders? Yer having fun, aren't you? 👏 I'll start a new branch and start adding your code.

Benjamin C 2023-05-20T20:35:50.317459Z

Haha yep, and on certain pages, everywhere and in great multitude. Thanks!

Benjamin C 2023-05-20T20:36:20.184639Z

make app - step 1:

(defn make-app []
  (let [title "Magic layout - Dynamic Text Size - wip"]
    (fx/material-app {:title title}
                     (fx/scaffold
                      {:appBar (fx/app-bar {:title (fx/text title)})}
                      (fx/center
                       (fx/magical-layout ; step 1: actually compile
                        (m/Text "hello" .style (m/TextStyle .fontSize 200))))))))

kennytilton 2023-05-20T20:40:23.159989Z

Your deftag ^^^ has an interesting backquote: (fx/deftag `kid->prop-layout-builder..... Whassat?

Benjamin C 2023-05-20T20:41:16.302449Z

Oh, the first problem! :P not sure how that happened..

kennytilton 2023-05-20T20:43:46.473669Z

And you provided above the source for kid->layout-builder, but your deftag has kid->prop-layout-builder.

Benjamin C 2023-05-20T20:44:25.373709Z

Yep! Sorry, trying to move to quickly

Benjamin C 2023-05-20T20:44:51.666389Z

Ignore my deftag and start from scratch :P

kennytilton 2023-05-20T20:45:33.936099Z

np! Take your time. I will put on the golf.

Benjamin C 2023-05-20T20:47:41.143139Z

In mx, would be like this: (fx/deftag tiltontec.flutter-mx.factory/kid->layout-builder magical-layout m/LayoutBuilder)

Benjamin C 2023-05-20T20:53:28.951649Z

Acidental extra hyphen prefix on with-dart-callback

Benjamin C 2023-05-20T20:57:19.825659Z

Ah, and another problem, I moved the kids into the builder, but now make-fx is missing it's last arg.

kennytilton 2023-05-20T20:59:50.092529Z

Right, use nil for the last arg.

Benjamin C 2023-05-20T21:00:46.124879Z

Ah cool didn't know I could send nil, and I'm guessing this would have other problems:

(defmacro kid->layout-builder [fx-class fx-props mx-props & child]
  `(let [mx-kids (tiltontec.matrix.api/cFkids ~@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]
                                                            (~fx-class
                                                             ~(symbol ".builder")
                                                             (fx/as-dart-callback [_# constraints]
                                                                                  (fx/fx-render ctx (tiltontec.matrix.api/cFkids ~@child)))
                                                             ~@(let [kvs (for [[k# _#] fx-props]
                                                                           [(symbol (str "." (name k#)))
                                                                            `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                   (tiltontec.matrix.api/mget me ~k#))])]
                                                                 (apply concat kvs)))))
                                           mx-kids)))

kennytilton 2023-05-20T21:03:42.313569Z

Is this a new version we should work on? ^^^

Benjamin C 2023-05-20T21:04:20.563989Z

I think so, after nixing the let

Benjamin C 2023-05-20T21:04:44.995559Z

like so:

(defmacro kid->layout-builder [fx-class fx-props mx-props & 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]
                                                          (~fx-class
                                                           ~(symbol ".builder")
                                                           (fx/as-dart-callback [_# constraints]
                                                                                (fx/fx-render ctx (tiltontec.matrix.api/cFkids ~@child)))
                                                           ~@(let [kvs (for [[k# _#] fx-props]
                                                                         [(symbol (str "." (name k#)))
                                                                          `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                 (tiltontec.matrix.api/mget me ~k#))])]
                                                               (apply concat kvs)))))
                                         nil))

Benjamin C 2023-05-20T21:05:11.318949Z

The flutter ref can prob. be put back in as well, removed to simplify earlier

kennytilton 2023-05-20T21:05:29.193259Z

Ok, but now we can lose the trailing nil?

kennytilton 2023-05-20T21:06:05.404699Z

I am over here getting back up to speed on this builder pattern.

Benjamin C 2023-05-20T21:08:59.814139Z

with nil, :kids will be nil. If we instead use the let approach instead kids will be set, but I'm not sure if we will have problems or not because of the fx-render that happens in .builder arg?

kennytilton 2023-05-20T21:13:18.867459Z

I am looking at the todo app:

(defn todo-items []
  (fx/expanded
    ;; ^^^ sizer is required to join column, which demands children know their size
    (fx/list-view+builder
      {:padding     (m.EdgeInsets/all 0.0)
       :itemCount   (cF (count (mkids me)))
       :itemBuilder (cF (fx/as-is
                          (fn [ctx i]
                            ;; we must yield a native Flutter widget ready for Flutter, so we must "render" here,
                            (fx/fx-render ctx
                              (nth (mkids me) i)))))}
      {:name :lv-builder}
      (map todo-list-item
        (sort-by todo/td-created-at
          (todo/app-todos (my-app)))))))
list-view+builder uses:
(defmacro kids-for-builder [fx-class fx-props mx-props & children]
  (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]
                   (with-flutter-ref
                     (~fx-class
                       ~@(let [kvs (for [[k# _#] fx-props]
                                     [(symbol (str "." (name k#)))
                                      `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                         (tiltontec.matrix.api/mget me ~k#))])]
                           (apply concat kvs))))))
       (tiltontec.matrix.api/cFkids ~@children))))
Lemme remind myself why this does not fx-render the kids. brb

kennytilton 2023-05-20T21:19:29.561869Z

Aha. fx-render grabs the :fx-gen property to get the code that actually renders, and we can see ^^^ it just calls the constructor (of the parent) and sets the properties, ignoring children. One of the properties is sth like :itemBuilder which pulls in the kids. I cannot believe I wrote all this. It was exhausting, I remember. ðŸĪŊ

Benjamin C 2023-05-20T21:24:44.302539Z

Ah, okie dokie. Haha yaah when I first started perusing the fx part of f/mx I was just like ðŸ˜ĩ‍ðŸ’Ŧ

kennytilton 2023-05-20T21:29:14.347249Z

OK, compile is good, ready to give it a run.

👍ðŸŧ 1
kennytilton 2023-05-20T21:34:48.339579Z

OK, the usual: "Exception: No extension of protocol IFn found for type CBToResolve." So I need to figure out where to call fx-resolve on what.

Benjamin C 2023-05-20T21:38:03.193679Z

This might help?: I found if I pass in a m/Text instead of an fx/text

(xu/magical-layout ; step 1: actually compile
                        (m/Text "hello")))))))
I get Error: The method '$_invoke$0' isn't defined for the class 'Text'.

Benjamin C 2023-05-20T21:38:53.288709Z

using this as the factory:

(defmacro kid->layout-builder [fx-class fx-props mx-props & 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]
                                                          (~fx-class
                                                           ~(symbol ".builder")
                                                           (fx/as-dart-callback [_# constraints]
                                                                                (fx/fx-render ctx ~child))
                                                           ~@(let [kvs (for [[k# _#] fx-props]
                                                                         [(symbol (str "." (name k#)))
                                                                          `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                 (tiltontec.matrix.api/mget me ~k#))])]
                                                               (apply concat kvs)))))
                                         nil))

kennytilton 2023-05-20T21:40:14.746419Z

Actually, I am seeing the other builder examples use standard factories, but have properties like :builder or :itemBuilder . I think that is the way to go.

kennytilton 2023-05-20T21:42:40.121519Z

I am about to crash, but this example seems closest in that the widget has kids and an :itemBuilder:

(defn todo-items []
  (fx/expanded
    ;; ^^^ sizer is required to join column, which demands children know their size
    (fx/list-view+builder
      {:padding     (m.EdgeInsets/all 0.0)
       :itemCount   (cF (count (mkids me)))
       :itemBuilder (cF (fx/as-is
                          (fn [ctx i]
                            ;; we must yield a native Flutter widget ready for Flutter, so we must "render" here,
                            (fx/fx-render ctx
                              (nth (mkids me) i)))))}
      {:name :lv-builder}
      (map todo-list-item
        (sort-by todo/td-created-at
          (todo/app-todos (my-app)))))))
With just one kid you will not get the i parameter.

kennytilton 2023-05-20T21:45:38.541369Z

Maybe even closer:

(defn expanding-action-button [me anime & {:keys [action direction-degrees max-distance progress-key]}]
  (fx/animated-builder
    {:animation anime                                       ;; (mget (mx/fasc :fab) :expand-animation)
     :builder   (as-dart-callback [ctx child]
                  (let [progress ^m/CurvedAnimation anime #_(mget me :animation) #_(mget (mx/fasc :fab) :expand-animation)
                        offset (m.Offset/fromDirection
                                 (* direction-degrees (/ math/pi 180.00))
                                 (* (.-value progress) max-distance))]
                    ;; N.B! alpha widgets are welcome at leaves of the MX tree...
                    (f/widget
                      (f/nest
                        (m/Positioned
                          .right (+ 4.0 (.-dx offset))
                          .bottom (+ 4.0 (.-dy offset)))
                        (m.Transform/rotate
                          .angle (* (- 1.0 (.-value progress))
                                   math/pi 0.5))
                        child))))}
    {:name :ani-builder}
    (fx/fade-transition
      {:opacity anime #_(mget (mx/fasc :fab) :expand-animation)}
      (action-button
        :icon (:icon action)
        :onPressed (fx/in-my-context [me ctx]
                     (fx/->CBAsIs
                       #(show-action ctx action)))))))
The deftag:
(deftag tiltontec.flutter-mx.factory/k1-child-stateful animated-builder m/AnimatedBuilder)

Benjamin C 2023-05-20T21:47:40.180779Z

Hmm, so maybe this basic idea (it it actually can be made to work) could be generalized to other builder widgets as well thinking-face

kennytilton 2023-05-20T21:48:26.971269Z

Hang on. That ^^^ fx-gen makes the first kid into a child. Lemme chech sth.

Benjamin C 2023-05-20T21:50:52.838239Z

Oh, the apply convat kvs maybe trying to call the builder prop?

Benjamin C 2023-05-20T21:51:18.207449Z

Eh, nope

Benjamin C 2023-05-20T21:51:40.460879Z

forgot not passing that anymore anyway

Benjamin C 2023-05-20T21:52:11.340839Z

Note to self: I really should run code before I send chats :P

kennytilton 2023-05-20T21:52:56.320799Z

No, that is fine, it will just convert it to the function expected by .builder. I have to go watch the Preakness, but I am looking at what we have for fx/layout-builder . Did that not work for this use case?

Benjamin C 2023-05-20T21:55:30.170999Z

Aside from the wierd markNeedsBuild called during build stuff, it works :) Sorry, didn't mean to make it sound otherwise, this is just me trying to achieve aa more inline syntax.

Benjamin C 2023-05-20T21:57:34.512989Z

Hmm, off the top of my head, would it be feasible to make CBToResolve extend IFn and resolve + call?

kennytilton 2023-05-20T22:00:58.109959Z

"just me trying to achieve aa more inline syntax." Ah, so perhaps a new macro cobbled together from the todo items example, but does not expect i and just grabs the first kid? Gotta 🏃 !

👍ðŸŧ 1
1
Benjamin C 2023-05-20T22:09:23.266989Z

For when you return:

Benjamin C 2023-05-20T22:10:06.692039Z

This renders: 😁

(defmacro kid->layout-builder [fx-class fx-props mx-props & [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]
                     (~fx-class
                      ~(symbol ".builder")
                      (fn [_# constraints]
                        (fx/fx-render ctx ~child)))))
    nil))
Expanding back to fuller factory:
(defmacro kid->layout-builder [fx-class fx-props mx-props child]
  `(let [mx-kids (tiltontec.matrix.api/cFkids ~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]
                                                            (tiltontec.flutter-mx.factory/ctx-check (quote ~fx-class) me ctx)
                                                            (~fx-class
                                                             ~(symbol ".builder")
                                                             (fn [_# constraints]
                                                               (fx/fx-render ctx (mx/with-par me ~child)))
                                                             ~@(let [kvs (for [[k# _#] fx-props]
                                                                           [(symbol (str "." (name k#)))
                                                                            `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                                                                   (tiltontec.matrix.api/mget me ~k#))])]
                                                                 (apply concat kvs)))))
                                           mx-kids)))
Now onto step 2.

👏 1
kennytilton 2023-05-20T23:19:05.703369Z

Ain't macros grand? And we have only scratched the surface.

Benjamin C 2023-05-20T23:21:27.443239Z

There comes a time where nothing else comes close, and Flutter definately needs a lot of them to have some sanity. :P

Benjamin C 2023-05-20T23:23:52.770819Z

Yippy-yi-yay! Still have yet to polish/test thoroughly, but may I present to you: Magic Layout (alpha) â„Ēïļ ! ðŸĪŠ

(defmacro kid->layout-builder [fx-class fx-props mx-props child]
  `(let [mx-kids (tiltontec.matrix.api/cFkids ~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]
                       (tiltontec.flutter-mx.factory/ctx-check (quote ~fx-class) me ctx)
                       (~fx-class
                        ~(symbol ".builder")
                        (fn [_# ^m/BoxConstraints box-constraints#]
                          (let [min-h#          (.-minHeight box-constraints#)
                                min-w#          (.-minWidth box-constraints#)
                                ancestor-max-h# (or (get-prop-up me :max-h)
                                                    (-> m/MediaQuery (.of ctx) .-size .-height))
                                ancestor-max-w# (or (get-prop-up me :min-h)
                                                    (-> m/MediaQuery (.of ctx) .-size .-width))
                                max-h#          (min (.-maxHeight box-constraints#) ancestor-max-h#)
                                max-w#          (min (.-maxWidth box-constraints#) ancestor-max-w#)]
                            (swap! me assoc
                                   :min-h min-h# :max-h max-h#
                                   :min-w min-w# :max-w max-w#)
                            (fx/fx-render ctx (mx/with-par me ~child))))
                        ~@(let [kvs (for [[k# _#] fx-props]
                                      [(symbol (str "." (name k#)))
                                       `(tiltontec.flutter-mx.core/fx-resolve ~k# me ctx
                                                                              (tiltontec.matrix.api/mget me ~k#))])]
                            (apply concat kvs)))))
      mx-kids)))

🊄 1
Benjamin C 2023-05-20T23:25:14.343779Z

Since this is during build, I don't want to trigger any matrix reactivity, thus the swap! on me.

kennytilton 2023-05-20T23:33:04.347189Z

Grassshopper ready to leave MX temple! I was thinking swap!.

ðŸĪĢ 1
Benjamin C 2023-05-20T23:36:07.258129Z

I feel armed and dangerous now that I have a little handle on custom f/mx widgets -- bye bye flutter clutter :P Just need the careful, this was more addictive than hacking my emacs config.

kennytilton 2023-05-20T23:41:44.073699Z

Sorry, my memory is fading. Had you done Flutter from Dart before CLJD? Anyway, I do look at the clutter and marvel that it was tolerated at all. I guess it is one part "we are used to being abused" and one part "Web, mobile, and desktop in one? OMG!". Glad to see the first convert confirming the CLJD opportunity.

1
Benjamin C 2023-05-20T23:44:21.134149Z

Haha, yeah I think your spot on with that recipe.

Benjamin C 2023-05-20T23:45:37.798459Z

No, I haven't used flutter before cljd, I looked at it with my last project, and decided I preferred the pain of react-native (albeit buffered a little by using clojurescript, it's still a mess).

Benjamin C 2023-05-20T23:47:16.483589Z

As far I know the only flutter -> cljd convert so far is @windlejacob12

Benjamin C 2023-05-20T23:53:21.981509Z

Hmm, seems I didn't get the :kids quite right...

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _Exception was thrown building LayoutBuilder:
Exception: MXAPI_COMPUTE_CYCLE_DETECTED> cyclic dependency detected while computing prop ' :kids '
of model ' anon '.
 ...> formula for  :kids :

Benjamin C 2023-05-20T23:57:10.208229Z

Only happens when I add the mget

Benjamin C 2023-05-20T23:57:45.551789Z

Or rather the (get-prop-up ,,,) from before.

Benjamin C 2023-05-21T00:00:42.157989Z

For now I've worked around it my passing nil instead of mx-kids, but I'd definitely be interested in a real solution.

Benjamin C 2023-05-21T00:04:46.772089Z

Something I got wrong in the fmnavig, perchance?

(defn first-fm-up-with-prop [me prop]
  (mx/fm-navig #(not (nil? (mx/mget? % prop))) me :me? false? :up? true :inside? false))

(defn get-prop-up [me prop]
  (when-let [first-parent-with-prop (first-fm-up-with-prop me prop)]
    (mget first-parent-with-prop prop)))

kennytilton 2023-05-21T00:13:43.532379Z

What is the new code? A change to make-app?

Benjamin C 2023-05-21T00:14:13.656939Z

Oops sorry, forgot to paste example: just a sec.

kennytilton 2023-05-21T00:14:20.971389Z

The navig looks OK at first blush.

Benjamin C 2023-05-21T00:20:46.619899Z

Heh, repro works fine, time to get more elaborate :P

Benjamin C 2023-05-21T00:41:19.388249Z

Oh, I think I found it... its not the kids, it's the me , methinks:

(defn make-app []
  (let [title "Magic layout - Dynamic Text Size - wip"]
    (fx/material-app {:title title}
                     (fx/scaffold
                      {:appBar (fx/app-bar {:title (fx/text title)})}
                      {:name :scaffo}
                      (fx/column
                       (fx/magical-layout
                        {} {:name :magic?-1}
                        (fx/container {:decoration (m/BoxDecoration .color m/Colors.blue)
                                       :width      (or (xu/get-prop-up me :max-w) 200)}
                                      (fx/text (str [:container (deref (:parent @me))]))
                                      ))
                       (fx/magical-layout
                        {} {:name :magic?-2}
                        (fx/container {:decoration (m/BoxDecoration .color m/Colors.blue)
                                       :width      (or (xu/get-prop-up me :max-w) 200)}
                                      (fx/text (str [:magical-layout (deref (:parent (deref (:parent @me))))]))
                                      )))))))

Benjamin C 2023-05-21T00:41:56.826389Z

(edited to change fxx/ to fx/)

kennytilton 2023-05-21T00:45:51.809899Z

Ya gotta watch out for me! https://github.com/kennytilton/web-mx/wiki/Who%3F-Me%3F Do we need a cF around (or (xu/get-prop-up me :max-w) 200)?

👀 1
Benjamin C 2023-05-21T00:47:05.630819Z

Ohh, not sure, I may have been missing those in my whole app!

kennytilton 2023-05-21T00:47:21.807089Z

I'll give that make-app a try.

Benjamin C 2023-05-21T00:47:41.699969Z

I think I mistakenly thought they were implicit same as child/children

kennytilton 2023-05-21T00:49:59.598799Z

A too-high asc-wise me is OK if what we seek is higher than the me we take by mistake.

Benjamin C 2023-05-21T00:51:06.991489Z

Yes, that was why my first repro failed to repro

kennytilton 2023-05-21T00:51:45.789859Z

I have to scroll back ang get your get-prop-up. Is that inclusive of the me param?

Benjamin C 2023-05-21T00:52:11.572359Z

not in the navig iiuc

Benjamin C 2023-05-21T00:52:24.903399Z

(defn first-fm-up-with-prop [me prop] (mx/fm-navig #(not (nil? (mx/mget? % prop))) me :me? false? :up? true :inside? false)) (defn get-prop-up [me prop] (when-let [first-parent-with-prop (first-fm-up-with-prop me prop)] (mget first-parent-with-prop prop)))

Benjamin C 2023-05-21T00:53:06.553139Z

Oh, yes it is: typo in there

Benjamin C 2023-05-21T00:54:58.827099Z

false? ; => truthy :P

kennytilton 2023-05-21T00:57:05.762389Z

Hmm. I see :me? false:

(defn first-fm-up-with-prop [me prop]
  (mx/fm-navig #(not (nil? (mx/mget? % prop))) me :me? false? :up? true :inside? false))
Oh, Ok. So now we have?:
(defn first-fm-up-with-prop [me prop]
  (mx/fm-navig #(not (nil? (mx/mget? % prop))) me :me? false :up? true :inside? false))
That would not be inclusive.

Benjamin C 2023-05-21T00:57:41.571059Z

Now, yes, so far same error.

kennytilton 2023-05-21T01:03:19.087719Z

I see the two magicals as siblings under the column. Intended? That will run afoul of fm-navig "up".

Benjamin C 2023-05-21T01:04:22.886099Z

Ooh, yes, was intended, didn't know that would mess with up. Also was the first repro of the cycle error.

kennytilton 2023-05-21T01:06:08.928129Z

Recall that "up" is really "outside" the tree with me as the root. So my sibling is outside me [hence the cycle, I think]. fm-navig does not have an "ascendant-only" capability. I am zonked, but suggest you do an fasc-prop hack.

Benjamin C 2023-05-21T01:08:13.423999Z

Oh, me is the root! Now I get it.

Benjamin C 2023-05-21T01:09:52.587679Z

Alright, thank you so much for all your help 🙂

kennytilton 2023-05-21T01:14:44.783999Z

heh-heh, you are helping me to improve MX! Thank you!

👍ðŸŧ 1
Benjamin C 2023-05-21T01:36:12.579339Z

Monkey-patch to get by:

(defn get-prop-up
  ([me prop]
   (get-prop-up me prop nil))
  ([me prop maybe-found]
   (if (or maybe-found (not (:parent @me)))
     maybe-found
     (recur (:parent @me) prop (mx/mget? me prop)))))

Benjamin C 2023-05-21T02:59:06.188689Z

Also improved magical-layout that does't "shrink" because of history:

Benjamin C 2023-05-21T03:36:26.954839Z

as "magical" as it feels esp. compared the the headache I had prior, I feel like with-layoutmight be a better fitting name.

kennytilton 2023-05-23T07:20:03.552499Z

Ah!!!!!!!!!! So instead of (container....) being evaluated when the def w-in-def is evaluated, it runs when (w-in-def ...) is called, and the special *parent* is bound to The Right Thing(tm)! Perfect, Now what about that naked (/ (xu/get-prop-up me :max-w) 3) . Can we get a cF around that?

kennytilton 2023-05-23T07:55:27.199949Z

btw, this is not the first time this has happened, but I am greatly encouraged by folks showing up withworking MX projects who I never knew about until they showed up! Makes me think MX is not too hard to pick up. But this can lead to some non-idiomatic code, and my apologies for not picking up that def sooner. Do you follow now why the defn works so much differently? In brief, MX works dynamically, and f/mx or web/mx macros are especially run-time beasts, so when code runs matters. Good luck with the deadline! Have you figured out how to deploy?

kennytilton 2023-05-23T12:21:14.400479Z

Also, have we looked at resource leaks? I added the quiesce API to support clean-ups, but have not documented it. I am also concerned about the final image size. eg, Does all that macrology expand into bloat? I imagine a few macro-helping functions can help, but at POC-time I was just trying to get the thing working. Caveat Shippers!

Benjamin C 2023-05-23T16:42:47.790679Z

> Perfect, Now what about that naked (/ (xu/get-prop-up me :max-w) 3) . Can we get a cF around that? Sure thing. :) Seems with layout builder, most of the time it's not needed, because it's forcing a rebuild, nothings out-of-date. However there is a certain point where enough layers away and certain abstracted children need the cF, presumably because some flutter mech. recognizes it could be more efficient and not rebuild that child. > Makes me think MX is not too hard to pick up. Yep! Originally, I was a bit skeptical as it was "smallstream" (relative to clojure's already "smallstream"), but it's proved to be so useful I want it everywhere, even though it probably wouldn't fit on the 8kb ram micro controllers we're using :P. > my apologies for not picking up that def sooner. There was no sooner, this was the first time I realized it was relevant to put in the repro as I had done that bit a long time ago. :) > Do you follow now why the defn works so much differently? Yep! Makes a lot of sense, it was a newbie mistake on my part. (Newbie to programming, not to MX). > Good luck with the deadline! Have you figured out how to deploy? Thanks! - Yes, one thing I do appreciate about flutter is that the docs are nicely thorough. > Also, have we looked at resource leaks? I added the quiesce API to support clean-ups, but have not documented it. Not really. Flutter has a profiler build option, I'll give that a shot at some point. > Does all that macrology expand into bloat? Not sure, but it's not too much for this app, at least. About 27mb for a release build. (or 47 for a bundle that includes each abi). Oh, is the quiesce api user-facing? 👀 I assumed it was also magical. :P

kennytilton 2023-05-23T17:03:47.583819Z

Oh, is the quiesce api user-facing?  

I assumed it was also magical. :P
I suppose it could be. Here was the first time I thought to worry about resource leaks:
:msg-rcvd (cF+n [:ephemeral? true
                 :on-quiesce (fn [cell]
                               (when-let [sub (:subscription @cell)]
                                 (.cancel ^#/(async/StreamSubscription void) sub)))
                 :watch (fn [_ me new-source old-source cell]
                          (when (= old-source mx/unbound)
                            (let [sub (.listen (.-stream ^async/StreamController new-source)
                                        (fn [^String msg]
                                          (mset! me :msg-rcvd msg)))]
                              (rmap-set! [:subscription cell] sub))))]
            (mget (fm* :msg-sender) :msg-stream))
(Later it occurred to me that the formula itself could have subscribed, then I would not need to stash the subscription in a cell property :subscription.) Anyway, the Flutter doc says it is wise to cancel subscriptions when no longer needed, so I thought I would handle quiescing. As for automating, I think we can think about having cells/models have a meta property :resources where a widget could keep those. Then, yeah, at least the cleanup would be more automatic. Version 2!

👍ðŸŧ 1
Benjamin C 2023-05-23T17:10:06.251509Z

> Flutter doc says it is wise So maybe I can get by without it right at first 😅

kennytilton 2023-05-23T17:14:48.886329Z

I guess the thing to look out for is "After X hours it gets pretty slow, but we turn it off and restart and it flies again."

👍ðŸŧ 1
Benjamin C 2023-05-23T23:53:33.562069Z

Ah, now I remember why I was using defs -- seems to make hot reload work a lot better. It's surprising to me just how well it worked, given that it seems it shouldn't ðŸĪ·ðŸŧ‍♂ïļ

kennytilton 2023-05-23T23:58:51.451539Z

Hmm, maybe there is a window for improvement. Can you describe what seemed better?

Benjamin C 2023-05-24T00:00:43.856649Z

Faster. My guess is, with a def it only re-evals if it changes. When a fn call, re-evals every time period.

kennytilton 2023-05-24T00:05:57.263129Z

I suppose we could offer as a performance tip: 'If we have a self-contained tree of f/mx widgets -- no formulas searching outside the tree -- and we need to add it to our app only once, define it in a def.' ðŸĪ”

Benjamin C 2023-05-24T00:33:43.288309Z

Wait a minute, Try this:

(def w-in-def
  (fx/container
   {:decoration (m/BoxDecoration .color m/Colors.blue)
    :width      (cF (/ (xu/get-prop-up me :max-w) 3))}
   (fx/text (str "If this renders, surprise! :scaffo 's :isolated value:  " (xu/get-prop-up me :isolated)))))

(defn make-app []
  (let [title "Magic layout - Dynamic Text Size - wip"]
    (fx/material-app
     {:title title}
     (fx/scaffold
      {:appBar (fx/app-bar {:title (fx/text title)})}
      {:name :scaffo
       :max-w 900
       :isolated "Hello, can you see me, w-in-def?"}
      (fx/center
       (fx/column
        (fx/text "always visible")
        w-in-def))))))

👀 1
Benjamin C 2023-05-24T00:39:12.041139Z

^ outside the tree, no?

Benjamin C 2023-05-24T00:43:18.647489Z

To make sure it's not "stuck in time"

(def w-in-def
  (fx/container
   {:decoration (m/BoxDecoration .color m/Colors.blue)
    :width      (cF (/ (xu/get-prop-up me :max-w) 3))}
   (fx/text (str "If this renders, surprise! :scaffo 's :isolated value:  " (xu/get-prop-up me :isolated)))))

(defn make-app []
  (let [title "Magic layout - Dynamic Text Size - wip"]
    (fx/material-app
     {:title title}
     (fx/scaffold
      {:appBar (fx/app-bar {:title (fx/text title)})}
      {:name :scaffo
       :max-w 900
       :isolated (cI "Hello, can you see me, w-in-def? .... this message overriden")}
      (fx/center
       (fx/column
        (fx/text "always visible")
        w-in-def
        (do (with-cc :test (mset! (fasc :scaffo) :isolated "Now all you see is this, because the matrix somehow works with def iso'ed trees, no?"))
            (fx/text "the end"))))))))

Benjamin C 2023-05-24T00:44:27.785069Z

BTW, Probably not a finished product perf boost, just a hot-reload perf. boost. Perhaps only really noticeable an my wimpy phone :P

Benjamin C 2023-05-24T00:48:44.616949Z

Maybe it works because fx-resolve/fx-gen doesn't render the defed code until it's mounted or something like that?

Benjamin C 2023-05-24T01:04:52.565139Z

This allows for direct referening of matrixs, instead of tree searching fwiw:

(def w-in-def
  (fx/container
   {:decoration (m/BoxDecoration .color m/Colors.blue)
    :width      (cF (/ (xu/get-prop-up me :max-w) 3))}
   (do (dc/print scaff)
       ;; Here we access the fx/scaffold matrix directly
       (with-cc :test (mset! scaff :isolated "Now all you see is this, because the matrix somehow works with def iso'ed trees, no?"))
       (fx/text (str "If this renders, surprise! :scaffo 's :isolated value:  " (xu/get-prop-up me :isolated))))))

(def scaff
  (fx/scaffold
   {:appBar (fx/app-bar {:title (fx/text "Why Hello")})}
   {:name     :scaffo
    :max-w    900
    :isolated (cI "Hello, can you see me, w-in-def? .... this message overriden")}
   (fx/center
    (fx/column
     (fx/text "always visible")
     w-in-def
     (fx/text "the end")))))

(defn make-app [] (let [title "Magic layout - Dynamic Text Size - wip"]
                (fx/material-app
                 {:title title}
                 scaff)))

kennytilton 2023-05-24T06:23:48.886769Z

Yikes! def is lazy! In CLJD, not CLJ or Common Lisp. CLJS has not been checked. Asking the lads in a sec...

kennytilton 2023-05-24T06:44:50.289869Z

Heads up, CLJD fans, def is lazy! https://clojurians.slack.com/archives/C03A6GE8D32/p1684910461277039

kennytilton 2023-05-24T06:51:59.092049Z

Anyway, assuming def stays lazy because of the nature of compilation to Dart...well, I will explore some more. I am curious if the expression is evaluated every time the deffed term is accessed. If not, using w-in-def twice would fail. btw, @zenflowapp, I am curious now about what difference you saw moving from def to defn. Maybe this gets back to hot restart/reload? I think no matter what we learn, I would stay away from (def xyz (fx/any-widget...))!! 🙀

Benjamin C 2023-05-20T01:20:32.453759Z

thinking-face Good question! I've think I've read somewhere that capturing the context was a common newbie mistake among darters, but the reason given was that you could never be sure where your widget was in the tree. That the context is a handle to the location of a widget in the widget tree. Aha, in the docs: > Avoid storing instances of BuildContexts because they may become invalid if the widget they are associated with is unmounted from the widget tree. So presumably, so long as we handle discarding the context on unmount, we'd be okay?

Benjamin C 2023-05-20T01:31:12.923599Z

Perhaps worth mentioning: The main reason this comes to mind again and again, is how many tries it takes me to figure out where I need to place an (fx/in-my-context [me ctx] ,,,) where the CBToResolve will actually resolve :P Sometimes I just give up and try a different approach.

Benjamin C 2023-05-20T01:36:07.980469Z

Seems where it finally works is a fair bit up from where I want to use it, and it pulls me out of flow state a bit. But it is a pet-peeve/convenience thing mostly, not a show-stopper.

Benjamin C 2023-05-22T17:26:32.140399Z

Hmm, :builder-watch sounds like a good idea! > loses track of the :max-w I've had a situation like that here too. Perhaps because we're using swap! the cF doesn't think anything's changed and uses a memoized value?

Benjamin C 2023-05-22T17:27:16.367009Z

(Seems to only happen in a cF if I'm not mistaken.) Edit: Oh nvm, there must be another factor here.

Benjamin C 2023-05-22T17:36:41.002169Z

Latest factory:

kennytilton 2023-05-22T17:51:48.817889Z

Thx, I will give this a try. I need a break from deep cells internals occasioned by the novel support for :async? cells. Almost there, but a break will help. I gotta think we are getting a re-gen of a widget along the way, so the cached max gets lost. I have improved the diagnostics available, let me see what I can see.

kennytilton 2023-05-22T17:52:25.201909Z

Did the make-app change?

kennytilton 2023-05-22T17:59:15.808639Z

Oh, and what about this?

btw, did you mean the two magicals to be nested one under the other? The make-app I have has them both with the column as the parent. I recall you mentioning nesting.
I am concerned about interacting issues, tho I grok it should work either way. I will carry on with the two as siblings.

Benjamin C 2023-05-22T18:00:09.879819Z

Yes, should â„Ēïļ work either way :P

Benjamin C 2023-05-22T18:00:22.838259Z

I'll have a new make-app example soon I think

kennytilton 2023-05-22T18:03:26.140249Z

OK, I'll play with the one I have in the meantime.

kennytilton 2023-05-22T18:21:56.563399Z

Might just be a logic error. Where do we take the max of two values? Reformatted:

(let [...
      max-w# (if (= dart:core/double.infinity current-max-w#)
                 ancestor-max-w#
                 current-max-w#))
     ....

kennytilton 2023-05-22T18:26:42.944699Z

This seems OK:

(if (= dart:core/double.infinity current-max-w#)
  ancestor-max-w#
  (if ancestor-max-w#
    (max ancestor-max-w# current-max-w#)
    current-max-w#))

Benjamin C 2023-05-22T18:29:41.750499Z

So, were not actually after the max of two values. The only reason ancestor is there at all is because fx/column and row and several others have double.infinite as the max, which is not helpful for using as a value for sizing text or anything else layout-wise. So ancestor is there to work around that. I propbably should put the media query back in as a default for the ancestor, in case one forgets to add one above an double.infinite max-w/h

kennytilton 2023-05-22T18:31:50.837489Z

OK, well the original code is correctly toggling between alternating current-max's, not tracking any max reached during the widget lifetime.

Benjamin C 2023-05-22T18:33:33.452739Z

Oh, I missed your comment "this seems OK", let me take a look...

Benjamin C 2023-05-22T18:40:07.042519Z

Oh, maybe it means that get-prop-up is pulling up a value from previous build on the current widget...

Benjamin C 2023-05-22T18:44:43.567259Z

or even old value on parent widget would cause it.

Benjamin C 2023-05-22T18:45:01.895329Z

My assumption was parent would build first

Benjamin C 2023-05-22T18:45:10.517529Z

maybe not in some cases

kennytilton 2023-05-22T18:45:22.218169Z

I guess I a lost. Is this a use case? My sim is vertical, the Max-w is 430 or so. I rotate the sim. The max-w shows as 930. Now I rotate back to vertical. What should the max-w be?

Benjamin C 2023-05-22T18:45:42.781519Z

430

Benjamin C 2023-05-22T18:46:02.890879Z

We're not after max-w of all time :P

kennytilton 2023-05-22T18:47:14.325669Z

OK, that is what I was seeing before these patches I sent. I thought we wanted to track the max ever seen. Anyway, are we OK then with this solution?

Benjamin C 2023-05-22T18:47:16.794469Z

Should be fine as a native-app btw, that way you can resize the window and see live update

Benjamin C 2023-05-22T18:48:23.832109Z

Oh! Sorry, I really need to improve my communiction skills/code-comments

kennytilton 2023-05-22T18:51:44.711579Z

np! Natural language is a terrible medium. There is a reason the military developed that jargon.

Benjamin C 2023-05-22T18:52:20.817909Z

Should be mostly okay then. I do have a weird thing going on where in one case I have a thing where it works on first layout, but not on resize, and I think that is something to do with mx not detecting that :max-w changed due to using swap, so it gives the old value.

kennytilton 2023-05-22T18:57:44.209739Z

Come to think of it, this has me puzzled:

(defn get-prop-up
  ([me prop]
   (get-prop-up me prop nil))
  ([me prop maybe-found]
   (if (or maybe-found (not (:parent @me)))
     maybe-found
     (recur (:parent @me) prop (mx/mget? me prop)))))
If I suppy a non-nil maybe-found, that is what gets returned. It is not behaving as a default.

Benjamin C 2023-05-22T18:59:18.659339Z

Okay right about now I'm really missing not having a repl :P I'll take a look

Benjamin C 2023-05-22T18:59:59.022329Z

Wait, it's returning the fn itself?

kennytilton 2023-05-22T19:01:50.852869Z

I was expecting:

(defn get-prop-up
  ([me prop]
   (get-prop-up me prop nil))
  ([me prop default-value]
   (or (mx/mget? me prop)
     (if (:parent @me)
       (recur (:parent @me) prop default-value)
       default-value))))

kennytilton 2023-05-22T19:07:14.860189Z

Yeah, I just throw code in the main function and do a hot restart when I need a REPL. It's OK.

Benjamin C 2023-05-22T19:07:40.470199Z

Oh, that reads much more clearly, I like it!

kennytilton 2023-05-22T19:09:33.464689Z

I'm not smart like you guys, I have to code like a five year-old or my head explodes.

Benjamin C 2023-05-22T19:12:16.855839Z

Haha, mine isn't smart coding, it's coding-after-my-brain-is-far-spent-and-i-know-it-should-work-because-ive-used-structual-editing-to-modify-the-simple-use-case--to-its-now-unreadable-form---so-it-should-work :P

kennytilton 2023-05-22T19:16:37.966649Z

Ok, I am headed out for some R&R, I'll check when I get back for any updates. Have fun!

👍ðŸŧ 1
Benjamin C 2023-05-22T20:01:38.274799Z

I'm suspicious that using a direct fn instead of as-dart-callback is causing funny things to happen to me. Or, more accurately, what me is mein the build phase.

Benjamin C 2023-05-22T20:23:22.851319Z

Aha, repro:

(def w-in-def
  (fx/container
   {:decoration (m/BoxDecoration .color m/Colors.blue)
    :width      (cF (/ (xu/get-prop-up me :max-w) 3))}
   (fx/text (str (xu/get-prop-up me :max-w)))))

(defn make-app []
  (let [title "Magic layout - Dynamic Text Size - wip"]
    (fx/material-app
     {:title title}
     (fx/scaffold
      {:appBar (fx/app-bar {:title (fx/text title)})}
      {:name :scaffo}
      (fxx/magical-layout
       (fx/column
        (fx/container
         {:decoration (m/BoxDecoration .color m/Colors.blue)
          :width      (/ (xu/get-prop-up me :max-w) 3)}
         (fx/text (str (xu/get-prop-up me :max-w))))
        w-in-def))))))
max-w/his stuck to initial layout when you use a widget in a def. Putting it in a defn instead works as expected.

Benjamin C 2023-05-22T20:25:06.852939Z

For now I'll just use defns, since the deadline is soon and it works â„Ēïļ

kennytilton 2023-05-22T22:04:49.886599Z

You know, I have been puzzling over this:

(def w-in-def
  (fx/container
   {:decoration (m/BoxDecoration .color m/Colors.blue)
    :width      (cF (/ (xu/get-prop-up me :max-w) 3))}
   (fx/text (str (xu/get-prop-up me :max-w)))))
...followed by using w-in-def in the child/kids position. When did we come up with that? I ask because in the example, the w-in-def container will be parentless, because parent gets established when the widget factory make-fx runs, calling model.core/make, which starts out like this:
(defn make [& arg-list]
  ;;(prn :make-entry (count arg-list) (first arg-list))
  (cond
    (odd? (count arg-list)) (apply make :mx-type arg-list)
    :else
    (do
      (let [iargs (apply hash-map arg-list)
            me (atom
                 (let [mdmap (merge {:parent *md-parent* ;; <===================
                                     :host   *md-host*}
....
I will look around to see where that pattern originated. It would be fine (I think) if we were not now searching up the ascendant tree looking for stuff. Also, in:
(fx/container
         {:decoration (m/BoxDecoration .color m/Colors.blue)
          :width      (/ (xu/get-prop-up me :max-w) 3)}
         (fx/text (str (xu/get-prop-up me :max-w))))
...I am concerned about the :width value not being wrapped in (cF ....). That means the nearest cell is the dependent, whch would be the hidden :kids formula for the next guy up, the column. It is OK, btw, that in (fx/text (str (xu/get-prop-up me :max-w)) the str form is not wrapped in a cF, because it is in the :kids position of the fx/text, and kids are all wrapped in cF by my GUI element macros, HTML or Flutter. I know you have a deadline, but if you get me your latest repro I will play with it. It might be wise to sort this out if it is just a couple of no-brainer adjustments. Your call.

Benjamin C 2023-05-23T00:08:50.661309Z

> When did we come up with that? Back when I first started experimenting with f/mx and saw that it seemed to work :P Clearly a bad idea on my part ðŸĪŠ .

Benjamin C 2023-05-23T00:10:04.695789Z

Now that I'm using defn s it's working great :)

logbot 2023-05-20T04:44:34.349179Z

@logbot has joined the channel

2023-05-20T04:44:41.959799Z

@zulip-mirror-bot has joined the channel

seancorfield 2023-05-20T04:45:39.249889Z

point_up::skin-tone-2 That will ensure future content here in #matrix is mirrored to the ClojureVerse logs and to Zulip. It would be a shame for all this knowledge to be lost if we lose Pro status later this year.

👍ðŸŧ 1
🙏 2
🙏ðŸŧ 1