pub const SLIDE_WIDTH_EMU: u32 = 9144000;
pub const SLIDE_HEIGHT_EMU: u32 = 6858000;
const EMU_PER_INCH: f64 = 914400.0;
const EMU_PER_CM: f64 = 360000.0;
const EMU_PER_PT: f64 = 12700.0;
#[derive(Clone, Debug, PartialEq)]
pub enum Dimension {
Emu(u32),
Inches(f64),
Cm(f64),
Pt(f64),
Ratio(f64),
}
impl Dimension {
pub fn to_emu(&self, reference_emu: u32) -> u32 {
match self {
Dimension::Emu(v) => *v,
Dimension::Inches(v) => (v * EMU_PER_INCH) as u32,
Dimension::Cm(v) => (v * EMU_PER_CM) as u32,
Dimension::Pt(v) => (v * EMU_PER_PT) as u32,
Dimension::Ratio(r) => (r.clamp(0.0, 1.0) * reference_emu as f64) as u32,
}
}
pub fn to_emu_x(&self) -> u32 {
self.to_emu(SLIDE_WIDTH_EMU)
}
pub fn to_emu_y(&self) -> u32 {
self.to_emu(SLIDE_HEIGHT_EMU)
}
}
impl From<u32> for Dimension {
fn from(emu: u32) -> Self {
Dimension::Emu(emu)
}
}
impl Dimension {
pub fn inches(v: f64) -> Self {
Dimension::Inches(v)
}
pub fn cm(v: f64) -> Self {
Dimension::Cm(v)
}
pub fn pt(v: f64) -> Self {
Dimension::Pt(v)
}
pub fn ratio(v: f64) -> Self {
Dimension::Ratio(v)
}
pub fn emu(v: u32) -> Self {
Dimension::Emu(v)
}
pub fn percent(v: f64) -> Self {
Dimension::Ratio(v / 100.0)
}
}
#[derive(Clone, Debug)]
pub struct FlexPosition {
pub x: Dimension,
pub y: Dimension,
}
impl FlexPosition {
pub fn new(x: Dimension, y: Dimension) -> Self {
Self { x, y }
}
pub fn to_emu(&self) -> (u32, u32) {
(self.x.to_emu_x(), self.y.to_emu_y())
}
pub fn to_emu_with(&self, slide_width: u32, slide_height: u32) -> (u32, u32) {
(self.x.to_emu(slide_width), self.y.to_emu(slide_height))
}
}
#[derive(Clone, Debug)]
pub struct FlexSize {
pub width: Dimension,
pub height: Dimension,
}
impl FlexSize {
pub fn new(width: Dimension, height: Dimension) -> Self {
Self { width, height }
}
pub fn to_emu(&self) -> (u32, u32) {
(self.width.to_emu_x(), self.height.to_emu_y())
}
pub fn to_emu_with(&self, slide_width: u32, slide_height: u32) -> (u32, u32) {
(
self.width.to_emu(slide_width),
self.height.to_emu(slide_height),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_emu_passthrough() {
assert_eq!(Dimension::Emu(914400).to_emu(0), 914400);
}
#[test]
fn test_inches_to_emu() {
assert_eq!(Dimension::Inches(1.0).to_emu(0), 914400);
assert_eq!(Dimension::Inches(0.5).to_emu(0), 457200);
assert_eq!(Dimension::Inches(10.0).to_emu(0), 9144000);
}
#[test]
fn test_cm_to_emu() {
assert_eq!(Dimension::Cm(2.54).to_emu(0), 914400);
assert_eq!(Dimension::Cm(1.0).to_emu(0), 360000);
}
#[test]
fn test_pt_to_emu() {
assert_eq!(Dimension::Pt(72.0).to_emu(0), 914400); assert_eq!(Dimension::Pt(1.0).to_emu(0), 12700);
}
#[test]
fn test_ratio_to_emu() {
assert_eq!(Dimension::Ratio(0.1).to_emu(SLIDE_WIDTH_EMU), 914400);
assert_eq!(Dimension::Ratio(0.5).to_emu(SLIDE_WIDTH_EMU), 4572000);
assert_eq!(Dimension::Ratio(1.0).to_emu(SLIDE_WIDTH_EMU), 9144000);
assert_eq!(Dimension::Ratio(0.0).to_emu(SLIDE_WIDTH_EMU), 0);
}
#[test]
fn test_ratio_clamped() {
assert_eq!(Dimension::Ratio(1.5).to_emu(SLIDE_WIDTH_EMU), 9144000);
assert_eq!(Dimension::Ratio(-0.5).to_emu(SLIDE_WIDTH_EMU), 0);
}
#[test]
fn test_percent() {
assert_eq!(Dimension::percent(50.0).to_emu(SLIDE_WIDTH_EMU), 4572000);
assert_eq!(Dimension::percent(10.0).to_emu(SLIDE_WIDTH_EMU), 914400);
}
#[test]
fn test_to_emu_x_y() {
let x = Dimension::Ratio(0.5);
let y = Dimension::Ratio(0.5);
assert_eq!(x.to_emu_x(), SLIDE_WIDTH_EMU / 2);
assert_eq!(y.to_emu_y(), SLIDE_HEIGHT_EMU / 2);
}
#[test]
fn test_flex_position() {
let pos = FlexPosition::new(Dimension::Inches(1.0), Dimension::Ratio(0.5));
let (x, y) = pos.to_emu();
assert_eq!(x, 914400);
assert_eq!(y, SLIDE_HEIGHT_EMU / 2);
}
#[test]
fn test_flex_size() {
let size = FlexSize::new(Dimension::Ratio(0.8), Dimension::Inches(2.0));
let (w, h) = size.to_emu();
assert_eq!(w, (SLIDE_WIDTH_EMU as f64 * 0.8) as u32);
assert_eq!(h, 914400 * 2);
}
#[test]
fn test_flex_position_custom_slide() {
let custom_w = 12192000_u32; let custom_h = 6858000_u32;
let pos = FlexPosition::new(Dimension::Ratio(0.5), Dimension::Ratio(0.5));
let (x, y) = pos.to_emu_with(custom_w, custom_h);
assert_eq!(x, custom_w / 2);
assert_eq!(y, custom_h / 2);
}
#[test]
fn test_from_u32() {
let d: Dimension = 914400_u32.into();
assert_eq!(d, Dimension::Emu(914400));
}
#[test]
fn test_shorthand_constructors() {
assert_eq!(Dimension::inches(1.0), Dimension::Inches(1.0));
assert_eq!(Dimension::cm(2.54), Dimension::Cm(2.54));
assert_eq!(Dimension::pt(72.0), Dimension::Pt(72.0));
assert_eq!(Dimension::ratio(0.5), Dimension::Ratio(0.5));
assert_eq!(Dimension::emu(914400), Dimension::Emu(914400));
}
}