blockworx_editor/edit/
lower.rs1use blockworx_doc::{
8 block_model::{Asset, Label},
9 geometry::{GridRect, GridSize},
10 values::Role,
11};
12use blockworx_geom::Pos2;
13
14use crate::grid::{GRID_SIZE, grid_rect, max_pin_slot, snap_block_height_cells};
15use crate::shape::ShapeLabel;
16
17pub fn slot_capacity(height: u32) -> u32 {
20 max_pin_slot(height as f32 * GRID_SIZE)
21}
22
23pub fn block_rect(start: Pos2, end: Pos2) -> GridRect {
28 let rect = grid_rect(start, end);
29 GridRect {
30 size: GridSize {
31 h: snap_block_height_cells(rect.size.h),
32 ..rect.size
33 },
34 ..rect
35 }
36}
37
38pub fn role_from_accent(accent: Option<u8>) -> Role {
43 match accent {
44 None => Role::Accent0,
45 Some(0) => Role::Accent1,
46 Some(1) => Role::Accent2,
47 Some(2) => Role::Accent3,
48 Some(3) => Role::Accent4,
49 Some(4) => Role::Accent5,
50 Some(5) => Role::Accent6,
51 Some(6) => Role::Accent7,
52 Some(_) => Role::Accent8,
53 }
54}
55
56pub fn shape_label(label: &Label) -> ShapeLabel<'_> {
62 ShapeLabel {
63 name: &label.name,
64 hidden: label.hidden,
65 side: label.side,
66 offset: (label.offset).into(),
67 }
68}
69
70pub fn asset_within_limit(asset: &Asset, name: &str) -> bool {
75 if asset.within_limit() {
76 return true;
77 }
78 tracing::error!(
79 "{name} is {} bytes; artwork is limited to {} bytes because it rides the commit log",
80 asset.bytes().len(),
81 blockworx_doc::block_model::ASSET_LIMIT,
82 );
83 false
84}
85
86pub fn accent_from_role(role: Role) -> Option<u8> {
89 match role {
90 Role::Accent0 => None,
91 Role::Accent1 => Some(0),
92 Role::Accent2 => Some(1),
93 Role::Accent3 => Some(2),
94 Role::Accent4 => Some(3),
95 Role::Accent5 => Some(4),
96 Role::Accent6 => Some(5),
97 Role::Accent7 => Some(6),
98 Role::Accent8 => Some(7),
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use blockworx_doc::geometry::GridPoint;
105 use blockworx_geom::pos2;
106
107 use super::*;
108 use crate::grid::{GRID_SIZE, max_pin_slot};
109
110 #[test]
111 fn accent_and_role_are_an_involution_over_the_picker_range() {
112 for accent in std::iter::once(None).chain((0..=7).map(Some)) {
113 assert_eq!(accent_from_role(role_from_accent(accent)), accent);
114 }
115 }
116
117 #[test]
118 fn a_block_rect_settles_on_the_height_ladder_keeping_its_top_edge() {
119 let cell = |x: f32, y: f32| pos2(x * GRID_SIZE, y * GRID_SIZE);
120 let rect = block_rect(cell(1.0, 2.0), cell(9.0, 7.0));
121 assert_eq!(
122 grid_rect(cell(1.0, 2.0), cell(9.0, 7.0)).size.h,
123 5,
124 "precondition: the drag's own height is off the ladder"
125 );
126 assert_eq!(rect.top_left, GridPoint { x: 1, y: 2 });
127 assert_eq!(rect.size, GridSize { w: 8, h: 4 });
128
129 for (drag, ladder) in [(1, 4), (5, 4), (6, 7), (9, 10)] {
131 let rect = block_rect(cell(0.0, 0.0), cell(3.0, drag as f32));
132 assert_eq!(rect.size.h, ladder);
133 assert_eq!(
134 max_pin_slot(ladder as f32 * GRID_SIZE),
135 (ladder - 4) / 3,
136 "a valid height's capacity is a whole number of slots"
137 );
138 }
139 }
140}