[PATCH v2] Add support for horizontal LinearLayouts
Export this patch
---
The closing '```' had been forgotton for the added example
src/elements.rs | 54 +++++++++++++++++++++++++++++++++++++++++++ ------
src/lib.rs | 11 ++++++++++
2 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/src/elements.rs b/src/elements.rs
index 2f20e34..9541012 100644
--- a/src/elements.rs
+++ b/src/elements.rs
@@ -74,10 +74,13 @@ impl IntoBoxedElement for Box<dyn Element> {
}
}
+ enum RenderDirection {
+ Horizontal,
+ Vertical,
+ }
+
/// Arranges a list of elements sequentially.
///
- /// Currently, elements can only be arranged vertically.
- ///
/// # Examples
///
/// With setters:
@@ -96,22 +99,37 @@ impl IntoBoxedElement for Box<dyn Element> {
/// .element(elements::Paragraph::new("Test2"));
/// ```
///
+ /// Horizontal:
+ /// ```
+ /// use genpdf::elements;
+ /// let layout = elements::LinearLayout::horizontal()
+ /// .element(elements::Paragraph::new("Test1"))
+ /// .element(elements::Paragraph::new("Test2"));
+ /// ```
+ ///
pub struct LinearLayout {
elements: Vec<Box<dyn Element>>,
render_idx: usize,
+ render_direction: RenderDirection,
}
impl LinearLayout {
- fn new() -> LinearLayout {
+ fn new(render_direction: RenderDirection) -> LinearLayout {
LinearLayout {
elements: Vec::new(),
render_idx: 0,
+ render_direction,
}
}
/// Creates a new linear layout that arranges its elements vertically.
pub fn vertical() -> LinearLayout {
- LinearLayout::new()
+ Self::new(RenderDirection::Vertical)
+ }
+
+ /// Creates a new linear layout that arranges its elements horizontally.
+ pub fn horizontal() -> LinearLayout {
+ Self::new(RenderDirection::Horizontal)
}
/// Adds the given element to this layout.
@@ -146,6 +164,28 @@ impl LinearLayout {
result.has_more = self.render_idx < self.elements.len();
Ok(result)
}
+
+ fn render_horizontal(
+ &mut self,
+ context: &Context,
+ mut area: render::Area<'_>,
+ style: Style,
+ ) -> Result<RenderResult, Error> {
+ let mut result = RenderResult::default();
+ while area.size().width > Mm(0.0) && self.render_idx < self.elements.len() {
+ let element_result =
+ self.elements[self.render_idx].render(context, area.clone(), style)?;
+ area.add_offset(Position::new(element_result.size.width, 0));
+ result.size = result.size.stack_horizontal(element_result.size);
+ if element_result.has_more {
+ result.has_more = true;
+ return Ok(result);
+ }
+ self.render_idx += 1;
+ }
+ result.has_more = self.render_idx < self.elements.len();
+ Ok(result)
+ }
}
impl Element for LinearLayout {
@@ -155,8 +195,10 @@ impl Element for LinearLayout {
area: render::Area<'_>,
style: Style,
) -> Result<RenderResult, Error> {
- // TODO: add horizontal layout
- self.render_vertical(context, area, style)
+ match self.render_direction {
+ RenderDirection::Vertical => self.render_vertical(context, area, style),
+ RenderDirection::Horizontal => self.render_horizontal(context, area, style),
+ }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 4a16461..aef7e03 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -435,6 +435,17 @@ impl Size {
self.height += other.height;
self
}
+
+ /// Stacks the given size horizontally on this size and returns the result.
+ ///
+ /// This means that the height is set to the maximum of the heights and the width is set to the
+ /// sum of the widths.
+ #[must_use]
+ pub fn stack_horizontal(mut self, other: Size) -> Size {
+ self.width += other.width;
+ self.height = self.height.max(other.height);
+ self
+ }
}
impl<W: Into<Mm>, H: Into<Mm>> From<(W, H)> for Size {
--
2.32.0
Hi Erik,
thank you for the patch! I’ve received a nearly identical patch three
days ago, see:
https://lists.sr.ht/~ireas/public-inbox/%3C162370213657.22528.15833839867279751390-0%40git.sr.ht%3E
https://lists.sr.ht/~ireas/public-inbox/%3C162370324348.13472.14147745046729338585-0%40git.sr.ht%3E
https://lists.sr.ht/~ireas/public-inbox/%3CCAP_ocU-as%2BiWb1Sw8HkqCgbec3NpfyszJ2ud491GwEYn9V5Rrw%40mail.gmail.com%3E
I think the issue raised in that discussion also applies for this patch,
namely what happens if the elements of the layout do not fit
horizontally and/or vertically. Please let me know what you think about
this and, if you are interested in implementing a solution, coordinate
with Ferdinand.
/Robin