Controls that bjogui does not wrap, with (bjogui native)

A native is made with a function that makes the control and hooks its
events, and one that puts a value on it. hosted puts it in a view: the
control is made once for its place, given a value only when the view's
value changes, and what it sends while it is given one is dropped. Its
outputs become the app's messages through on-output and view-map, and
may be sent from any thread.

🤖 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 21:02:17 +01:00
parent 5237bf3273
commit 52ebd0ace8
5 changed files with 346 additions and 9 deletions

View file

@ -255,6 +255,53 @@ a playhead, marks and a hover line. ~start-headless!~ sets Avalonia up with no
screen, so that a test can draw components and read their pixels; see
~tests/components.bjo~.
* Controls bjogui does not wrap: (bjogui native)
Any control of Avalonia's, or of another package's, can be put in a view.
The program makes the control and hooks its events itself, so this is the
one place where it names Avalonia's types.
#+BEGIN_SRC scheme
(import (std interop))
(import (bjogui native))
(import/class (Control (: Avalonia.Controls.Control))
(Calendar (: Avalonia.Controls.Calendar (-> Calendar)))
(DateTime (: System.DateTime))
((Nullable %a) (: System.Nullable)))
(import/extern
(selected-date (: Avalonia.Controls.Calendar.SelectedDate (-> Calendar (Nullable DateTime)) #:get))
(selected-date! (: Avalonia.Controls.Calendar.SelectedDate (-> Calendar (Nullable DateTime) void) #:set))
(parse-date (: System.DateTime.Parse (-> string DateTime))))
;; A calendar, for a date as "2026-10-25".
(: calendar (Native string string))
(def calendar
(native (fun (send) ; makes one control
(def c (Calendar.))
(ignore (add-event-handler! c "SelectedDatesChanged"
(: (fun (s e)
(def d (selected-date c))
(when (.-HasValue d) (send (.ToString (.-Value d) "yyyy-MM-dd"))))
(-> Object Object void))))
(cast Control c))
(fun (control date) ; puts a value on it
(selected-date! (cast Calendar control) (parse-date date)))))
;; In a view:
(hosted calendar (.date model) Picked)
#+END_SRC
- ~(make send)~ makes the control once for its place in the view. ~send~
gives an output to the app, as a message that ~hosted~ makes with
~on-output~. It may be called from any thread.
- ~(put-value control value)~ is called after ~make~, and again each time the
view gives another value. What the control sends while it is given a value
is dropped, because it is not the user's.
- ~#:width~, ~#:height~ and ~#:margin~ are set on the control, as on any
view. A control measures itself, as Avalonia's do.
- Make a ~native~ once, at the top of a module. A view in the place of
another one is a new control.
* Styles and themes
[[file:docs/styles.png]]
@ -410,6 +457,7 @@ bjo run tests/dialogs.bjo # prints "bjogui dialogs ok"
bjo run tests/tree.bjo # prints "bjogui tree ok"
bjo run tests/canvas.bjo # prints "bjogui canvas ok"
bjo run tests/components.bjo # prints "bjogui components ok"
bjo run tests/native.bjo # prints "bjogui native ok"
bjo run examples/counter.bjo
bjo run examples/stopwatch.bjo
bjo run examples/todo.bjo
@ -424,7 +472,6 @@ bjo run examples/mixer.bjo
- Dialogs of one's own, with a view and a state.
- The macOS menu bar.
- Pointer-over and pressed colours for kinds other than buttons.
- Controls of Avalonia's or another package's that bjogui does not wrap.
- A component asks for no size of its own: it is given one, or fills the
space it gets. Measuring itself, an accessibility tree, and text input
inside a component would need a subclass.