List boxes, tabs, colours and borders

A list box's items and a tab control's tabs are views, patched by key as a
column's children are: Panel.Children and ItemsControl.Items are both an
IList, so one patch serves both. A list can choose an item only once its
items are there, so the choice is set after the children.

A routed event bubbles, so each handler now takes only its own control's
events. Before, a dropdown in a list item would have been heard as the
list's choice too.

paint gives any view a text and a background colour, and border a frame. A
colour that cannot be read leaves the theme's.

🤖 Generated with [ECA](https://eca.dev) (anthropic/claude-opus-4-8)

Co-Authored-By: eca-agent <git@eca.dev>
This commit is contained in:
Linus Björnstam 2026-10-25 17:21:40 +01:00
parent 95b6707cc1
commit e773bc424e
4 changed files with 432 additions and 36 deletions

View file

@ -58,9 +58,12 @@ being changed, and they are dropped, so only the user's events are messages.
| ~(progress-bar value)~ | ~ProgressBar~ | nothing |
| ~(dropdown options selected on-select)~ | ~ComboBox~ | ~(on-select index)~ |
| ~(image path)~ | ~Image~ | nothing |
| ~(list-box views selected on-select)~ | ~ListBox~ | ~(on-select index)~ |
| ~(tabs selected on-select (tab header view) ...)~ | ~TabControl~ | ~(on-select index)~ |
| ~(column child ...)~, ~(row child ...)~ | ~StackPanel~ | nothing |
| ~(grid #:columns #:rows child ...)~ | ~Grid~ | nothing |
| ~(scroll child)~ | ~ScrollViewer~ | nothing |
| ~(border child)~ | ~Border~ | nothing |
They take keywords where they apply: ~#:size~ (the font size of a text),
~#:wrap~ (a text breaks its lines at its width), ~#:width~, ~#:height~,
@ -86,6 +89,35 @@ number is pixels. ~(at row column view)~ puts a view in a cell, counting from
An image that cannot be read shows nothing.
A list box's items are views, so an item can be anything: a text, a row with
a checkbox, a dropdown. Give them keys if the list can change order. Each
item is a control, so a list of thousands makes thousands of controls.
#+BEGIN_SRC scheme
(tabs (.tab m) Tab
(tab "Todo" (list-box (vec-map (fun (t) (keyed (.id t) (text (.title t)))) (.todos m))
(.chosen m) Chose))
(tab "Settings" (checkbox "Dark" (.dark m) Dark)))
#+END_SRC
* Colours and borders
~(paint view #:colour #:background)~ colours any view: ~#:colour~ is the
text, ~#:background~ what is behind it. A colour is a name such as ~"red"~,
or ~"#rgb"~, ~"#rrggbb"~ or ~"#aarrggbb"~. The empty string, the default,
leaves the colour to the theme, and so does a colour that cannot be read.
~(border child #:colour #:thickness #:radius #:background #:padding)~ draws
a line around a view, with round corners if ~#:radius~ is more than zero.
#+BEGIN_SRC scheme
(border (paint (text "Saved") #:colour "#c0392b")
#:colour "#2980b9" #:radius 8.0 #:background "#ecf0f1" #:padding 8.0)
#+END_SRC
The Fluent theme gives a button its own colours when the pointer is over it
or it is pressed, so a painted button shows the theme's colour then.
* Work: commands and subscriptions
~gui-update~ is a plain function, so it cannot wait, and the compiler says so
@ -154,13 +186,15 @@ cancelled, and the program ends.
bjo run tests/app.bjo # prints "bjogui ok"
bjo run tests/effects.bjo # prints "bjogui effects ok"
bjo run tests/controls.bjo # prints "bjogui controls ok"
bjo run tests/lists.bjo # prints "bjogui lists ok"
bjo run examples/counter.bjo
bjo run examples/stopwatch.bjo
#+END_SRC
* Not yet
- A list box with a selection, tabs, menus and dialogs.
- Colours, borders and styles of one's own.
- Menus and dialogs.
- Styles of one's own, with classes, and colours for the pointer-over and
pressed states.
- A moved control is taken out of the panel and put back, so it may lose the
keyboard focus.