From a0d8bbd1f43cb3928f45f0f6cab9a688e828394f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 6 Nov 2025 20:37:41 +0100 Subject: [PATCH] rounded corners --- src/core/config.rs | 40 ++++++++++++++++ src/core/graphics.rs | 107 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 137 insertions(+), 10 deletions(-) diff --git a/src/core/config.rs b/src/core/config.rs index e9c66c5..fe49d45 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -64,6 +64,9 @@ pub struct Configuration { wayland_height: i32, wayland_im_enable: bool, + key_padding: u64, + key_corner_radius: u64, + colors: KeyboardColors, } @@ -160,6 +163,9 @@ impl Configuration { wayland_im_enable: true, evfb_height: 0.25, + key_padding: 2, + key_corner_radius: 5, + colors: KeyboardColors::default(), }; @@ -212,6 +218,27 @@ impl Configuration { cfg.load_evfb(evfb); } + let key_padding = yaml.get(&Yaml::String(String::from("key_padding"))); + if let Some(key_padding) = key_padding { + let key_padding = match key_padding.as_i64() { + Some(l) => l.try_into().ok(), + None => None, + }; + let key_padding = key_padding.expect("Key padding should be a 64-bit unsigned integer"); + cfg.key_padding = key_padding; + } + + let key_corner_radius = yaml.get(&Yaml::String(String::from("key_corner_radius"))); + if let Some(key_corner_radius) = key_corner_radius { + let key_corner_radius = match key_corner_radius.as_i64() { + Some(l) => l.try_into().ok(), + None => None, + }; + let key_corner_radius = key_corner_radius.expect("Key corner radius should be a 64-bit unsigned integer"); + cfg.key_corner_radius = key_corner_radius; + } + + let colors = yaml.get(&Yaml::String(String::from("colors"))); if let Some(colors) = colors { let colors = colors.as_hash().expect("Color configuration should be a YAML mapping"); @@ -269,4 +296,17 @@ impl Configuration { { &self.colors } + + #[inline(always)] + pub fn key_padding(&self) -> u64 + { + self.key_padding + } + + #[inline(always)] + pub fn key_corner_radius(&self) -> u64 + { + self.key_corner_radius + } + } diff --git a/src/core/graphics.rs b/src/core/graphics.rs index b36fd6e..6d86683 100644 --- a/src/core/graphics.rs +++ b/src/core/graphics.rs @@ -49,6 +49,70 @@ fn fill_image(dest: &mut ImgRefMut>, src: BGRA) } } +fn distance(x1: usize, y1: usize, x2: usize, y2: usize) -> f32 +{ + (((x1 as isize - x2 as isize).pow(2) + (y1 as isize - y2 as isize).pow(2)) as f32).sqrt() +} + +fn is_point_in_rounded_rectangle( + x: usize, + y: usize, + width: usize, + height: usize, + radius: usize, +) -> bool +{ + // Check if the point is within the rectangle's main area + if x >= radius && x <= width - radius && y <= height { + return true; + } + if x <= width && y >= radius && y <= height - radius { + return true; + } + + // Check the corners + // Top-left corner + + + + + if distance(x, y, radius, radius) < radius as f32 { + return true; + } + + // Top-right corner + if distance(x, y, width - radius, radius) < radius as f32 { + return true; + } + + // Bottom-left corner + if distance(x, y, radius, height - radius) < radius as f32 { + return true; + } + + // Bottom-right corner + if distance(x, y, width - radius, height - radius) < radius as f32 { + return true; + } + + false +} + + +fn rounded_rectangle(dest: &mut ImgRefMut>, src: BGRA, radius: usize) +{ + let (width, height) = (dest.width(), dest.height()); + + for (y, row) in dest.rows_mut().enumerate() { + for (x, dest) in row.iter_mut().enumerate() { + if is_point_in_rounded_rectangle(x, y, width, height, radius) { + *dest = src; + } + } + } +} + + fn bitmap_to_imgref(bitmap: &freetype::FT_Bitmap) -> ImgRef { unsafe { @@ -93,6 +157,9 @@ pub struct Graphics { x_scale: f64, y_scale: f64, + key_padding: u64, + key_corner_radius: u64, + colors: KeyboardColors, } @@ -217,6 +284,9 @@ impl Graphics { x_scale: 0.0, y_scale: 0.0, + key_padding: cfg.key_padding(), + key_corner_radius: cfg.key_corner_radius(), + colors: cfg.colors().clone(), } } @@ -473,6 +543,9 @@ impl Graphics { let src = labels.get(label) .expect("Layout and size should be set before drawing"); + assert!(src.img.height() > src.y, "Not enough space to draw label, reduce padding and/or corner radius"); + + let width = src.img.width(); let height = src.img.height() - src.y; @@ -533,12 +606,13 @@ impl Graphics { x_scale: f64, y_scale: f64, img: &mut ImgRefMut>, key: &Key, mod_state: &[ModState], + key_padding: usize, key_corner_radius: usize, colors: &KeyboardColors) { - let x1 = (key.x1 * x_scale) as usize; - let y1 = (key.y1 * y_scale) as usize; - let x2 = (key.x2 * x_scale) as usize; - let y2 = (key.y2 * y_scale) as usize; + let x1 = (key.x1 * x_scale) as usize + key_padding; + let y1 = (key.y1 * y_scale) as usize + key_padding; + let x2 = (key.x2 * x_scale) as usize - key_padding; + let y2 = (key.y2 * y_scale) as usize - key_padding; let mut keyimg = img.sub_image_mut(x1, y1, x2 - x1, y2 - y1); @@ -557,21 +631,30 @@ impl Graphics { } if pressed { - fill_image(&mut keyimg, colors.keycap_pressed); + rounded_rectangle(&mut keyimg, colors.keycap_pressed, key_corner_radius); } else { - fill_image(&mut keyimg, colors.keycap); + rounded_rectangle(&mut keyimg, colors.keycap, key_corner_radius); } + let half_radius = key_corner_radius / 2; + let mut labelimg = keyimg.sub_image_mut( + half_radius, + half_radius, + keyimg.width() - half_radius * 2, + keyimg.height() - half_radius * 2 + ); + + let color = Self::keypart_to_color(&key.parts[0], false, mod_state, colors); let label = key.parts[0].display_label(); Self::draw_label_part(labels, Anchor::Center, Anchor::Center, - &mut keyimg, label, color.map(|c| c as f32 / 255.)); + &mut labelimg, label, color.map(|c| c as f32 / 255.)); for i in 0..8 { let color = Self::keypart_to_color(&key.parts[i + 1], true, mod_state, colors); let label = key.parts[i + 1].display_label(); Self::draw_label_part(sublabels, ANCHORS[i].0, ANCHORS[i].1, - &mut keyimg, label, color.map(|c| c as f32 / 255.)); + &mut labelimg, label, color.map(|c| c as f32 / 255.)); } } @@ -586,7 +669,9 @@ impl Graphics { Self::draw_key(&self.labels, &self.sublabels, self.x_scale, self.y_scale, - &mut img, key, mod_state, &self.colors); + &mut img, key, mod_state, + self.key_padding as usize, self.key_corner_radius as usize, + &self.colors); self.disp.end(x1, y1, x2 - x1, y2 - y1); } @@ -617,7 +702,9 @@ impl Graphics { for key in row { Self::draw_key(&self.labels, &self.sublabels, self.x_scale, self.y_scale, - &mut img, key, mod_state, &self.colors); + &mut img, key, mod_state, + self.key_padding as usize, self.key_corner_radius as usize, + &self.colors); } }