Keyed children, and eight more controls
A child is now known by its key, or by its place among the children with no key. One whose identity was there before keeps its control, and the controls are put in the new order by moving only those out of place. So a list that is sorted, or has an item put in front, keeps its controls. Text areas, sliders, progress bars, dropdowns, images, grids with cells and spans, and scroll views. A grid's sizes are .NET properties and not Avalonia's, so they are set by a setter of their own. A text is centred in its height, so a label lines up with the control beside it. 🤖 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
4f48282314
commit
95b6707cc1
4 changed files with 680 additions and 91 deletions
148
src/view.bjo
148
src/view.bjo
|
|
@ -18,10 +18,13 @@
|
|||
View Kind Prop On
|
||||
|
||||
;; Constructors.
|
||||
text button text-input checkbox column row
|
||||
text button text-input text-area checkbox slider progress-bar dropdown image
|
||||
column row grid scroll
|
||||
;; Wrappers.
|
||||
keyed at
|
||||
|
||||
;; Reading one.
|
||||
view-kind view-props view-events view-children)
|
||||
view-kind view-props view-events view-children view-key)
|
||||
|
||||
(import (std prelude))
|
||||
|
||||
|
|
@ -30,7 +33,9 @@
|
|||
;; ---------------------------------------------------------------------------
|
||||
|
||||
;; What control a view is.
|
||||
(type (: Kind (Union TextKind ButtonKind TextInputKind CheckBoxKind ColumnKind RowKind)))
|
||||
(type (: Kind (Union TextKind ButtonKind TextInputKind TextAreaKind CheckBoxKind
|
||||
SliderKind ProgressKind DropdownKind ImageKind
|
||||
ColumnKind RowKind GridKind ScrollKind)))
|
||||
|
||||
;; A property of a control. A kind takes only some of them; the app ignores
|
||||
;; the others.
|
||||
|
|
@ -44,18 +49,40 @@
|
|||
(: Height double)
|
||||
(: Margin double)
|
||||
(: Padding double)
|
||||
(: Spacing double))))
|
||||
(: Spacing double)
|
||||
(: Wrap bool) ; a text breaks its lines at the width
|
||||
(: Minimum double) ; of a slider or a progress bar
|
||||
(: Maximum double)
|
||||
(: Amount double) ; where a slider or a progress bar is
|
||||
(: Step double) ; what an arrow key moves a slider by
|
||||
(: Items (Vec string)) ; what a dropdown offers
|
||||
(: Selected int) ; which of them is chosen; -1 for none
|
||||
(: Source string) ; the file an image shows
|
||||
(: Columns string) ; a grid's columns, as "Auto,*,2*"
|
||||
(: Rows string)
|
||||
(: Row int) ; where a view is in its grid
|
||||
(: Column int)
|
||||
(: RowSpan int)
|
||||
(: ColumnSpan int))))
|
||||
|
||||
;; An event, and the message it sends.
|
||||
(type (: (On %m) (Union (: Click %m)
|
||||
(: Input (-> string %m))
|
||||
(: Toggle (-> bool %m)))))
|
||||
(: Toggle (-> bool %m))
|
||||
(: Slide (-> double %m))
|
||||
(: Select (-> int %m)))))
|
||||
|
||||
;; One control and what is in it.
|
||||
;;
|
||||
;; `key` says which child of its parent a view is. Children with keys are
|
||||
;; matched by key when the next view is compared with the last one, so a
|
||||
;; child that moves keeps its control. Children without one are matched by
|
||||
;; their place among the others without one.
|
||||
(type (: (View %m) (Record (: kind Kind)
|
||||
(: props (Vec Prop))
|
||||
(: events (Vec (On %m)))
|
||||
(: children (Vec (View %m))))))
|
||||
(: children (Vec (View %m)))
|
||||
(: key (Option string)))))
|
||||
|
||||
(: view-kind (-> (View %m) Kind))
|
||||
(defun (view-kind v) (.kind v))
|
||||
|
|
@ -69,6 +96,26 @@
|
|||
(: view-children (-> (View %m) (Vec (View %m))))
|
||||
(defun (view-children v) (.children v))
|
||||
|
||||
(: view-key (-> (View %m) (Option string)))
|
||||
(defun (view-key v) (.key v))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Wrappers
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
;; The view, with a key that says which child it is. Give each item of a list
|
||||
;; that can change order a key of its own, such as its id.
|
||||
(: keyed (-> string (View %m) (View %m)))
|
||||
(defun (keyed key v)
|
||||
(record-set v (key (Some key))))
|
||||
|
||||
;; The view, in a cell of its grid. Rows and columns count from 0.
|
||||
(: at (-> int int (View %m) (#:row-span int) (#:column-span int) (View %m)))
|
||||
(defun (at row column v #:row-span 1 #:column-span 1)
|
||||
(record-set v (props (vec-add (vec-add (vec-add (vec-add (.props v) (Row row)) (Column column))
|
||||
(RowSpan row-span))
|
||||
(ColumnSpan column-span)))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Constructors
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
|
@ -88,14 +135,15 @@
|
|||
|
||||
(: (-> Kind (Vec Prop) (Vec (On %m)) (View %m)))
|
||||
(defun (leaf kind props events)
|
||||
(View (kind kind) (props props) (events events) (children [])))
|
||||
(View (kind kind) (props props) (events events) (children []) (key None)))
|
||||
|
||||
;; A text.
|
||||
(: (-> string (#:size double) (#:width double) (#:height double) (#:margin double)
|
||||
(: (-> string (#:size double) (#:wrap bool) (#:width double) (#:height double)
|
||||
(#:margin double)
|
||||
(View %m)))
|
||||
(defun (text s #:size 0.0 #:width 0.0 #:height 0.0 #:margin 0.0)
|
||||
(defun (text s #:size 0.0 #:wrap #f #:width 0.0 #:height 0.0 #:margin 0.0)
|
||||
(leaf TextKind
|
||||
(with-layout (with-size [(Label s)] FontSize size) width height margin 0.0)
|
||||
(with-layout (with-size [(Label s) (Wrap wrap)] FontSize size) width height margin 0.0)
|
||||
[]))
|
||||
|
||||
;; A button that sends `msg` when it is clicked.
|
||||
|
|
@ -118,6 +166,59 @@
|
|||
width 0.0 margin 0.0)
|
||||
[(Input on-input)]))
|
||||
|
||||
;; A text input of several lines, that breaks its lines at its width. Each
|
||||
;; change sends `(on-input text)`, with the whole text.
|
||||
(: (-> string (-> string %m) (#:placeholder string) (#:enabled bool)
|
||||
(#:width double) (#:height double) (#:margin double)
|
||||
(View %m)))
|
||||
(defun (text-area value on-input #:placeholder "" #:enabled #t #:width 0.0 #:height 0.0
|
||||
#:margin 0.0)
|
||||
(leaf TextAreaKind
|
||||
(with-layout [(Value value) (Placeholder placeholder) (Enabled enabled)]
|
||||
width height margin 0.0)
|
||||
[(Input on-input)]))
|
||||
|
||||
;; A slider at `value`, from `minimum` to `maximum`. A move sends `(on-change
|
||||
;; value)`.
|
||||
(: (-> double double double (-> double %m) (#:step double) (#:enabled bool)
|
||||
(#:width double) (#:margin double)
|
||||
(View %m)))
|
||||
(defun (slider value minimum maximum on-change #:step 1.0 #:enabled #t #:width 0.0
|
||||
#:margin 0.0)
|
||||
;; The bounds come before the value, because a value outside the bounds
|
||||
;; that are there is moved inside them.
|
||||
(leaf SliderKind
|
||||
(with-layout [(Minimum minimum) (Maximum maximum) (Amount value) (Step step)
|
||||
(Enabled enabled)]
|
||||
width 0.0 margin 0.0)
|
||||
[(Slide on-change)]))
|
||||
|
||||
;; A bar that is `value` of the way from 0 to `#:maximum`, 1 unless told
|
||||
;; otherwise.
|
||||
(: (-> double (#:maximum double) (#:width double) (#:margin double) (View %m)))
|
||||
(defun (progress-bar value #:maximum 1.0 #:width 0.0 #:margin 0.0)
|
||||
(leaf ProgressKind
|
||||
(with-layout [(Minimum 0.0) (Maximum maximum) (Amount value)] width 0.0 margin 0.0)
|
||||
[]))
|
||||
|
||||
;; A list to choose one of `options` from, with the one at `selected` chosen,
|
||||
;; or none for -1. A choice sends `(on-select index)`.
|
||||
(: (-> (Vec string) int (-> int %m) (#:enabled bool) (#:width double) (#:margin double)
|
||||
(View %m)))
|
||||
(defun (dropdown options selected on-select #:enabled #t #:width 0.0 #:margin 0.0)
|
||||
;; The items come before the choice, because the choice is an index into
|
||||
;; them.
|
||||
(leaf DropdownKind
|
||||
(with-layout [(Items options) (Selected selected) (Enabled enabled)]
|
||||
width 0.0 margin 0.0)
|
||||
[(Select on-select)]))
|
||||
|
||||
;; The picture in the file at `path`. A file that cannot be read shows
|
||||
;; nothing.
|
||||
(: (-> string (#:width double) (#:height double) (#:margin double) (View %m)))
|
||||
(defun (image path #:width 0.0 #:height 0.0 #:margin 0.0)
|
||||
(leaf ImageKind (with-layout [(Source path)] width height margin 0.0) []))
|
||||
|
||||
;; 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)))
|
||||
|
|
@ -126,12 +227,14 @@
|
|||
(with-layout [(Label label) (Checked checked?) (Enabled enabled)] 0.0 0.0 margin 0.0)
|
||||
[(Toggle on-toggle)]))
|
||||
|
||||
(: (-> Kind (Vec Prop) (Vec (View %m)) (View %m)))
|
||||
(defun (container kind props children)
|
||||
(View (kind kind) (props props) (events []) (children children) (key None)))
|
||||
|
||||
(: (-> 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))))
|
||||
(container kind (with-layout (with-size [] Spacing spacing) 0.0 0.0 margin 0.0)
|
||||
(array->vec children)))
|
||||
|
||||
;; Views one above the other.
|
||||
(: (-> (#:spacing double) (#:margin double) #:rest (View %m) (View %m)))
|
||||
|
|
@ -142,3 +245,20 @@
|
|||
(: (-> (#:spacing double) (#:margin double) #:rest (View %m) (View %m)))
|
||||
(defun (row #:spacing 0.0 #:margin 0.0 #:rest children)
|
||||
(stack RowKind spacing margin children))
|
||||
|
||||
;; Views in the cells of a grid. `#:columns` and `#:rows` are the sizes, as
|
||||
;; in Avalonia: "Auto" fits the content, "*" shares what is left, "2*" takes
|
||||
;; two shares, and a number is pixels. Put a view in a cell with `at`; one
|
||||
;; that is not put anywhere is in the first.
|
||||
(: (-> (#:columns string) (#:rows string) (#:spacing double) (#:margin double)
|
||||
#:rest (View %m) (View %m)))
|
||||
(defun (grid #:columns "*" #:rows "*" #:spacing 0.0 #:margin 0.0 #:rest children)
|
||||
(container GridKind
|
||||
(with-layout (with-size [(Columns columns) (Rows rows)] Spacing spacing)
|
||||
0.0 0.0 margin 0.0)
|
||||
(array->vec children)))
|
||||
|
||||
;; A view that scrolls when it is taller than the space it has.
|
||||
(: (-> (View %m) (#:width double) (#:height double) (#:margin double) (View %m)))
|
||||
(defun (scroll child #:width 0.0 #:height 0.0 #:margin 0.0)
|
||||
(container ScrollKind (with-layout [] width height margin 0.0) [child]))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue