use crate::graphics::{
Color, HorizontalAlignment, Point, Rectangle, VerticalAlignment,
};
use crate::input::{mouse, ButtonState};
use crate::ui::core::{
Align, Element, Event, Hasher, Layout, MouseCursor, Node, Widget,
};
use crate::ui::widget::{text, Column, Row, Text};
use std::hash::Hash;
pub struct Radio<Message> {
is_selected: bool,
on_click: Message,
label: String,
label_color: Color,
}
impl<Message> std::fmt::Debug for Radio<Message>
where
Message: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Radio")
.field("is_selected", &self.is_selected)
.field("on_click", &self.on_click)
.field("label", &self.label)
.field("label_color", &self.label_color)
.finish()
}
}
impl<Message> Radio<Message> {
pub fn new<F, V>(value: V, label: &str, selected: Option<V>, f: F) -> Self
where
V: Eq + Copy,
F: 'static + Fn(V) -> Message,
{
Radio {
is_selected: Some(value) == selected,
on_click: f(value),
label: String::from(label),
label_color: Color::WHITE,
}
}
pub fn label_color(mut self, color: Color) -> Self {
self.label_color = color;
self
}
}
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message>
where
Renderer: self::Renderer + text::Renderer,
Message: Copy + std::fmt::Debug,
{
fn node(&self, renderer: &Renderer) -> Node {
Row::<(), Renderer>::new()
.spacing(15)
.align_items(Align::Center)
.push(Column::new().width(28).height(28))
.push(Text::new(&self.label))
.node(renderer)
}
fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
messages: &mut Vec<Message>,
) {
match event {
Event::Mouse(mouse::Event::Input {
button: mouse::Button::Left,
state: ButtonState::Pressed,
}) => {
if layout.bounds().contains(cursor_position) {
messages.push(self.on_click);
}
}
_ => {}
}
}
fn draw(
&self,
renderer: &mut Renderer,
layout: Layout<'_>,
cursor_position: Point,
) -> MouseCursor {
let children: Vec<_> = layout.children().collect();
let mut text_bounds = children[1].bounds();
text_bounds.y -= 2.0;
text::Renderer::draw(
renderer,
text_bounds,
&self.label,
20.0,
self.label_color,
HorizontalAlignment::Left,
VerticalAlignment::Top,
);
self::Renderer::draw(
renderer,
cursor_position,
children[0].bounds(),
layout.bounds(),
self.is_selected,
)
}
fn hash(&self, state: &mut Hasher) {
self.label.hash(state);
}
}
pub trait Renderer {
fn draw(
&mut self,
cursor_position: Point,
bounds: Rectangle<f32>,
label_bounds: Rectangle<f32>,
is_selected: bool,
) -> MouseCursor;
}
impl<'a, Message, Renderer> From<Radio<Message>>
for Element<'a, Message, Renderer>
where
Renderer: self::Renderer + text::Renderer,
Message: 'static + Copy + std::fmt::Debug,
{
fn from(checkbox: Radio<Message>) -> Element<'a, Message, Renderer> {
Element::new(checkbox)
}
}