use crate::elements::{
BarcodeElement, GraphicalBoxElement, GraphicalCircleElement, GraphicalDiagonalLineElement,
GraphicalEllipseElement, TextElement,
};
use crate::types::{
AxisPosition, BarcodeHeight, BarcodeWidth, BoxDimension, Font, FontSize, GraphicDimension,
Rounding, Thickness, WidthRatio, ZplError,
};
use std::fmt::Display;
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Orientation {
Normal,
Rotated,
Inverted,
Bottom,
}
impl Display for Orientation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Orientation::Normal => write!(f, "N"),
Orientation::Rotated => write!(f, "R"),
Orientation::Inverted => write!(f, "I"),
Orientation::Bottom => write!(f, "B"),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DiagonalOrientation {
RightLeaning,
LeftLeaning,
}
impl Display for DiagonalOrientation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DiagonalOrientation::RightLeaning => write!(f, "R"),
DiagonalOrientation::LeftLeaning => write!(f, "L"),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[allow(missing_docs)]
pub enum BarcodeType {
Aztec,
Code11,
Interleaved,
Code39,
Code49,
PlanetCode,
Pdf417,
EAN8,
UpcE,
Code93,
CodaBlock,
Code128,
UPSMaxiCode,
EAN13,
MicroPDF417,
Industrial,
Standard,
ANSICodeBar,
LogMars,
MSI,
Plessey,
QrCode,
Rss,
UpcEanExtension,
Tlc39,
UpcA,
DataMatrix,
}
impl Display for BarcodeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BarcodeType::Aztec => write!(f, "^BO"),
BarcodeType::Code11 => write!(f, "^B1"),
BarcodeType::Interleaved => write!(f, "^B2"),
BarcodeType::Code39 => write!(f, "^B3"),
BarcodeType::Code49 => write!(f, "^B4"),
BarcodeType::PlanetCode => write!(f, "^B5"),
BarcodeType::Pdf417 => write!(f, "^B7"),
BarcodeType::EAN8 => write!(f, "^B8"),
BarcodeType::UpcE => write!(f, "^B9"),
BarcodeType::Code93 => write!(f, "^BA"),
BarcodeType::CodaBlock => write!(f, "^BB"),
BarcodeType::Code128 => write!(f, "^BC"),
BarcodeType::UPSMaxiCode => write!(f, "^BD"),
BarcodeType::EAN13 => write!(f, "^BE"),
BarcodeType::MicroPDF417 => write!(f, "^BF"),
BarcodeType::Industrial => write!(f, "^BI"),
BarcodeType::Standard => write!(f, "^BJ"),
BarcodeType::ANSICodeBar => write!(f, "^BK"),
BarcodeType::LogMars => write!(f, "^BL"),
BarcodeType::MSI => write!(f, "^BM"),
BarcodeType::Plessey => write!(f, "^BP"),
BarcodeType::QrCode => write!(f, "^BQ"),
BarcodeType::Rss => write!(f, "^BR"),
BarcodeType::UpcEanExtension => write!(f, "^BS"),
BarcodeType::Tlc39 => write!(f, "^BT"),
BarcodeType::UpcA => write!(f, "^BU"),
BarcodeType::DataMatrix => write!(f, "^BX"),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[allow(missing_docs)]
pub enum Color {
Black,
White,
}
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Color::Black => write!(f, "B"),
Color::White => write!(f, "W"),
}
}
}
#[derive(Debug, PartialEq)]
pub struct LabelBuilder {
elements: Vec<String>,
x_origin: AxisPosition,
y_origin: AxisPosition,
}
fn get_axis_position(x: u16, y: u16) -> Result<(AxisPosition, AxisPosition), ZplError> {
let x_position = AxisPosition::try_from(x)?;
let y_position = AxisPosition::try_from(y)?;
Ok((x_position, y_position))
}
impl LabelBuilder {
#[must_use]
pub fn new() -> Self {
Self {
elements: Vec::new(),
x_origin: AxisPosition(0),
y_origin: AxisPosition(0),
}
}
pub fn set_home_position(mut self, x_origin: u16, y_origin: u16) -> Result<Self, ZplError> {
let (x_origin, y_origin) = get_axis_position(x_origin, y_origin)?;
self.x_origin = x_origin;
self.y_origin = y_origin;
Ok(self)
}
pub fn add_text(
mut self,
text: &str,
x: u16,
y: u16,
font: char,
font_size: u16,
orientation: Orientation,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let font_size = FontSize::try_from(font_size)?;
let font = Font::try_from(font)?;
let zpl_text = TextElement::new(text, x, y, font, font_size, orientation).to_zpl();
self.elements.push(zpl_text);
Ok(self)
}
pub fn add_barcode(
mut self,
_type: BarcodeType,
data: &str,
x: u16,
y: u16,
width: u8,
width_ratio: f32,
height: u16,
orientation: Orientation,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let width = BarcodeWidth::try_from(width)?;
let width_ratio = WidthRatio::try_from(width_ratio)?;
let height = BarcodeHeight::try_from(height)?;
let zpl_barcode =
BarcodeElement::new(_type, data, x, y, width, width_ratio, height, orientation)
.to_zpl();
self.elements.push(zpl_barcode);
Ok(self)
}
pub fn add_graphical_box(
mut self,
x: u16,
y: u16,
width: u16,
height: u16,
thickness: u16,
color: Color,
rounding: u8,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let rounding = Rounding::try_from(rounding)?;
let thickness = Thickness::try_from(thickness)?;
let width = BoxDimension::try_new(width, thickness)?;
let height = BoxDimension::try_new(height, thickness)?;
let zpl_box =
GraphicalBoxElement::new(x, y, width, height, thickness, color, rounding).to_zpl();
self.elements.push(zpl_box);
Ok(self)
}
pub fn add_graphical_circle(
mut self,
x: u16,
y: u16,
diameter: u16,
thickness: u16,
color: Color,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let thickness = Thickness::try_from(thickness)?;
let diameter = GraphicDimension::try_from(diameter)?;
let zpl_circle = GraphicalCircleElement::new(x, y, diameter, thickness, color).to_zpl();
self.elements.push(zpl_circle);
Ok(self)
}
pub fn add_graphical_ellipse(
mut self,
x: u16,
y: u16,
width: u16,
height: u16,
thickness: u16,
color: Color,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let thickness = Thickness::try_from(thickness)?;
let width = GraphicDimension::try_from(width)?;
let height = GraphicDimension::try_from(height)?;
let zpl_ellipse =
GraphicalEllipseElement::new(x, y, width, height, thickness, color).to_zpl();
self.elements.push(zpl_ellipse);
Ok(self)
}
pub fn add_graphical_diagonal_line(
mut self,
x: u16,
y: u16,
box_width: u16,
box_height: u16,
thickness: u16,
color: Color,
orientation: DiagonalOrientation,
) -> Result<Self, ZplError> {
let (x, y) = get_axis_position(x, y)?;
let thickness = Thickness::try_from(thickness)?;
let box_width = BoxDimension::try_new(box_width, thickness)?;
let box_height = BoxDimension::try_new(box_height, thickness)?;
let zpl_diagonal = GraphicalDiagonalLineElement::new(
x,
y,
box_width,
box_height,
thickness,
color,
orientation,
)
.to_zpl();
self.elements.push(zpl_diagonal);
Ok(self)
}
#[must_use]
pub fn build(&self) -> String {
let mut zpl = String::new();
zpl.push_str("^XA\n");
zpl.push_str(format!("^LH{},{}\n", self.x_origin, self.y_origin).as_str());
for element in &self.elements {
zpl.push_str(element);
}
zpl.push_str("^XZ");
zpl
}
}
impl Default for LabelBuilder {
fn default() -> Self {
Self::new()
}
}