1# whiskers-chooser 2 3The character chooser: the main screen in an edit mode. She taps the character in the side panel and sees the 4character with an arrow on each side (previous and next, wrapping around), under it the name of its voice with an 5arrow on each side (previous and next voice, wrapping), and the bottom buttons are a check (save) and a cross (throw the 6change away and leave). Choosing a voice speaks "Hi Ada, this voice is called Jennifer" in that voice; changing the 7character says "Hi Ada" in that character's saved voice. **Nothing is saved until the check**, and the check saves exactly 8the shown character and the voice shown for it. 9 10## The rules 11 12What each thing she does means is not code in the shell. It is [`src/domain.rs`](src/domain.rs): twenty rules on the 13estate's shared Rete engine (`rete`, in the submodule `third-party/rustcrates`, the same engine lmjtfy runs). A rule is a 14list of tests on facts (what she did, whether the chooser is open, whether anything is unsaved, whether voices are listed, 15and what an earlier effect already did) and what to do when they hold; order is priority. The picture of the network that 16runs is [`docs/chooser-rules.svg`](docs/chooser-rules.svg), drawn by `rete-draw` and held to the network by a test 17(`cargo run -p whiskers-chooser --example draw` writes it again). 18 19| Input | Rule | What happens | 20|---|---|---| 21| open | open | the chooser opens on the saved character and its saved voice (says nothing) | 22| right, left | next / previous character | the next or previous character shows, with the voice saved for it, then it says hi in that voice | 23| voice right, left | next / previous voice | the next or previous listed voice shows, then it says its name in that voice | 24| check | check saves | with something unsaved, the shown character and its voice are kept, then the chooser closes | 25| check | check with no change closes | nothing to keep: it closes | 26| cross | cross throws away | what shows is put back to what is saved, then the chooser closes | 27| anything that means nothing now | closed: ..., open already, no voices to step | a note says so; nothing changes | 28 29## What it is 30 31[`Chooser`](src/lib.rs) holds the state the rules act on, because a character and a voice are too wide to be facts: which 32are shown, which are saved. `Chooser::input(Input)` runs the rules and returns an `Output`: the `View` to draw, the 33`ShellEffect`s to do in order (speak an `Utterance`, keep a `Save`, leave), and the trace. The engine (`Engine::chooser_input`) 34keeps one between inputs, rebuilds it each time the chooser opens, and keeps the choice on a `Save`; `whiskers-ffi` exports 35it, so the Kotlin shell only sends an input, draws the view and does the effects. 36 37Every step leaves one JSON line per event (which rule fired, which facts it stood on, counts; names and ids only, never the 38child's name or a voice's name or what was said) and the chooser logs them at info level as `chooser {...}`. 39 40## Files 41 42| File | What | 43|---|---| 44| [`src/domain.rs`](src/domain.rs) | The vocabulary (facts, values, effects, notes) and the rules. | 45| [`src/lib.rs`](src/lib.rs) | `Chooser`: the state and the effects the rules decide. | 46| [`src/tests.rs`](src/tests.rs) | The laws: wrap-around both ways, a preview does not save, the check saves exactly one character and its voice, the cross changes nothing, a character shows its own saved voice, the lines said. | 47| [`tests/drawing.rs`](tests/drawing.rs), [`tests/common/mod.rs`](tests/common/mod.rs), [`examples/draw.rs`](examples/draw.rs) | The picture, and the test that holds it to the rules. | 48| [`docs/chooser-rules.svg`](docs/chooser-rules.svg) | The network, drawn. |