use crate::core::{Color, Rect};
use crate::event::{Event, EventHandler};
use crate::render::RenderContext;
use crate::widget::{BaseWidget, Draw, Widget, WidgetKind};
pub struct Divider {
base: BaseWidget,
vertical: bool,
thickness: u32,
color: Color,
}
impl Divider {
pub fn new(geometry: Rect) -> Self {
Self {
base: BaseWidget::new(WidgetKind::Divider, geometry, "Divider"),
vertical: false,
thickness: 1,
color: Color::rgba(180, 180, 180, 200),
}
}
pub fn set_vertical(&mut self, vertical: bool) {
self.vertical = vertical;
self.base.request_redraw();
}
pub fn is_vertical(&self) -> bool {
self.vertical
}
pub fn set_thickness(&mut self, thickness: u32) {
self.thickness = thickness;
self.base.request_redraw();
}
pub fn set_color(&mut self, color: Color) {
self.color = color;
self.base.request_redraw();
}
}
impl Widget for Divider {
fn base(&self) -> &BaseWidget {
&self.base
}
fn base_mut(&mut self) -> &mut BaseWidget {
&mut self.base
}
}
impl Draw for Divider {
fn draw(&mut self, context: &mut RenderContext) {
let rect = self.geometry();
let thickness = self.thickness.max(1);
if self.vertical {
let x = rect.x + (rect.width as i32 / 2);
let top = rect.y;
let bottom = rect.y + (rect.height as i32).saturating_sub(1);
context.draw_line_stroke(
crate::core::Point::new(x, top),
crate::core::Point::new(x, bottom),
self.color,
thickness,
);
} else {
let y = rect.y + (rect.height as i32 / 2);
let left = rect.x;
let right = rect.x + (rect.width as i32).saturating_sub(1);
context.draw_line_stroke(
crate::core::Point::new(left, y),
crate::core::Point::new(right, y),
self.color,
thickness,
);
}
}
}
impl EventHandler for Divider {
fn handle_event(&mut self, event: &Event) {
self.base.handle_event(event);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::Point;
#[test]
fn divider_default_is_horizontal() {
let div = Divider::new(Rect::new(0, 0, 100, 10));
assert!(!div.is_vertical());
assert_eq!(div.kind(), WidgetKind::Divider);
}
#[test]
fn divider_set_vertical() {
let mut div = Divider::new(Rect::new(0, 0, 10, 100));
assert!(!div.is_vertical());
div.set_vertical(true);
assert!(div.is_vertical());
div.set_vertical(false);
assert!(!div.is_vertical());
}
#[test]
fn divider_set_thickness() {
let mut div = Divider::new(Rect::new(0, 0, 100, 10));
assert_eq!(div.thickness, 1);
div.set_thickness(3);
div.set_thickness(5);
}
#[test]
fn divider_set_color() {
let mut div = Divider::new(Rect::new(0, 0, 100, 10));
div.set_color(Color::RED);
assert_eq!(div.kind(), WidgetKind::Divider);
}
#[test]
fn divider_svg_output_horizontal() {
let mut div = Divider::new(Rect::new(0, 0, 100, 10));
let svg = crate::widget::svg::render_to_svg(&mut div);
assert!(svg.starts_with("<svg"));
assert!(svg.contains("line") || svg.contains("stroke"));
}
#[test]
fn divider_svg_output_vertical() {
let mut div = Divider::new(Rect::new(0, 0, 10, 100));
div.set_vertical(true);
let svg = crate::widget::svg::render_to_svg(&mut div);
assert!(svg.starts_with("<svg"));
}
#[test]
fn divider_event_delegation() {
let mut div = Divider::new(Rect::new(0, 0, 100, 10));
div.handle_event(&Event::MousePress { pos: Point::new(10, 5), button: 1 });
div.handle_event(&Event::MouseRelease { pos: Point::new(10, 5), button: 1 });
assert!(!div.is_vertical());
}
#[test]
fn divider_geometry_reflects_kind() {
let div = Divider::new(Rect::new(0, 0, 100, 10));
let geom = div.geometry();
assert_eq!(geom.width, 100);
assert_eq!(geom.height, 10);
}
}