canrust 1.1.0

A Rust library drawing shapes onto a canvas
Documentation
//! Utilities for font handling and image processing

use crate::canvas::Color;
use fontconfig::Fontconfig;
use sfml::graphics::Image as Img;
use std::path::Path;

#[derive(Debug, Clone)]
/// Struct responsible for font loading and handling .
pub struct FontHandler {
    font_path: String,
}

impl FontHandler {
    /// Use your own specific font file. Pass it's path as a String
    /// Supported formats can be found in SFML's documentation:
    /// [SFML DOCUMENTATION](https://docs.rs/sfml/0.15.1/sfml/graphics/struct.Font.html#method.from_file)
    /// ```no_run
    ///
    /// let handler = FontHandler::custom("~/myfont.ttf").expect("Unable to construct object!");
    ///
    /// ```
    pub fn custom(font_path: String) -> Option<Self> {
        let path = Path::new(&font_path);
        if path.is_dir() || path.exists() {
            let mut ret = String::new();
            match path.to_str() {
                Some(val) => ret = val.to_string(),
                None => return None,
            }
            Some(Self { font_path: ret }) // TODO
        } else {
            return None;
        }
    }

    /// Tries to match the given String and returns its path.
    /// ```no_run
    ///
    /// let handler = FontHandler::find_fonts("Source Code Pro").expect("Unable to construct object!");
    ///
    /// ```
    #[cfg(target_os = "linux")]
    pub fn find_fonts(f: String) -> Option<Self> {
        let mut ret = String::new();
        if let Some(fc) = Fontconfig::new() {
            match fc.find(f.as_str(), None) {
                Some(val) => {
                    match val.path.to_str() {
                        Some(s) => ret = s.to_string(),
                        None => ret = "unable to retrieve font".to_string(),
                    };
                }
                None => (),
            };
        }
        Some(Self { font_path: ret })
    }
    /// Not tested!
    /// Looks for the font file in the C:\Windows\Fonts\
    /// ```no_run
    ///
    /// let fonthlander = FontHandler::find_fonts("Arial.ttf").expect("Font not found!");
    ///
    /// ```
    #[cfg(target_os = "windows")]
    pub fn find_fonts(font: String) -> Option<Self> {
        let path = Path::new(
            "C:\\Windows\\Fonts"
                .to_owned()
                .push_str(font.as_str())
                .as_str(),
        );
        if path.exits() && path.is_dir() == false {
            return Some(Self { font_path: path });
        } else {
            return None;
        }
    }

    /// Returns font path filed of the struct.
    /// Mainly used for debugging.
    pub fn get(&self) -> String {
        return self.font_path.clone();
    }
}

// Image
#[derive(Clone)]
/// Struct containing an image which can be projected onto the Canvas.
pub struct Image {
    pub(crate) image: Img,
    position: (f32, f32),
    rotation: f32,
}

impl Image {
    /// Load a new image from file.
    pub fn from_file(path: &str, position: (f32, f32)) -> Result<Self, String> {
        let img = match Img::from_file(path) {
            Some(i) => i,
            None => return Err("Failed to load image from file".to_string()),
        };

        Ok(Self {
            image: img,
            position,
            rotation: 0f32,
        })
    }

    /// Clones an existing image from reference
    pub fn from_image(img: &Image) -> Option<Self> {
        Some(Self {
            image: img.image.clone(),
            position: img.position.clone(),
            rotation: img.rotation.clone(),
        })
    }
}

impl Image {
    /// Saves Image to file
    pub fn save(&self, path: &str) -> Result<(), String> {
        match &self.image.save_to_file(path) {
            true => Ok(()),
            false => Err("Failed to save image".to_string()),
        }
    }

    /// Returns size of the Image
    pub fn get_size(&self) -> Option<(u32, u32)> {
        let res = &self.image.size();

        Some((res.x, res.y))
    }

    /// Returns color of a pixel at give coordinates
    pub fn get_pixel(&self, x: u32, y: u32) -> Option<Color> {
        let res = &self.image.pixel_at(x, y);

        match Color::from_sfml_color(res.clone()) {
            Some(c) => return Some(c),
            None => return None,
        }
    }

    /// Gives a pixel at given coordinates a color.
    /// Returns and Error if the coordinates are too large.
    pub fn put_pixel(&mut self, x: u32, y: u32, color: Color) -> Result<(), String> {
        let size = self.get_size().unwrap();
        if x > size.0 {
            return Err("X value out of range, this causes undefined behavior".to_string());
        };
        if y > size.1 {
            return Err("Y value out of range, this causes undefined behavior".to_string());
        } else {
            self.image.set_pixel(x, y, color.c);

            Ok(())
        }
    }

    /// Returns Images memory buffer
    pub fn pixels_memory(&self) -> Option<&[u8]> {
        Some(self.image.pixel_data())
    }

    /// Sets objects position on the Canvas
    pub fn set_position(&mut self, pos: (f32, f32)) -> Result<(), String> {
        self.position = pos;

        Ok(())
    }

    /// Returns objects position on the Canvas
    pub fn get_position(&self) -> Option<(f32, f32)> {
        let pos = self.position;

        Some(pos)
    }

    /// Sets the angle at which the image will be displayed on Canvas
    pub fn set_rotation(&mut self, angle: f32) -> Result<(), String> {
        self.rotation = angle;

        Ok(())
    }
}