use crate::primitives::radio_group::{
RadioGroup, RadioGroupLayout, RadioOption, RadioOptionMeasure,
};
pub fn mac_radio_group_layout(
group: &RadioGroup,
x: f64,
y: f64,
w: f64,
h: f64,
row_height: f64,
) -> RadioGroupLayout {
let bounds = crate::event::Rect::new(x as f32, y as f32, w as f32, h as f32);
group.layout(bounds, |_option: &RadioOption| RadioOptionMeasure {
width: w as f32,
height: row_height as f32,
})
}
#[cfg(test)]
mod tests {
use super::super::headless::BitmapSurface;
use super::super::text::make_font;
use super::super::MacBackend;
use super::*;
use crate::event::{Point, Rect as QRect, Viewport};
use crate::primitives::radio_group::{RadioGroupEvent, RadioGroupHit};
use crate::theme::Theme;
use crate::types::WidgetId;
use crate::Backend;
use core_text::font::CTFont;
const W: u32 = 120;
const H: u32 = 40;
fn font() -> CTFont {
make_font("Menlo", 14.0).expect("Menlo installed")
}
fn mk_group() -> RadioGroup {
RadioGroup::new(
WidgetId::new("settings:theme"),
vec![
RadioOption::new(WidgetId::new("settings:theme:light"), "Light"),
RadioOption::new(WidgetId::new("settings:theme:dark"), "Dark"),
],
)
}
fn paint_via_backend(group: &RadioGroup) -> (BitmapSurface, RadioGroupLayout) {
let surface = BitmapSurface::new(W, H);
surface.fill(0.0, 0.0, 0.0, 0.0);
let mut backend = MacBackend::new();
backend.set_current_font(font());
backend.begin_frame(Viewport::new(W as f32, H as f32, 1.0));
let layout = std::cell::RefCell::new(None);
backend.enter_frame_scope(surface.context_ptr(), |b| {
let l = b.draw_radio_group(QRect::new(0.0, 0.0, W as f32, H as f32), group);
*layout.borrow_mut() = Some(l);
});
backend.end_frame();
(surface, layout.into_inner().unwrap())
}
fn marker_center(marker: QRect) -> (u32, u32) {
let marker_size = marker.height.min(marker.width);
(
(marker.x + marker_size / 2.0) as u32,
(marker.y + marker_size / 2.0) as u32,
)
}
#[test]
fn selected_option_marker_uses_accent_fg() {
let mut group = mk_group();
group.selected = Some(0);
let (surface, layout) = paint_via_backend(&group);
let theme = Theme::default();
let (x, y) = marker_center(layout.items[0]);
let (r, g, b, _) = surface.pixel(x, y);
assert_eq!(
(r, g, b),
(theme.accent_fg.r, theme.accent_fg.g, theme.accent_fg.b)
);
}
fn marker_contains_color(
surface: &BitmapSurface,
marker: QRect,
color: crate::types::Color,
) -> bool {
let marker_size = marker.height.min(marker.width) as u32;
let (x0, y0) = (marker.x as u32, marker.y as u32);
(0..marker_size).any(|dy| {
(0..marker_size).any(|dx| {
let (r, g, b, _) = surface.pixel(x0 + dx, y0 + dy);
(r, g, b) == (color.r, color.g, color.b)
})
})
}
#[test]
fn disabled_option_marker_uses_muted_fg() {
let mut group = mk_group();
group.options[1].disabled = true;
let (surface, layout) = paint_via_backend(&group);
let theme = Theme::default();
assert!(marker_contains_color(
&surface,
layout.items[1],
theme.muted_fg
));
assert!(!marker_contains_color(
&surface,
layout.items[1],
theme.accent_fg
));
}
fn hit_test_round_trip_at(origin_x: f64, origin_y: f64) {
let layout = mac_radio_group_layout(&mk_group(), origin_x, origin_y, 40.0, 16.0, 8.0);
let first = layout.hit_test(Point::new(origin_x as f32 + 4.0, origin_y as f32 + 2.0));
assert_eq!(first, RadioGroupHit::Option(0));
let second = layout.hit_test(Point::new(origin_x as f32 + 4.0, origin_y as f32 + 9.0));
assert_eq!(second, RadioGroupHit::Option(1));
let outside = layout.hit_test(Point::new(origin_x as f32 + 400.0, origin_y as f32));
assert_eq!(outside, RadioGroupHit::Outside);
}
#[test]
fn hit_test_round_trip() {
hit_test_round_trip_at(0.0, 0.0);
}
#[test]
fn hit_test_round_trip_at_nonzero_origin() {
hit_test_round_trip_at(7.0, 13.0);
}
#[test]
fn click_selects_option_after_painting() {
let group = mk_group();
let (_surface, layout) = paint_via_backend(&group);
assert_eq!(
layout.hit_test(Point::new(2.0, 2.0)),
RadioGroupHit::Option(0)
);
assert_eq!(
group.select(1),
Some(RadioGroupEvent::SelectionChanged { index: 1 })
);
}
#[test]
fn keyboard_moves_cursor_when_focused() {
let mut group = mk_group();
group.focused = true;
let event = group.handle_key(
&crate::event::Key::Named(crate::event::NamedKey::Down),
&crate::types::Modifiers::default(),
);
assert_eq!(event, Some(RadioGroupEvent::SelectionChanged { index: 0 }));
}
}