From 21226614d8977e210475ae80ab82719da1e8f0b0 Mon Sep 17 00:00:00 2001 From: Bogdan Popa Date: Mon, 18 Dec 2023 08:45:49 +0200 Subject: [PATCH] core: fix container sequence bracketing Before this change, an error raised during the creation of a child could leave these containers in a state where they would never update again because the nesting depth of the sequencing could never reach 0 again. --- .../gui/easy/private/view/container.rkt | 13 ++- gui-easy-lib/gui/easy/private/view/if.rkt | 19 +++-- gui-easy-lib/gui/easy/private/view/list.rkt | 80 +++++++++---------- .../gui/easy/private/view/observable.rkt | 8 +- gui-easy-lib/gui/easy/private/view/panel.rkt | 7 +- gui-easy-lib/gui/easy/private/view/tabs.rkt | 7 +- gui-easy-lib/info.rkt | 2 +- 7 files changed, 71 insertions(+), 65 deletions(-) diff --git a/gui-easy-lib/gui/easy/private/view/container.rkt b/gui-easy-lib/gui/easy/private/view/container.rkt index 3bd9af3..6afb1aa 100644 --- a/gui-easy-lib/gui/easy/private/view/container.rkt +++ b/gui-easy-lib/gui/easy/private/view/container.rkt @@ -3,7 +3,8 @@ (require racket/class) (provide - container%) + container% + with-container-sequence) (define container% (class object% @@ -42,3 +43,13 @@ (define/private (get-children-to-widgets v) (send v get-context! 'children-to-widgets make-hasheq)))) + +(define-syntax-rule (with-container-sequence container body0 body ...) + (dynamic-wind + (lambda () + (send container begin-container-sequence)) + (lambda () + body0 + body ...) + (lambda () + (send container end-container-sequence)))) diff --git a/gui-easy-lib/gui/easy/private/view/if.rkt b/gui-easy-lib/gui/easy/private/view/if.rkt index 403c31c..48aaac6 100644 --- a/gui-easy-lib/gui/easy/private/view/if.rkt +++ b/gui-easy-lib/gui/easy/private/view/if.rkt @@ -47,16 +47,15 @@ [@cond-e (define this-bool (->bool val)) (unless (eq? (get-last-bool v) this-bool) - (send v begin-container-sequence) - (when (has-then-view? v) - (remove&destroy-then-view v)) - (when (has-else-view? v) - (remove&destroy-else-view v)) - (if this-bool - (create&add-then-view v) - (create&add-else-view v)) - (send v set-context 'last-bool this-bool) - (send v end-container-sequence))])) + (with-container-sequence v + (when (has-then-view? v) + (remove&destroy-then-view v)) + (when (has-else-view? v) + (remove&destroy-else-view v)) + (if this-bool + (create&add-then-view v) + (create&add-else-view v)) + (send v set-context 'last-bool this-bool)))])) (define/public (destroy v) (when (has-then-view? v) diff --git a/gui-easy-lib/gui/easy/private/view/list.rkt b/gui-easy-lib/gui/easy/private/view/list.rkt index 78b5c0c..426fb00 100644 --- a/gui-easy-lib/gui/easy/private/view/list.rkt +++ b/gui-easy-lib/gui/easy/private/view/list.rkt @@ -97,51 +97,49 @@ (define keys-to-children (get-keys-to-children the-panel)) (begin0 the-panel - (send the-panel begin-container-sequence) - (for ([e (in-list (peek @entries))]) - (define k (key-proc e)) - (define v (make-view k (make-keyed-obs k e))) - (define w (send v create the-panel)) - (add-child-handlers! the-panel v) - (add-child the-panel v w) - (hash-set! keys-to-children k v)) - (send the-panel end-container-sequence))) + (with-container-sequence the-panel + (for ([e (in-list (peek @entries))]) + (define k (key-proc e)) + (define v (make-view k (make-keyed-obs k e))) + (define w (send v create the-panel)) + (add-child-handlers! the-panel v) + (add-child the-panel v w) + (hash-set! keys-to-children k v))))) (define/public (update v what val) (case/dep what [@entries - (send v begin-container-sequence) - (define keys-to-children - (get-keys-to-children v)) - (define new-keys - (for/list ([e (in-list val)]) - (define k (key-proc e)) - (begin0 k - (unless (hash-has-key? keys-to-children k) - (define child-v (make-view k (make-keyed-obs k e))) - (define child-w (send child-v create v)) - (add-child-handlers! v child-v) - (add-child v child-v child-w) - (hash-set! keys-to-children k child-v))))) - (for ([(old-k old-v) (in-hash keys-to-children)]) - (unless (member old-k new-keys) - (define old-w (get-child v old-v)) - (define focused? (send old-w has-focus?)) - (send old-v destroy old-w) - (send v delete-child old-w) - (remove-child-handlers! v old-v) - (remove-child v old-v) - (hash-remove! keys-to-children old-k) - (when focused? - (define children (send v get-children)) - (cond - [(null? children) (send v focus)] - [else (send (last children) focus)])))) - (send v change-children - (λ (_) - (for/list ([k (in-list new-keys)]) - (get-child v (hash-ref keys-to-children k))))) - (send v end-container-sequence)] + (with-container-sequence v + (define keys-to-children + (get-keys-to-children v)) + (define new-keys + (for/list ([e (in-list val)]) + (define k (key-proc e)) + (begin0 k + (unless (hash-has-key? keys-to-children k) + (define child-v (make-view k (make-keyed-obs k e))) + (define child-w (send child-v create v)) + (add-child-handlers! v child-v) + (add-child v child-v child-w) + (hash-set! keys-to-children k child-v))))) + (for ([(old-k old-v) (in-hash keys-to-children)]) + (unless (member old-k new-keys) + (define old-w (get-child v old-v)) + (define focused? (send old-w has-focus?)) + (send old-v destroy old-w) + (send v delete-child old-w) + (remove-child-handlers! v old-v) + (remove-child v old-v) + (hash-remove! keys-to-children old-k) + (when focused? + (define children (send v get-children)) + (cond + [(null? children) (send v focus)] + [else (send (last children) focus)])))) + (send v change-children + (λ (_) + (for/list ([k (in-list new-keys)]) + (get-child v (hash-ref keys-to-children k))))))] [@alignment (send/apply v set-alignment val)] [@enabled? diff --git a/gui-easy-lib/gui/easy/private/view/observable.rkt b/gui-easy-lib/gui/easy/private/view/observable.rkt index df6ce00..b20b580 100644 --- a/gui-easy-lib/gui/easy/private/view/observable.rkt +++ b/gui-easy-lib/gui/easy/private/view/observable.rkt @@ -4,6 +4,7 @@ (prefix-in gui: racket/gui) "../renderer.rkt" "common.rkt" + "container.rkt" "proxy.rkt" "view.rkt") @@ -29,10 +30,9 @@ (case/dep what [@data (unless (equal?-proc val (get-data v)) - (send v begin-container-sequence) - (remove&destroy-child v) - (create&add-child v val) - (send v end-container-sequence))]) + (with-container-sequence v + (remove&destroy-child v) + (create&add-child v val)))]) (define child (send v get-context 'view #f)) (when child diff --git a/gui-easy-lib/gui/easy/private/view/panel.rkt b/gui-easy-lib/gui/easy/private/view/panel.rkt index 0a35894..7f11849 100644 --- a/gui-easy-lib/gui/easy/private/view/panel.rkt +++ b/gui-easy-lib/gui/easy/private/view/panel.rkt @@ -46,10 +46,9 @@ (define/public (create parent) (define the-panel (-make-panel parent)) (begin0 the-panel - (send the-panel begin-container-sequence) - (for ([c (in-list children)]) - (add-child the-panel c (send c create the-panel))) - (send the-panel end-container-sequence))) + (with-container-sequence the-panel + (for ([c (in-list children)]) + (add-child the-panel c (send c create the-panel)))))) (define/public (update v what val) (case/dep what diff --git a/gui-easy-lib/gui/easy/private/view/tabs.rkt b/gui-easy-lib/gui/easy/private/view/tabs.rkt index 294ae11..fb22507 100644 --- a/gui-easy-lib/gui/easy/private/view/tabs.rkt +++ b/gui-easy-lib/gui/easy/private/view/tabs.rkt @@ -95,10 +95,9 @@ (send the-panel set-context 'last-selection selection) (send the-panel set-context 'last-index index) (send the-panel set-selection index)) - (send the-panel begin-container-sequence) - (for ([c (in-list children)]) - (add-child the-panel c (send c create the-panel))) - (send the-panel end-container-sequence))) + (with-container-sequence the-panel + (for ([c (in-list children)]) + (add-child the-panel c (send c create the-panel)))))) (define/public (update v what val) (case/dep what diff --git a/gui-easy-lib/info.rkt b/gui-easy-lib/info.rkt index ed133aa..a4a8220 100644 --- a/gui-easy-lib/info.rkt +++ b/gui-easy-lib/info.rkt @@ -1,7 +1,7 @@ #lang info (define license 'BSD-3-Clause) -(define version "0.16") +(define version "0.16.1") (define collection "racket") (define deps '("base" "box-extra-lib"