;; 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"))