max / quasi
| 1 | //! Where this renderer drew each described row, for a host that has to read a |
| 2 | //! gesture the description does not carry. |
| 3 | //! |
| 4 | //! <!-- wiki: quasi-overview --> |
| 5 | //! |
| 6 | //! # Why this is here and not in the vocabulary |
| 7 | //! |
| 8 | //! asked what, if anything, a description should hand a host about where it |
| 9 | //! drew what. The answer is nothing. A description says what is on the screen |
| 10 | //! and never where, which is the same rule that keeps `Act::shows` a picture |
| 11 | //! rather than a box and keeps an anchor a described id rather than a point. |
| 12 | //! Geometry is the *renderer's* answer and a different answer per host: a |
| 13 | //! terminal has cells, a webview has the DOM, and this host has rects. |
| 14 | //! |
| 15 | //! So the fact travels from the renderer to its own host, beside the drawing, |
| 16 | //! rather than through the description. A webview host asks the DOM the same |
| 17 | //! question and needs nothing from here. |
| 18 | //! |
| 19 | //! # What it is for |
| 20 | //! |
| 21 | //! audiofiles drags samples into a DAW. That gesture is not an outcome -- an OS |
| 22 | //! drag is this host's, and `quasi::panel::dragging_out` performs it -- and to |
| 23 | //! start it correctly the host has to know two things this renderer knew and |
| 24 | //! did not say: whether the press landed on a row at all, and which row. Without |
| 25 | //! them a press on the toolbar could start a drag, and a press on an unchosen |
| 26 | //! row dragged the chosen set instead of the row under the cursor. |
| 27 | //! |
| 28 | //! # Why egui's own memory rather than a return value |
| 29 | //! |
| 30 | //! `Immediate::screen` and `chromed` answer `Option<Fired>`, which is what the |
| 31 | //! user set off. Widening that to carry geometry would change every call site |
| 32 | //! in every host to thread a fact almost none of them want. The rects are |
| 33 | //! per-frame data belonging to a `Context`, which is what `Context` data is for, |
| 34 | //! and a host that never asks pays a `Vec` push per row and nothing else. |
| 35 | |
| 36 | use ; |
| 37 | use Anchor; |
| 38 | |
| 39 | /// A described row, and where this renderer put it. |
| 40 | |
| 41 | |
| 42 | /// The row's own value, when the description gave it one. |
| 43 | /// |
| 44 | /// `Row::value`, which is the identifier the description |
| 45 | /// already uses for a row: it is what a tick travels under and what |
| 46 | /// survives a reorder. `None` on a row that carries none, where the index |
| 47 | /// is all there is. |
| 48 | pub value: , |
| 49 | /// Where the row sat in the list or table this frame. |
| 50 | /// |
| 51 | /// Positional, so it does not survive a reorder. Read it only against the |
| 52 | /// same frame's description. |
| 53 | pub index: usize, |
| 54 | |
| 55 | |
| 56 | /// The key the rects live under, which is this crate's and not a host's. |
| 57 | |
| 58 | new |
| 59 | |
| 60 | |
| 61 | /// What is remembered between the drawing and the asking. |
| 62 | |
| 63 | |
| 64 | /// The pass these rects were measured in. |
| 65 | /// |
| 66 | /// egui redraws on its own schedule, so a host asking about a pointer needs |
| 67 | /// the rects from the frame it is asking about rather than whatever was |
| 68 | /// left behind. Rows are cleared when the number moves rather than by a |
| 69 | /// begin-frame hook, because this crate has none. |
| 70 | pass: u64, |
| 71 | /// Value, position, rect, and whether the row is part of a live selection. |
| 72 | /// |
| 73 | /// The last is `Anchor::Selection`'s other half. A staged tick lives in |
| 74 | /// the runtime's view and is passed in; a live selection is the |
| 75 | /// description's, so it arrives here with the row that carried it. |
| 76 | rows: , |
| 77 | /// Where each described region was drawn, by `Slot::id`. |
| 78 | /// |
| 79 | /// The rows above answer "is the pointer over one"; these answer "where is |
| 80 | /// the thing this menu was anchored to", which is the same class of fact |
| 81 | /// and belongs in the same place rather than in a second store that can |
| 82 | /// disagree about which pass it is describing. |
| 83 | regions: , |
| 84 | /// Where each *named* control was drawn, by `Act::id`. |
| 85 | /// |
| 86 | /// Only the named ones. `Act::id` is `None` on nearly every control, so a |
| 87 | /// screen that anchors nothing pushes nothing here. |
| 88 | acts: , |
| 89 | |
| 90 | |
| 91 | /// Say a row was drawn here. |
| 92 | /// |
| 93 | /// Called for every described row whether or not it answers a gesture: a row |
| 94 | /// that is neither pressable nor menued still occupies the space, and "is the |
| 95 | /// pointer over a row" is the question that has to be answerable for the |
| 96 | /// dangerous case -- a press on the toolbar that would otherwise start a drag. |
| 97 | pub |
| 98 | noting |
| 99 | drawn |
| 100 | .rows |
| 101 | .push; |
| 102 | ; |
| 103 | |
| 104 | |
| 105 | /// Say a region was drawn here. |
| 106 | /// |
| 107 | /// Every described region, whether or not anything is ever anchored to it, for |
| 108 | /// [`note_row`]'s reason: nothing in a description says which regions an app |
| 109 | /// anchors to, and the answer has to exist before the question is asked. |
| 110 | pub |
| 111 | noting; |
| 112 | |
| 113 | |
| 114 | /// Say a named control was drawn here. |
| 115 | /// |
| 116 | /// Called only for an [`Act`](quasi_router::Act) carrying an |
| 117 | /// [`id`](quasi_router::Act::id), so a screen with no anchored menus pays |
| 118 | /// nothing. |
| 119 | pub |
| 120 | noting; |
| 121 | |
| 122 | |
| 123 | /// Clear a stale pass and hand the store to whoever is adding to it. |
| 124 | /// |
| 125 | /// One place, so the pass check cannot be forgotten by a note function added |
| 126 | /// later -- which is exactly how a menu would come to be anchored at where its |
| 127 | /// control sat two frames ago. |
| 128 | |
| 129 | let pass = ui.ctx.cumulative_pass_nr; |
| 130 | ui.ctx.data_mut |
| 131 | let drawn: &mut Drawn = data.get_temp_mut_or_default; |
| 132 | if drawn.pass != pass |
| 133 | drawn.pass = pass; |
| 134 | drawn.rows.clear; |
| 135 | drawn.regions.clear; |
| 136 | drawn.acts.clear; |
| 137 | |
| 138 | add; |
| 139 | ; |
| 140 | |
| 141 | |
| 142 | /// Where the thing an anchor names was drawn, if it was drawn this pass. |
| 143 | /// |
| 144 | /// This is the ruling in `600c9e42` doing its work: the description named a |
| 145 | /// thing, and the renderer that drew it is the one that answers where. |
| 146 | /// |
| 147 | /// `ticked` is the values the view holds ticked, which is **half** of what |
| 148 | /// [`Anchor::Selection`] resolves against -- the runtime owns that set and this |
| 149 | /// module does not, so it is passed in rather than reached for. The other half |
| 150 | /// is `Row::chosen`, a selection already in force, which the description |
| 151 | /// carries and which therefore arrived with the row. |
| 152 | /// |
| 153 | /// `None` means the anchor named nothing on this pass: a region or control that |
| 154 | /// is not on the screen, or a selection with nothing in it. The caller falls |
| 155 | /// back to drawing the menu unanchored, which is what every renderer does with |
| 156 | /// an anchor it cannot resolve. |
| 157 | pub |
| 158 | ctx.data |
| 159 | let drawn: Drawn = data.get_temp?; |
| 160 | match anchor |
| 161 | Region => find, |
| 162 | Control => find, |
| 163 | // The box around every ticked row, so a menu over a set opens |
| 164 | // against the set rather than against whichever member happens to |
| 165 | // be first. Rows scrolled out of view contribute nothing, which is |
| 166 | // right: they were not drawn, so this renderer has no rect for them |
| 167 | // and inventing one would put the menu off screen. |
| 168 | Selection => drawn |
| 169 | .rows |
| 170 | .iter |
| 171 | .filter |
| 172 | *chosen |
| 173 | || value |
| 174 | .as_deref |
| 175 | .is_some_and |
| 176 | |
| 177 | .map |
| 178 | .reduce, |
| 179 | |
| 180 | |
| 181 | |
| 182 | |
| 183 | /// The last rect noted under a name, or `None` if nothing was. |
| 184 | /// |
| 185 | /// Last wins, matching [`row_at`]: where one name is drawn twice -- a region |
| 186 | /// inside an overlay over the region it names -- the later one is on top. |
| 187 | |
| 188 | noted |
| 189 | .iter |
| 190 | .rev |
| 191 | .find |
| 192 | .map |
| 193 | |
| 194 | |
| 195 | /// The described row under this point, if the point is over one. |
| 196 | /// |
| 197 | /// `None` means the point is not over a row: over the chrome, over a control |
| 198 | /// beside the table, over nothing. That is the answer a host guarding a drag |
| 199 | /// wants, and it is the one this renderer could not give before. |
| 200 | /// |
| 201 | /// Last drawn wins. Rows do not overlap within a list or a table, and where two |
| 202 | /// do -- an overlay's row over the row underneath -- the later one is on top, |
| 203 | /// which is the order they were drawn in. |
| 204 | /// |
| 205 | /// Reads the frame that has most recently drawn. A host asking before anything |
| 206 | /// has been drawn gets `None` rather than a stale answer. |
| 207 | |
| 208 | |
| 209 | ctx.data |
| 210 | let drawn: Drawn = data.get_temp?; |
| 211 | drawn |
| 212 | .rows |
| 213 | .iter |
| 214 | .rev |
| 215 | .find |
| 216 | .map |
| 217 | value: value.clone, |
| 218 | index: *index, |
| 219 | |
| 220 | |
| 221 | |
| 222 |