Giter Site home page Giter Site logo

Comments (11)

Bogdanp avatar Bogdanp commented on June 20, 2024 1

This is a limitation of dyn-view, and one of the reasons it's not documented yet/why I'm not sure it's a good idea. The problem is that while it can discover what dependencies the generated views have, it has no way to register those deps with the renderer. Probably the easiest fix would be to make dyn-view add its own observers to dependencies reported by its children, but I'll have to sit down and think that through in case it would cause other problems. In the mean time, using obs-combine is the right approach here, though you also have to make sure your monster group view uses the ability decks value from the combined observable and not the main one (if you don't, things might work out most of the time, but you're going to be depending on a race between the observables).

from racket-gui-easy.

Bogdanp avatar Bogdanp commented on June 20, 2024 1

I just pushed a set of changes to track hidden deps in dyn-views and to make it so that if-view (and derivatives like cond-view and case-view) short circuit. This should make it easier to create disjoint views like you're trying to do, though there are some caveats still:

;; While the `case-view' short circuits, changing the underlying type
;; of an observable isn't a completely safe operation because derived
;; observables aren't immediately garbage-collected when a view is
;; destroyed.
;;
;; For example, when `@current-character' is a `human', the
;; `human-editor' procedure creates a derived obervable that maps
;; `@current-character' to a string name using `human-name'. After
;; that view is replaced, that mapping lingers for some time until it
;; is garbage-collected, and if the "type" of character changes, it
;; raises an error asynchronously. That error can be safely ignored
;; since it's on a different thread, but that's not exactly pretty.
;; Instead, we use this procedure to ensure disjoint views always get
;; observables of the correct type by plugging in dummy values when
;; the type changes.

from racket-gui-easy.

Bogdanp avatar Bogdanp commented on June 20, 2024 1

Yes, I think they should generally be avoided. Ultimately, views are objects with internal mutable state so re-using the same view can be problematic.

In that case specifically, if-view calls destroy on its children when they get replaced, so the static view would get torn down after its first use and on subsequent uses it would appear empty. This would've been a problem before this set of commits too, but commit bebc226 makes it more apparent since it removes children from containers to avoid retaining them unnecessarily.

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024 1

Thank you for this; unless you feel strongly otherwise, I'm going to close this issue because I was successfully able to update to 0.5 and use a cond-view where I had this dyn-view before. 🎉 ❤️

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024

This is a limitation of dyn-view, and one of the reasons it's not documented yet/why I'm not sure it's a good idea. The problem is that while it can discover what dependencies the generated views have, it has no way to register those deps with the renderer. Probably the easiest fix would be to make dyn-view add its own observers to dependencies reported by its children, but I'll have to sit down and think that through in case it would cause other problems.

That makes sense, and is kind of what I figured. It's unfortunate that cond-view really won't work here without producing errors (though IIRC they don't prevent the application from running).

In the mean time, using obs-combine is the right approach here, though you also have to make sure your monster group view uses the ability decks value from the combined observable and not the main one (if you don't, things might work out most of the time, but you're going to be depending on a race between the observables).

That is unexpected, in some way, but also makes sense. Unfortunately the use of the @ability-decks in make-monster-group-view needs to be an observable—is your suggestion just to @-wrap the correct value, then?

At any rate, this might give me the motivation I need to drop some of the cons objects and put more things in structs (there's already a large number floating around, but no harm in adding more).

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024

This is wonderful! I haven't updated to try this out yet, but I plan to soon.

I completely follow the coerce problem in your link, but I'm still trying to digest what's happening in 87580f8 where you say that referring to a static view is a problem: does this mean that static views should be considered something of an anti-pattern (i.e., all views should be returned by functions)?

from racket-gui-easy.

Bogdanp avatar Bogdanp commented on June 20, 2024

I want to expand on this some more, in case I forget some of these details by the next time I get to work on this stuff.

Initially, when I came up with view<%>, I imagined view implementations would end up being stateless. That's why create returns a native widget instance and why update and destroy get passed those instances. In those cases, you can pass the same instance of a view<%> around multiple times and it won't cause any issues because the instances don't have any internal state. By the time I started implementing container views, I stopped worrying about retaining that property, because it made the implementation of those views much simpler. However, that breaks the promise that view<%>s are purely representations of GUIs, which I'm not too happy about, but, in practice, it doesn't seem to cause many issues (of all the GUIs I've written with gui-easy so far, that example was the only one where I had reused a view like that).

I think for now I'm going to leave things as they are so we can see how much this trips people up. If it turns out to cause a lot of pain and confusion, what we can do is change those views that are stateful to parameterize their state per native widget instance. To give a concrete example, if-view's then-view and else-view would change from being (or/c #f (is-a/c view<%>)) to (weak-hasheq/c any/c (or/c #f view<%>)). Alternatively, we could wrap native widgets in a mixin that lets us store contextual data directly on those instances, simplifying some of the state & memory management.

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024

Ok, that seems to make sense to me at the moment.

One last question: I saw a current-renderer parameter at a glance; is that considered public/stable? I don't recall seeing an update to the docs mentioning it, but it is certainly something I'm interested in. Though, using (render (dialog …)) without a parent argument hasn't caused any trouble for me so far…

from racket-gui-easy.

Bogdanp avatar Bogdanp commented on June 20, 2024

No, it won't be public. I added it for internal use only and mostly as a way of getting around changing the view<%> interface s.t. create, update and destroy take an additional renderer param. I probably will eventually change the interface and get rid of it.

You can bind the top level window's renderer (or store it in your own param) and use it to make modal dialogs already (see "examples/modal.rkt"). What you can't currently do is bind the renderer for a dialog because rendering a dialog blocks until the dialog is closed. I haven't yet thought of a nice way to get around that.

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024

Got it, thanks!

from racket-gui-easy.

benknoble avatar benknoble commented on June 20, 2024

Here's an example of making your own parameter, for the record. I couldn't think of a thread-safe/re-entrant way to do it without a parameter containing a thunk:

#lang racket
(require racket/gui/easy)
(define cr (make-parameter (thunk #f)))
(define root
  (parameterize ([cr (thunk root)])
    (render
      (window
        (button
          "Click me"
          (lambda ()
            (render
              (dialog
                (text "hello"))
              ((cr)))))))))

The view construction could then be placed in its own function(s) as long as it had access to the parameter. Thunk-ing is necessary because without it the value root is evaluated in the first form of parameterize before root is bound to the value that parameterize would return (i.e., it is undefined)!

from racket-gui-easy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.