mirror of
https://codeberg.org/Fl1tzi/microdeck.git
synced 2024-05-20 03:21:04 +00:00
Compare commits
2 commits
42dce219f2
...
005f062ff9
Author | SHA1 | Date | |
---|---|---|---|
Fl1tzi | 005f062ff9 | ||
Fl1tzi | 1f1c388eb3 |
|
@ -46,6 +46,7 @@ pub struct ImageBuilder {
|
||||||
scale: f32,
|
scale: f32,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
|
text_color: [u8; 3],
|
||||||
image: Option<DynamicImage>,
|
image: Option<DynamicImage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ impl Default for ImageBuilder {
|
||||||
scale: 60.0,
|
scale: 60.0,
|
||||||
font_size: 16.0,
|
font_size: 16.0,
|
||||||
text: None,
|
text: None,
|
||||||
|
// black
|
||||||
|
text_color: [255, 255, 255],
|
||||||
image: None,
|
image: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +95,12 @@ impl ImageBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_text_color(mut self, text_color: [u8; 3]) -> Self {
|
||||||
|
self.text_color = text_color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn set_image(mut self, image: DynamicImage) -> Self {
|
pub fn set_image(mut self, image: DynamicImage) -> Self {
|
||||||
self.image = Some(image);
|
self.image = Some(image);
|
||||||
|
@ -108,6 +117,7 @@ impl ImageBuilder {
|
||||||
image: self.image.unwrap(),
|
image: self.image.unwrap(),
|
||||||
scale: self.scale,
|
scale: self.scale,
|
||||||
font_size: self.font_size,
|
font_size: self.font_size,
|
||||||
|
text_color: self.text_color,
|
||||||
text: self.text.unwrap(),
|
text: self.text.unwrap(),
|
||||||
};
|
};
|
||||||
return c.render();
|
return c.render();
|
||||||
|
@ -116,6 +126,7 @@ impl ImageBuilder {
|
||||||
height: self.height,
|
height: self.height,
|
||||||
width: self.width,
|
width: self.width,
|
||||||
font_size: self.font_size,
|
font_size: self.font_size,
|
||||||
|
text_color: self.text_color,
|
||||||
text,
|
text,
|
||||||
};
|
};
|
||||||
return c.render();
|
return c.render();
|
||||||
|
@ -170,6 +181,7 @@ struct TextComponent {
|
||||||
height: usize,
|
height: usize,
|
||||||
width: usize,
|
width: usize,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
|
text_color: [u8; 3],
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,27 +189,10 @@ impl Component for TextComponent {
|
||||||
fn render(&self) -> DynamicImage {
|
fn render(&self) -> DynamicImage {
|
||||||
let mut image = RgbImage::new(self.width as u32, self.height as u32);
|
let mut image = RgbImage::new(self.width as u32, self.height as u32);
|
||||||
|
|
||||||
let scale = Scale::uniform(self.font_size);
|
let font_scale = Scale::uniform(self.font_size);
|
||||||
let font = &GLOBAL_FONT.get().unwrap();
|
let text = wrap_text(self.height as u32, font_scale, &self.text);
|
||||||
|
|
||||||
let v_metrics = font.v_metrics(scale);
|
draw_text_on_image(&text, &mut image, Rgb(self.text_color), font_scale);
|
||||||
let height = (v_metrics.ascent - v_metrics.descent + v_metrics.line_gap).round() as i32;
|
|
||||||
|
|
||||||
// start at y = 10
|
|
||||||
let mut y_pos = 10;
|
|
||||||
|
|
||||||
for line in self.text.split("\n") {
|
|
||||||
draw_text_mut(
|
|
||||||
&mut image,
|
|
||||||
Rgb([255, 255, 255]),
|
|
||||||
10,
|
|
||||||
y_pos,
|
|
||||||
scale,
|
|
||||||
&GLOBAL_FONT.get().unwrap(),
|
|
||||||
&line,
|
|
||||||
);
|
|
||||||
y_pos += height;
|
|
||||||
}
|
|
||||||
|
|
||||||
image::DynamicImage::ImageRgb8(image)
|
image::DynamicImage::ImageRgb8(image)
|
||||||
}
|
}
|
||||||
|
@ -210,6 +205,7 @@ struct ImageTextComponent {
|
||||||
image: DynamicImage,
|
image: DynamicImage,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
|
text_color: [u8; 3],
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,19 +220,9 @@ impl Component for ImageTextComponent {
|
||||||
|
|
||||||
let mut base_image = RgbImage::new(self.height as u32, self.width as u32);
|
let mut base_image = RgbImage::new(self.height as u32, self.width as u32);
|
||||||
|
|
||||||
let font = &GLOBAL_FONT.get().unwrap();
|
|
||||||
let font_scale = Scale::uniform(self.font_size);
|
let font_scale = Scale::uniform(self.font_size);
|
||||||
|
let text = wrap_text(self.height as u32, font_scale, &self.text);
|
||||||
// TODO: allow new line
|
draw_text_on_image(&text, &mut base_image, Rgb(self.text_color), font_scale);
|
||||||
draw_text_mut(
|
|
||||||
&mut base_image,
|
|
||||||
Rgb([255, 255, 255]),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
font_scale,
|
|
||||||
font,
|
|
||||||
&self.text,
|
|
||||||
);
|
|
||||||
// position at the middle
|
// position at the middle
|
||||||
let free_space = self.width - image.width() as usize;
|
let free_space = self.width - image.width() as usize;
|
||||||
// TODO: allow padding to be manually set
|
// TODO: allow padding to be manually set
|
||||||
|
@ -250,3 +236,37 @@ impl Component for ImageTextComponent {
|
||||||
image::DynamicImage::ImageRgb8(base_image)
|
image::DynamicImage::ImageRgb8(base_image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_text_on_image(text: &String, image: &mut RgbImage, color: Rgb<u8>, font_scale: Scale) {
|
||||||
|
let font = &GLOBAL_FONT.get().unwrap();
|
||||||
|
let v_metrics = font.v_metrics(font_scale);
|
||||||
|
|
||||||
|
let line_height = (v_metrics.ascent - v_metrics.descent + v_metrics.line_gap).round() as i32;
|
||||||
|
let mut y_pos = 0;
|
||||||
|
|
||||||
|
for line in text.split('\n') {
|
||||||
|
draw_text_mut(image, color, 0, y_pos, font_scale, font, &line);
|
||||||
|
y_pos += line_height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This functions adds '\n' to the line endings. It does not wrap
|
||||||
|
/// words but characters.
|
||||||
|
pub fn wrap_text(max_width: u32, font_size: Scale, text: &String) -> String {
|
||||||
|
let font = &GLOBAL_FONT.get().unwrap();
|
||||||
|
|
||||||
|
let mut new_text: Vec<char> = Vec::new();
|
||||||
|
let mut line_size = 0.0;
|
||||||
|
|
||||||
|
for character in text.chars() {
|
||||||
|
let h_size = font.glyph(character).scaled(font_size).h_metrics();
|
||||||
|
let complete_width = h_size.advance_width + h_size.left_side_bearing;
|
||||||
|
if (line_size + complete_width) as u32 > max_width {
|
||||||
|
new_text.push('\n');
|
||||||
|
line_size = 0.0;
|
||||||
|
}
|
||||||
|
new_text.push(character);
|
||||||
|
line_size += h_size.advance_width + h_size.left_side_bearing;
|
||||||
|
}
|
||||||
|
String::from_iter(new_text)
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use self::space::Space;
|
||||||
// other things
|
// other things
|
||||||
use crate::config::{Button, ButtonConfigError};
|
use crate::config::{Button, ButtonConfigError};
|
||||||
use crate::device::ImageCache;
|
use crate::device::ImageCache;
|
||||||
use crate::image_rendering::load_image;
|
use crate::image_rendering::{load_image, ImageBuilder};
|
||||||
use ::image::imageops::FilterType;
|
use ::image::imageops::FilterType;
|
||||||
use ::image::DynamicImage;
|
use ::image::DynamicImage;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -91,13 +91,13 @@ pub async fn start_module(
|
||||||
button.index,
|
button.index,
|
||||||
device.kind().key_image_format().size,
|
device.kind().key_image_format().size,
|
||||||
);
|
);
|
||||||
let da = DeviceAccess::new(device, button.index).await;
|
let da = DeviceAccess::new(device.clone(), button.index).await;
|
||||||
|
|
||||||
// init
|
// init
|
||||||
//
|
//
|
||||||
// This function should be called after the config was checked,
|
// This function should be called after the config was checked,
|
||||||
// otherwise it will panic and the module wont be started.
|
// otherwise it will panic and the module wont be started.
|
||||||
let mut module = match module_init_function(button, mc).await {
|
let mut module = match module_init_function(button.clone(), mc).await {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
|
@ -105,7 +105,19 @@ pub async fn start_module(
|
||||||
// then run module
|
// then run module
|
||||||
match module.run(da, br).await {
|
match module.run(da, br).await {
|
||||||
Ok(_) => debug!("RETURNED"),
|
Ok(_) => debug!("RETURNED"),
|
||||||
Err(e) => error!("RETURNED_ERROR: {}", e),
|
// TODO: maybe find calculation for font size
|
||||||
|
// print error on display
|
||||||
|
Err(e) => {
|
||||||
|
error!("{e}");
|
||||||
|
let da = DeviceAccess::new(device, button.index).await;
|
||||||
|
let res = da.resolution();
|
||||||
|
let image = ImageBuilder::new(res.0, res.1)
|
||||||
|
.set_text(format!("E: {}", e))
|
||||||
|
.set_font_size(12.0)
|
||||||
|
.set_text_color([255, 0, 0])
|
||||||
|
.build();
|
||||||
|
da.write_img(image).await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,8 +248,6 @@ pub trait Module: Sync + Send {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
/// Function for actually running the module and interacting with the device. Errors that
|
/// Function for actually running the module and interacting with the device. Errors that
|
||||||
/// happen here should be mostly prevented.
|
/// happen here should be mostly prevented.
|
||||||
///
|
|
||||||
/// TODO: The return error is not sent anywhere and is just a panic
|
|
||||||
async fn run(
|
async fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
device: DeviceAccess,
|
device: DeviceAccess,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use super::{
|
||||||
ReturnError,
|
ReturnError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::image_rendering::wrap_text;
|
||||||
use crate::GLOBAL_FONT;
|
use crate::GLOBAL_FONT;
|
||||||
use image::{DynamicImage, Rgb, RgbImage};
|
use image::{DynamicImage, Rgb, RgbImage};
|
||||||
use imageproc::drawing::draw_text_mut;
|
use imageproc::drawing::draw_text_mut;
|
||||||
|
@ -96,18 +97,19 @@ fn render_text(
|
||||||
|
|
||||||
let scale = Scale::uniform(title_size);
|
let scale = Scale::uniform(title_size);
|
||||||
let font = &GLOBAL_FONT.get().unwrap();
|
let font = &GLOBAL_FONT.get().unwrap();
|
||||||
|
|
||||||
let v_metrics = font.v_metrics(scale);
|
let v_metrics = font.v_metrics(scale);
|
||||||
let height = (v_metrics.ascent - v_metrics.descent + v_metrics.line_gap).round() as i32;
|
let height = (v_metrics.ascent - v_metrics.descent + v_metrics.line_gap).round() as i32;
|
||||||
|
|
||||||
// start at y = 10
|
let text = wrap_text(image.width(), scale, &title);
|
||||||
let mut y_pos = 10;
|
|
||||||
|
|
||||||
for line in title.split("\n") {
|
// start at y = 0
|
||||||
|
let mut y_pos = 0;
|
||||||
|
|
||||||
|
for line in text.split("\n") {
|
||||||
draw_text_mut(
|
draw_text_mut(
|
||||||
&mut image,
|
&mut image,
|
||||||
Rgb([255, 255, 255]),
|
Rgb([255, 255, 255]),
|
||||||
10,
|
0,
|
||||||
y_pos,
|
y_pos,
|
||||||
Scale::uniform(title_size),
|
Scale::uniform(title_size),
|
||||||
&GLOBAL_FONT.get().unwrap(),
|
&GLOBAL_FONT.get().unwrap(),
|
||||||
|
@ -119,7 +121,7 @@ fn render_text(
|
||||||
draw_text_mut(
|
draw_text_mut(
|
||||||
&mut image,
|
&mut image,
|
||||||
Rgb([255, 255, 255]),
|
Rgb([255, 255, 255]),
|
||||||
10,
|
0,
|
||||||
y_pos,
|
y_pos,
|
||||||
Scale::uniform(number_size),
|
Scale::uniform(number_size),
|
||||||
&GLOBAL_FONT.get().unwrap(),
|
&GLOBAL_FONT.get().unwrap(),
|
||||||
|
|
Loading…
Reference in a new issue