This commit is contained in:
Claude
2026-10-11 11:47:27 +00:00
+36 -17
View File
@@ -545,27 +545,36 @@ pub fn icon_button(ui: &mut Ui, id: &str, icon: Icon, size: egui::Vec2, active:
pub fn stars(ui: &mut Ui, id: &str, rating: u8, size: f32) -> Option<u8> {
let t = Tokens::get(ui.ctx());
let mut out = None;
let hover_n = {
let mut h = None;
for i in 0..5u8 {
let (r, resp) = ui.allocate_exact_size(vec2(size, size), Sense::click());
register(ui.ctx(), format!("star:{id}:{}", i + 1), r);
if resp.hovered() {
h = Some(i + 1);
}
if resp.clicked() {
out = Some(if rating == i + 1 { 0 } else { i + 1 });
}
ui.painter().text(r.center(), Align2::CENTER_CENTER, "", t.font(1.0), t.star);
let filled = i < rating;
paint(ui.painter(), r.shrink(size * 0.12), if filled { Icon::StarFilled } else { Icon::Star }, if filled { t.star } else { t.icon });
let mut hover_n = None;
let mut rects = [Rect::NOTHING; 5];
for (i, slot) in (0..5u8).zip(rects.iter_mut()) {
let (r, resp) = ui.allocate_exact_size(vec2(size, size), Sense::click());
register(ui.ctx(), format!("star:{id}:{}", i + 1), r);
if resp.hovered() {
hover_n = Some(i + 1);
}
h
};
let _ = hover_n;
if resp.clicked() {
out = Some(if rating == i + 1 { 0 } else { i + 1 });
}
*slot = r;
}
// Hover previews the rating a click would set: stars 1..=hovered light up. The hovered star also gets the
// icon_button hover square, so hovering the current rating (where the preview looks the same) still shows feedback.
for (i, r) in (0..5u8).zip(rects) {
if hover_n == Some(i + 1) {
ui.painter().rect_filled(r, 4.0, t.hover.gamma_multiply(0.7));
}
let filled = star_lit(i, rating, hover_n);
paint(ui.painter(), r.shrink(size * 0.12), if filled { Icon::StarFilled } else { Icon::Star }, if filled { t.star } else { t.icon });
}
out
}
/// Whether the star at zero-based index `i` is drawn filled: the hovered star's rating previews over the current one.
fn star_lit(i: u8, rating: u8, hover: Option<u8>) -> bool {
i < hover.unwrap_or(rating)
}
/// A borderless dropdown button: `text` followed by a painted chevron (no font glyph needed).
pub fn dropdown(ui: &mut Ui, id: &str, text: &str, font: egui::FontId, color: Color32) -> Response {
let t = Tokens::get(ui.ctx());
@@ -584,6 +593,16 @@ pub fn dropdown(ui: &mut Ui, id: &str, text: &str, font: egui::FontId, color: Co
mod tests {
use super::*;
/// Issue #647: hovering a star previews the rating a click would set.
#[test]
fn hovered_star_previews_its_rating() {
let lit = |rating, hover| (0..5u8).filter(|&i| star_lit(i, rating, hover)).count();
assert_eq!(lit(2, None), 2, "no hover shows the rating");
assert_eq!(lit(2, Some(4)), 4);
assert_eq!(lit(5, Some(1)), 1);
assert_eq!(lit(0, Some(3)), 3);
}
#[test]
fn nudges_are_a_sensible_step() {
let spec = |id, min, max, step| ControlSpec {