bjogui/tests/inputs.bjo

145 lines
7.9 KiB
Text
Raw Permalink Normal View History

;; 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/inputs.bjo — switches, radios, numbers, dates, completion,
;; expanders, tooltips, flows and docks.
;;
;; bjo run tests/inputs.bjo
;;
;; No window is opened. A control is changed as a user's input would change
;; it, through its Avalonia property, and the message is checked.
(import (std prelude))
(import (std simpletest))
(import (bjogui view))
(import (bjogui app))
(import/class
(Object (: System.Object))
(ClrString (: System.String))
(Disposable (: System.IDisposable))
(AvaloniaObject (: Avalonia.AvaloniaObject))
(AvaloniaProperty (: Avalonia.AvaloniaProperty))
(Priority (: Avalonia.Data.BindingPriority))
(Control (: Avalonia.Controls.Control))
(Controls (: Avalonia.Controls.Controls))
(Panel (: Avalonia.Controls.Panel))
(ToggleButton (: Avalonia.Controls.Primitives.ToggleButton))
(NumericUpDown (: Avalonia.Controls.NumericUpDown))
(DatePicker (: Avalonia.Controls.DatePicker))
(DateTimeOffset (: System.DateTimeOffset))
(AutoCompleteBox (: Avalonia.Controls.AutoCompleteBox))
(Expander (: Avalonia.Controls.Expander))
(DockEdge (: Avalonia.Controls.Dock))
(StyledElement (: Avalonia.StyledElement))
(Classes (: Avalonia.Controls.Classes))
((Nullable %a) (: System.Nullable)))
(import/extern
(set-value (: Avalonia.AvaloniaObject.SetValue
(-> AvaloniaObject AvaloniaProperty Object Priority Disposable)))
(checked-property (: Avalonia.Controls.Primitives.ToggleButton.IsCheckedProperty #:get))
(number-property (: Avalonia.Controls.NumericUpDown.ValueProperty #:get))
(date-property (: Avalonia.Controls.DatePicker.SelectedDateProperty #:get))
(auto-property (: Avalonia.Controls.AutoCompleteBox.TextProperty #:get))
(expanded-property (: Avalonia.Controls.Expander.IsExpandedProperty #:get))
(is-checked (: Avalonia.Controls.Primitives.ToggleButton.IsChecked
(-> ToggleButton (Nullable bool)) #:get))
(number-value (: Avalonia.Controls.NumericUpDown.Value (-> NumericUpDown (Nullable decimal)) #:get))
(selected-date (: Avalonia.Controls.DatePicker.SelectedDate (-> DatePicker (Nullable DateTimeOffset)) #:get))
(parse-date (: System.DateTimeOffset.Parse (-> string DateTimeOffset)))
(expanded? (: Avalonia.Controls.Expander.IsExpanded (-> Expander bool) #:get))
(tip-of (: Avalonia.Controls.ToolTip.GetTip (-> Control Object)))
(dock-of (: Avalonia.Controls.DockPanel.GetDock (-> Control DockEdge)))
(children (: Avalonia.Controls.Panel.Children (-> Panel Controls) #:get))
(count (: Avalonia.Controls.Controls.Count (-> Controls int) #:get))
(classes-of (: Avalonia.StyledElement.Classes (-> StyledElement Classes) #:get))
(clr-string (: System.Convert.ToString (-> string ClrString))))
(type (: Msg (Union (: Switched bool) (: Picked string) (: Amount double) (: Dated string)
(: Typed string) (: Opened bool))))
(type (: Model (Record (: on bool) (: pick string) (: amount double) (: date string)
(: typed string) (: open bool))))
(: (-> Msg Model (Tuple Model (List (Event Msg)))))
(defun (gui-update msg m)
(next (match msg
((Switched b) (record-set m (on b)))
((Picked s) (record-set m (pick s)))
((Amount d) (record-set m (amount d)))
((Dated s) (record-set m (date s)))
((Typed s) (record-set m (typed s)))
((Opened b) (record-set m (open b))))))
(: (-> Model (View Msg)))
(defun (view m)
(column
(toggle-switch "Wi-Fi" (.on m) Switched) ; 0
(row (radio "tea" (= (.pick m) "tea") (Picked "tea")) ; 1 0
(radio "coffee" (= (.pick m) "coffee") (Picked "coffee"))) ; 1 1
(number-input (.amount m) Amount #:minimum 0.0 #:maximum 10.0 #:step 0.5) ; 2
(date-picker (.date m) Dated) ; 3
(auto-complete (.typed m) ["apple" "apricot" "banana"] Typed) ; 4
(expander "More" (.open m) Opened (text "inside")) ; 5
(tooltip (text "hover me") "a tip") ; 6
(flow #:spacing 4.0 (text "a") (text "b") (text "c")) ; 7
(dock (at-top (text "top")) (text "fill")) ; 8
(if (.open m) (classed (text "c") "wide") (classed (text "c") "big" "red")))) ; 9
(defun (main)
(def app (start-app (Model (on #f) (pick "tea") (amount 2.0) (date "2026-10-25")
(typed "") (open #f))
gui-update view (fun (c) unit)))
(defun (ctl path) (app-control-at app path))
(defun (put! path property value)
(ignore (set-value (cast AvaloniaObject (ctl path)) property value Priority.LocalValue)))
(defun (model) (app-model app))
;; --- switch and radios --------------------------------------------------------
(put! '(0) (cast AvaloniaProperty checked-property) (cast Object #t))
(expect "a switch sends its state" (.on (model)) #t)
(expect "a radio shows the model's choice"
(.GetValueOrDefault (is-checked (cast ToggleButton (ctl '(1 0))))) #t)
(put! '(1 1) (cast AvaloniaProperty checked-property) (cast Object #t))
(expect "choosing a radio sends its message" (.pick (model)) "coffee")
(expect "the other one is not chosen any more"
(.GetValueOrDefault (is-checked (cast ToggleButton (ctl '(1 0))))) #f)
;; --- number ---------------------------------------------------------------------
(expect "a number input's value" (cast System.Double (.GetValueOrDefault (number-value (cast NumericUpDown (ctl '(2)))))) 2.0)
(put! '(2) (cast AvaloniaProperty number-property) (cast Object (cast System.Decimal 3.5)))
(expect "a number sends its value" (.amount (model)) 3.5)
;; --- date -----------------------------------------------------------------------
(expect "a date picker's date" (.ToString (.-Value (selected-date (cast DatePicker (ctl '(3))))) "yyyy-MM-dd")
"2026-10-25")
(put! '(3) (cast AvaloniaProperty date-property) (cast Object (parse-date "2026-12-24")))
(expect "a date picked is sent" (.date (model)) "2026-12-24")
;; --- completion -------------------------------------------------------------------
(put! '(4) (cast AvaloniaProperty auto-property) (cast Object (clr-string "ap")))
(expect "completion sends what is typed" (.typed (model)) "ap")
;; --- expander ---------------------------------------------------------------------
(expect "an expander starts closed" (expanded? (cast Expander (ctl '(5)))) #f)
(put! '(5) (cast AvaloniaProperty expanded-property) (cast Object #t))
(expect "opening it sends a message" (.open (model)) #t)
;; --- tooltip, flow, dock ---------------------------------------------------------
(expect "a tooltip" (.ToString (tip-of (ctl '(6)))) "a tip")
(expect "a flow's children" (count (children (cast Panel (ctl '(7))))) 3)
(expect "a docked child" (written (dock-of (ctl '(8 0)))) "Top")
;; --- classes ---------------------------------------------------------------------
;; The expander was opened above, so the view has "wide" and not the others.
(def cls (classes-of (cast StyledElement (ctl '(9)))))
(defun (has-class? (: c Classes) (: name string)) (.Contains c name))
(expect "a class" (has-class? cls "wide") #t)
(expect "the classes of the last view are gone" (has-class? cls "big") #f)
(put! '(5) (cast AvaloniaProperty expanded-property) (cast Object #f))
(expect "and change with the model" (list (has-class? cls "big") (has-class? cls "red") (has-class? cls "wide"))
'(#t #t #f))
(println "bjogui inputs ok"))