max / quasi
| 1 | //! Which regions and questions are not applicable right now. |
| 2 | //! |
| 3 | //! A region says which control and which value bring it out, and a renderer |
| 4 | //! answers that from what it already holds. No request, no fragment, no re- |
| 5 | //! render of a form the reader is midway through. |
| 6 | //! |
| 7 | //! **The host with no cursor is why the condition sits on the region.** A |
| 8 | //! terminal does not hide a region the way a browser hides an element: the |
| 9 | //! honest reading here is "this region does not apply right now", which is a |
| 10 | //! property of the region. This renderer answers it by leaving the region out, |
| 11 | //! which is one of the three the ruling names -- dim it, omit it, or explain it |
| 12 | //! -- and is the one that costs the reader nothing to skip. |
| 13 | //! |
| 14 | //! # Why the answer is a set of ids rather than a question asked per region |
| 15 | //! |
| 16 | //! Because the drawing and the focus walk have to agree exactly. The caret is |
| 17 | //! an index into the walk and the drawing counts as it paints, so a region left |
| 18 | //! out of one and not the other lights the wrong control. Both read this list, |
| 19 | //! computed once from the screen and the view, and neither is in a position to |
| 20 | //! evaluate a condition differently from the other. |
| 21 | //! |
| 22 | //! It also keeps the walk cheap: [`Screen::holds`] searches the screen for a |
| 23 | //! control, and asking it once per conditional region per frame is the same |
| 24 | //! work whatever the drawing is doing. |
| 25 | |
| 26 | use ; |
| 27 | |
| 28 | use crate::; |
| 29 | |
| 30 | /// The ids of the regions on this screen that do not apply right now. |
| 31 | /// |
| 32 | /// Empty for a screen with no conditional region, which is nearly all of them, |
| 33 | /// and empty is what every caller with no view to read hands on: a region whose |
| 34 | /// condition nobody evaluated is drawn, which is the same direction the webview |
| 35 | /// degrades in when its script is not served. |
| 36 | pub |
| 37 | let mut found = none; |
| 38 | for slot in &screen.slots |
| 39 | walk; |
| 40 | |
| 41 | found |
| 42 | |
| 43 | |
| 44 | /// Whether one question is out, on the same terms as a region. |
| 45 | /// |
| 46 | /// A form's questions are a flat list, so a single conditional question inside |
| 47 | /// one carries the condition itself rather than being wrapped in a region that |
| 48 | /// could. Answered from the same [`held`] as a region's, so the two cannot |
| 49 | /// come apart over what a control is holding. |
| 50 | |
| 51 | let Some = field.watches else |
| 52 | return true; |
| 53 | ; |
| 54 | field.revealed |
| 55 | |
| 56 | |
| 57 | /// The questions in one node that do not apply, added to the list. |
| 58 | /// |
| 59 | /// A form's fields and a standalone control, which is where a described field |
| 60 | /// is. A field asked by an act is not here: it is answered by the press that |
| 61 | /// asked for it rather than drawn on the screen. |
| 62 | |
| 63 | node: &'a Node, |
| 64 | screen: &Screen, |
| 65 | chrome: &Chrome, |
| 66 | view: &View, |
| 67 | found: &mut , |
| 68 | |
| 69 | let fields: & = match node |
| 70 | Field => from_ref, |
| 71 | Form => fields, |
| 72 | _ => &, |
| 73 | ; |
| 74 | for field in fields |
| 75 | if !asked |
| 76 | found.fields.push; |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | /// This region and the regions inside it, adding the ones that are not out. |
| 82 | /// |
| 83 | /// A region inside one that does not apply is not visited: it is not on the |
| 84 | /// screen either way, and naming it would say the caret should skip something |
| 85 | /// it was never going to reach. |
| 86 | |
| 87 | if !out |
| 88 | found.regions.push; |
| 89 | return; |
| 90 | |
| 91 | for placed in slot |
| 92 | .run |
| 93 | .iter |
| 94 | .flat_map |
| 95 | .chain |
| 96 | |
| 97 | if let Region = &placed.node |
| 98 | walk; |
| 99 | else |
| 100 | questions; |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | /// Whether one region is out, given what the reader has done so far. |
| 106 | |
| 107 | let Some = slot.watches else |
| 108 | return true; |
| 109 | ; |
| 110 | slot.revealed |
| 111 | |
| 112 | |
| 113 | /// What a control is holding: what was typed, or what the description offered. |
| 114 | /// |
| 115 | /// The same order a submit reads a form in, so a region comes out on an |
| 116 | /// untouched select resting on the value its description named, rather than |
| 117 | /// waiting for the reader to pick the value it is already showing. |
| 118 | /// |
| 119 | /// The chrome is searched after the screen because a panel outlives the screen |
| 120 | /// under it: a form kept on screen from everywhere can gate a section of |
| 121 | /// itself, and its fields are in no screen for [`Screen::holds`] to find. |
| 122 | |
| 123 | control: &str, |
| 124 | screen: &'a Screen, |
| 125 | chrome: &'a Chrome, |
| 126 | view: &'a View, |
| 127 | |
| 128 | view.edit.or_else |
| 129 | screen.holds.or_else |
| 130 | chrome |
| 131 | .panels |
| 132 | .iter |
| 133 | .find_map |
| 134 | |
| 135 | |
| 136 | |
| 137 |