use crate::widget::draw::Draw;
use crate::widget::widget_trait::Widget;
#[macro_export]
macro_rules! impl_draw_bridge {
() => {
fn as_draw_mut(&mut self) -> Option<&mut dyn $crate::widget::Draw> {
Some(self)
}
};
}
#[macro_export]
macro_rules! impl_default_via_new {
($type:ty) => {
impl ::core::default::Default for $type {
fn default() -> Self {
Self::new()
}
}
};
}
pub fn draw_of(widget: &mut dyn Widget) -> Option<&mut dyn Draw> {
widget.as_draw_mut()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Color, Rect, Size};
use crate::render::{PaintBackend, RenderContext, SoftwarePaintBackend};
use crate::widget::base_widgets::button::Button;
#[test]
fn a_bridged_control_reaches_its_draw_impl() {
let mut button = Button::new("ok".to_string(), Rect::new(0, 0, 40, 24));
let dyn_widget: &mut dyn Widget = &mut button;
assert!(
draw_of(dyn_widget).is_some(),
"Button implements Draw, so the bridge must report it as paintable"
);
}
#[test]
fn a_bridged_control_actually_paints() {
let mut button = Button::new("ok".to_string(), Rect::new(0, 0, 40, 24));
let dyn_widget: &mut dyn Widget = &mut button;
let drawable = draw_of(dyn_widget).expect("bridge");
let mut surface = SoftwarePaintBackend::new(Size::new(40, 24), 1.0);
surface.begin_frame(Color::WHITE);
{
let mut context = RenderContext::new(&mut surface);
drawable.draw(&mut context);
}
surface.end_frame();
assert!(
surface.frame_rgba().chunks_exact(4).any(|px| px[3] != 0),
"a bridged Button must paint at least one pixel"
);
}
#[test]
fn a_widget_without_draw_reports_none() {
use crate::core::Rect;
use crate::event::{Event, EventHandler};
use crate::widget::base::BaseWidget;
struct Inert {
base: BaseWidget,
}
impl Widget for Inert {
fn base(&self) -> &BaseWidget {
&self.base
}
fn base_mut(&mut self) -> &mut BaseWidget {
&mut self.base
}
}
impl EventHandler for Inert {
fn handle_event(&mut self, _event: &Event) {}
}
let mut inert = Inert {
base: BaseWidget::new(
crate::widget::WidgetKind::Panel,
Rect::new(0, 0, 10, 10),
"inert",
),
};
let dyn_widget: &mut dyn Widget = &mut inert;
assert!(
draw_of(dyn_widget).is_none(),
"a widget with no Draw impl must not claim to be paintable, or the \
bridge would be reporting something it cannot deliver"
);
}
#[cfg(full_widgets)]
#[test]
fn every_factory_widget_can_be_painted() {
use crate::widget::capability::WidgetFactory;
let factory = WidgetFactory::new_with_defaults();
let names = factory.widget_names();
assert!(!names.is_empty(), "the factory must register widgets");
let mut paintless = Vec::new();
for name in names {
let Some(mut widget) = factory.create(name, Rect::new(0, 0, 64, 48), "x") else {
continue;
};
if draw_of(widget.as_mut()).is_none() {
paintless.push(name);
}
}
assert!(
paintless.is_empty(),
"these widgets implement Draw but are not reachable through \
Widget::as_draw_mut, so mounting them paints nothing: {paintless:?}"
);
}
}