Dialogs, file pickers, and closing by the program's leave
(bjogui dialogs) has alert, confirm and prompt, the open, save and folder pickers, and quit, each a command whose answer comes back as a message. A dialog is a window, which only the UI thread may make, so the command posts it there and awaits its Task in a fiber. Avalonia's dialogs take no CancellationToken, so they cannot be task->event; the Task is awaited through the non-generic Task.WhenAll, and its result read by reflection, because Bjolang reads no Task's Result. With no window, as under start-app, each answers as if cancelled. run-app's #:on-close turns the close button into a message, and quit closes the windows by program, which is not asked again. 🤖 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
be288ac03e
commit
cfcb1851b7
3 changed files with 483 additions and 1 deletions
54
tests/dialogs.bjo
Normal file
54
tests/dialogs.bjo
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
;; 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/tests/dialogs.bjo — dialogs and pickers with no window.
|
||||
;;
|
||||
;; bjo run tests/dialogs.bjo
|
||||
;;
|
||||
;; A dialog needs a window to belong to, and an app started with `start-app`
|
||||
;; has none. So each answers as if it was cancelled, and that is what this
|
||||
;; checks: that the command goes to the UI thread and back, and its message
|
||||
;; comes. A dialog on a screen is looked at by a person.
|
||||
|
||||
(import (std prelude))
|
||||
(import (std simpletest))
|
||||
(import (bjogui view))
|
||||
(import (bjogui app))
|
||||
(import (bjogui dialogs))
|
||||
|
||||
(import/extern
|
||||
(sleep-ms (: System.Threading.Thread.Sleep (-> int void) #:blocking)))
|
||||
|
||||
(type (: Msg (Union Ask (: Answer string))))
|
||||
|
||||
(: (-> Msg (List string) (Tuple (List string) (List (Event Msg)))))
|
||||
(defun (gui-update msg answers)
|
||||
(match msg
|
||||
(Ask (next answers
|
||||
(alert "Saved." (Answer "alert"))
|
||||
(confirm "Delete?" (fun (b) (Answer #"confirm ${b}")))
|
||||
(prompt "Name?" (fun (s) (Answer #"prompt ${(option-ref-or s "none")}")) #:value "Ada")
|
||||
(open-file (fun (p) (Answer #"open-file ${(option-ref-or p "none")}")))
|
||||
(open-files (fun (ps) (Answer #"open-files ${(length ps)}")))
|
||||
(save-file (fun (p) (Answer #"save-file ${(option-ref-or p "none")}")) #:name "a.txt")
|
||||
(open-folder (fun (p) (Answer #"open-folder ${(option-ref-or p "none")}")))
|
||||
(quit)))
|
||||
((Answer s) (next (cons s answers)))))
|
||||
|
||||
(defun (main)
|
||||
(def app (start-app '() gui-update (fun (m) (text "")) (fun (c) unit)))
|
||||
(app-dispatch! app Ask)
|
||||
(let go ((tries 0))
|
||||
(app-run-pending! app)
|
||||
(when (and (< (length (app-model app)) 7) (< tries 300))
|
||||
(sleep-ms 10)
|
||||
(go (+ tries 1))))
|
||||
(def answers (list-sort (app-model app)))
|
||||
(expect "every dialog answered" (length answers) 7)
|
||||
(expect "the answers with no window"
|
||||
answers
|
||||
(list-sort '("alert" "confirm #f" "prompt none" "open-file none" "open-files 0"
|
||||
"save-file none" "open-folder none")))
|
||||
(app-stop! app)
|
||||
(println "bjogui dialogs ok"))
|
||||
Loading…
Add table
Add a link
Reference in a new issue