;; 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/src/view.bjo — the module (bjogui view). ;; ;; A view is a value: what the window shows for one model. `view` functions ;; build it with the constructors here, and (bjogui app) makes the controls ;; for it and changes them when the next view differs. Nothing here knows ;; about Avalonia, so a view can be built and compared in a test with no ;; window. ;; ;; An event is a message, or a function that makes one from what the control ;; holds. The app gives the message to `update`. (export ;; Types. View Kind Prop On ;; Constructors. text button text-input checkbox column row ;; Reading one. view-kind view-props view-events view-children) (import (std prelude)) ;; --------------------------------------------------------------------------- ;; The types ;; --------------------------------------------------------------------------- ;; What control a view is. (type (: Kind (Union TextKind ButtonKind TextInputKind CheckBoxKind ColumnKind RowKind))) ;; A property of a control. A kind takes only some of them; the app ignores ;; the others. (type (: Prop (Union (: Label string) ; the text of a text, a button or a checkbox (: Value string) ; the text in a text input (: Placeholder string) ; shown in an empty text input (: Checked bool) (: Enabled bool) (: FontSize double) (: Width double) (: Height double) (: Margin double) (: Padding double) (: Spacing double)))) ;; An event, and the message it sends. (type (: (On %m) (Union (: Click %m) (: Input (-> string %m)) (: Toggle (-> bool %m))))) ;; One control and what is in it. (type (: (View %m) (Record (: kind Kind) (: props (Vec Prop)) (: events (Vec (On %m))) (: children (Vec (View %m)))))) (: view-kind (-> (View %m) Kind)) (defun (view-kind v) (.kind v)) (: view-props (-> (View %m) (Vec Prop))) (defun (view-props v) (.props v)) (: view-events (-> (View %m) (Vec (On %m)))) (defun (view-events v) (.events v)) (: view-children (-> (View %m) (Vec (View %m)))) (defun (view-children v) (.children v)) ;; --------------------------------------------------------------------------- ;; Constructors ;; --------------------------------------------------------------------------- ;; A size of zero or less means: the size the control asks for. The ;; constructors leave such a size out of the props, so the control keeps its ;; own. (: (-> (Vec Prop) (-> double Prop) double (Vec Prop))) (defun (with-size props make size) (if (> size 0.0) (vec-add props (make size)) props)) (: (-> (Vec Prop) double double double double (Vec Prop))) (defun (with-layout props width height margin padding) (with-size (with-size (with-size (with-size props Width width) Height height) Margin margin) Padding padding)) (: (-> Kind (Vec Prop) (Vec (On %m)) (View %m))) (defun (leaf kind props events) (View (kind kind) (props props) (events events) (children []))) ;; A text. (: (-> string (#:size double) (#:width double) (#:height double) (#:margin double) (View %m))) (defun (text s #:size 0.0 #:width 0.0 #:height 0.0 #:margin 0.0) (leaf TextKind (with-layout (with-size [(Label s)] FontSize size) width height margin 0.0) [])) ;; A button that sends `msg` when it is clicked. (: (-> string %m (#:enabled bool) (#:width double) (#:height double) (#:margin double) (#:padding double) (View %m))) (defun (button label msg #:enabled #t #:width 0.0 #:height 0.0 #:margin 0.0 #:padding 0.0) (leaf ButtonKind (with-layout [(Label label) (Enabled enabled)] width height margin padding) [(Click msg)])) ;; A one-line text input that holds `value`. Each change sends `(on-input ;; text)`, with the whole text. (: (-> string (-> string %m) (#:placeholder string) (#:enabled bool) (#:width double) (#:margin double) (View %m))) (defun (text-input value on-input #:placeholder "" #:enabled #t #:width 0.0 #:margin 0.0) (leaf TextInputKind (with-layout [(Value value) (Placeholder placeholder) (Enabled enabled)] width 0.0 margin 0.0) [(Input on-input)])) ;; A checkbox that is `checked?`. A click sends `(on-toggle checked)`, with ;; the new state. (: (-> string bool (-> bool %m) (#:enabled bool) (#:margin double) (View %m))) (defun (checkbox label checked? on-toggle #:enabled #t #:margin 0.0) (leaf CheckBoxKind (with-layout [(Label label) (Checked checked?) (Enabled enabled)] 0.0 0.0 margin 0.0) [(Toggle on-toggle)])) (: (-> Kind double double (Array (View %m)) (View %m))) (defun (stack kind spacing margin children) (View (kind kind) (props (with-layout (with-size [] Spacing spacing) 0.0 0.0 margin 0.0)) (events []) (children (array->vec children)))) ;; Views one above the other. (: (-> (#:spacing double) (#:margin double) #:rest (View %m) (View %m))) (defun (column #:spacing 0.0 #:margin 0.0 #:rest children) (stack ColumnKind spacing margin children)) ;; Views side by side. (: (-> (#:spacing double) (#:margin double) #:rest (View %m) (View %m))) (defun (row #:spacing 0.0 #:margin 0.0 #:rest children) (stack RowKind spacing margin children))