| 1 | //! Insert Space's feedback, as OneNote 2010 draws it: lines across the view where the drag |
| 2 | //! began and where it is, an arrow between them in the middle of the view, and a tint where |
| 3 | //! what moves lands. |
| 4 | |
| 5 | use crate::gpu::colorref; |
| 6 | use draw::Primitive; |
| 7 | |
| 8 | /// Appends the feedback for lines at `from` and `to` along `axis` (0 for x), with `moved` the |
| 9 | /// extents of what moves, over `view`, the page's visible rectangle; `pixel` is page units |
| 10 | /// per pixel. |
| 11 | pub(super) fn append( |
| 12 | axis: usize, |
| 13 | [from, to]: [f32; 2], |
| 14 | moved: &[[f32; 4]], |
| 15 | view: [f32; 4], |
| 16 | pixel: f32, |
| 17 | primitives: &mut Vec<Primitive<'_>>, |
| 18 | ) { |
| 19 | let across = 1 - axis; |
| 20 | let rect = |along: [f32; 2], side: [f32; 2]| { |
| 21 | let [a0, a1] = [along[0].min(along[1]), along[0].max(along[1])]; |
| 22 | let [s0, s1] = side; |
| 23 | if axis == 1 { |
| 24 | [s0, a0, s1, a1] |
| 25 | } else { |
| 26 | [a0, s0, a1, s1] |
| 27 | } |
| 28 | }; |
| 29 | let point = |along: f32, side: f32| { |
| 30 | let mut point = [side; 2]; |
| 31 | point[axis] = along; |
| 32 | point |
| 33 | }; |
| 34 | let delta = to - from; |
| 35 | let mut tint = colorref(0x00f7e4cc); |
| 36 | tint[3] = 0.6; |
| 37 | for extent in moved { |
| 38 | let mut extent = *extent; |
| 39 | extent[axis] += delta; |
| 40 | extent[axis + 2] += delta; |
| 41 | primitives.push(Primitive::Rect { |
| 42 | rect: extent, |
| 43 | color: tint, |
| 44 | }); |
| 45 | } |
| 46 | if delta.abs() >= pixel { |
| 47 | let (fill, edge) = (colorref(0x00fff2e5), colorref(0x00e8a460)); |
| 48 | let middle = (view[across] + view[across + 2]) / 2.0; |
| 49 | let [shaft, head] = [36.5 * pixel, 73.0 * pixel]; |
| 50 | let length = (31.0 * pixel).min(delta.abs()); |
| 51 | let base = to - length * delta.signum(); |
| 52 | primitives.push(Primitive::Rect { |
| 53 | rect: rect([from, base], [middle - shaft, middle + shaft]), |
| 54 | color: fill, |
| 55 | }); |
| 56 | let rows = (length / pixel).ceil().max(1.0); |
| 57 | for row in 0..rows as u32 { |
| 58 | let row = row as f32; |
| 59 | let half = head * (1.0 - (row + 0.5) / rows); |
| 60 | let near = base + delta.signum() * row * pixel; |
| 61 | let far = base + delta.signum() * ((row + 1.0) * pixel).min(length); |
| 62 | primitives.push(Primitive::Rect { |
| 63 | rect: rect([near, far], [middle - half, middle + half]), |
| 64 | color: fill, |
| 65 | }); |
| 66 | } |
| 67 | let segments = [ |
| 68 | (point(from, middle - shaft), point(base, middle - shaft)), |
| 69 | (point(from, middle + shaft), point(base, middle + shaft)), |
| 70 | (point(base, middle - shaft), point(base, middle - head)), |
| 71 | (point(base, middle + shaft), point(base, middle + head)), |
| 72 | (point(base, middle - head), point(to, middle)), |
| 73 | (point(base, middle + head), point(to, middle)), |
| 74 | ]; |
| 75 | for (from, to) in segments { |
| 76 | primitives.push(Primitive::Segment { |
| 77 | from, |
| 78 | to, |
| 79 | width: pixel, |
| 80 | round: false, |
| 81 | color: edge, |
| 82 | }); |
| 83 | } |
| 84 | } |
| 85 | for at in [from, to] { |
| 86 | primitives.push(Primitive::Rect { |
| 87 | rect: rect( |
| 88 | [at - pixel / 2.0, at + pixel / 2.0], |
| 89 | [view[across], view[across + 2]], |
| 90 | ), |
| 91 | color: colorref(0x00df862d), |
| 92 | }); |
| 93 | } |
| 94 | } |