From a5fcc3add6aa51840cce8eb3d01c435cbb0af7b7 Mon Sep 17 00:00:00 2001 From: Prokop Randacek Date: Mon, 27 Feb 2023 12:56:07 +0100 Subject: [PATCH] add example website --- index.lua | 100 +++++++++++++++++++++++++++++++ src/layout.rs | 160 +++++++++++++++++++++++++++----------------------- 2 files changed, 187 insertions(+), 73 deletions(-) create mode 100644 index.lua diff --git a/index.lua b/index.lua new file mode 100644 index 0000000..31c5dbe --- /dev/null +++ b/index.lua @@ -0,0 +1,100 @@ +local font = readfont(fetch("/usr/share/fonts/inconsolata/Inconsolata-Bold.otf")) + +function Title(text) + return Box { + text = text, font = font, + fS = 42, fR = 238 / 255, fG = 238 / 255, fB = 238 / 255, + } +end + +function Link(text) + return Box { + text = text, font = font, + fS = 24, fR = 140 / 255, fG = 194 / 255, fB = 221 / 255, + t = 20 * Px, + r = 40 * Px, + } +end + +function NavItem(text) + return Box { + text = text, font = font, + fS = 24, fR = 140 / 255, fG = 194 / 255, fB = 221 / 255, + t = 20 * Px, + r = 40 * Px, + } +end + +function H1(text) + return Box { + text = text, font = font, + fS = 52, fR = 238 / 255, fG = 238 / 255, fB = 238 / 255, + t = 20 * Px, + } +end + +function H2(text) + return Box { + text = text, font = font, + fS = 30, fR = 238 / 255, fG = 238 / 255, fB = 238 / 255, + t = 20 * Px, + b = 20 * Px, + } +end + +function P(text) + return Box { + text = text, font = font, + fS = 24, fR = 238 / 255, fG = 238 / 255, fB = 238 / 255, + t = 20 * Px, + } +end + +function Hr() + return Box { + R = 238 / 255, G = 238 / 255, B = 238 / 255, + w = 1 * Pct, + h = 2 * Px, + t = 20 * Px, + } +end + +return Box { + w = 1 * Pct, + h = 1 * Pct, + + R = 34 / 255, + G = 40 / 255, + B = 49 / 255, + + Box { -- content + t = 40 * Px, + l = 0.2 * Pct, + w = 0.6 * Pct, + + Title('rdck.dev'), -- header + Box { -- nav bar + direction = "right", + NavItem('Home'), NavItem('Contact'), NavItem('Posts'), NavItem('Fun stuff'), NavItem('Maps'), + }, + Box { + H1('Hi!'), + P('My name is Prokop Randáček. I write code, like cats and play Factorio.'), + Hr(), + H2('Cool websites in alphabetical order'), + Box { + l = 20 * Px, + Link('Bear blog'), + Link('Command Line Interface Guidelines'), + Link('Drew DeVault'), + Link('Kubíkovo'), + Link('LuaJIT'), + Link('Lua'), + Link('Marek Maškarinec'), + Link('SourceHut'), + Link('Zig'), + Link('rxi'), + } + } + } +} diff --git a/src/layout.rs b/src/layout.rs index 42d8d05..1930ac7 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -156,16 +156,16 @@ impl Default for Box { impl Box { #[must_use] pub fn layout(&self, screen_size: Vec2) -> Vec { - let padding_top = Vec2::new(0.0, self.padding_top.eval(screen_size.y, 0.0)); - let padding_bottom = Vec2::new(0.0, self.padding_bottom.eval(screen_size.y, 0.0)); - let padding_left = Vec2::new(self.padding_left.eval(screen_size.x, 0.0), 0.0); - let padding_right = Vec2::new(self.padding_right.eval(screen_size.x, 0.0), 0.0); + let pad_top = Vec2::new(0.0, self.padding_top.eval(screen_size.y, 0.0)); + let pad_bottom = Vec2::new(0.0, self.padding_bottom.eval(screen_size.y, 0.0)); + let pad_left = Vec2::new(self.padding_left.eval(screen_size.x, 0.0), 0.0); + let pad_right = Vec2::new(self.padding_right.eval(screen_size.x, 0.0), 0.0); let mut cmds = Vec::::new(); - cmds.push(Command::PushOffset(padding_top + padding_left)); + cmds.push(Command::PushOffset(pad_top + pad_left)); let _ = self.layout_intern( - screen_size - (padding_top + padding_bottom + padding_left + padding_right), + screen_size - (pad_top + pad_bottom + pad_left + pad_right), &mut cmds, ); @@ -199,50 +199,55 @@ impl Box { // number of children on a line let mut children_on_line = 0; - for n in children.iter() { + // collect child sizes + // TODO: could be very parallel + let children: Vec<_> = children.iter().map(|c| { + let index = cmds.len(); + cmds.push(Command::PopOffset); // will be overwritten + let child_size = c.layout_intern(max_self_size, cmds); + cmds.push(Command::PopOffset); + + let pad_top = Vec2::new_y(c.padding_top.eval(max_self_size.y, 0.0)); + let pad_bottom = Vec2::new_y(c.padding_bottom.eval(max_self_size.y, 0.0)); + let pad_left = Vec2::new_x(c.padding_left.eval(max_self_size.x, 0.0)); + let pad_right = Vec2::new_x(c.padding_right.eval(max_self_size.x, 0.0)); + // TODO: cap the values? + + (child_size, index, pad_top, pad_bottom, pad_left, pad_right) + }).collect(); + + for (child_size, index, pad_top, pad_bottom, pad_left, pad_right) in children.into_iter() { children_on_line += 1; - let padding_top = Vec2::new_y(n.padding_top.eval(max_self_size.y, 0.0)); - let padding_bottom = Vec2::new_y(n.padding_bottom.eval(max_self_size.y, 0.0)); - let padding_left = Vec2::new_x(n.padding_left.eval(max_self_size.x, 0.0)); - let padding_right = Vec2::new_x(n.padding_right.eval(max_self_size.x, 0.0)); - // TODO: cap the values - - let pre_child_padding = match layout.direction { - Direction::Up => padding_bottom * -1.0, - Direction::Left => padding_right * -1.0, - Direction::Down => padding_top, - Direction::Right => padding_left, + + let pre_child_pad = match layout.direction { + Direction::Up => pad_bottom * -1.0, + Direction::Left => pad_right * -1.0, + Direction::Down => pad_top, + Direction::Right => pad_left, }; - let post_child_padding = match layout.direction { - Direction::Up => padding_top * -1.0, - Direction::Left => padding_left * -1.0, - Direction::Down => padding_bottom, - Direction::Right => padding_right, + let post_child_pad = match layout.direction { + Direction::Up => pad_top * -1.0, + Direction::Left => pad_left * -1.0, + Direction::Down => pad_bottom, + Direction::Right => pad_right, }; // box padding orthogonal to the layout direction #[allow(clippy::match_same_arms)] - let orthogonal_padding = match (&layout.origin, &layout.direction) { - (Origin::TopLeft, Direction::Up | Direction::Down) => padding_left, - (Origin::TopLeft, Direction::Left | Direction::Right) => padding_top, - (Origin::TopRight, Direction::Up | Direction::Down) => padding_right, - (Origin::TopRight, Direction::Left | Direction::Right) => padding_top, - (Origin::BottomLeft, Direction::Up | Direction::Down) => padding_left, - (Origin::BottomLeft, Direction::Left | Direction::Right) => padding_bottom, - (Origin::BottomRight, Direction::Up | Direction::Down) => padding_right, - (Origin::BottomRight, Direction::Left | Direction::Right) => padding_bottom, + let orthogonal_pad = match (&layout.origin, &layout.direction) { + (Origin::TopLeft, Direction::Up | Direction::Down) => pad_left, + (Origin::TopLeft, Direction::Left | Direction::Right) => pad_top, + (Origin::TopRight, Direction::Up | Direction::Down) => pad_right, + (Origin::TopRight, Direction::Left | Direction::Right) => pad_top, + (Origin::BottomLeft, Direction::Up | Direction::Down) => pad_left, + (Origin::BottomLeft, Direction::Left | Direction::Right) => pad_bottom, + (Origin::BottomRight, Direction::Up | Direction::Down) => pad_right, + (Origin::BottomRight, Direction::Left | Direction::Right) => pad_bottom, }; // move over the padding - head += pre_child_padding; - - let offset_index = cmds.len(); - cmds.push(Command::PopOffset); // will be overwritten - - let child_size = n.layout_intern(max_self_size, cmds); - - cmds.push(Command::PopOffset); + head += pre_child_pad; // shift child so that head is always on the correct corner of the child // according to Origin and Direction @@ -252,8 +257,8 @@ impl Box { Direction::Down | Direction::Right => Vec2::ZERO, }; - cmds[offset_index] = - Command::PushOffset(head + orthogonal_padding + child_offset_for_origin); + cmds[index] = + Command::PushOffset(head + orthogonal_pad + child_offset_for_origin); let head_over_child = match layout.direction { Direction::Up => Vec2::new_y(child_size.y * -1.0), @@ -263,20 +268,16 @@ impl Box { }; // for calculating the size of the line for stepping over it when wrapping - max_child_size.x = f32::max( - max_child_size.x, - child_size.x + padding_right.x + padding_left.x, - ); - max_child_size.y = f32::max( - max_child_size.y, - child_size.y + padding_top.y + padding_bottom.y, - ); + max_child_size.x = + f32::max(max_child_size.x, child_size.x + pad_right.x + pad_left.x); + max_child_size.y = + f32::max(max_child_size.y, child_size.y + pad_top.y + pad_bottom.y); // move over the child head += head_over_child; // move over the padding - head += post_child_padding; + head += post_child_pad; // handle overflowing if layout.overflow == Overflow::Wrap && children_on_line > 1 { @@ -303,25 +304,25 @@ impl Box { // we need to move the last child that caused the overflow to new line // move over the padding - head += pre_child_padding; + head += pre_child_pad; // fix child offset - cmds[offset_index] = Command::PushOffset( - head + orthogonal_padding + child_offset_for_origin, + cmds[index] = Command::PushOffset( + head + orthogonal_pad + child_offset_for_origin, ); head += head_over_child; // move over the padding - head += post_child_padding; + head += post_child_pad; } } let orthogonal_len = match layout.direction { Direction::Up | Direction::Down => { - padding_left + padding_right + Vec2::new(child_size.x, 0.0) + pad_left + pad_right + Vec2::new(child_size.x, 0.0) } Direction::Left | Direction::Right => { - padding_top + padding_bottom + Vec2::new(0.0, child_size.y) + pad_top + pad_bottom + Vec2::new(0.0, child_size.y) } }; @@ -367,7 +368,7 @@ impl Box { cmds.push(Command::PopOffset); - max_self_size + content_size } BoxType::Leaf(leaf_type) => { let (leaf_size, leaf_content) = match leaf_type { @@ -385,6 +386,7 @@ impl Box { TextOptions::new().with_wrap_to_width(text_width, TextAlignment::Left), ); + let text_width = f32::min(text_width, text_box.width()); // it could be smaller let text_height = self.height.eval(max_size.y, text_box.height()); ( @@ -486,33 +488,45 @@ mod tests { }) } - #[test_case(Origin::TopLeft , Direction::Right, [(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (3.0, 0.0)])] - #[test_case(Origin::TopLeft , Direction::Down , [(0.0, 0.0), (0.0, 1.0), (0.0, 2.0), (0.0, 3.0)])] - #[test_case(Origin::TopLeft , Direction::Left , [(3.0, 0.0), (2.0, 0.0), (1.0, 0.0), (0.0, 0.0)])] - #[test_case(Origin::TopLeft , Direction::Up , [(0.0, 3.0), (0.0, 2.0), (0.0, 1.0), (0.0, 0.0)])] - #[test_case(Origin::TopRight , Direction::Right, [(6.0, 0.0), (7.0, 0.0), (8.0, 0.0), (9.0, 0.0)])] - #[test_case(Origin::TopRight , Direction::Down , [(9.0, 0.0), (9.0, 1.0), (9.0, 2.0), (9.0, 3.0)])] - #[test_case(Origin::TopRight , Direction::Left , [(9.0, 0.0), (8.0, 0.0), (7.0, 0.0), (6.0, 0.0)])] - #[test_case(Origin::TopRight , Direction::Up , [(9.0, 3.0), (9.0, 2.0), (9.0, 1.0), (9.0, 0.0)])] - #[test_case(Origin::BottomLeft, Direction::Right, [(0.0, 9.0), (1.0, 9.0), (2.0, 9.0), (3.0, 9.0)])] - #[test_case(Origin::BottomLeft, Direction::Down , [(0.0, 6.0), (0.0, 7.0), (0.0, 8.0), (0.0, 9.0)])] - #[test_case(Origin::BottomLeft, Direction::Left , [(3.0, 9.0), (2.0, 9.0), (1.0, 9.0), (0.0, 9.0)])] - #[test_case(Origin::BottomLeft, Direction::Up , [(0.0, 9.0), (0.0, 8.0), (0.0, 7.0), (0.0, 6.0)])] - fn origin_direction(origin: Origin, direction: Direction, rect_pos: [(f32, f32); 4]) { + #[test_case(Origin::TopLeft , Direction::Right, (10.0, 10.0), [(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (3.0, 0.0)])] + #[test_case(Origin::TopLeft , Direction::Down , (10.0, 10.0), [(0.0, 0.0), (0.0, 1.0), (0.0, 2.0), (0.0, 3.0)])] + #[test_case(Origin::TopLeft , Direction::Left , (10.0, 10.0), [(3.0, 0.0), (2.0, 0.0), (1.0, 0.0), (0.0, 0.0)])] + #[test_case(Origin::TopLeft , Direction::Up , (10.0, 10.0), [(0.0, 3.0), (0.0, 2.0), (0.0, 1.0), (0.0, 0.0)])] + #[test_case(Origin::TopRight , Direction::Right, (10.0, 10.0), [(6.0, 0.0), (7.0, 0.0), (8.0, 0.0), (9.0, 0.0)])] + #[test_case(Origin::TopRight , Direction::Down , (10.0, 10.0), [(9.0, 0.0), (9.0, 1.0), (9.0, 2.0), (9.0, 3.0)])] + #[test_case(Origin::TopRight , Direction::Left , (10.0, 10.0), [(9.0, 0.0), (8.0, 0.0), (7.0, 0.0), (6.0, 0.0)])] + #[test_case(Origin::TopRight , Direction::Up , (10.0, 10.0), [(9.0, 3.0), (9.0, 2.0), (9.0, 1.0), (9.0, 0.0)])] + #[test_case(Origin::BottomLeft, Direction::Right, (10.0, 10.0), [(0.0, 9.0), (1.0, 9.0), (2.0, 9.0), (3.0, 9.0)])] + #[test_case(Origin::BottomLeft, Direction::Down , (10.0, 10.0), [(0.0, 6.0), (0.0, 7.0), (0.0, 8.0), (0.0, 9.0)])] + #[test_case(Origin::BottomLeft, Direction::Left , (10.0, 10.0), [(3.0, 9.0), (2.0, 9.0), (1.0, 9.0), (0.0, 9.0)])] + #[test_case(Origin::BottomLeft, Direction::Up , (10.0, 10.0), [(0.0, 9.0), (0.0, 8.0), (0.0, 7.0), (0.0, 6.0)])] + //#[test_case(Origin::TopLeft , Direction::Right, (2.0, 2.0), [(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (0.0, 1.0)])] + //#[test_case(Origin::TopLeft , Direction::Left , (3.0, 10.0), [(3.0, 0.0), (2.0, 0.0), (1.0, 0.0), (0.0, 0.0)])] + //#[test_case(Origin::TopRight , Direction::Right, (3.0, 10.0), [(6.0, 0.0), (7.0, 0.0), (8.0, 0.0), (9.0, 0.0)])] + //#[test_case(Origin::TopRight , Direction::Left , (3.0, 10.0), [(0.5, 0.0), (8.0, 0.0), (7.0, 0.0), (6.0, 0.0)])] + //#[test_case(Origin::BottomLeft, Direction::Right, (3.0, 10.0), [(0.0, 9.0), (1.0, 9.0), (2.0, 9.0), (3.0, 9.0)])] + //#[test_case(Origin::BottomLeft, Direction::Left , (3.0, 10.0), [(3.0, 9.0), (2.0, 9.0), (1.0, 9.0), (0.0, 9.0)])] + fn origin_direction( + origin: Origin, + direction: Direction, + size: (f32, f32), + rect_pos: [(f32, f32); 4], + ) { let rects = create_test_case( NodeLayout { origin, direction, ..NodeLayout::default() }, - Vec2::new(10.0, 10.0), + size.into(), iter::repeat(Vec2::new(1.0, 1.0)).take(4).collect(), ); assert_eq!(rects.len(), 5); - assert_eq!(rects[0], (Vec2::new(0.0, 0.0), Vec2::new(10.0, 10.0))); + assert_eq!(rects[0], (Vec2::new(0.0, 0.0), size.into())); assert_eq!(rects[1], (rect_pos[0].into(), Vec2::new(1.0, 1.0))); assert_eq!(rects[2], (rect_pos[1].into(), Vec2::new(1.0, 1.0))); assert_eq!(rects[3], (rect_pos[2].into(), Vec2::new(1.0, 1.0))); assert_eq!(rects[4], (rect_pos[3].into(), Vec2::new(1.0, 1.0))); } + // TODO: wrap 1, 2, 4 } -- 2.45.2