From a7c84315a57c5ecb1fed30c44ad72cfc97bc023e Mon Sep 17 00:00:00 2001 From: eqs Date: Tue, 7 Jun 2022 23:39:15 +0900 Subject: [PATCH 1/6] Add FontStyle --- src/lib.rs | 25 +++++++++++++++++++++++++ src/system.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 37174bc..0f19e5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,6 +193,11 @@ fn stroke_weight(w: f32) { instance().stroke_weight(w); } +#[pyfunction] +fn font_size(font_size: u32) { + instance().font_size(font_size); +} + #[pyfunction] fn background(r: u8, g: Option, b: Option, a: Option) { let draw = get_draw(); @@ -286,6 +291,24 @@ fn polyline_list(points: &PyList) { })); } +#[pyfunction] +fn text(text: &str, x: f32, y: f32, w: Option, h: Option) { + let draw = get_draw(); + + match (w, h) { + (None, None) => + draw.text(text) + .text_style() + .x_y(x, y), + (Some(w), Some(h)) => + draw.text(text) + .text_style() + .x_y(x, y) + .w_h(w, h), + _ => panic!("Invalid arguments") + }; +} + #[pyfunction] fn save_frame(file_path: &str) { get_app().main_window().capture_frame(file_path); @@ -312,6 +335,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(stroke, m)?)?; m.add_function(wrap_pyfunction!(no_stroke, m)?)?; m.add_function(wrap_pyfunction!(stroke_weight, m)?)?; + m.add_function(wrap_pyfunction!(font_size, m)?)?; m.add_function(wrap_pyfunction!(background, m)?)?; m.add_function(wrap_pyfunction!(ellipse, m)?)?; m.add_function(wrap_pyfunction!(circle, m)?)?; @@ -320,6 +344,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(arrow, m)?)?; m.add_function(wrap_pyfunction!(polygon_list, m)?)?; m.add_function(wrap_pyfunction!(polyline_list, m)?)?; + m.add_function(wrap_pyfunction!(text, m)?)?; m.add_function(wrap_pyfunction!(save_frame, m)?)?; add_event_class(&m)?; diff --git a/src/system.rs b/src/system.rs index bf31a40..2f702fa 100644 --- a/src/system.rs +++ b/src/system.rs @@ -104,6 +104,7 @@ pub struct AppState<'a> { pub height: u32, pub title: &'a str, drawing_style: DrawingStyle, + font_style: FontStyle, transform_matrix: Mat4, matrix_stack: Vec, @@ -139,6 +140,7 @@ impl<'a> AppState<'a> { height: 800, title: "q5", drawing_style: DrawingStyle::new(), + font_style: FontStyle::new(), transform_matrix: Mat4::IDENTITY, matrix_stack, mouse_event_state: MouseEventState::new(0.0, 0.0), @@ -219,6 +221,10 @@ impl<'a> AppState<'a> { pub fn get_stroke_weight(&self) -> f32 { self.drawing_style.stroke_weight } + + pub fn font_size(&mut self, font_size: u32) { + self.font_style.font_size = font_size; + } } impl<'a> PythonCallback for AppState<'a> { @@ -387,3 +393,38 @@ impl<'a, T> PathStyle for Drawing<'a, T> } } } + +pub struct FontStyle { + pub font_size: u32, + pub line_spacing: f32, + pub horizontal_align: TextAlign, + pub vertical_align: TextAlign, +} + +pub enum TextAlign { + Start, + Middle, + End, +} + +impl FontStyle { + pub fn new() -> FontStyle { + FontStyle { + font_size: 24, + line_spacing: 0.0, + horizontal_align: TextAlign::Middle, + vertical_align: TextAlign::Middle, + } + } +} + +pub trait TextStyle { + fn text_style(self) -> Self; +} + +impl<'a> TextStyle for Drawing<'a, Text> { + fn text_style(self) -> Self { + let state = instance(); + self.font_size(state.font_style.font_size) + } +} From f95dacb70678ac90e1b0110140628baea29af777 Mon Sep 17 00:00:00 2001 From: eqs Date: Wed, 8 Jun 2022 00:01:04 +0900 Subject: [PATCH 2/6] Add text color --- src/system.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/system.rs b/src/system.rs index 2f702fa..6b33c41 100644 --- a/src/system.rs +++ b/src/system.rs @@ -425,6 +425,12 @@ pub trait TextStyle { impl<'a> TextStyle for Drawing<'a, Text> { fn text_style(self) -> Self { let state = instance(); - self.font_size(state.font_style.font_size) + let ctx = match state.drawing_style.fill_color { + PColor::Gray8(lum) => self.color(rgb8(lum, lum, lum)), + PColor::Rgb8(r, g, b) => self.color(rgb8(r, g, b)), + PColor::Rgba8(r, g, b, a) => self.color(rgba8(r, g, b, a)), + _ => self, + }; + ctx.font_size(state.font_style.font_size) } } From 3f9c1fe18b15a3c8fe98a0afb31a039c2a8eb5a7 Mon Sep 17 00:00:00 2001 From: eqs Date: Wed, 8 Jun 2022 00:07:04 +0900 Subject: [PATCH 3/6] Add text leading --- src/lib.rs | 6 ++++++ src/system.rs | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0f19e5c..5c4bb4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,6 +198,11 @@ fn font_size(font_size: u32) { instance().font_size(font_size); } +#[pyfunction] +fn text_leading(text_leading: f32) { + instance().text_leading(text_leading); +} + #[pyfunction] fn background(r: u8, g: Option, b: Option, a: Option) { let draw = get_draw(); @@ -336,6 +341,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(no_stroke, m)?)?; m.add_function(wrap_pyfunction!(stroke_weight, m)?)?; m.add_function(wrap_pyfunction!(font_size, m)?)?; + m.add_function(wrap_pyfunction!(text_leading, m)?)?; m.add_function(wrap_pyfunction!(background, m)?)?; m.add_function(wrap_pyfunction!(ellipse, m)?)?; m.add_function(wrap_pyfunction!(circle, m)?)?; diff --git a/src/system.rs b/src/system.rs index 6b33c41..f1fc931 100644 --- a/src/system.rs +++ b/src/system.rs @@ -225,6 +225,10 @@ impl<'a> AppState<'a> { pub fn font_size(&mut self, font_size: u32) { self.font_style.font_size = font_size; } + + pub fn text_leading(&mut self, text_leading: f32) { + self.font_style.line_spacing = text_leading; + } } impl<'a> PythonCallback for AppState<'a> { @@ -432,5 +436,6 @@ impl<'a> TextStyle for Drawing<'a, Text> { _ => self, }; ctx.font_size(state.font_style.font_size) + .line_spacing(state.font_style.line_spacing) } } From 4e6cba564c8487897364058ec50e51a90ebf7ab9 Mon Sep 17 00:00:00 2001 From: eqs Date: Wed, 8 Jun 2022 20:26:52 +0900 Subject: [PATCH 4/6] Implement text alignment --- src/constant.rs | 17 +++++++++++++++++ src/lib.rs | 8 ++++++++ src/system.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/src/constant.rs b/src/constant.rs index 6ea87a8..cbdb38d 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,8 +1,18 @@ use pyo3::prelude::*; +pub type Align = u32; pub type MouseButton = u32; pub type Key = u32; + +pub const LEFT: Align = 0 as Align; +pub const RIGHT: Align = 1 as Align; +pub const TOP: Align = 2 as Align; +pub const BOTTOM: Align = 3 as Align; +pub const CENTER: Align = 4 as Align; +pub const MIDDLE: Align = 4 as Align; + + pub const MOUSE_LEFT: MouseButton = 0 as MouseButton; pub const MOUSE_RIGHT: MouseButton = 1 as MouseButton; pub const MOUSE_MIDDLE: MouseButton = 2 as MouseButton; @@ -178,6 +188,13 @@ pub fn add_module_constants(m: &PyModule) -> PyResult<()> { }; } + add_constant!(LEFT)?; + add_constant!(RIGHT)?; + add_constant!(TOP)?; + add_constant!(BOTTOM)?; + add_constant!(MIDDLE)?; + add_constant!(CENTER)?; + add_constant!(MOUSE_LEFT)?; add_constant!(MOUSE_RIGHT)?; add_constant!(MOUSE_MIDDLE)?; diff --git a/src/lib.rs b/src/lib.rs index 5c4bb4b..02b63f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ use crate::event::add_event_class; use crate::numpy_lib::add_numpy_functions; use crate::math_utils::add_math_functions; use crate::constant::add_module_constants; +use crate::constant::*; struct Model { _window: window::Id, @@ -203,6 +204,12 @@ fn text_leading(text_leading: f32) { instance().text_leading(text_leading); } +#[pyfunction] +fn text_align(h_align: Align, v_align: Option) { + let v_align = v_align.unwrap_or(LEFT); + instance().text_align(h_align, v_align); +} + #[pyfunction] fn background(r: u8, g: Option, b: Option, a: Option) { let draw = get_draw(); @@ -342,6 +349,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(stroke_weight, m)?)?; m.add_function(wrap_pyfunction!(font_size, m)?)?; m.add_function(wrap_pyfunction!(text_leading, m)?)?; + m.add_function(wrap_pyfunction!(text_align, m)?)?; m.add_function(wrap_pyfunction!(background, m)?)?; m.add_function(wrap_pyfunction!(ellipse, m)?)?; m.add_function(wrap_pyfunction!(circle, m)?)?; diff --git a/src/system.rs b/src/system.rs index f1fc931..6a16dbb 100644 --- a/src/system.rs +++ b/src/system.rs @@ -10,6 +10,7 @@ use nannou::draw::primitive::polygon::*; use nannou::event::{Key, MouseButton}; use crate::event::*; +use crate::constant::*; static mut INSTANCE: *mut AppState = 0 as *mut AppState; static mut APP_INSTANCE: *mut App = 0 as *mut App; @@ -229,6 +230,22 @@ impl<'a> AppState<'a> { pub fn text_leading(&mut self, text_leading: f32) { self.font_style.line_spacing = text_leading; } + + pub fn text_align(&mut self, h_align: Align, v_align: Align) { + self.font_style.horizontal_align = match h_align { + LEFT => TextAlign::Start, + MIDDLE => TextAlign::Middle, + RIGHT => TextAlign::End, + _ => self.font_style.horizontal_align, + }; + + self.font_style.vertical_align = match v_align { + TOP => TextAlign::Start, + MIDDLE => TextAlign::Middle, + BOTTOM => TextAlign::End, + _ => self.font_style.vertical_align, + }; + } } impl<'a> PythonCallback for AppState<'a> { @@ -405,6 +422,7 @@ pub struct FontStyle { pub vertical_align: TextAlign, } +#[derive(Debug, Copy, Clone)] pub enum TextAlign { Start, Middle, @@ -435,6 +453,19 @@ impl<'a> TextStyle for Drawing<'a, Text> { PColor::Rgba8(r, g, b, a) => self.color(rgba8(r, g, b, a)), _ => self, }; + + let ctx = match state.font_style.vertical_align { + TextAlign::Start => ctx.align_text_top(), + TextAlign::Middle => ctx.align_text_middle_y(), + TextAlign::End => ctx.align_text_bottom(), + }; + + let ctx = match state.font_style.horizontal_align { + TextAlign::Start => ctx.left_justify(), + TextAlign::Middle => ctx.center_justify(), + TextAlign::End => ctx.right_justify(), + }; + ctx.font_size(state.font_style.font_size) .line_spacing(state.font_style.line_spacing) } From 6f61abf180fb5fdf7766fee97cbcb97b16c023ab Mon Sep 17 00:00:00 2001 From: eqs Date: Wed, 8 Jun 2022 20:45:04 +0900 Subject: [PATCH 5/6] Implement text padding --- src/lib.rs | 13 +++++++++++-- src/system.rs | 8 +++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 02b63f6..0cd0aa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -204,6 +204,11 @@ fn text_leading(text_leading: f32) { instance().text_leading(text_leading); } +#[pyfunction] +fn text_padding(padding: f32) { + instance().text_padding(padding); +} + #[pyfunction] fn text_align(h_align: Align, v_align: Option) { let v_align = v_align.unwrap_or(LEFT); @@ -312,11 +317,14 @@ fn text(text: &str, x: f32, y: f32, w: Option, h: Option) { draw.text(text) .text_style() .x_y(x, y), - (Some(w), Some(h)) => + (Some(w), Some(h)) => { + let rect = Rect::from_w_h(w, h) + .pad(instance().font_style.padding); draw.text(text) .text_style() .x_y(x, y) - .w_h(w, h), + .wh(rect.wh()) + } _ => panic!("Invalid arguments") }; } @@ -349,6 +357,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(stroke_weight, m)?)?; m.add_function(wrap_pyfunction!(font_size, m)?)?; m.add_function(wrap_pyfunction!(text_leading, m)?)?; + m.add_function(wrap_pyfunction!(text_padding, m)?)?; m.add_function(wrap_pyfunction!(text_align, m)?)?; m.add_function(wrap_pyfunction!(background, m)?)?; m.add_function(wrap_pyfunction!(ellipse, m)?)?; diff --git a/src/system.rs b/src/system.rs index 6a16dbb..e3dec75 100644 --- a/src/system.rs +++ b/src/system.rs @@ -105,7 +105,7 @@ pub struct AppState<'a> { pub height: u32, pub title: &'a str, drawing_style: DrawingStyle, - font_style: FontStyle, + pub font_style: FontStyle, transform_matrix: Mat4, matrix_stack: Vec, @@ -231,6 +231,10 @@ impl<'a> AppState<'a> { self.font_style.line_spacing = text_leading; } + pub fn text_padding(&mut self, padding: f32) { + self.font_style.padding = padding; + } + pub fn text_align(&mut self, h_align: Align, v_align: Align) { self.font_style.horizontal_align = match h_align { LEFT => TextAlign::Start, @@ -418,6 +422,7 @@ impl<'a, T> PathStyle for Drawing<'a, T> pub struct FontStyle { pub font_size: u32, pub line_spacing: f32, + pub padding: f32, pub horizontal_align: TextAlign, pub vertical_align: TextAlign, } @@ -434,6 +439,7 @@ impl FontStyle { FontStyle { font_size: 24, line_spacing: 0.0, + padding: 0.0, horizontal_align: TextAlign::Middle, vertical_align: TextAlign::Middle, } From 95a714dd1a8678baed444090662c89ad1713e07f Mon Sep 17 00:00:00 2001 From: eqs Date: Wed, 8 Jun 2022 21:09:54 +0900 Subject: [PATCH 6/6] Add Font class --- src/lib.rs | 8 ++++++++ src/system.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0cd0aa0..271f809 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ mod numpy_lib; mod math_utils; mod constant; +use crate::system::add_system_class; use crate::system::*; use crate::event::add_event_class; use crate::numpy_lib::add_numpy_functions; @@ -194,6 +195,11 @@ fn stroke_weight(w: f32) { instance().stroke_weight(w); } +#[pyfunction] +fn text_font(font: QFont) { + instance().text_font(font); +} + #[pyfunction] fn font_size(font_size: u32) { instance().font_size(font_size); @@ -355,6 +361,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(stroke, m)?)?; m.add_function(wrap_pyfunction!(no_stroke, m)?)?; m.add_function(wrap_pyfunction!(stroke_weight, m)?)?; + m.add_function(wrap_pyfunction!(text_font, m)?)?; m.add_function(wrap_pyfunction!(font_size, m)?)?; m.add_function(wrap_pyfunction!(text_leading, m)?)?; m.add_function(wrap_pyfunction!(text_padding, m)?)?; @@ -370,6 +377,7 @@ fn engine(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(text, m)?)?; m.add_function(wrap_pyfunction!(save_frame, m)?)?; + add_system_class(&m)?; add_event_class(&m)?; add_numpy_functions(&m)?; add_module_constants(&m)?; diff --git a/src/system.rs b/src/system.rs index e3dec75..e462a43 100644 --- a/src/system.rs +++ b/src/system.rs @@ -223,6 +223,10 @@ impl<'a> AppState<'a> { self.drawing_style.stroke_weight } + pub fn text_font(&mut self, qfont: QFont) { + self.font_style.font = qfont.font; + } + pub fn font_size(&mut self, font_size: u32) { self.font_style.font_size = font_size; } @@ -420,6 +424,7 @@ impl<'a, T> PathStyle for Drawing<'a, T> } pub struct FontStyle { + pub font: nannou::text::Font, pub font_size: u32, pub line_spacing: f32, pub padding: f32, @@ -437,6 +442,7 @@ pub enum TextAlign { impl FontStyle { pub fn new() -> FontStyle { FontStyle { + font: nannou::text::font::default_notosans(), font_size: 24, line_spacing: 0.0, padding: 0.0, @@ -472,7 +478,32 @@ impl<'a> TextStyle for Drawing<'a, Text> { TextAlign::End => ctx.right_justify(), }; - ctx.font_size(state.font_style.font_size) + ctx.font(state.font_style.font.clone()) + .font_size(state.font_style.font_size) .line_spacing(state.font_style.line_spacing) } } + +#[pyclass] +#[derive(Debug, Clone)] +pub struct QFont { + pub font: nannou::text::Font, +} + +#[pymethods] +impl QFont { + #[new] + fn new(font_path: Option<&str>) -> Self { + let font = match font_path { + Some(path) => nannou::text::font::from_file(path) + .unwrap_or_else(|_| panic!("Failed to load font file.")), + None => nannou::text::font::default_notosans(), + }; + QFont { font } + } +} + +pub fn add_system_class(m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +}