Commands and subscriptions, and gui-update
gui-update is a plain function, so it cannot wait. It returns the work to do as values. A command is an (Event %m), synced in a fiber of its own, whose answer is the next message. A subscription is a source of messages that the model asks for: after each update the app starts the new ones and cancels the ones that are gone, by key. every sends a message on a timer, and subscription takes a source of one's own. The fibers belong to the app's scope and post their messages to the UI thread, so gui-update and view only run there. Closing the window cancels them. The prelude's path macros already use the name update, hence gui-update. 🤖 Generated with [ECA](https://eca.dev) (anthropic/claude-opus-4-8) Co-Authored-By: eca-agent <git@eca.dev>
This commit is contained in:
parent
2f4c99ba62
commit
4f48282314
6 changed files with 460 additions and 67 deletions
|
|
@ -13,12 +13,13 @@
|
|||
(type (: Msg (Union Inc Dec (: Typed string))))
|
||||
(type (: Model (Record (: count int) (: name string))))
|
||||
|
||||
(: update (-> Msg Model Model))
|
||||
(defun (update msg m)
|
||||
(match msg
|
||||
(Inc (record-set m (count (+ (.count m) 1))))
|
||||
(Dec (record-set m (count (- (.count m) 1))))
|
||||
((Typed s) (record-set m (name s)))))
|
||||
(: gui-update (-> Msg Model (Tuple Model (List (Event Msg)))))
|
||||
(defun (gui-update msg m)
|
||||
(next
|
||||
(match msg
|
||||
(Inc (record-set m (count (+ (.count m) 1))))
|
||||
(Dec (record-set m (count (- (.count m) 1))))
|
||||
((Typed s) (record-set m (name s))))))
|
||||
|
||||
(: view (-> Model (View Msg)))
|
||||
(defun (view m)
|
||||
|
|
@ -31,4 +32,4 @@
|
|||
(button "+" Inc #:width 40.0))))
|
||||
|
||||
(defun (main)
|
||||
(run-app (Model (count 0) (name "")) update view #:title "Counter" #:width 320.0 #:height 200.0))
|
||||
(run-app (Model (count 0) (name "")) gui-update view #:title "Counter" #:width 320.0 #:height 200.0))
|
||||
|
|
|
|||
55
examples/stopwatch.bjo
Normal file
55
examples/stopwatch.bjo
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
;; bjogui/examples/stopwatch.bjo — a subscription and a command.
|
||||
;;
|
||||
;; bjo run examples/stopwatch.bjo
|
||||
;;
|
||||
;; The stopwatch ticks while it runs: `subscriptions` asks for a tick only
|
||||
;; then, so stopping it stops the fiber. "Lap" saves the time after a pause,
|
||||
;; to show a command: the pause runs in a fiber, and the window does not wait
|
||||
;; for it.
|
||||
|
||||
(import (std prelude))
|
||||
(import (bjogui view))
|
||||
(import (bjogui app))
|
||||
|
||||
(type (: Msg (Union Toggle Tick Reset Lap (: Saved int))))
|
||||
(type (: Model (Record (: tenths int) (: running bool) (: saving bool) (: laps (List int)))))
|
||||
|
||||
(: gui-update (-> Msg Model (Tuple Model (List (Event Msg)))))
|
||||
(defun (gui-update msg m)
|
||||
(match msg
|
||||
(Toggle (next (record-set m (running (not (.running m))))))
|
||||
(Tick (next (record-set m (tenths (+ (.tenths m) 1)))))
|
||||
(Reset (next (record-set m (tenths 0) (laps '()))))
|
||||
;; The time is taken now, and saved half a second later.
|
||||
(Lap (next (record-set m (saving #t))
|
||||
(wrap (timeout (milliseconds 500)) (fun (_) (Saved (.tenths m))))))
|
||||
((Saved t) (next (record-set m (saving #f) (laps (cons t (.laps m))))))))
|
||||
|
||||
(: subscriptions (-> Model (List (Sub Msg))))
|
||||
(defun (subscriptions m)
|
||||
(if (.running m) (list (every (milliseconds 100) Tick)) '()))
|
||||
|
||||
(: (-> int string))
|
||||
(defun (show tenths)
|
||||
#"${(/ tenths 10)}.${(% tenths 10)} s")
|
||||
|
||||
(: view (-> Model (View Msg)))
|
||||
(defun (view m)
|
||||
(column #:spacing 8.0 #:margin 16.0
|
||||
(text (show (.tenths m)) #:size 32.0)
|
||||
(row #:spacing 8.0
|
||||
(button (if (.running m) "Stop" "Start") Toggle #:width 80.0)
|
||||
(button "Lap" Lap #:enabled (not (.saving m)) #:width 80.0)
|
||||
(button "Reset" Reset #:width 80.0))
|
||||
(apply column (vec->array (vec-map (fun (t) (text #"lap: ${(show t)}"))
|
||||
(list->vec (.laps m)))))))
|
||||
|
||||
(defun (main)
|
||||
(run-app (Model (tenths 0) (running #f) (saving #f) (laps '()))
|
||||
gui-update view
|
||||
#:subscriptions subscriptions
|
||||
#:title "Stopwatch" #:width 320.0 #:height 300.0))
|
||||
Loading…
Add table
Add a link
Reference in a new issue