max / makeover-layout
| 1 | use crateNesting; |
| 2 | |
| 3 | // Names this module's prose links to, resolved for rustdoc. |
| 4 | |
| 5 | use crate::; |
| 6 | |
| 7 | /// A named dimension a set can be narrowed by. |
| 8 | /// |
| 9 | /// One word for six things that were six mechanisms. MNW's discover page filters |
| 10 | /// by free text, a flat any-of over item types, a tree of tags, a numeric range |
| 11 | /// over price, a nested one-of over AI tier, and a browse position in the tag |
| 12 | /// tree held separately from the tag selection — and the last two being separate |
| 13 | /// is the whole reason a filter row there needs a tick box *and* a chevron. The |
| 14 | /// panel is a mixed bag of hand-written controls because nothing named the thing |
| 15 | /// they all are. |
| 16 | /// |
| 17 | /// Deliberately wider than that one page. audiofiles' library browser and |
| 18 | /// goingson's filters are the same shape, and a word that only fitted discover |
| 19 | /// would be discover's markup with a neutral name on it. |
| 20 | /// |
| 21 | /// # What it does not say |
| 22 | /// |
| 23 | /// **What picking a value calls.** This crate names no address, so a facet is |
| 24 | /// paired with routes the way a column's [`sortable`](Column::sortable) flag is |
| 25 | /// paired with what reordering calls. |
| 26 | /// |
| 27 | /// **How a tree is drawn.** Indented rows, a column of panes, a breadcrumb and a |
| 28 | /// list: all four are honest renderings of the same described facet, and a |
| 29 | /// terminal will not pick the same one a browser does. [`FacetValue::depth`] is |
| 30 | /// what a renderer needs to draw any of them; the choice is not described. |
| 31 | /// |
| 32 | /// **Which values to show.** A tag tree has thousands of nodes and a panel shows |
| 33 | /// a handful. Deciding which handful is the app's — it is the same question as |
| 34 | /// which rows go in a table, and no table member answers it either. |
| 35 | |
| 36 | |
| 37 | |
| 38 | /// What the dimension is called, as the user reads it. |
| 39 | pub name: &'a str, |
| 40 | /// How many of its values may be in force, and in what shape. |
| 41 | pub mode: Selecting, |
| 42 | /// The values on offer, in the order they are drawn. |
| 43 | /// |
| 44 | /// A [`Selecting::Text`] facet has none: the value is whatever was typed, |
| 45 | /// and a description that listed the possible strings would be listing the |
| 46 | /// corpus. A [`Selecting::Range`] facet has none either, for the reason |
| 47 | /// [`FieldKind::Range`] takes bounds rather than options — the ends are the |
| 48 | /// question and the values between them are not enumerable. |
| 49 | pub values: &'a [], |
| 50 | |
| 51 | |
| 52 | |
| 53 | /// A dimension with values to pick from. |
| 54 | |
| 55 | pub const |
| 56 | Self |
| 57 | |
| 58 | |
| 59 | /// Whether the facet is narrowing the set right now. |
| 60 | /// |
| 61 | /// The question a renderer asks to decide whether to offer a way out of it, |
| 62 | /// and the reason it is derived rather than carried: a facet with nothing |
| 63 | /// standing is unengaged by construction, so a member saying so could |
| 64 | /// disagree with the values beside it. [`Standing::Inherited`] does not |
| 65 | /// count — something further up is what is doing the narrowing, and clearing |
| 66 | /// a child that was never picked clears nothing. |
| 67 | /// |
| 68 | /// Always false for [`Selecting::Text`] and [`Selecting::Range`], which |
| 69 | /// carry no values. A host that wants a clear affordance on those knows |
| 70 | /// whether its own box is empty; the description does not hold the typed |
| 71 | /// string. |
| 72 | |
| 73 | |
| 74 | self.values.iter.any |
| 75 | |
| 76 | |
| 77 | /// The deepest value in the facet, or zero when it is flat. |
| 78 | /// |
| 79 | /// What an indenting renderer needs to reserve a gutter before it draws the |
| 80 | /// first row, which is "First paint is final paint" applied to a tree: a |
| 81 | /// gutter widened as deeper values arrive is the reflow that rule forbids. |
| 82 | |
| 83 | |
| 84 | self.values |
| 85 | .iter |
| 86 | .map |
| 87 | .max |
| 88 | .unwrap_or |
| 89 | |
| 90 | |
| 91 | |
| 92 | /// How many of a [`Facet`]'s values may be in force, and in what shape. |
| 93 | /// |
| 94 | /// Five, and the fifth is what made this an enum rather than a bool. `one-of`, |
| 95 | /// `any-of`, a range and free text are the four a form vocabulary already has in |
| 96 | /// [`FieldKind`]; a tree's selection is none of them, and describing tags as |
| 97 | /// any-of was what forced browsing to be a second mechanism beside filtering. |
| 98 | |
| 99 | |
| 100 | |
| 101 | /// Exactly one value, and picking another replaces it. |
| 102 | /// |
| 103 | /// MNW's AI tier, whose three options are nested ranges rather than |
| 104 | /// independent values, so two of them at once means nothing. |
| 105 | OneOf, |
| 106 | /// Any number of values, each independent of the others. |
| 107 | AnyOf, |
| 108 | /// A low end, a high end, or both. |
| 109 | /// |
| 110 | /// Carries no values for [`FieldKind::Range`]'s reason: the ends are the |
| 111 | /// question. |
| 112 | Range, |
| 113 | /// Whatever the user types. |
| 114 | Text, |
| 115 | /// A position in a tree, edited by taking branches in and pruning branches |
| 116 | /// out. |
| 117 | /// |
| 118 | /// The one mode that is not reducible to the others, and the one gesture |
| 119 | /// that replaced two. Picking a value narrows the set to it *and* reveals |
| 120 | /// its children, so browsing a tree and filtering by it stop being separate |
| 121 | /// mechanisms with separate state. What a selection then is: a set of |
| 122 | /// branches taken and a set pruned, resolved nearest-ancestor-first, so |
| 123 | /// `music` in and `music/synths` out is sayable and no flat mode can say it. |
| 124 | /// |
| 125 | /// Resolution happens in the app, and what reaches a renderer is the |
| 126 | /// [`Standing`] each drawn value ended up with. A renderer walking ancestors |
| 127 | /// itself would be a renderer that can disagree with the results beside it. |
| 128 | Subtree, |
| 129 | |
| 130 | |
| 131 | |
| 132 | /// Whether the mode picks from values the description lists. |
| 133 | /// |
| 134 | /// False for [`Text`](Self::Text) and [`Range`](Self::Range), which are the |
| 135 | /// two whose answer is not one of a set. A renderer asks this before it |
| 136 | /// looks at [`Facet::values`], the way it asks |
| 137 | /// [`FieldKind::offers_options`] before it looks at [`Field::options`]. |
| 138 | |
| 139 | pub const |
| 140 | matches! |
| 141 | |
| 142 | |
| 143 | /// Whether a value can be pruned as well as picked. |
| 144 | /// |
| 145 | /// [`Subtree`](Self::Subtree) alone. Excluding a value from a flat facet is |
| 146 | /// the same fact as not picking it, so an exclude affordance there would be |
| 147 | /// a second control for a state the first one already holds. |
| 148 | |
| 149 | pub const |
| 150 | matches! |
| 151 | |
| 152 | |
| 153 | /// Whether picking a second value keeps the first. |
| 154 | |
| 155 | pub const |
| 156 | matches! |
| 157 | |
| 158 | |
| 159 | |
| 160 | /// One value a [`Facet`] offers, as it currently stands. |
| 161 | |
| 162 | |
| 163 | |
| 164 | /// What identifies it, and what a host keys its route on. |
| 165 | /// |
| 166 | /// [`Choice::value`]'s split, and a tree is why it is not optional: two |
| 167 | /// leaves under different parents are legitimately both called "Ambient", |
| 168 | /// and the path is the only thing telling them apart. It is also what |
| 169 | /// nearest-ancestor-wins resolves over, so an app that carried only labels |
| 170 | /// could not compute the [`standing`](Self::standing) it hands back here. |
| 171 | pub value: &'a str, |
| 172 | /// What it is called, as the user reads it. |
| 173 | /// |
| 174 | /// The leaf's own name rather than its path: a facet drawn as an indented |
| 175 | /// tree repeats every ancestor on every line otherwise, and one drawn as a |
| 176 | /// breadcrumb has the ancestors already. |
| 177 | pub label: &'a str, |
| 178 | /// How many members of the set carry it. |
| 179 | /// |
| 180 | /// Optional, and settled that way rather than made mandatory: a count is a |
| 181 | /// measured fact the app may not have. Counting a tag subtree under an |
| 182 | /// active text search is a second query, and an app that will not pay for it |
| 183 | /// should be able to describe the facet anyway rather than write a zero that |
| 184 | /// reads as "none of them". That is [`Awaiting::amount`]'s rule in a second |
| 185 | /// place — state a number when it was measured, and nothing when it was not. |
| 186 | pub count: , |
| 187 | /// Whether it is narrowing the set, and how it came to be. |
| 188 | pub standing: Standing, |
| 189 | /// How far down the tree it sits, counting from zero at the root. |
| 190 | /// |
| 191 | /// Always zero for a flat facet, which is what makes an indenting renderer |
| 192 | /// one code path rather than two. A renderer that draws no tree at all still |
| 193 | /// reads this, since a value's depth is what distinguishes two same-named |
| 194 | /// leaves under different parents. |
| 195 | pub depth: Nesting, |
| 196 | /// Whether taking it reveals values under it. |
| 197 | /// |
| 198 | /// Distinct from having a nonzero [`depth`](Self::depth): a leaf deep in the |
| 199 | /// tree branches no further, and a root with children does. Both facts are |
| 200 | /// needed and neither implies the other, which is why the pair is two |
| 201 | /// members rather than one count. |
| 202 | pub branching: bool, |
| 203 | |
| 204 | |
| 205 | |
| 206 | /// An unpicked value at the root of the facet. |
| 207 | |
| 208 | pub const |
| 209 | Self |
| 210 | value, |
| 211 | label, |
| 212 | count: None, |
| 213 | standing: Open, |
| 214 | depth: top, |
| 215 | branching: false, |
| 216 | |
| 217 | |
| 218 | |
| 219 | /// A value whose identifier is also what the user reads. |
| 220 | /// |
| 221 | /// [`Choice::plain`]'s convenience, and it is the flat case: a type or a tier |
| 222 | /// is its own name, and only a tree needs a path that is not one. |
| 223 | |
| 224 | pub const |
| 225 | Selfnew |
| 226 | |
| 227 | |
| 228 | /// How many members carry it, when that was measured. |
| 229 | |
| 230 | pub const |
| 231 | self.count = Some; |
| 232 | self |
| 233 | |
| 234 | |
| 235 | /// How it stands in the current selection. |
| 236 | |
| 237 | pub const |
| 238 | self.standing = standing; |
| 239 | self |
| 240 | |
| 241 | |
| 242 | /// Where it sits in the tree, and whether anything hangs off it. |
| 243 | |
| 244 | pub const |
| 245 | self.depth = depth; |
| 246 | self.branching = branching; |
| 247 | self |
| 248 | |
| 249 | |
| 250 | |
| 251 | /// Whether a [`FacetValue`] is narrowing the set, and how it came to be. |
| 252 | /// |
| 253 | /// Four rather than a bool, and the two extra members are what a tree costs. A |
| 254 | /// pruned branch and an untaken one are not the same state — one was decided |
| 255 | /// against and the other was never reached — and a child under a taken parent is |
| 256 | /// in force without anybody having picked it. A renderer given a bool either |
| 257 | /// marks every descendant of a taken branch, which reads as forty deliberate |
| 258 | /// choices, or marks none of them, which reads as unfiltered. |
| 259 | |
| 260 | |
| 261 | |
| 262 | /// Not picked, and nothing above it is either. |
| 263 | |
| 264 | Open, |
| 265 | /// Picked here. The set is narrowed to it and whatever hangs off it. |
| 266 | Taken, |
| 267 | /// In force because something above it was taken. |
| 268 | Inherited, |
| 269 | /// Pruned out, though something above it was taken. |
| 270 | /// |
| 271 | /// The state that only [`Selecting::Subtree`] can reach, and the reason |
| 272 | /// exclusion is drawn as a visible affordance beside each label rather than |
| 273 | /// as a modifier on the ordinary one: a gesture a terminal cannot express is |
| 274 | /// a gesture half the renderers would have to leave out, and an affordance |
| 275 | /// nothing teaches is one users do not find. |
| 276 | Pruned, |
| 277 | |
| 278 | |
| 279 | |
| 280 | /// Whether the user decided this value, either way. |
| 281 | /// |
| 282 | /// True for [`Taken`](Self::Taken) and [`Pruned`](Self::Pruned) — both are |
| 283 | /// choices, and both are things a "clear this" affordance has to clear. |
| 284 | /// [`Inherited`](Self::Inherited) is not: clearing it clears nothing, |
| 285 | /// because the decision is further up. |
| 286 | |
| 287 | pub const |
| 288 | matches! |
| 289 | |
| 290 | |
| 291 | /// Whether the value narrows the set in. |
| 292 | /// |
| 293 | /// [`Taken`](Self::Taken) and [`Inherited`](Self::Inherited): one was picked |
| 294 | /// and one came down from above, and to the set they mean the same thing. |
| 295 | /// The pair is named here so a renderer colouring in-force values does not |
| 296 | /// have to know which is which. |
| 297 | |
| 298 | pub const |
| 299 | matches! |
| 300 | |
| 301 | |
| 302 | /// The content intent the value takes. |
| 303 | /// |
| 304 | /// [`Pruned`](Self::Pruned) reads back a step, which is the three-tone rule |
| 305 | /// above rather than a new decision: a pruned branch is still a live control |
| 306 | /// — pressing it takes the prune off — so it may not wear `content-muted`, |
| 307 | /// and it is not the thing itself either. |
| 308 | |
| 309 | pub const |
| 310 | match self |
| 311 | SelfTaken | SelfInherited | SelfOpen => "content", |
| 312 | SelfPruned => "content-secondary", |
| 313 | |
| 314 | |
| 315 | |
| 316 |