Skip to content

Conversation

@aanastasiou
Copy link
Contributor

This PR proposes an intermediate solution to the way observable based views update their content once their observable has been updated.

Currently, observable based views completely recreate their content once their observable gets updated to reflect the new data values. This creates the interesting behaviour, where, when a view's controls update the view's observable, they get re-created and this means that an input control would lose focus. For example (try to edit the text in either of these boxes):

#lang racket
(require racket/gui/easy
         racket/gui/easy/operator)

(define actual-value '("Alpha" "Beta"))
(define @value-a (obs (first actual-value)))
(define @value-b (obs (second actual-value)))
(define @top-obs (obs-combine (lambda (u v) (cons u v)) @value-a @value-b))

(define cursed-view
  (observable-view @top-obs
                   (lambda (d)
                     (vpanel
                     (input @value-a
                            (lambda (u v) (obs-set! @value-a v))                              
                            #:label "Value - A")
                     (input @value-b
                            (lambda (u v) (obs-set! @value-b v))
                            #:label "Value - B")
                   #:min-size '(150 50)))))

(render
 (dialog cursed-view))

This PR adds two more events in the input control's action, has-focus and lost-focus. This does not change the updating behaviour of a given observable based view but makes the "re-creation" invisible because most of the times, the user has finished editing text in a given text box.

Compare the previous behaviour of the "Value - A" input to:

#lang racket
(require racket/gui/easy
         racket/gui/easy/operator)

(define actual-value '("Alpha" "Beta"))
(define @value-a (obs (first actual-value)))
(define @value-b (obs (second actual-value)))
(define @top-obs (obs-combine (lambda (u v) (cons u v)) @value-a @value-b))

(define cursed-view
  (observable-view @top-obs
                   (lambda (d)
                     (vpanel
                     (input @value-a
                            (lambda (u v)
                              (case u
                                ['lost-focus (obs-set! @value-a v)]))                              
                            #:label "Value - A")
                     (input @value-b
                            (lambda (u v) (obs-set! @value-b v))
                            #:label "Value - B")
                   #:min-size '(150 50)))))

(render
 (dialog cursed-view))

(send the-field set-field-background background-color))
(begin0 the-field
(send the-field set-context 'last-val content)))
(send the-field set-context 'last-val content)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meta note: I think you've formatted a bunch of code that didn't need to be touched

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, hate it when that happens. :/

Is there a particular linting set of rules I could use to avoid these problems?
I mostly use drracket but otherwise a neovim user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure: I might have configured begin0 to indent correctly recently, but I'm not sure about case/dep.

Depending on the (Neo)Vim plugins you use, it might be as simple as adding those forms to lispwords.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DrRacket, you can add begin0 and case/dep to "Preferences" -> "Editing" -> "Define-like Keywords".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked, and if you're using my vim-racket, both forms should already be configured correctly for indentation. They should also be in lispwords if you have a recent-ish Vim (since I contribute some parts of that plugin back to upstream runtime files occasionally). Vim users (but not Neovim, sorry) also benefit from the indentexpr I wrote that correctly handles for and for/fold forms, FWIW.

Copy link
Owner

@Bogdanp Bogdanp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks! If you fixup the indentation problems and rebase, I'll go ahead and merge.

@Bogdanp
Copy link
Owner

Bogdanp commented Sep 2, 2025

Rebased and merged locally. Thanks!

@Bogdanp Bogdanp closed this Sep 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants