zpl-builder 0.1.0

A builder for ZPL II label strings, for use with Zebra thermal printers
Documentation
//! Internal ZPL element types.
//!
//! Each struct holds the validated parameters for one ZPL command and exposes
//! a single `to_zpl` method that formats them into the corresponding command
//! string. Construction is always done through the builder — these types are
//! not part of the public API.

use crate::types::{
    AxisPosition, BarcodeHeight, BarcodeWidth, BoxDimension, Font, FontSize, GraphicDimension,
    Rounding, Thickness, WidthRatio,
};
use crate::{BarcodeType, Color, DiagonalOrientation, Orientation};

// ---- Text (`^A` / `^FD`) ----

pub(crate) struct TextElement {
    data: String,
    x: AxisPosition,
    y: AxisPosition,
    font: Font,
    font_size: FontSize,
    orientation: Orientation,
}

impl TextElement {
    #[must_use]
    pub(crate) fn new(
        data: &str,
        x: AxisPosition,
        y: AxisPosition,
        font: Font,
        font_size: FontSize,
        orientation: Orientation,
    ) -> Self {
        Self {
            data: data.to_string(),
            x,
            y,
            font,
            font_size,
            orientation,
        }
    }

    /// Format as a ZPL text field.
    ///
    /// Non-normal orientations add a `^FW` field-orientation command before
    /// the field origin so the printer rotates the text correctly.
    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        if self.orientation != Orientation::Normal {
            return format!(
                "^A{},{}^FW{}^FO{},{}^FD{}^FS\n",
                self.font, self.font_size, self.orientation, self.x, self.y, self.data
            );
        }
        format!(
            "^A{},{}^FO{},{}^FD{}^FS\n",
            self.font, self.font_size, self.x, self.y, self.data
        )
    }
}

// ---- Barcode (`^BY` / `^B*`) ----

pub(crate) struct BarcodeElement {
    _type: BarcodeType,
    data: String,
    x: AxisPosition,
    y: AxisPosition,
    width: BarcodeWidth,
    width_ratio: WidthRatio,
    height: BarcodeHeight,
    orientation: Orientation,
}

impl BarcodeElement {
    #[must_use]
    pub(crate) fn new(
        _type: BarcodeType,
        data: &str,
        x: AxisPosition,
        y: AxisPosition,
        width: BarcodeWidth,
        width_ratio: WidthRatio,
        height: BarcodeHeight,
        orientation: Orientation,
    ) -> Self {
        Self {
            _type,
            data: data.to_string(),
            x,
            y,
            width,
            width_ratio,
            height,
            orientation,
        }
    }

    /// Format as a ZPL barcode field.
    ///
    /// The `^BY` bar-defaults command precedes the barcode command. For
    /// non-normal orientations the orientation letter is appended directly
    /// after the barcode-type command (e.g. `^BC,I`).
    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        if self.orientation != Orientation::Normal {
            return format!(
                "^BY{},{},{}\n^FO{},{}{},{}^FD{}^FS\n",
                self.width,
                self.width_ratio,
                self.height,
                self.x,
                self.y,
                self._type,
                self.orientation,
                self.data
            );
        }
        format!(
            "^BY{},{},{}\n^FO{},{}{}^FD{}^FS\n",
            self.width, self.width_ratio, self.height, self.x, self.y, self._type, self.data
        )
    }
}

// ---- Graphical box (`^GB`) ----

pub(crate) struct GraphicalBoxElement {
    x: AxisPosition,
    y: AxisPosition,
    width: BoxDimension,
    height: BoxDimension,
    thickness: Thickness,
    color: Color,
    rounding: Rounding,
}

impl GraphicalBoxElement {
    #[must_use]
    pub(crate) fn new(
        x: AxisPosition,
        y: AxisPosition,
        width: BoxDimension,
        height: BoxDimension,
        thickness: Thickness,
        color: Color,
        rounding: Rounding,
    ) -> Self {
        Self {
            x,
            y,
            width,
            height,
            thickness,
            color,
            rounding,
        }
    }

    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        format!(
            "^FO{},{}^GB{},{},{},{},{}^FS\n",
            self.x, self.y, self.width, self.height, self.thickness, self.color, self.rounding
        )
    }
}

// ---- Graphical circle (`^GC`) ----

pub(crate) struct GraphicalCircleElement {
    x: AxisPosition,
    y: AxisPosition,
    diameter: GraphicDimension,
    thickness: Thickness,
    color: Color,
}

impl GraphicalCircleElement {
    #[must_use]
    pub(crate) fn new(
        x: AxisPosition,
        y: AxisPosition,
        diameter: GraphicDimension,
        thickness: Thickness,
        color: Color,
    ) -> Self {
        Self {
            x,
            y,
            diameter,
            thickness,
            color,
        }
    }

    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        format!(
            "^FO{},{}^GC{},{},{}^FS\n",
            self.x, self.y, self.diameter, self.thickness, self.color,
        )
    }
}

// ---- Graphical ellipse (`^GE`) ----

pub(crate) struct GraphicalEllipseElement {
    x: AxisPosition,
    y: AxisPosition,
    width: GraphicDimension,
    height: GraphicDimension,
    thickness: Thickness,
    color: Color,
}

impl GraphicalEllipseElement {
    #[must_use]
    pub(crate) fn new(
        x: AxisPosition,
        y: AxisPosition,
        width: GraphicDimension,
        height: GraphicDimension,
        thickness: Thickness,
        color: Color,
    ) -> Self {
        Self {
            x,
            y,
            width,
            height,
            thickness,
            color,
        }
    }

    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        format!(
            "^FO{},{}^GE{},{},{},{}^FS\n",
            self.x, self.y, self.width, self.height, self.thickness, self.color,
        )
    }
}

// ---- Diagonal line (`^GD`) ----

pub(crate) struct GraphicalDiagonalLineElement {
    x: AxisPosition,
    y: AxisPosition,
    box_width: BoxDimension,
    box_height: BoxDimension,
    thickness: Thickness,
    color: Color,
    orientation: DiagonalOrientation,
}

impl GraphicalDiagonalLineElement {
    #[must_use]
    pub(crate) fn new(
        x: AxisPosition,
        y: AxisPosition,
        box_width: BoxDimension,
        box_height: BoxDimension,
        thickness: Thickness,
        color: Color,
        orientation: DiagonalOrientation,
    ) -> Self {
        Self {
            x,
            y,
            box_width,
            box_height,
            thickness,
            color,
            orientation,
        }
    }

    #[must_use]
    pub(crate) fn to_zpl(&self) -> String {
        format!(
            "^FO{},{}^GD{},{},{},{},{}^FS\n",
            self.x,
            self.y,
            self.box_width,
            self.box_height,
            self.thickness,
            self.color,
            self.orientation
        )
    }
}