GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat: implement independent widget fonts for Button, ButtonStrip, Labels, Dropdown, TextBox, Spinbox, and Slider
src/layout.rs | 532 ++++++++++++++++++++++++++++++++++
src/widget/container/parameters_bg.rs | 4 +
src/widget/input/button.rs | 4 +
src/widget/input/button_strip.rs | 10 +-
src/widget/input/dropdown.rs | 2 +-
src/widget/input/slider.rs | 4 +
src/widget/input/spinbox.rs | 2 +-
src/widget/input/text_box.rs | 2 +-
8 files changed, 554 insertions(+), 6 deletions(-)
diff --git a/src/layout.rs b/src/layout.rs
index fffb09b..da005fa 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -108,6 +108,20 @@ static TOGGLE_FONT: RwLock<String> = RwLock::new(String::new());
static TOGGLE_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
static FONT_SELECTOR_FONT: RwLock<String> = RwLock::new(String::new());
static FONT_SELECTOR_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static BUTTON_STRIP_FONT: RwLock<String> = RwLock::new(String::new());
+static BUTTON_STRIP_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static BUTTON_FONT: RwLock<String> = RwLock::new(String::new());
+static BUTTON_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static LABEL_FONT: RwLock<String> = RwLock::new(String::new());
+static LABEL_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static DROPDOWN_FONT: RwLock<String> = RwLock::new(String::new());
+static DROPDOWN_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static TEXTBOX_FONT: RwLock<String> = RwLock::new(String::new());
+static TEXTBOX_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static SPINBOX_FONT: RwLock<String> = RwLock::new(String::new());
+static SPINBOX_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
+static SLIDER_FONT: RwLock<String> = RwLock::new(String::new());
+static SLIDER_FONT_CACHED: RwLock<Option<(String, f32)>> = RwLock::new(None);
static PLATE_CORNER_RADIUS: RwLock<f32> = RwLock::new(12.0);
static PLATE_OPACITY: RwLock<f32> = RwLock::new(1.0);
static PAGE_OPACITY: RwLock<f32> = RwLock::new(1.0);
@@ -140,6 +154,13 @@ pub fn reload_config() {
let mut menubar_font_changed = false;
let mut toggle_font_changed = false;
let mut font_selector_font_changed = false;
+ let mut button_strip_font_changed = false;
+ let mut button_font_changed = false;
+ let mut label_font_changed = false;
+ let mut dropdown_font_changed = false;
+ let mut textbox_font_changed = false;
+ let mut spinbox_font_changed = false;
+ let mut slider_font_changed = false;
for line in content.lines() {
let trimmed = line.trim();
if let Some(rest) = trimmed.strip_prefix("label_margin") {
@@ -537,6 +558,111 @@ pub fn reload_config() {
font_selector_font_changed = true;
}
}
+ if let Some(rest) = trimmed.strip_prefix("button_strip_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = BUTTON_STRIP_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ button_strip_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("button_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = BUTTON_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ button_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("label_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = LABEL_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ label_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("dropdown_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = DROPDOWN_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ dropdown_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("textbox_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = TEXTBOX_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ textbox_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("spinbox_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = SPINBOX_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ spinbox_font_changed = true;
+ }
+ }
+ if let Some(rest) = trimmed.strip_prefix("slider_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ let font = rest.trim().to_string();
+ let mut changed = false;
+ if let Ok(mut lock) = SLIDER_FONT.write() {
+ if *lock != font {
+ *lock = font;
+ changed = true;
+ }
+ }
+ if changed {
+ slider_font_changed = true;
+ }
+ }
}
if menubar_font_changed {
if let Ok(mut lock) = MENUBAR_FONT_CACHED.write() {
@@ -553,6 +679,41 @@ pub fn reload_config() {
*lock = None;
}
}
+ if button_strip_font_changed {
+ if let Ok(mut lock) = BUTTON_STRIP_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if button_font_changed {
+ if let Ok(mut lock) = BUTTON_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if label_font_changed {
+ if let Ok(mut lock) = LABEL_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if dropdown_font_changed {
+ if let Ok(mut lock) = DROPDOWN_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if textbox_font_changed {
+ if let Ok(mut lock) = TEXTBOX_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if spinbox_font_changed {
+ if let Ok(mut lock) = SPINBOX_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
+ if slider_font_changed {
+ if let Ok(mut lock) = SLIDER_FONT_CACHED.write() {
+ *lock = None;
+ }
+ }
crate::color::reload_colors(&content);
}
}
@@ -1309,6 +1470,377 @@ pub fn set_font_selector_font(font: &str) {
}
}
+// Button Strip Font
+pub fn button_strip_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("button_strip_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = BUTTON_STRIP_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = BUTTON_STRIP_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn button_strip_font_parsed() -> (String, f32) {
+ if let Ok(lock) = BUTTON_STRIP_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = button_strip_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = BUTTON_STRIP_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_button_strip_font(font: &str) {
+ if let Ok(mut lock) = BUTTON_STRIP_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = BUTTON_STRIP_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Button Font
+pub fn button_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("button_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = BUTTON_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = BUTTON_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn button_font_parsed() -> (String, f32) {
+ if let Ok(lock) = BUTTON_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = button_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = BUTTON_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_button_font(font: &str) {
+ if let Ok(mut lock) = BUTTON_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = BUTTON_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Label Font
+pub fn label_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("label_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = LABEL_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = LABEL_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn label_font_parsed() -> (String, f32) {
+ if let Ok(lock) = LABEL_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = label_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = LABEL_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_label_font(font: &str) {
+ if let Ok(mut lock) = LABEL_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = LABEL_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Dropdown Font
+pub fn dropdown_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("dropdown_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = DROPDOWN_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = DROPDOWN_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn dropdown_font_parsed() -> (String, f32) {
+ if let Ok(lock) = DROPDOWN_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = dropdown_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = DROPDOWN_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_dropdown_font(font: &str) {
+ if let Ok(mut lock) = DROPDOWN_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = DROPDOWN_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Textbox Font
+pub fn textbox_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("textbox_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = TEXTBOX_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = TEXTBOX_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn textbox_font_parsed() -> (String, f32) {
+ if let Ok(lock) = TEXTBOX_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = textbox_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = TEXTBOX_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_textbox_font(font: &str) {
+ if let Ok(mut lock) = TEXTBOX_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = TEXTBOX_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Spinbox Font
+pub fn spinbox_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "monospace".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("spinbox_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = SPINBOX_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = SPINBOX_FONT.read().unwrap();
+ if lock.is_empty() {
+ "monospace".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn spinbox_font_parsed() -> (String, f32) {
+ if let Ok(lock) = SPINBOX_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = spinbox_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = SPINBOX_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_spinbox_font(font: &str) {
+ if let Ok(mut lock) = SPINBOX_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = SPINBOX_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
+// Slider Font
+pub fn slider_font() -> String {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ let mut font = "Outfit".to_string();
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("slider_font") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=');
+ let rest = mod_rest(rest);
+ font = rest.trim().to_string();
+ }
+ }
+ }
+ if let Ok(mut lock) = SLIDER_FONT.write() {
+ *lock = font;
+ }
+ });
+ let lock = SLIDER_FONT.read().unwrap();
+ if lock.is_empty() {
+ "Outfit".to_string()
+ } else {
+ lock.clone()
+ }
+}
+
+pub fn slider_font_parsed() -> (String, f32) {
+ if let Ok(lock) = SLIDER_FONT_CACHED.read() {
+ if let Some(ref val) = *lock {
+ return val.clone();
+ }
+ }
+ let font_str = slider_font();
+ let parsed = parse_font_string(&font_str);
+ let size = parsed.1.unwrap_or(12.0);
+ let val = (parsed.0, size);
+ if let Ok(mut lock) = SLIDER_FONT_CACHED.write() {
+ *lock = Some(val.clone());
+ }
+ val
+}
+
+pub fn set_slider_font(font: &str) {
+ if let Ok(mut lock) = SLIDER_FONT.write() {
+ *lock = font.to_string();
+ }
+ if let Ok(mut lock) = SLIDER_FONT_CACHED.write() {
+ *lock = None;
+ }
+}
+
pub fn section_label_font() -> String {
use std::sync::Once;
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index 265df53..9198417 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -284,6 +284,10 @@ fn parse_float3_value(val_str: &str, min: f32, max: f32) -> [f32; 3] {
impl Element for ParametersBg {
crate::impl_widget_base!(ParametersBg);
+ fn widget_font(&self) -> Option<String> {
+ Some(crate::layout::label_font())
+ }
+
fn rounded_corners(&self) -> (bool, bool, bool, bool) { (true, true, true, true) }
fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 16e32ed..dae2fd6 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -272,6 +272,10 @@ impl Element for Button {
}
}
+ fn widget_font(&self) -> Option<String> {
+ Some(crate::layout::button_font())
+ }
+
fn corner_radius(&self) -> f32 {
crate::layout::button_corner_radius()
}
diff --git a/src/widget/input/button_strip.rs b/src/widget/input/button_strip.rs
index 2c87f1a..3f6e5cf 100644
--- a/src/widget/input/button_strip.rs
+++ b/src/widget/input/button_strip.rs
@@ -88,7 +88,7 @@ impl ButtonStrip {
let inactive_g = (active_g as f32 * 0.78) as u8;
let inactive_b = (active_b as f32 * 0.78) as u8;
- let (font_fam, font_size) = crate::layout::menubar_font_parsed();
+ let (font_fam, font_size) = crate::layout::button_strip_font_parsed();
let scale = crate::scale::scale_factor().max(1.0);
for (i, page_name) in self.buttons.iter().enumerate() {
@@ -187,7 +187,7 @@ impl ButtonStrip {
let get_button_weight = |i: usize| -> f32 {
let label = &self.buttons[i];
let trimmed = label.trim();
- let font_info = crate::layout::menubar_font_parsed();
+ let font_info = crate::layout::button_strip_font_parsed();
let font_fam = font_info.0;
let font_size = font_info.1;
let padding = crate::layout::button_padding();
@@ -373,7 +373,7 @@ impl Element for ButtonStrip {
fn text_labels(&self) -> Vec<TextLabel> {
let mut labels = Vec::new();
- let font_info = crate::layout::menubar_font_parsed();
+ let font_info = crate::layout::button_strip_font_parsed();
let font_fam = font_info.0;
let font_size = font_info.1;
for (i, btn_label) in self.buttons.iter().enumerate() {
@@ -452,6 +452,10 @@ impl Element for ButtonStrip {
}
false
}
+
+ fn widget_font(&self) -> Option<String> {
+ Some(crate::layout::button_strip_font())
+ }
}
impl Control for ButtonStrip {}
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index ffdbcbd..6cda685 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -186,7 +186,7 @@ impl Element for Dropdown {
}
fn widget_font(&self) -> Option<String> {
- Some(self.font_family.clone())
+ Some(crate::layout::dropdown_font())
}
fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
diff --git a/src/widget/input/slider.rs b/src/widget/input/slider.rs
index e7b06dc..08c4f9e 100644
--- a/src/widget/input/slider.rs
+++ b/src/widget/input/slider.rs
@@ -113,6 +113,10 @@ impl Slider {
impl Element for Slider {
crate::impl_widget_base!(Slider);
+ fn widget_font(&self) -> Option<String> {
+ Some(crate::layout::slider_font())
+ }
+
fn get_value_string(&self) -> Option<String> {
let scaled_val = self.min + self.value * (self.max - self.min);
Some(format!("{:.2}", scaled_val))
diff --git a/src/widget/input/spinbox.rs b/src/widget/input/spinbox.rs
index 3a4751c..3d4c9a5 100644
--- a/src/widget/input/spinbox.rs
+++ b/src/widget/input/spinbox.rs
@@ -133,7 +133,7 @@ impl Element for Spinbox {
fn color(&self) -> [f32; 4] { [0.0, 0.0, 0.0, 0.0] }
fn value(&self) -> i32 { self.value }
- fn widget_font(&self) -> Option<String> { Some("monospace".to_string()) }
+ fn widget_font(&self) -> Option<String> { Some(crate::layout::spinbox_font()) }
fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
let was = self.base.hovered;
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 98c6799..0ee9be8 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -467,7 +467,7 @@ impl Element for TextBox {
fn draggable(&self) -> bool { !self.disabled }
fn is_dragging(&self) -> bool { self.dragging }
- fn widget_font(&self) -> Option<String> { Some(self.font_family.clone()) }
+ fn widget_font(&self) -> Option<String> { Some(crate::layout::textbox_font()) }
fn drag_begin(&mut self, _px: f32, _py: f32) {
if self.disabled || !self.editing { return; }