#[non_exhaustive]pub enum Region<'a> {
Band,
Sidebar,
Pane,
Group,
Split,
Columns,
TabGroup,
Modal,
Handover {
name: &'a str,
},
Ceded {
name: &'a str,
},
Widget {
name: &'a str,
},
}Expand description
A named part of a screen.
The thing makeover-geometry deliberately does not name: it names the space
between things by relationship, and nothing named the things. Six named
members, taken from what the two webview apps actually use, plus
Region::Handover and Region::Ceded for the parts no description
should reach. Both apps’
layout.css currently names exactly two things, .raised and .well, so
this layer is absent rather than divergent, which makes it the cheapest of
the schemas to add and the easiest to over-build.
#[non_exhaustive], for RowPart’s and Readiness’ reason: the member
after this one should not be a lockstep event across three renderers.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Band
A full-width strip with a title slot and an actions cluster, either of
which may be empty. goingson’s .page-header, Balanced Breakfast’s
.header and .detail-header are all this, differing only in which
slots they fill.
Sidebar
A persistent column beside the content, holding navigation.
Pane
A region of content with its own scroll.
Group
Things that belong together, and nothing else.
The block Heading::Section names, which the vocabulary otherwise
cannot contain. A section heading is a leaf sitting
beside the things it names, so nothing said where a section started or
ended and a renderer learned one had ended only because the next heading
arrived.
§The measurement
41 Heading::Section sites across the ten screens described through
the router, not one of them contained. audiofiles’ settings screen is the
clearest: one pane holding a heading, a field, a heading, two toggles, a
heading, a toggle and a heading, which is four sections and no
containers. Under the hand-written CSS the ports are replacing the same
block is spelled .settings-section in goingson, .form-section and
.content-section in the MNW server, .help-section in Balanced
Breakfast: three apps, four names, one shape.
§Why the existing members were the wrong answer
Pane is what apps reached for, and it is 28 of the 45
regions in the described screens. It claims a scroll of its own and
Depth::Well, so four settings groups inside a pane are four wells
inside a well and four scroll contexts. Neither claim is true of a group.
Widget is wrong from the other side. Its own docs say a
widget is never how a primitive gets added by the back door, and a run of
related controls under a heading is furniture any app would have, which
is the generic-against-bespoke bar a primitive has to clear.
§What it does not carry
A heading. A group usually has one and it is an ordinary node in the body, the way it already was. A group of related toggles with no heading is a real thing and a mandatory slot would forbid it.
A depth. Depth::Flat, on Handover’s reasoning:
it inherits, and an app that wants its group in a well puts it in a
Pane, which composes rather than adding a knob here.
A colour. Distinguishing sibling groups by colour is the thing this member was asked for and it is deliberately not stated here. The description says these things belong together; which of the theme’s categorical colours a renderer reaches for, and whether it reaches for one at all, is derived from sibling order at the renderer. A terminal that tints nothing and separates with a rule is honouring this.
Split
Two panes side by side, where the left chooses what the right shows.
Columns
Peer regions across, all of them equals.
A kanban board’s columns, and the shape Split is not:
a split’s two panes stand in a master-detail relationship, where the
left chooses what the right shows. These choose nothing about each
other. Each is a whole region and the set is the arrangement.
§What it does not carry
How many. The children say, and a count here would be a second source for something the description already states by containing them.
How wide. Peers are equal by definition, so there is no Share to
state. A board whose columns wanted different widths would be a
different member, and no app has one.
What happens when there is no room. Scroll across, wrap, or collapse to one column at a time: all three are right on some host, none is derivable from the description, and every one of them is presentation. A terminal that stacks them vertically is honouring this, not degrading it.
§Why it is not an Arrangement
Arrangement is the page’s shape, and a board is usually a region
inside a page that also has a band over it. Naming it here composes;
naming it there would make a screen either a board or a list-detail and
never a band above a board. It also keeps Arrangement::share
meaningful, which a peer arrangement has no answer for.
TabGroup
A set of panes, one visible at a time, and a Selector::Tabs that
chooses between them.
Which way the strip runs is a Strip, stated by whoever holds the
region and carried beside it, the way Showing carries the index.
Where the strip goes when there is no room is still the renderer’s to
measure, the same as its overflow.
Modal
Content over a scrim, taking input until dismissed.
Handover
A region this crate names the place of, whose contents the app still owes every host.
The escape hatch, and the thing that keeps the description honest about its own limits. A day-plan timeline, a kanban board, a calendar and the paint interaction over the timeline are not describable here and are not going to become describable: a description expressive enough to produce a timeline is a widget library wearing a description’s name.
But a screen containing one still has to be a screen. Without this member the description covers only the boring screens, and the four that make goingson worth using would need a second, undescribed path beside the router. Two paths is how the vocabulary starts drifting from the app again, which is the exact failure this crate exists to end.
So the description says “a thing called day-plan goes here” and stops.
The name is opaque: this crate never interprets it, and no renderer is
expected to know what it means beyond handing the space over.
§What separates it from Ceded
A fill is owed here in every host’s currency. A renderer handed one
of these and given nothing to put in it is looking at a hole the app
meant to fill, and saying so is the honest drawing. owed
is how it asks.
That is the whole of the split. Before it there was one opaque member, so a region the description had given up on and a region nobody had converted yet were the same value, and both drew as a silently empty box on the two renderers that answer no fill.
Ceded
A region this crate names the place of, whose contents no host is owed.
The other half of the old single opaque member. The app has decided this space is not the description’s to fill and is not going to become so: a chart, a waveform, a rendered picture of domain data with marks painted over it at positions no description knows.
Silence is the correct drawing. A renderer with no fill for this
draws nothing and is right to; unlike Handover there
is nothing missing. That is what makes the pair worth two members rather
than a flag: the two want opposite behaviour from a renderer that cannot
fill them, and one name cannot carry both.
The measured sites are MNW’s analytics charts, which already carry the ruling that a bar chart is not describable and should not be, and audiofiles’ waveform, whose exclusion had no vocabulary to live in and was recorded in a doc comment instead.
Widget
A named assembly of things the vocabulary already says.
The third tier, between a primitive and the two opaque members.
§What separates it from the two members either side
A primitive is a thing every renderer draws from scratch, and the test
it has to pass is that every host has an honest answer. A carousel fails
that test — a terminal has no carousel — which is the same refusal
Node::Html got and is why the carousel sat unsayable for months.
Handover fails it from the other side. It is for
what one app owns and nobody will build twice, and it carries no
contents: the description names the place and stops. A carousel is
furniture any app would have, and every part of it — an ordered set of
frames, a position, prev and next, a strip of position indicators — is
already sayable. Only the assembly had no name.
So this member is the pair the other two are not: a name and contents. The contents are the assembly, in the region’s own body, said in members that already exist.
§Why the name does not have to be understood
A renderer that recognises the name draws it the way its host does it: a carousel in a webview, a pager with a count in a terminal, a selector in egui. A renderer that does not recognise it walks the body, which is primitives all the way down and which it can already draw.
That is what lets the widget set be open without every renderer
knowing every widget. An unrecognised widget degrades to its assembly
instead of failing, so a second or third party can name one without
three renderers releasing in lockstep to accept it. Contrast
Handover, which no renderer can degrade: there is
nothing under it to fall back to.
§What it does not do
A widget is an assembly of things the vocabulary already says, so it
buys no expressive power. Anything needing a member the vocabulary does
not have is a finding about the vocabulary, and the answer to a finding
is to add the member. A widget is never the way a primitive gets added
by the back door. A timeline is describable because Track was added
to say it, not because a screen was dressed up as an assembly.
Implementations§
Source§impl<'a> Region<'a>
impl<'a> Region<'a>
Sourcepub const fn described(self) -> bool
pub const fn described(self) -> bool
Whether this crate can say anything about the region’s contents.
A renderer walks the description and hands every region it understands
to the right drawing code. This is how it tells the two apart, and the
reason it is a method rather than a matches! at each renderer: there
is exactly one opaque member and there should stay exactly one.
Widget is described, and that is the whole of what
separates it from the two opaque members here. All three carry a name
this crate never interprets; only the widget carries contents under it.
A renderer that does not recognise a widget’s name still walks its body,
so there is nothing for it to hand over and nothing it cannot draw.
Sourcepub const fn owed(self) -> bool
pub const fn owed(self) -> bool
Whether a fill is owed here, for a renderer that has none.
The question the single opaque member could not answer. True for
Handover: the app meant to fill this and a renderer
with nothing to put in it should say so. False for everything else,
Ceded included, where silence is the correct drawing
because nothing is missing.
A method rather than a matches! at each renderer, for
described’s reason: three renderers writing the
same match is three chances to disagree about what an empty region
means.
Sourcepub const fn name(self) -> Option<&'a str>
pub const fn name(self) -> Option<&'a str>
The name an app gave this region, if it gave one.
Handover, Ceded and
Widget are the members that carry a name, for two
different purposes: the first two say what the app puts in the space,
the third says what the assembly under it is called. A renderer dispatching on either wants the string without
caring which member it came from, and writing that matches! at each
renderer is how the two drift apart.