Bogdanp / racket-gui-easy

Declarative GUIs in Racket.
https://docs.racket-lang.org/gui-easy/index.html
134 stars 18 forks source link

is there a way to close a dialog programmatically? #24

Open kurinoku opened 2 years ago

kurinoku commented 2 years ago

Right now closing a rendered dialog is non-trivial, or is too ugly. Maybe there is a way, but I can only think of either using a mixin or this which doesn't work on dialog but does on frames.

(define (d r)
       (define (close-dialog) (send (renderer-root (force r)) show #f))
       (dialog
        (text (format "~a: first ~a characters" identity len))
        (input "" (λ (evt str)
                    (displayln evt)
                    (when (eq? evt 'return)
                      (cond
                        [(string=? str (substring password 0 len)) 
                         (close-dialog)
                         (next-dialog)]
                        [else
                         (close-dialog)
                         (error-dialog)]))))))
(define r (render (d (delay r)) (get-parent)))

This throws an error since r isn't defined because of how dialog's yield work.

kurinoku commented 2 years ago

I guess the real question is that if there's a more idiomatic way of doing this? Right now is not obvious

(define (d)
       (define (close-dialog) (:= @show #f))
       (define @show (@ #t))
       (apply-if-window-view
        dialog
        #:mixin
        (λ (klass)
          (class klass
            (super-new)
            (inherit show)
            (obs-observe! @show (λ (val) (show val)))))
        (text (format "~a: first ~a characters" identity len))
        error
        (text (format "Wrong password: ~a tries left" tries))
        (input "" (λ (evt str)
                    (when (eq? evt 'return)
                      (cond
                        [(string=? str (substring password 0 len)) 
                         (close-dialog)
                         (next-dialog)]
                        [else
                         (close-dialog)
                         (error-dialog)]))))))
     (define r (render (d) (get-parent)))
Bogdanp commented 2 years ago

Mixins are the way to go right now -- they're how you can hook in functionality that the library doesn't provide in general, but I agree that the current state is not ideal. Maybe we could get away with windows and dialogs having a #:show? observable arg? I'll try to find some time next week to investigate.

kurinoku commented 2 years ago

yes, that was what I thought, thank you for answering, maybe having an example in the documentation might be a good idea?

benknoble commented 1 year ago

Another version:

;; calls `out` with `close-proc`, which closes the window when invoked
(define (make-closing-proc-mixin out)
  (mixin (top-level-window<%>) (top-level-window<%>) (super-new)
    (out (λ ()
           (when (send this can-close?)
             (send this on-close)
             (send this show #f))))))

(define close! (box #f))
(define (set-close! c) (set-box! close! c))
(dialog #:mixin (make-closing-proc-mixin set-close!)
  … call ((unbox close!)) to close the dialog …)
benknoble commented 4 months ago

In fact, I’ve written a macro for this which I use a lot.