max / quasi
| 1 | //! What the user has done to a screen since it arrived. |
| 2 | //! |
| 3 | //! Two of the five things `quasi-tui`'s `View` holds, and the other three are |
| 4 | //! egui's. That is the whole difference between the two crates' state, and it is |
| 5 | //! worth saying which is which so the next reader does not go looking for the |
| 6 | //! missing ones: |
| 7 | //! |
| 8 | //! | Fact | terminal | here | |
| 9 | //! |---|---|---| |
| 10 | //! | what is typed | `View` | **`View`** | |
| 11 | //! | what is ticked | `View` | **`View`** | |
| 12 | //! | what has focus | `View` | egui's id stack | |
| 13 | //! | how far a pane is scrolled | `View` | `egui::ScrollArea` | |
| 14 | //! | where back goes | `Runtime` | [`Runtime`](crate::Runtime) | |
| 15 | //! |
| 16 | //! **Why typing is not egui's, when focus is.** egui holds widget state against |
| 17 | //! an id, and a described field is rebuilt from the description every frame; its |
| 18 | //! `TextEdit` needs a `&mut String` that outlives the frame, and the description |
| 19 | //! deliberately does not carry the value. So the buffer is the app's, held here. |
| 20 | //! That is the same conclusion `makeover-immediate`'s `Filling` reached one layer |
| 21 | //! down and for the same reason. |
| 22 | |
| 23 | use ; |
| 24 | |
| 25 | use Instant; |
| 26 | |
| 27 | use ; |
| 28 | |
| 29 | /// The host's side of an outstanding wait. |
| 30 | /// |
| 31 | /// Two `Option`s rather than an `Option` of a pair, because they arrive at |
| 32 | /// different moments: the clock starts when the call goes out and a delivery |
| 33 | /// count arrives only if something is watching. Most waits never get one. |
| 34 | |
| 35 | |
| 36 | /// When the call went out. |
| 37 | since: , |
| 38 | /// How much has arrived, in the unit the description counted. |
| 39 | delivered: , |
| 40 | |
| 41 | |
| 42 | /// What a waiting consult belongs to. |
| 43 | /// |
| 44 | /// Two things ask questions while the reader works — a box about its own |
| 45 | /// value, and a region about the values inside it — and both address |
| 46 | /// themselves with a string. The strings live in different namespaces and |
| 47 | /// nothing stops them colliding, so the namespace is part of the key rather |
| 48 | /// than a convention nobody enforces. |
| 49 | |
| 50 | |
| 51 | /// A box's own question, by [`Field::name`](quasi_router::Field::name). |
| 52 | Field, |
| 53 | /// A region's question, by [`Slot::id`](quasi_router::Slot::id). |
| 54 | Region, |
| 55 | |
| 56 | |
| 57 | /// What the user has done to a screen since it arrived. |
| 58 | /// |
| 59 | /// A host makes one beside the screen it is holding and keeps the two together. |
| 60 | /// Empty is the honest starting state and it draws exactly what the description |
| 61 | /// says. |
| 62 | |
| 63 | |
| 64 | /// What has been typed, by [`Field::name`](quasi_router::Field::name). |
| 65 | /// |
| 66 | /// Absent means untouched, which is different from present and empty: one |
| 67 | /// draws the description's value and the other draws a box the user has |
| 68 | /// cleared. |
| 69 | edits: , |
| 70 | /// What has been ticked, by [`Row::value`](quasi_router::Row::value). |
| 71 | ticked: , |
| 72 | /// Which branches the reader has folded or unfolded, by |
| 73 | /// [`Outline::key`](quasi_router::Outline::key). |
| 74 | /// |
| 75 | /// Absent means the description's own answer stands, so a screen arriving |
| 76 | /// with a branch shut draws it shut until the reader says otherwise. |
| 77 | opened: , |
| 78 | /// Which child each region showing one at a time is showing, by |
| 79 | /// [`Slot::id`](quasi_router::Slot::id). |
| 80 | /// |
| 81 | /// Absent means the description's own answer stands, which is `opened`'s |
| 82 | /// rule one region-kind along: a screen arriving on its second tab draws |
| 83 | /// its second tab until the reader presses something else. |
| 84 | /// |
| 85 | /// `Option<usize>` where quasi-tui's is a bare `usize`, and the difference |
| 86 | /// is real rather than a spelling. `Showing::AtMostOne` closed is `None`, |
| 87 | /// and a terminal's prev/next row cannot reach it -- there is no key that |
| 88 | /// means "close" once a strip has been walked onto a child. A summary line |
| 89 | /// here is one control that opens and shuts, so closed has to be a state |
| 90 | /// the reader can put a region back into. |
| 91 | shown: , |
| 92 | /// The value a field's [`writes`](quasi_router::Field::writes) last fired |
| 93 | /// with, by field name. |
| 94 | /// |
| 95 | /// `changes` fires when the value is complete rather than on the way to |
| 96 | /// it, so "complete" needs a baseline to be different from: a blur that |
| 97 | /// changed nothing must not write, which is what a browser's `change` |
| 98 | /// event already promises. Absent means nothing has been fired for that |
| 99 | /// field, and the description's own value is the baseline. |
| 100 | /// |
| 101 | /// Beside `edits` rather than derived from it, because they answer |
| 102 | /// different questions: `edits` is what is on screen and this is what the |
| 103 | /// route has been told. |
| 104 | written: , |
| 105 | /// When a consult is due, by what asks it and the consult's place in that |
| 106 | /// asker's list. |
| 107 | /// |
| 108 | /// `N8`. The second half of the key is the cost the ruling named: a box may |
| 109 | /// ask two routes at two rates -- MNW's discover search asks its suggestion |
| 110 | /// route after 200ms and its results route after 150 -- and one deadline |
| 111 | /// per field would have the faster question cancel the slower one. |
| 112 | /// |
| 113 | /// A deadline rather than an elapsed count, so a keystroke arriving during |
| 114 | /// the wait moves it forward by overwriting the entry: that is the whole of |
| 115 | /// debouncing, and it needs no tick counter and no second clock. |
| 116 | /// |
| 117 | /// Here rather than in `Pass` because a `Pass` is one frame and the wait |
| 118 | /// spans many. It is the same reason `edits` lives here. |
| 119 | /// |
| 120 | /// Keyed by [`Asking`] rather than by a bare name, so a region and a field |
| 121 | /// that happen to share a string keep their own deadlines: a |
| 122 | /// [`Slot::id`](quasi_router::Slot::id) and a |
| 123 | /// [`Field::name`](quasi_router::Field::name) are addresses in two |
| 124 | /// namespaces and nothing keeps them apart, so a map keyed on the string |
| 125 | /// would have had a panel's recompute cancelled by a box that shared its |
| 126 | /// name. |
| 127 | awaiting: , |
| 128 | /// The question the caret is owed, until the frame that gives it to it. |
| 129 | /// |
| 130 | /// [`Screen::opens_at`](quasi_router::Screen::opens_at) read once on |
| 131 | /// arrival, and taken by the field that claims it. Focus is egui's here -- |
| 132 | /// the table at the top of this module says so -- so this is not the caret, |
| 133 | /// it is the one-frame instruction to ask egui for it. |
| 134 | /// |
| 135 | /// Taken rather than read, so it happens on the arrival frame and no |
| 136 | /// other. A flag left standing would ask for focus every frame and the |
| 137 | /// reader could never move the caret off the box. |
| 138 | opens: , |
| 139 | /// The action this screen is waiting on, when one is outstanding. |
| 140 | /// |
| 141 | /// Only an action carrying [`Action::awaiting`] lands here: the |
| 142 | /// description says which calls are worth locking a control for, and this |
| 143 | /// renderer does not decide that a route is slow. Beside `awaiting` above |
| 144 | /// and not folded into it, which is the distinction the ruling turns on: a |
| 145 | /// consult is a wait this renderer chose to impose, and this is a wait the |
| 146 | /// description declared. |
| 147 | outstanding: , |
| 148 | /// When the outstanding call went out, and how much of it has landed. |
| 149 | /// |
| 150 | /// Wiki `loading-and-progress-standard`, rule 1. `Action::awaiting` carries |
| 151 | /// the size of the payload and nothing can carry how much of it has |
| 152 | /// arrived: that is a fact about bytes in flight, so it is the host's to |
| 153 | /// report and it lands here beside the action it belongs to. |
| 154 | /// |
| 155 | /// Both are `None` for a host that is not watching, and that is the honest |
| 156 | /// common case rather than a gap. A bar drawn out of a total alone would be |
| 157 | /// claiming somebody is counting. |
| 158 | progress: Awaited, |
| 159 | /// The candidates a field's suggestion route answered with. |
| 160 | /// |
| 161 | /// [`Field::suggests`](quasi_router::Field::suggests) is answered with a |
| 162 | /// list belonging to a control rather than a region, so there is nowhere |
| 163 | /// in the screen to land it: it lands here, beside what has been typed |
| 164 | /// into the box it belongs to. |
| 165 | /// |
| 166 | /// One at a time and named by its field, for `quasi-tui`'s reason: a list |
| 167 | /// belongs to the box being typed into, and keeping a second field's stale |
| 168 | /// candidates would draw a list under a box nobody is in. |
| 169 | suggesting: , |
| 170 | /// How many slots a repeating question stands in, by |
| 171 | /// [`Field::name`](quasi_router::Field::name), where the reader has changed |
| 172 | /// it. |
| 173 | /// |
| 174 | /// And the same discovery as everything else here: the description says |
| 175 | /// how many answers it was given, and how many boxes there are *now* is a |
| 176 | /// fact about what the reader has done since. A browser owns it as |
| 177 | /// elements in the document, so nobody had to name it there; there is no |
| 178 | /// document here. |
| 179 | /// |
| 180 | /// Absent means the description's own count still stands, which is what |
| 181 | /// makes an untouched screen draw what the handler said. |
| 182 | slots: , |
| 183 | |
| 184 | |
| 185 | |
| 186 | /// Nothing typed and nothing ticked. |
| 187 | |
| 188 | |
| 189 | Selfdefault |
| 190 | |
| 191 | |
| 192 | /// What a field is showing: what was typed, or what the description offers. |
| 193 | |
| 194 | |
| 195 | self.edits |
| 196 | .get |
| 197 | .map_or |
| 198 | |
| 199 | |
| 200 | /// How many slots this repeating question stands in right now. |
| 201 | /// |
| 202 | /// `described` is what the description offered, which is |
| 203 | /// [`Field::slots`](quasi_router::Field::slots). What the reader has added |
| 204 | /// or taken away wins, and the answer is held to the question's own floor |
| 205 | /// and ceiling so that no walk can offer a slot the description refuses. |
| 206 | |
| 207 | |
| 208 | let Some = &field.repeats else |
| 209 | return 1; |
| 210 | ; |
| 211 | let described = repeat.standing; |
| 212 | let count = self.slots.get.copied.unwrap_or; |
| 213 | count |
| 214 | .max |
| 215 | .min |
| 216 | |
| 217 | |
| 218 | /// Add a slot to a repeating question, if its ceiling allows another. |
| 219 | /// |
| 220 | /// No request, which is the third of the three things the member is for: |
| 221 | /// the reader creates and destroys slots, and the box that appears is a box |
| 222 | /// nothing was asked for. |
| 223 | |
| 224 | let Some = &field.repeats else |
| 225 | return; |
| 226 | ; |
| 227 | let standing = self.standing; |
| 228 | if !repeat.more |
| 229 | return; |
| 230 | |
| 231 | self.slots.insert; |
| 232 | |
| 233 | |
| 234 | /// Take one slot out of a repeating question, if its floor allows one |
| 235 | /// fewer. |
| 236 | /// |
| 237 | /// The answers after it move up, buffer and all, because the names are |
| 238 | /// positional: leaving them where they were would submit a hole under the |
| 239 | /// name the reader had just emptied and drop the last answer off the end. |
| 240 | /// That is the same renumbering `repeat.js` does in the browser. |
| 241 | |
| 242 | let Some = &field.repeats else |
| 243 | return; |
| 244 | ; |
| 245 | let standing = self.standing; |
| 246 | if at >= standing || !repeat.fewer |
| 247 | return; |
| 248 | |
| 249 | // Every name the slot submits under, which is one for an ordinary |
| 250 | // repeating question and one per part for a grouped one. Read off |
| 251 | // `Field::instance_fields` rather than spelled here, so this moves the |
| 252 | // same names the drawing and the submission use. |
| 253 | for slot in at..standing - 1 |
| 254 | for in field |
| 255 | .instance_fields |
| 256 | .iter |
| 257 | .zip |
| 258 | |
| 259 | let carried = self |
| 260 | .edits |
| 261 | .get |
| 262 | .cloned |
| 263 | .or_else; |
| 264 | match carried |
| 265 | Some => |
| 266 | self.edits.insert; |
| 267 | |
| 268 | None => |
| 269 | self.edits.remove; |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | for last in field.instance_fields |
| 275 | self.edits.remove; |
| 276 | |
| 277 | self.slots.insert; |
| 278 | |
| 279 | |
| 280 | /// The buffer a text control writes through, seeded from the description. |
| 281 | /// |
| 282 | /// `&mut` because that is what an immediate-mode text control takes: there |
| 283 | /// is no DOM to read the value back out of afterwards. Seeding on first |
| 284 | /// touch rather than up front is what keeps "untouched" distinguishable |
| 285 | /// from "cleared". |
| 286 | |
| 287 | self.edits |
| 288 | .entry |
| 289 | .or_insert_with |
| 290 | |
| 291 | |
| 292 | /// What has been typed into a field, if anything has. |
| 293 | |
| 294 | |
| 295 | self.edits.get.map |
| 296 | |
| 297 | |
| 298 | /// Put a value in, as a host restoring one would. |
| 299 | |
| 300 | self.edits.insert; |
| 301 | |
| 302 | |
| 303 | /// Whether this value is one the field's `changes` has already fired with. |
| 304 | /// |
| 305 | /// The baseline a completed value is compared against. Falls back to what |
| 306 | /// the description offered, so the first blur on a box nobody touched |
| 307 | /// writes nothing. |
| 308 | |
| 309 | |
| 310 | match self.written.get |
| 311 | Some => written != value, |
| 312 | None => described.unwrap_or_default != value, |
| 313 | |
| 314 | |
| 315 | |
| 316 | /// Remember what a field's `changes` fired with. |
| 317 | |
| 318 | self.written.insert; |
| 319 | |
| 320 | |
| 321 | /// The open suggestion list, if it belongs to this field. |
| 322 | |
| 323 | |
| 324 | self.suggesting |
| 325 | .as_ref |
| 326 | .filter |
| 327 | .map |
| 328 | |
| 329 | |
| 330 | /// What a field's suggestion route answered with. |
| 331 | /// |
| 332 | /// An empty answer closes the list rather than opening an empty one: a |
| 333 | /// route with nothing to suggest and a route that was never asked leave the |
| 334 | /// screen in the same state. |
| 335 | |
| 336 | let name = name.into; |
| 337 | self.suggesting = .then_some; |
| 338 | |
| 339 | |
| 340 | /// Put the list away. |
| 341 | |
| 342 | self.suggesting = None; |
| 343 | |
| 344 | |
| 345 | /// Start, or restart, the wait before a consult is asked. |
| 346 | /// |
| 347 | /// Called on every keystroke, which is what makes it a debounce rather |
| 348 | /// than a delay: the second keystroke overwrites the first one's deadline, |
| 349 | /// so a name typed in one go is asked about once. A region's question is |
| 350 | /// restarted by a keystroke in any of the boxes it contains, which is the |
| 351 | /// same sentence one turn out. |
| 352 | |
| 353 | self.awaiting.insert; |
| 354 | |
| 355 | |
| 356 | /// When this consult is due, if one is waiting. |
| 357 | |
| 358 | |
| 359 | self.awaiting.get.copied |
| 360 | |
| 361 | |
| 362 | /// Forget the wait, because the question has now been asked. |
| 363 | |
| 364 | self.awaiting.remove; |
| 365 | |
| 366 | |
| 367 | /// The values other controls contribute to a question, by name. |
| 368 | /// |
| 369 | /// [`Consult::sends`](quasi_router::Consult::sends). Read out of what has |
| 370 | /// been drawn, which is where a described field's own offer lands the first |
| 371 | /// time it is drawn, so an untouched filter still sends what it is showing. |
| 372 | /// |
| 373 | /// A name nothing on the screen carries contributes nothing rather than an |
| 374 | /// empty value, so a route can tell "not on this screen" from "on it and |
| 375 | /// blank". |
| 376 | |
| 377 | |
| 378 | let mut params = new; |
| 379 | for name in names |
| 380 | if let Some = self.edits.get |
| 381 | params = params.with; |
| 382 | |
| 383 | |
| 384 | params |
| 385 | |
| 386 | |
| 387 | /// The action this view is waiting on. |
| 388 | |
| 389 | pub const |
| 390 | self.outstanding.as_ref |
| 391 | |
| 392 | |
| 393 | /// Say that this action is outstanding, or that nothing is. |
| 394 | /// |
| 395 | /// The runtime's to set, from what the description marked as awaiting. |
| 396 | /// |
| 397 | /// Starts the clock, and clears whatever the last wait had delivered. A |
| 398 | /// wait's elapsed time is the one time value it may show, and it is only |
| 399 | /// honest if it belongs to this call rather than to the one before it. |
| 400 | pub |
| 401 | self.await_on_at; |
| 402 | |
| 403 | |
| 404 | /// [`await_on`](Self::await_on) with the clock handed in, for tests. |
| 405 | pub |
| 406 | self.progress = Awaited |
| 407 | since: action.as_ref.map, |
| 408 | delivered: None, |
| 409 | ; |
| 410 | self.outstanding = action; |
| 411 | |
| 412 | |
| 413 | /// Say how much of the outstanding call has arrived. |
| 414 | /// |
| 415 | /// The host's to call, as often as it likes, from whatever it is watching: |
| 416 | /// bytes off a socket, rows out of an import. In the unit the description |
| 417 | /// counted, which is the app's business either way -- see |
| 418 | /// `makeover_layout::Awaiting::amount`. |
| 419 | /// |
| 420 | /// Ignored when nothing is outstanding. A delivery count with no wait |
| 421 | /// attached would be drawn against the next call to go out, which is a |
| 422 | /// number belonging to the wrong wait. |
| 423 | |
| 424 | if self.outstanding.is_some |
| 425 | self.progress.delivered = Some; |
| 426 | |
| 427 | |
| 428 | |
| 429 | /// What is known about the wait that is running, at `now`. |
| 430 | /// |
| 431 | /// Empty when nothing is outstanding, which is what makes the drawing |
| 432 | /// degrade to the activity mark rather than to a bar of nothing. |
| 433 | |
| 434 | |
| 435 | Progress |
| 436 | delivered: self.progress.delivered, |
| 437 | elapsed: self |
| 438 | .progress |
| 439 | .since |
| 440 | .map, |
| 441 | |
| 442 | |
| 443 | |
| 444 | /// Whether this is the control that was pressed and has not been answered. |
| 445 | /// |
| 446 | /// What the drawing consults to disable it, which in an immediate-mode |
| 447 | /// renderer is also the whole of the guard: a disabled control reports no |
| 448 | /// click, so the second press does not exist rather than being discarded. |
| 449 | |
| 450 | |
| 451 | self.outstanding.as_ref == Some |
| 452 | |
| 453 | |
| 454 | /// Whether a branch is open, given what its description says. |
| 455 | /// |
| 456 | /// The description says where the outline starts and the reader says where |
| 457 | /// it is now, the way the shipped egui sidebar this describes already |
| 458 | /// worked -- expansion was egui's own state and the app never held it. See |
| 459 | /// [`Row::open`](quasi_router::Row::open) for why folding a branch asks |
| 460 | /// the app nothing. |
| 461 | |
| 462 | |
| 463 | self.opened.get.copied.unwrap_or |
| 464 | |
| 465 | |
| 466 | /// Fold an open branch, or open a shut one. |
| 467 | |
| 468 | let open = self.open; |
| 469 | self.opened.insert; |
| 470 | |
| 471 | |
| 472 | /// Which child a region is showing, given what its description says. |
| 473 | /// |
| 474 | /// [`open`](Self::open)'s shape, and the same split: the description says |
| 475 | /// which child a screen arrives on and the reader says which one it is on |
| 476 | /// now. Clamped to the body, for [`Slot::current`](quasi_router::Slot::current)'s reason -- a stale |
| 477 | /// index left behind by a screen with more children would report a region |
| 478 | /// that vanished. |
| 479 | |
| 480 | |
| 481 | match self.shown.get |
| 482 | Some => at.map, |
| 483 | None => slot.current, |
| 484 | |
| 485 | |
| 486 | |
| 487 | /// Show a particular child of a region. |
| 488 | |
| 489 | self.shown.insert; |
| 490 | |
| 491 | |
| 492 | /// Move a region to another of its children, wrapping at both ends. |
| 493 | /// |
| 494 | /// quasi-tui's rule, and for its reason: neither renderer has anything to |
| 495 | /// show you that you are on the last frame, so a next control that stops |
| 496 | /// dead reads as a broken control rather than as the end of the gallery. |
| 497 | /// |
| 498 | /// A closed region opens on its first child, which is the only reading of |
| 499 | /// "next" that does anything from closed. |
| 500 | |
| 501 | let count = slot.body.len; |
| 502 | if count == 0 |
| 503 | return; |
| 504 | |
| 505 | let at = match self.shown |
| 506 | Some => .rem_euclid as usize, |
| 507 | None => 0, |
| 508 | ; |
| 509 | self.show; |
| 510 | |
| 511 | |
| 512 | /// Open a shut disclosure, or shut an open one. |
| 513 | /// |
| 514 | /// Only reachable for [`Showing::AtMostOne`](quasi_router::layout::Showing::AtMostOne): |
| 515 | /// closing is what that member means and nothing else can be put into the |
| 516 | /// closed state. |
| 517 | |
| 518 | let next = self.shown.is_none.then_some; |
| 519 | self.shown.insert; |
| 520 | |
| 521 | |
| 522 | /// Whether a row's value is in the screen's selection. |
| 523 | |
| 524 | |
| 525 | self.ticked.contains |
| 526 | |
| 527 | |
| 528 | /// Add or remove a row's value from the selection. |
| 529 | |
| 530 | if !self.ticked.remove |
| 531 | self.ticked.insert; |
| 532 | |
| 533 | |
| 534 | |
| 535 | /// Everything ticked, in a stable order. |
| 536 | |
| 537 | self.ticked.iter.map |
| 538 | |
| 539 | |
| 540 | /// The rows a new screen says are already ticked. |
| 541 | /// |
| 542 | /// Applied once on arrival rather than read on every draw: after this the |
| 543 | /// user's ticks are the truth, and a description that kept overriding them |
| 544 | /// would undo a tick the moment anything redrew. |
| 545 | /// |
| 546 | /// This walked `Node::List` alone until the 2026-09-06 collapse, so a |
| 547 | /// *table* arriving with rows already ticked seeded nothing and the ticks |
| 548 | /// drew empty. One node now, and one walk reaches both arrangements. |
| 549 | |
| 550 | for slot in &screen.slots |
| 551 | for placed in slot.body.iter |
| 552 | if let Table = &placed.node |
| 553 | for row in rows |
| 554 | if let = |
| 555 | self.ticked.insert; |
| 556 | |
| 557 | |
| 558 | |
| 559 | |
| 560 | |
| 561 | |
| 562 | |
| 563 | /// Owe the caret to the question this screen opens at. |
| 564 | /// |
| 565 | /// Arrival behaviour, beside [`seed`](Self::seed) and for its reason: a |
| 566 | /// screen cannot pull the caret back on a redraw, so this is read once and |
| 567 | /// spent on the next frame. See |
| 568 | /// [`Screen::opens_at`](quasi_router::Screen::opens_at). |
| 569 | |
| 570 | self.opens.clone_from; |
| 571 | |
| 572 | |
| 573 | /// Whether this box is the one owed the caret, taking the claim with it. |
| 574 | /// |
| 575 | /// Taken rather than read: the frame that asks egui for focus is the only |
| 576 | /// frame that should, and a claim two boxes could both answer would be two |
| 577 | /// widgets fighting over the caret every frame. |
| 578 | pub |
| 579 | if self.opens.as_deref == Some |
| 580 | self.opens = None; |
| 581 | return true; |
| 582 | |
| 583 | false |
| 584 | |
| 585 | |
| 586 | /// Forget everything, for a screen that has been replaced. |
| 587 | /// |
| 588 | /// The outstanding consults go with the rest. A wait that survived the |
| 589 | /// screen would ask about a field that is no longer on it, and land the |
| 590 | /// answer in a region that no longer exists. |
| 591 | |
| 592 | self.edits.clear; |
| 593 | self.ticked.clear; |
| 594 | // What the last screen was owed. The next one says for itself, and a |
| 595 | // name carried across would put the caret in whatever box on the new |
| 596 | // screen happened to share it. |
| 597 | self.opens = None; |
| 598 | // Which frame a region was on belongs to the screen it was on, and a |
| 599 | // region id is only unique within one. quasi-tui clears this here for |
| 600 | // the same reason. |
| 601 | self.shown.clear; |
| 602 | self.awaiting.clear; |
| 603 | self.suggesting = None; |
| 604 | // A screen that has arrived is the answer to whatever was outstanding, |
| 605 | // or is somewhere else entirely. |
| 606 | self.outstanding = None; |
| 607 | self.progress = default; |
| 608 | |
| 609 | |
| 610 | /// The values a form submits, by the names it declared. |
| 611 | /// |
| 612 | /// Every declared name is sent, including the ones nothing was typed into, |
| 613 | /// because a form that omits an untouched field is a form that cannot clear |
| 614 | /// one. What is sent for those is whatever the description offered. |
| 615 | |
| 616 | |
| 617 | let mut params = new; |
| 618 | for name in names |
| 619 | let value = self |
| 620 | .edits |
| 621 | .get |
| 622 | .or_else |
| 623 | .map_or; |
| 624 | params = params.with; |
| 625 | |
| 626 | params |
| 627 | |
| 628 | |
| 629 | /// What the screen's selection sends with an action taken over it. |
| 630 | |
| 631 | |
| 632 | let mut params = new; |
| 633 | for value in self.ticks |
| 634 | params = params.with; |
| 635 | |
| 636 | params |
| 637 | |
| 638 | |
| 639 |