git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commitde954e89edd6871da8faf1261951f63b93a7ae6f
parent49c0527c6b
authorLucas Galante <[email protected]>
date2026-07-05 13:28
fix: compute dropdown label character positions using prefix layout advance metrics to preserve spacing and kerning

 src/widget/input/dropdown.rs | 38 +++++++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 2130b3c..d53c84b 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -534,10 +534,36 @@ impl Element for Dropdown {
             (bg_color[2] * 255.0).round().clamp(0.0, 255.0) as u8,
         ];
 
-        let mut cur_x = start_x;
-        for c in selected_text.chars() {
-            let c_str = c.to_string();
-            let c_w = crate::widget::display::measure_text_width(&c_str, &font_family, 12.0);
+        let w_dummy = crate::widget::display::measure_text_width("M", &font_family, 12.0);
+        let chars: Vec<char> = selected_text.chars().collect();
+        let n = chars.len();
+
+        let mut char_offsets = Vec::with_capacity(n);
+        if n > 0 {
+            char_offsets.push(0.0f32);
+        }
+
+        let mut prefix = String::new();
+        for i in 1..n {
+            prefix.push(chars[i - 1]);
+            let measure_str = format!("{}M", prefix);
+            let w_prefix_dummy = crate::widget::display::measure_text_width(&measure_str, &font_family, 12.0);
+            let offset = (w_prefix_dummy - w_dummy).max(0.0);
+            char_offsets.push(offset);
+        }
+
+        let total_advance = if n > 0 {
+            let measure_str = format!("{}M", selected_text);
+            (crate::widget::display::measure_text_width(&measure_str, &font_family, 12.0) - w_dummy).max(0.0)
+        } else {
+            0.0
+        };
+
+        for i in 0..n {
+            let offset = char_offsets[i];
+            let next_offset = if i < n - 1 { char_offsets[i + 1] } else { total_advance };
+            let c_w = next_offset - offset;
+            let cur_x = start_x + offset;
 
             if cur_x >= right_limit {
                 break;
@@ -556,14 +582,12 @@ impl Element for Dropdown {
             };
 
             labels.push(TextLabel {
-                text: c_str,
+                text: chars[i].to_string(),
                 x: cur_x,
                 y: text_y,
                 font_size: 12.0,
                 color,
             });
-
-            cur_x += c_w;
         }
 
         labels.push(TextLabel {