bjogui/src/view.bjo

145 lines
5.6 KiB
Text
Raw 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/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))