use log::{debug, info, warn};
use simplelog::{LevelFilter, TermLogger, TerminalMode, ColorChoice};
use structopt::StructOpt;
use strum::VariantNames;
use ptouch::{Options, PTouch, render::RenderTemplate};
use ptouch::device::{Media, PrintInfo, Status};
use ptouch::render::{FontKind, Op, Render, RenderConfig};
#[derive(Clone, Debug, PartialEq, StructOpt)]
pub struct Flags {
#[structopt(flatten)]
options: Options,
#[structopt(subcommand)]
command: Command,
#[structopt(long, default_value="16")]
pad: usize,
#[structopt(long, possible_values = &Media::VARIANTS, default_value="tze12mm")]
media: Media,
#[structopt(long, default_value = "info")]
log_level: LevelFilter,
}
#[derive(Clone, Debug, PartialEq, StructOpt)]
pub enum RenderCommand {
Text {
text: String,
#[structopt(long, possible_values = &FontKind::VARIANTS, default_value="12x16")]
font: FontKind,
},
QrText {
qr: String,
text: String,
#[structopt(long, possible_values = &FontKind::VARIANTS, default_value="12x16")]
font: FontKind,
},
Qr {
qr: String,
},
Barcode {
code: String,
},
Template{
file: String,
},
Image{
file: String,
},
Example,
}
#[derive(Clone, Debug, PartialEq, StructOpt)]
pub enum Command {
Info,
Status,
Preview(RenderCommand),
Render{
#[structopt(long)]
file: String,
#[structopt(subcommand)]
cmd: RenderCommand,
},
Print(RenderCommand),
}
fn main() -> anyhow::Result<()> {
let opts = Flags::from_args();
TermLogger::init(
opts.log_level,
simplelog::Config::default(),
TerminalMode::Mixed,
ColorChoice::Auto,
)
.unwrap();
let mut rc = RenderConfig{
y: opts.media.area().1 as usize,
..Default::default()
};
debug!("Connecting to PTouch device: {:?}", opts.options);
let connect = match PTouch::new(&opts.options) {
Ok(mut pt) => {
let status;
if opts.options.no_status_fetch {
info!("Connected! status request disabled, using default status...");
status = Status::new(&opts.media)?;
info!("Device status (default one used): {:?}", status);
} else {
info!("Connected! fetching status...");
status = pt.status()?;
info!("Device status (fetched from device): {:?}", status);
}
let media = Media::from((status.media_kind, status.media_width));
rc.y = media.area().1 as usize;
Ok((pt, status, media))
},
Err(e) => Err(e),
};
match &opts.command {
#[cfg(feature = "preview")]
Command::Preview(cmd) => {
if connect.is_err() {
warn!("Using default media: {}, override with `--media` argument", opts.media);
}
let ops = cmd.load(opts.pad)?;
let mut r = Render::new(rc);
r.render(&ops)?;
r.show()?;
return Ok(());
},
#[cfg(not(feature = "preview"))]
Command::Preview(_cmd) => {
warn!("Preview not enabled (or not supported on this platform");
warn!("Try `render` command to render to image files");
return Ok(())
}
Command::Render{ file, cmd } => {
if connect.is_err() {
warn!("Using default media: {}, override with `--media` argument", opts.media);
}
let ops = cmd.load(opts.pad)?;
let mut r = Render::new(rc);
r.render(&ops)?;
r.save(file)?;
return Ok(());
},
_ => (),
}
let (mut ptouch, status, media) = match connect {
Ok(d) => d,
Err(e) => {
return Err(anyhow::anyhow!("Error connecting to PTouch: {:?}", e));
}
};
match &opts.command {
Command::Info => {
let i = ptouch.info()?;
println!("Info: {:?}", i);
},
Command::Status => {
println!("Status: {:?}", status);
},
Command::Print(cmd) => {
let ops = cmd.load(opts.pad)?;
let mut r = Render::new(rc);
r.render(&ops)?;
let data = r.raster(media.area())?;
let info = PrintInfo {
width: Some(status.media_width),
length: Some(0),
raster_no: data.len() as u32,
..Default::default()
};
ptouch.print_raw(data, &info)?;
},
_ => (),
}
Ok(())
}
impl RenderCommand {
pub fn load(&self, pad: usize) -> Result<Vec<Op>, anyhow::Error> {
match self {
RenderCommand::Text { text, font } => {
let ops = vec![
Op::pad(pad),
Op::text_with_font(text, *font),
Op::pad(pad),
];
Ok(ops)
},
RenderCommand::QrText { qr, text, font } => {
let ops = vec![
Op::pad(pad),
Op::qr(qr),
Op::text_with_font(text, *font),
Op::pad(pad)
];
Ok(ops)
},
RenderCommand::Qr { qr } => {
let ops = vec![
Op::pad(pad),
Op::qr(qr),
Op::pad(pad)
];
Ok(ops)
},
RenderCommand::Barcode { code } => {
let ops = vec![
Op::pad(pad),
Op::barcode(code),
Op::pad(pad)
];
Ok(ops)
},
RenderCommand::Template { file } => {
let t = std::fs::read_to_string(file)?;
let c: RenderTemplate = toml::from_str(&t)?;
Ok(c.ops)
},
RenderCommand::Image { file } => {
let ops = vec![
Op::pad(pad),
Op::image(file),
Op::pad(pad)
];
Ok(ops)
}
RenderCommand::Example => {
let ops = vec![
Op::pad(pad),
Op::qr("https://hello.world"),
Op::text("hello world,,\nhow's it going?"),
Op::pad(pad)
];
Ok(ops)
}
}
}
}