2019-07-03 18:42:56 +00:00
|
|
|
#lang syndicate
|
|
|
|
|
2019-07-17 14:31:27 +00:00
|
|
|
(provide gui-eventspace
|
|
|
|
gui-callback
|
|
|
|
qc
|
|
|
|
spawn-frame
|
2019-07-03 18:42:56 +00:00
|
|
|
spawn-horizontal-pane
|
2019-07-15 18:24:58 +00:00
|
|
|
spawn-horizontal-panel
|
2019-07-12 17:01:39 +00:00
|
|
|
spawn-vertical-pane
|
2019-07-03 18:42:56 +00:00
|
|
|
spawn-text-field
|
|
|
|
spawn-button
|
2019-07-10 17:48:58 +00:00
|
|
|
spawn-choice
|
2019-07-11 20:01:38 +00:00
|
|
|
spawn-gauge
|
|
|
|
spawn-slider
|
2019-07-12 17:01:39 +00:00
|
|
|
spawn-list-box
|
2019-07-17 14:31:27 +00:00
|
|
|
spawn-dialog
|
2019-07-03 18:42:56 +00:00
|
|
|
(struct-out frame@)
|
2019-07-17 14:31:27 +00:00
|
|
|
(struct-out show)
|
2019-07-03 18:42:56 +00:00
|
|
|
(struct-out horizontal-pane@)
|
2019-07-15 18:24:58 +00:00
|
|
|
(struct-out horizontal-panel@)
|
2019-07-12 17:01:39 +00:00
|
|
|
(struct-out vertical-pane@)
|
2019-07-03 18:42:56 +00:00
|
|
|
(struct-out text-field@)
|
|
|
|
(struct-out set-text-field)
|
|
|
|
(struct-out button@)
|
2019-07-05 17:33:55 +00:00
|
|
|
(struct-out button-press)
|
|
|
|
(struct-out set-text-field-background)
|
2019-07-10 17:48:58 +00:00
|
|
|
(struct-out text-field-update)
|
2019-07-17 14:31:27 +00:00
|
|
|
(struct-out text-field-enter)
|
2019-07-10 17:48:58 +00:00
|
|
|
(struct-out choice@)
|
|
|
|
(struct-out choice-selection)
|
|
|
|
(struct-out set-selection)
|
2019-07-11 20:01:38 +00:00
|
|
|
(struct-out enable)
|
|
|
|
(struct-out gauge@)
|
|
|
|
(struct-out set-gauge-value)
|
|
|
|
(struct-out slider@)
|
2019-07-12 17:01:39 +00:00
|
|
|
(struct-out slider-update)
|
|
|
|
(struct-out list-box@)
|
|
|
|
(struct-out list-box-selection)
|
2019-07-15 18:24:58 +00:00
|
|
|
(struct-out set-list-box-choices)
|
|
|
|
(struct-out popup-menu)
|
|
|
|
(struct-out no-popdown-selected)
|
2019-07-17 14:31:27 +00:00
|
|
|
(struct-out popdown-item-selected)
|
|
|
|
(struct-out dialog@))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
|
|
|
(require (only-in racket/class
|
|
|
|
new
|
2019-07-05 17:33:55 +00:00
|
|
|
send
|
|
|
|
make-object))
|
2019-07-03 18:42:56 +00:00
|
|
|
(require racket/gui/base)
|
|
|
|
|
2019-07-17 14:31:27 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Eventspace Shennanigans
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
(define gui-eventspace (make-parameter (make-eventspace)))
|
|
|
|
|
|
|
|
(define (gui-callback thnk)
|
|
|
|
(parameterize ([current-eventspace (gui-eventspace)])
|
|
|
|
(queue-callback thnk)))
|
|
|
|
|
|
|
|
(define-syntax-rule (qc expr ...)
|
|
|
|
(gui-callback (lambda () expr ...)))
|
|
|
|
|
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
;; an ID is a (Sealof Any)
|
2019-07-12 17:01:39 +00:00
|
|
|
;; an Alignment is a (List (U 'left 'center 'right) (U 'top 'center 'bottom))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
2019-07-10 17:48:58 +00:00
|
|
|
(message-struct enable (id val))
|
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
(assertion-struct frame@ (id))
|
2019-07-17 14:31:27 +00:00
|
|
|
(message-struct show (id value))
|
2019-07-15 18:24:58 +00:00
|
|
|
(message-struct popup-menu (parent-id id title x y items))
|
|
|
|
(message-struct no-popdown-selected (id))
|
|
|
|
(message-struct popdown-item-selected (id item))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
|
|
|
(assertion-struct horizontal-pane@ (id))
|
2019-07-12 17:01:39 +00:00
|
|
|
(assertion-struct vertical-pane@ (id))
|
2019-07-15 18:24:58 +00:00
|
|
|
(assertion-struct horizontal-panel@ (id))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
2019-07-05 17:33:55 +00:00
|
|
|
(assertion-struct text-field@ (id value))
|
2019-07-03 18:42:56 +00:00
|
|
|
(message-struct set-text-field (id value))
|
2019-07-05 17:33:55 +00:00
|
|
|
(message-struct set-text-field-background (id color))
|
|
|
|
(message-struct text-field-update (id value))
|
2019-07-17 14:31:27 +00:00
|
|
|
(message-struct text-field-enter (id value))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
|
|
|
(assertion-struct button@ (id))
|
|
|
|
(message-struct button-press (id))
|
|
|
|
|
2019-07-10 17:48:58 +00:00
|
|
|
(assertion-struct choice@ (id selection))
|
|
|
|
(message-struct choice-selection (id val))
|
|
|
|
(message-struct set-selection (id idx))
|
|
|
|
|
2019-07-11 20:01:38 +00:00
|
|
|
(assertion-struct gauge@ (id))
|
|
|
|
(message-struct set-gauge-value (id value))
|
|
|
|
|
|
|
|
(assertion-struct slider@ (id value))
|
|
|
|
(message-struct slider-update (id value))
|
|
|
|
|
2019-07-12 17:01:39 +00:00
|
|
|
(assertion-struct list-box@ (id idx))
|
|
|
|
(message-struct list-box-selection (id idx))
|
|
|
|
(message-struct set-list-box-choices (id choices))
|
|
|
|
|
2019-07-17 14:31:27 +00:00
|
|
|
(assertion-struct dialog@ (id))
|
|
|
|
|
2019-07-10 17:48:58 +00:00
|
|
|
(define (enable/disable-handler self my-id)
|
|
|
|
(on (message (enable my-id $val))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send self enable val))))
|
2019-07-10 17:48:58 +00:00
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
;; String -> ID
|
2019-07-15 18:24:58 +00:00
|
|
|
(define (spawn-frame #:label label
|
2019-07-17 14:31:27 +00:00
|
|
|
#:width [width #f]
|
|
|
|
#:height [height #f])
|
2019-07-03 18:42:56 +00:00
|
|
|
(define frame
|
2019-07-17 14:31:27 +00:00
|
|
|
(parameterize ((current-eventspace (gui-eventspace)))
|
2019-07-15 18:24:58 +00:00
|
|
|
(new frame%
|
|
|
|
[label label]
|
2019-07-17 14:31:27 +00:00
|
|
|
[width width]
|
|
|
|
[height height])))
|
2019-07-03 18:42:56 +00:00
|
|
|
(define id (seal frame))
|
2019-07-15 18:24:58 +00:00
|
|
|
|
|
|
|
(define ((on-popdown! pid) self evt)
|
|
|
|
(when (eq? (send evt get-event-type) 'menu-popdown-none)
|
|
|
|
(send-ground-message (no-popdown-selected pid))))
|
|
|
|
(define ((popdown-item! pid i) . _x)
|
|
|
|
(send-ground-message (popdown-item-selected pid i)))
|
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
(spawn
|
|
|
|
(assert (frame@ id))
|
2019-07-17 14:31:27 +00:00
|
|
|
(on (message (show id $val))
|
|
|
|
(qc (send frame show val)))
|
2019-07-15 18:24:58 +00:00
|
|
|
(on (message (popup-menu id $pid $title $x $y $items))
|
|
|
|
(define pm (new popup-menu% [title title] [popdown-callback (on-popdown! pid)]))
|
|
|
|
(for ([i (in-list items)])
|
|
|
|
(new menu-item% [parent pm] [label i] [callback (popdown-item! pid i)]))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send frame popup-menu pm x y))
|
2019-07-15 18:24:58 +00:00
|
|
|
(react (stop-when (message (inbound (no-popdown-selected pid))) (send! (no-popdown-selected pid)))
|
|
|
|
(stop-when (message (inbound (popdown-item-selected pid $i))) (send! (popdown-item-selected pid i))))))
|
2019-07-03 18:42:56 +00:00
|
|
|
id)
|
|
|
|
|
2019-07-15 18:24:58 +00:00
|
|
|
;; ID ... -> ID
|
2019-07-12 17:01:39 +00:00
|
|
|
(define (spawn-horizontal-pane #:parent parent
|
|
|
|
#:border [border 0]
|
2019-07-15 18:24:58 +00:00
|
|
|
#:min-height [min-height #f]
|
2019-07-12 17:01:39 +00:00
|
|
|
#:alignment [alignment '(left center)])
|
2019-07-03 18:42:56 +00:00
|
|
|
(define parent-component (seal-contents parent))
|
2019-07-12 17:01:39 +00:00
|
|
|
(define pane (new horizontal-pane%
|
|
|
|
[parent parent-component]
|
|
|
|
[border border]
|
2019-07-15 18:24:58 +00:00
|
|
|
[min-height min-height]
|
2019-07-12 17:01:39 +00:00
|
|
|
[alignment alignment]))
|
2019-07-03 18:42:56 +00:00
|
|
|
(define id (seal pane))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (horizontal-pane@ id)))
|
|
|
|
|
|
|
|
id)
|
|
|
|
|
2019-07-15 18:24:58 +00:00
|
|
|
;; ID ... -> ID
|
|
|
|
(define (spawn-horizontal-panel #:parent parent
|
|
|
|
#:border [border 0]
|
|
|
|
#:min-height [min-height #f]
|
|
|
|
#:alignment [alignment '(left center)])
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define panel (new horizontal-panel%
|
|
|
|
[parent parent-component]
|
|
|
|
[border border]
|
|
|
|
[min-height min-height]
|
|
|
|
[alignment alignment]))
|
|
|
|
(define id (seal panel))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (horizontal-panel@ id)))
|
|
|
|
|
|
|
|
id)
|
|
|
|
|
2019-07-12 17:01:39 +00:00
|
|
|
;; ID Alignment -> ID
|
|
|
|
(define (spawn-vertical-pane #:parent parent
|
|
|
|
#:alignment [alignment '(center top)])
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define pane (new vertical-pane%
|
|
|
|
[parent parent-component]
|
|
|
|
[alignment alignment]))
|
|
|
|
(define id (seal pane))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (vertical-pane@ id)))
|
|
|
|
|
|
|
|
id)
|
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
; ID String String Bool Nat -> ID
|
|
|
|
(define (spawn-text-field #:parent parent
|
|
|
|
#:label label
|
|
|
|
#:init-value init
|
2019-07-05 17:33:55 +00:00
|
|
|
#:enabled [enabled? #t]
|
2019-07-17 14:31:27 +00:00
|
|
|
#:min-width [min-width #f]
|
|
|
|
#:min-height [min-height #f])
|
2019-07-03 18:42:56 +00:00
|
|
|
(define parent-component (seal-contents parent))
|
2019-07-05 17:33:55 +00:00
|
|
|
|
|
|
|
(define (inject-text-field-update! _ evt)
|
2019-07-17 14:31:27 +00:00
|
|
|
(case (send evt get-event-type)
|
|
|
|
[(text-field)
|
|
|
|
(send-ground-message (text-field-update id (send tf get-value)))]
|
|
|
|
[(text-field-enter)
|
|
|
|
(send-ground-message (text-field-enter id (send tf get-value)))]))
|
2019-07-05 17:33:55 +00:00
|
|
|
|
2019-07-03 18:42:56 +00:00
|
|
|
(define tf (new text-field%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[init-value init]
|
|
|
|
[enabled enabled?]
|
2019-07-05 17:33:55 +00:00
|
|
|
[min-width min-width]
|
2019-07-17 14:31:27 +00:00
|
|
|
[min-height min-height]
|
2019-07-05 17:33:55 +00:00
|
|
|
[callback inject-text-field-update!]))
|
2019-07-03 18:42:56 +00:00
|
|
|
(define id (seal tf))
|
|
|
|
|
|
|
|
(spawn
|
2019-07-05 17:33:55 +00:00
|
|
|
(field [val (send tf get-value)])
|
|
|
|
(assert (text-field@ id (val)))
|
2019-07-10 17:48:58 +00:00
|
|
|
(enable/disable-handler tf id)
|
2019-07-03 18:42:56 +00:00
|
|
|
(on (message (set-text-field id $value))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send tf set-value value))
|
2019-07-05 17:33:55 +00:00
|
|
|
(val value))
|
|
|
|
(on (message (set-text-field-background id $color))
|
|
|
|
(define c (make-object color% color))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send tf set-field-background c)))
|
2019-07-05 17:33:55 +00:00
|
|
|
(on (message (inbound (text-field-update id $value)))
|
2019-07-17 14:31:27 +00:00
|
|
|
(val value)
|
|
|
|
(send! (text-field-update id value)))
|
|
|
|
(on (message (inbound (text-field-enter id $value)))
|
|
|
|
(val value)
|
|
|
|
(send! (text-field-enter id value))))
|
2019-07-03 18:42:56 +00:00
|
|
|
|
|
|
|
id)
|
|
|
|
|
|
|
|
;; ID String -> ID
|
|
|
|
(define (spawn-button #:parent parent
|
|
|
|
#:label label)
|
|
|
|
(define (inject-button-press! b e)
|
|
|
|
(send-ground-message (button-press id)))
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define but (new button%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[callback inject-button-press!]))
|
|
|
|
(define id (seal but))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (button@ id))
|
2019-07-10 17:48:58 +00:00
|
|
|
(enable/disable-handler but id)
|
2019-07-03 18:42:56 +00:00
|
|
|
;; NOTE - this assumes we are one level away from ground
|
|
|
|
(on (message (inbound (button-press id)))
|
|
|
|
(send! (button-press id))))
|
|
|
|
|
|
|
|
id)
|
2019-07-10 17:48:58 +00:00
|
|
|
|
|
|
|
;; ID String (Listof String) -> ID
|
|
|
|
(define (spawn-choice #:parent parent
|
|
|
|
#:label label
|
|
|
|
#:choices choices)
|
|
|
|
(define (inject-selection! c e)
|
|
|
|
(send-ground-message (choice-selection id (send ch get-string-selection))))
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define ch (new choice%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[choices choices]
|
|
|
|
[callback inject-selection!]))
|
|
|
|
(define id (seal ch))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(field [selection (send ch get-string-selection)])
|
|
|
|
(assert (choice@ id (selection)))
|
|
|
|
|
|
|
|
(enable/disable-handler ch id)
|
|
|
|
(on (message (inbound (choice-selection id $val)))
|
|
|
|
(selection val)
|
|
|
|
(send! (choice-selection id val)))
|
|
|
|
(on (message (set-selection id $idx))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send ch set-selection idx))
|
2019-07-10 17:48:58 +00:00
|
|
|
(selection (send ch get-string-selection))))
|
|
|
|
|
|
|
|
id)
|
2019-07-11 20:01:38 +00:00
|
|
|
|
|
|
|
;; ID String Bool Nat -> ID
|
|
|
|
(define (spawn-gauge #:parent parent
|
|
|
|
#:label label
|
|
|
|
#:enabled [enabled? #t]
|
|
|
|
#:range [range 100])
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define g (new gauge%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[enabled enabled?]
|
|
|
|
[range range]))
|
|
|
|
(define id (seal g))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (gauge@ id))
|
|
|
|
(on (message (set-gauge-value id $v))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send g set-value v))))
|
2019-07-11 20:01:38 +00:00
|
|
|
|
|
|
|
id)
|
|
|
|
|
|
|
|
;; ID String Nat Nat -> ID
|
|
|
|
(define (spawn-slider #:parent parent
|
|
|
|
#:label label
|
2019-07-15 18:24:58 +00:00
|
|
|
#:min-value min-value
|
|
|
|
#:max-value max-value
|
|
|
|
#:init-value [init-value min-value])
|
2019-07-11 20:01:38 +00:00
|
|
|
(define (inject-slider-event! self evt)
|
|
|
|
(send-ground-message (slider-update id (get))))
|
|
|
|
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define s (new slider%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[min-value min-value]
|
|
|
|
[max-value max-value]
|
2019-07-15 18:24:58 +00:00
|
|
|
[init-value init-value]
|
2019-07-11 20:01:38 +00:00
|
|
|
[callback inject-slider-event!]))
|
|
|
|
(define id (seal s))
|
|
|
|
|
|
|
|
(define (get) (send s get-value))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(field [current (get)])
|
|
|
|
(assert (slider@ id (current)))
|
|
|
|
(on (message (inbound (slider-update id $val)))
|
|
|
|
(current val)
|
|
|
|
(send! (slider-update id val))))
|
|
|
|
|
|
|
|
id)
|
2019-07-12 17:01:39 +00:00
|
|
|
|
|
|
|
;; ID (U String #f) (Listof String) ... -> ID
|
|
|
|
(define (spawn-list-box #:parent parent
|
|
|
|
#:label label
|
|
|
|
#:choices choices
|
|
|
|
#:min-width [min-width #f]
|
|
|
|
#:min-height [min-height #f])
|
|
|
|
(define (inject-list-box-selection! self evt)
|
|
|
|
(send-ground-message (list-box-selection id (get))))
|
|
|
|
(define parent-component (seal-contents parent))
|
|
|
|
(define lb (new list-box%
|
|
|
|
[parent parent-component]
|
|
|
|
[label label]
|
|
|
|
[choices choices]
|
|
|
|
[min-width min-width]
|
|
|
|
[min-height min-height]
|
|
|
|
[callback inject-list-box-selection!]))
|
|
|
|
(define id (seal lb))
|
|
|
|
(define (get)
|
|
|
|
(send lb get-selection))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(field [selection (get)])
|
|
|
|
(assert (list-box@ id (selection)))
|
|
|
|
(on (message (inbound (list-box-selection id $val)))
|
|
|
|
(selection val)
|
|
|
|
(send! (list-box-selection id val)))
|
|
|
|
(on (message (set-list-box-choices id $val))
|
2019-07-17 14:31:27 +00:00
|
|
|
(qc (send lb set val))
|
2019-07-12 17:01:39 +00:00
|
|
|
(selection (get))))
|
|
|
|
|
|
|
|
id)
|
2019-07-17 14:31:27 +00:00
|
|
|
|
|
|
|
(define (spawn-dialog #:label label
|
|
|
|
#:parent [parent #f]
|
|
|
|
#:style [style null])
|
|
|
|
(define parent-component (and parent (seal-contents parent)))
|
|
|
|
(define evt-spc (if parent-component
|
|
|
|
(send parent-component get-eventspace)
|
|
|
|
(make-eventspace) #;(gui-eventspace)))
|
|
|
|
(define d (parameterize ((current-eventspace evt-spc))
|
|
|
|
(new dialog%
|
|
|
|
[label label]
|
|
|
|
[parent parent-component]
|
|
|
|
[style style])))
|
|
|
|
(define id (seal d))
|
|
|
|
|
|
|
|
(spawn
|
|
|
|
(assert (dialog@ id))
|
|
|
|
|
|
|
|
(on (message (show id $show?))
|
|
|
|
(qc (send d show show?))
|
|
|
|
(unless show? (stop-current-facet))))
|
|
|
|
|
|
|
|
id)
|