For LineStyle add From<Color>, Mm instead of f64 thickness, default to black and 1.0 thickness
Implement LineStyle for FrameCellDecorator
Add documentation for LineStyle
Remove rounded rect code comments
Accept impl into line style on FramedElement and Table
---
src/elements.rs | 76 +++++++++++++++++++++++++++++++------------------
src/render.rs | 20 ++++++-------
src/style.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 130 insertions(+), 38 deletions(-)
diff --git a/src/elements.rs b/src/elements.rs
index 1ff2dea..00a8a77 100644
--- a/src/elements.rs
+++ b/src/elements.rs
@@ -49,7 +49,7 @@ use std::mem;
use crate::error::{Error, ErrorKind};
use crate::render;
-use crate::style::{Style, StyledString};
+use crate::style::{Style, StyledString, LineStyle};
use crate::wrap;
use crate::{Alignment, Context, Element, Margins, Mm, Position, RenderResult, Size};
@@ -595,14 +595,22 @@ impl<E: Element> Element for StyledElement<E> {
pub struct FramedElement<E: Element> {
element: E,
is_first: bool,
+ line_style: LineStyle,
}
impl<E: Element> FramedElement<E> {
/// Creates a new framed element that wraps the given element.
pub fn new(element: E) -> FramedElement<E> {
- FramedElement {
- element,
+ FramedElement::with_line_style(element, LineStyle::new())
+ }
+
+ /// Creates a new framed element that wraps the given element,
+ /// and with the given line style.
+ pub fn with_line_style(element: E, line_style: impl Into<LineStyle>) -> FramedElement<E> {
+ Self {
is_first: true,
+ element,
+ line_style: line_style.into(),
}
}
}
@@ -615,30 +623,32 @@ impl<E: Element> Element for FramedElement<E> {
style: Style,
) -> Result<RenderResult, Error> {
let result = self.element.render(context, area.clone(), style)?;
- area.draw_line(
- vec![Position::default(), Position::new(0, result.size.height)],
- style,
- );
- area.draw_line(
- vec![
- Position::new(area.size().width, 0),
- Position::new(area.size().width, result.size.height),
- ],
- style,
- );
+
if self.is_first {
area.draw_line(
- vec![Position::default(), Position::new(area.size().width, 0)],
- style,
+ vec![Position::new(area.size().width, result.size.height),
+ Position::new(area.size().width, 0),
+ Position::default(),
+ Position::new(0, result.size.height)],
+ self.line_style,
);
}
if !result.has_more {
area.draw_line(
- vec![
- Position::new(0, result.size.height),
- Position::new(area.size().width, result.size.height),
- ],
- style,
+ vec![Position::default(),
+ Position::new(0, result.size.height),
+ Position::new(area.size().width, result.size.height),
+ Position::new(area.size().width, 0)],
+ self.line_style,
+ );
+ } else {
+ area.draw_line(
+ vec![Position::default(), Position::new(0, result.size.height)],
+ self.line_style,
+ );
+ area.draw_line(
+ vec![Position::new(area.size().width, 0), Position::new(area.size().width, result.size.height)],
+ self.line_style,
);
}
self.is_first = false;
@@ -909,7 +919,6 @@ pub trait CellDecorator {
row: usize,
has_more: bool,
area: render::Area<'_>,
- style: Style,
);
}
@@ -925,6 +934,7 @@ pub struct FrameCellDecorator {
inner: bool,
outer: bool,
cont: bool,
+ line_style: LineStyle,
num_columns: usize,
num_rows: usize,
last_row: Option<usize>,
@@ -942,6 +952,17 @@ impl FrameCellDecorator {
}
}
+ /// Creates a new frame cell decorator with the given border settings, as well as a line style.
+ pub fn with_line_style(inner: bool, outer: bool, cont: bool, line_style: impl Into<LineStyle>) -> FrameCellDecorator {
+ Self {
+ inner,
+ outer,
+ cont,
+ line_style: line_style.into(),
+ ..Default::default()
+ }
+ }
+
fn print_left(&self, column: usize) -> bool {
if column == 0 {
self.outer
@@ -993,14 +1014,13 @@ impl CellDecorator for FrameCellDecorator {
row: usize,
has_more: bool,
area: render::Area<'_>,
- style: Style,
) {
let size = area.size();
if self.print_left(column) {
area.draw_line(
vec![Position::default(), Position::new(0, size.height)],
- style,
+ self.line_style,
);
}
@@ -1010,14 +1030,14 @@ impl CellDecorator for FrameCellDecorator {
Position::new(size.width, 0),
Position::new(size.width, size.height),
],
- style,
+ self.line_style,
);
}
if self.print_top(row) {
area.draw_line(
vec![Position::default(), Position::new(size.width, 0)],
- style,
+ self.line_style,
);
}
@@ -1027,7 +1047,7 @@ impl CellDecorator for FrameCellDecorator {
Position::new(0, size.height),
Position::new(size.width, size.height),
],
- style,
+ self.line_style,
);
}
@@ -1213,7 +1233,7 @@ impl TableLayout {
if let Some(decorator) = &mut self.cell_decorator {
for (i, mut area) in areas.into_iter().enumerate() {
area.set_height(row_height);
- decorator.decorate_cell(i, self.render_idx, result.has_more, area, style);
+ decorator.decorate_cell(i, self.render_idx, result.has_more, area);
}
}
diff --git a/src/render.rs b/src/render.rs
index 5ecce1e..cdea762 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -22,7 +22,7 @@ use std::io;
use crate::error::{Context as _, Error, ErrorKind};
use crate::fonts;
-use crate::style::{Color, Style};
+use crate::style::{Color, Style, LineStyle};
use crate::{Margins, Mm, Position, Size};
#[cfg(feature = "images")]
@@ -333,11 +333,10 @@ impl<'a> Area<'a> {
);
}
- /// Draws a line with the given points and the given style.
+ /// Draws a line with the given points and the given line style.
///
- /// Currently, this method only uses the color of the given style as the outline color (if set).
/// The points are relative to the upper left corner of the area.
- pub fn draw_line(&self, points: Vec<Position>, style: Style) {
+ pub fn draw_line(&self, points: Vec<Position>, line_style: LineStyle) {
let line_points: Vec<_> = points
.into_iter()
.map(|pos| (self.transform_position(pos).into(), false))
@@ -349,13 +348,14 @@ impl<'a> Area<'a> {
has_stroke: true,
is_clipping_path: false,
};
- if let Some(color) = style.color() {
- self.layer().set_outline_color(color.into());
- }
+ self.layer().set_outline_thickness(line_style.thickness().into());
+ self.layer().set_outline_color(line_style.color().into());
+
self.layer().add_shape(line);
- if style.color().is_some() {
- self.layer().set_outline_color(Color::Rgb(0, 0, 0).into());
- }
+
+ let default_line_style = LineStyle::default();
+ self.layer().set_outline_thickness(printpdf::Pt::from(line_style.thickness()).0);
+ self.layer().set_outline_color(default_line_style.color().into());
}
/// Tries to draw the given string at the given position and returns `true` if the area was
diff --git a/src/style.rs b/src/style.rs
index e77258a..d7615b4 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -528,3 +528,75 @@ impl<'s> From<StyledString> for StyledCow<'s> {
StyledCow::new(s.s, s.style)
}
}
+
+/// A style for a line, used in styling borders and shapes.
+///
+/// Fields:
+/// - the line thickness in millimeters, (defaults to 1.0)
+/// - the color of the line, see [`Color`][] (defaults to black)
+///
+/// [`Color`]: enum.Color.html
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct LineStyle {
+ thickness: Mm, // NOTE: 0.0 is a special value, it does not make the line disappear, but rather makes it appear 1px wide across all devices
+ color: Color,
+}
+
+impl Default for LineStyle {
+ fn default() -> LineStyle {
+ LineStyle {
+ thickness: Mm::from(1.0),
+ color: Color::Rgb(0, 0, 0),
+ }
+ }
+}
+
+impl From<Color> for LineStyle {
+ fn from(color: Color) -> LineStyle {
+ LineStyle {
+ color,
+ ..LineStyle::default()
+ }
+ }
+}
+
+impl LineStyle {
+ /// Creates a new line style with default values.
+ pub fn new() -> LineStyle {
+ LineStyle::default()
+ }
+
+ /// Sets the line thickness. Setting this to 0.0 will not hide the line,
+ /// rather it's a special value that tells PDF viewers to render the line
+ /// as 1px regardless of the display size and zoom.
+ pub fn set_thickness(&mut self, thickness: Mm) {
+ self.thickness = thickness;
+ }
+
+ /// Sets the line thickness and returns the line style.
+ pub fn with_thickness(mut self, thickness: Mm) -> Self {
+ self.set_thickness(thickness);
+ self
+ }
+
+ /// Returns the line thickness if set.
+ pub fn thickness(&self) -> Mm {
+ self.thickness
+ }
+
+ /// Sets the line color.
+ pub fn set_color(&mut self, color: Color) {
+ self.color = color;
+ }
+
+ /// Sets the line color and returns the line style.
+ pub fn with_color(mut self, color: Color) -> Self {
+ self.set_color(color);
+ self
+ }
+
+ /// Returns the line color if set.
+ pub fn color(&self) -> Color {
+ self.color
+ }
+}
\ No newline at end of file
--
2.28.0