Fork me on GitHub
#membrane
<
2020-08-27
>
genekim04:08:48

@smith.adriane Thank you!!! Wow, trying it right now!

phronmophobic04:08:36

I forgot to mention you'll need to update you membrane dependency to [com.phronemophobic/membrane "0.9.12-beta"]

genekim04:08:44

Wow!!! It works!!! Not quite sure I understand how this magic works… Amazing! Mouse scrolling is reversed — on mac trackpad, text scrolls opposite way expected…. Trying to flip some signs to see if it fixes it. 🙂

genekim04:08:07

@smith.adriane So funny — it’s so autonomic, it’s difficult to remember which way textboxes are “supposed” to scroll! 😆

phronmophobic04:08:26

I think that's because I got used to the wrong way a long time ago and probably coded it to work the wrong way

phronmophobic04:08:45

mac books switched it at some point

genekim04:08:45

That’s super funny — so this bypasses all the native widget mouse handling… far out. 🙂 Stand by…. hopefully will have positive result shortly!

phronmophobic04:08:26

it's not a great fix, but you can change the scroll direction by wrapping the scrollview with:

(defn fix-scroll [elem]
  (ui/on-scroll (fn [[sx sy]]
                  (ui/scroll elem [(- sx) (- sy)]))
                elem))
eg:
(defn test-scrollview []
  [(ui/translate 10 10
                 (fix-scroll
                  (get-scrollview :my-scrollview [300 300]
                                  (ui/label lorem-ipsum))))])

genekim04:08:19

@smith.adriane Holy cow, that’s so helpful. I was studying how get-scrollview works…. Do I understand that you’re putting EDN s-expressions into the event dispatch? e.g., (list 'nil->val [0 0]). Just curious: why do this instead of putting.. I dunno.. anonymous functions instead? (LISPs are amazing…)

phronmophobic05:08:45

that's a good question

phronmophobic05:08:36

the way events work is that each events are a pure function like (fn [elem event] effects) . as the simplest example, here's the checkbox code:

(defui checkbox
  "Checkbox component."
  [& {:keys [checked?]}]
  (on
   :mouse-down
   (fn [_]
     [[::toggle $checked?]])
   (ui/checkbox checked?)))

phronmophobic05:08:55

mouse-down is a pure function that says returns what effects the checkbox proposes given a mouse-down event:

> (ui/mouse-down (membrane.basic-components/checkbox :checked true ) [0 0])
([:membrane.basic-components/toggle [:membrane.component/unknown]])

phronmophobic05:08:07

to make checkbox a pure function, it not only needs to know the value of checked, but it needs an identifier for the checked? property. for membrane.component, I use lenses

phronmophobic05:08:09

there's a bunch of macrology in membrane.component that automatically tracks where property values are derived from so you don't have to worry about it, but you can also pass those values directly:

> (ui/mouse-down (membrane.basic-components/checkbox :checked? true :$checked? ['ATOM :done?] ) [0 0])
([:membrane.basic-components/toggle [ATOM :done?]])

phronmophobic05:08:05

that's what the dollar sign prefix does. the proposed effect says to toggle the path [ATOM :done?]

phronmophobic05:08:35

the path is similar to a keypath like you use in get-in or assoc-in.

phronmophobic05:08:01

lenses give you a little more power than keypaths. if you're familiar with specter, that's what I use under the hood lenses give you a little more power than just walking an associative structure. if you're familiar with

phronmophobic05:08:55

i'm not sure I'm making any sense

phronmophobic05:08:46

regarding the (list 'nil->val [0 0]). it's part of specifying the identity of the :offset property of the scroll view

:$offset [(list 'get sid) :offset (list 'nil->val [0 0])]

genekim05:08:30

:exploding_head: Very cool…. It all works! Thanks so much for all this help — I will create a new sample program, using all of these constructs, and put in a couple of suggestions for the docs in a pull request. Super fun!!!

phronmophobic05:08:48

so it's saying if you want to update the :offset state, tell me this path back. when I get this back, I'll do the equivalent of (-> state (get sid) :offset (or [0 0]))

genekim05:08:19

…okay, wow, never thought I’d actually see Haskell-like lenses in real life, let alone in something UI-related. I’m copying this off to study more tomorrow! In the meantime, I’m going to hack away at the app for a bit! (Note to self: investigate potentially strange behavior around changing subscriptions, which seem to require a REPL restart…) Have a great night!!!

phronmophobic05:08:48

the membrane.component is a little offbeat and deserves its own longer/better explanation which is in the works.

phronmophobic05:08:07

have a great night!

genekim05:08:42

I’m making some great progress now! Another question, which hopefully has much shorter answer — if I want a scrollview, but wraps text, is there an easy way to do that? (I’m using to print out paragraphs of text…) @smith.adriane

phronmophobic05:08:22

I thought that's what the example did:

(defn test-scrollview []
  [(ui/translate 10 10
                 (fix-scroll
                  (get-scrollview :my-scrollview [300 300]
                                  (ui/label lorem-ipsum))))])

phronmophobic05:08:43

and just replace lorem-ipsum with whatever text you're trying to display

phronmophobic05:08:07

or maybe i'm missing some other requirement

genekim05:08:58

…hang on… let me post a screenshot… text that exceeds screen width is clipped, so you have to scroll right. Would love it if it wraps the text to the next line…

phronmophobic05:08:47

right, you can word wrap before passing to the label. I think I have some code that does that. one sec..

genekim05:08:59

Hahaha. You already have code for that? That’s super! PS: it occurs to me that you’re having to re-implement the functionality of almost all of the native windowing elements. I’m not sure whether to keep asking for these changes (which I’m super grateful for!!), or if this signals that you’re doomed to endlessly have to rebuild the wheel that every window manager/window framework has already built… But this is very gratifying to see come together!

phronmophobic06:08:35

I thought I had that, but it uses an apache lang library that's not included and I don't remember what the maven dependency is

phronmophobic06:08:57

I think right now, there's some creature comforts missing, but I think(hope) that eventually you get to the a place where you have 80-90% of what people expect out of the box

genekim06:08:17

Roger that! I’ll come up with something in the short term — will keep you posted! Catch you soon!!!

phronmophobic06:08:55

I found this old code as well:

(defn line-wrap [s n]
  (loop [s (seq s)
         current-line []
         lines []
         i 0]
    (if s
      (let [c (first s)]
        (cond

          (= c \newline)
          (do
            
            (recur (next s)
                   []
                   (conj lines current-line)
                   0))

          (>= i n)
          (recur s
                 []
                 (conj lines current-line)
                 0)

          :else
          (recur (next s)
                 (conj current-line c)
                 lines
                 (inc i)))
        
        )
      (clojure.string/join "\n" (map (partial apply str) lines)))))

(def line-wrap-memo (memoize line-wrap))

(defn test-scrollview []
  [(ui/translate 10 10
                 (fix-scroll
                  (get-scrollview :my-scrollview [300 300]
                                  (ui/label (line-wrap-memo lorem-ipsum 20)))))])

phronmophobic06:08:05

it's not perfect since it doesn't it will only necessarily work for non monospaced fonts

genekim06:08:49

Yep! I will either use yours or the WordUtils.wrap() in org.apache.commons.text…. tomorrow. Have a great night!!! PS: hopefully I’ll have my toy app done tomorrow, and I may redo it in cljfx, and compare/contrast, and write it up. I really love the feeling of doing everything without using clojurescript for once!