use denise::{Rect, Size};
use denise_forms::{Form, Handler, Payload, Picture, Scaling, Wiring};
use denise_ui::widgets::{Panel, Value};
use denise_ui::{Ui, Void};
struct Anything;
impl Wiring<Void> for Anything {
fn message(&mut self, _name: &str, payload: Payload) -> Option<Handler<Void>> {
Some(match payload {
Payload::None => Handler::Plain(Void),
Payload::Bool => Handler::Bool(|_| Void),
Payload::Index => Handler::Index(|_| Void),
Payload::Number => Handler::Number(|_| Void),
})
}
fn asset(&mut self, _path: &str) -> Option<Picture> {
Some(Picture {
pixels: vec![0xFF00_0000; 4],
size: Size::new(2, 2),
})
}
}
fn form(scaling: &str, body: &str) -> Form {
let said = if scaling.is_empty() {
String::new()
} else {
format!(" scaling={scaling}")
};
Form::parse(&format!(
"form \"F\" version=1 width=200 height=100{said} {{\n{body}}}\n"
))
.expect("a test form parses")
}
fn shown(form: &Form, surface: Size) -> (Ui<Void>, denise_forms::Built) {
let fit = form.fit(surface);
let mut ui: Ui<Void> = Ui::new(surface, form.theme().scaled(fit.uniform()));
let root = ui.root();
let stage = ui
.add(root, Panel::filled(form.background()), fit.rect)
.expect("the root takes a child");
let mut nothing = Anything;
let built = form
.build_fitted(&mut ui, stage, fit, &mut nothing)
.expect("builds");
(ui, built)
}
#[test]
fn a_form_that_says_nothing_is_never_scaled() {
assert_eq!(form("", "").scaling(), Scaling::None);
assert_eq!(form("none", "").scaling(), Scaling::None);
assert_eq!(form("proportional", "").scaling(), Scaling::Proportional);
assert_eq!(form("stretch", "").scaling(), Scaling::Stretch);
}
#[test]
fn a_fixed_form_on_a_bigger_surface_is_its_own_size_in_the_middle() {
let fixed = form(
"none",
" label \"hi\" name=hi x=10 y=10 w=100 h=20 size=16\n",
);
let fit = fixed.fit(Size::new(800, 600));
assert_eq!((fit.x, fit.y), (1.0, 1.0));
assert_eq!(fit.rect, Rect::new(300, 250, 200, 100), "not centred");
let (ui, built) = shown(&fixed, Size::new(800, 600));
let hi = built.node("hi").expect("named");
assert_eq!(ui.layout(hi), Some(Rect::new(10, 10, 100, 20)));
assert_eq!(ui.get_property(hi, "size"), Some(Value::Int(16)));
}
#[test]
fn a_fixed_form_on_a_smaller_surface_is_still_its_own_size() {
let fixed = form("none", "");
let fit = fixed.fit(Size::new(100, 100));
assert_eq!(fit.rect, Rect::new(-50, 0, 200, 100));
}
#[test]
fn proportional_letterboxes_on_whichever_axis_has_room_left() {
let fits = form("proportional", "");
let wide = fits.fit(Size::new(800, 200));
assert_eq!((wide.x, wide.y), (2.0, 2.0), "the tighter axis decides");
assert_eq!(wide.rect, Rect::new(200, 0, 400, 200));
let tall = fits.fit(Size::new(400, 400));
assert_eq!((tall.x, tall.y), (2.0, 2.0));
assert_eq!(tall.rect, Rect::new(0, 100, 400, 200));
let exact = fits.fit(Size::new(400, 200));
assert_eq!(exact.rect, Rect::from_size(Size::new(400, 200)));
}
#[test]
fn stretch_fills_the_surface_and_distorts_to_do_it() {
let fills = form(
"stretch",
" label \"hi\" name=hi x=10 y=10 w=100 h=20 size=16\n",
);
let surface = Size::new(400, 400);
let fit = fills.fit(surface);
assert_eq!((fit.x, fit.y), (2.0, 4.0));
assert_eq!(fit.rect, Rect::from_size(surface), "left a gap");
let (ui, built) = shown(&fills, surface);
let hi = built.node("hi").expect("named");
assert_eq!(ui.layout(hi), Some(Rect::new(20, 40, 200, 80)));
assert_eq!(ui.get_property(hi, "size"), Some(Value::Int(32)));
}
#[test]
fn panels_designed_to_touch_still_touch_at_a_fractional_scale() {
let side_by_side = form(
"proportional",
" panel name=left x=0 y=0 w=40 h=100\n panel name=right x=40 y=0 w=60 h=100\n",
);
let (ui, built) = shown(&side_by_side, Size::new(150, 75));
let left = ui
.layout(built.node("left").expect("named"))
.expect("laid out");
let right = ui
.layout(built.node("right").expect("named"))
.expect("laid out");
assert_eq!(left.right(), right.x, "a seam opened between them");
assert_eq!((left.width, right.width), (30, 45));
}
#[test]
fn a_length_that_would_round_to_nothing_keeps_a_pixel() {
let hairline = form(
"proportional",
" panel name=box x=0 y=0 w=100 h=50 border=primary border-width=1\n",
);
let (ui, built) = shown(&hairline, Size::new(100, 50));
let box_id = built.node("box").expect("named");
assert_eq!(ui.get_property(box_id, "border-width"), Some(Value::Int(1)));
let none = form(
"proportional",
" panel name=box x=0 y=0 w=100 h=50 border-width=0\n",
);
let (ui, built) = shown(&none, Size::new(400, 200));
let box_id = built.node("box").expect("named");
assert_eq!(ui.get_property(box_id, "border-width"), Some(Value::Int(0)));
}
#[test]
fn what_is_not_a_length_is_not_multiplied() {
let mixed = form(
"stretch",
" list name=nav x=0 y=0 w=100 h=80 selected=2 row-height=20 size=12 {\n \
item \"one\"\n item \"two\"\n item \"three\"\n }\n\
\x20 spinner name=busy x=100 y=0 w=20 h=20 period-ms=900 frame-ms=100 thickness=3\n",
);
let (ui, built) = shown(&mixed, Size::new(400, 200));
let nav = built.node("nav").expect("named");
assert_eq!(
ui.get_property(nav, "row-height"),
Some(Value::Int(40)),
"a length"
);
assert_eq!(
ui.get_property(nav, "size"),
Some(Value::Int(24)),
"a length"
);
assert_eq!(
ui.get_property(nav, "selected"),
Some(Value::Int(2)),
"an index"
);
let busy = built.node("busy").expect("named");
assert_eq!(
ui.get_property(busy, "thickness"),
Some(Value::Int(6)),
"a length"
);
assert_eq!(
ui.get_property(busy, "period-ms"),
Some(Value::Int(900)),
"a duration is not a length",
);
assert_eq!(ui.get_property(busy, "frame-ms"), Some(Value::Int(100)));
}
#[test]
fn build_scaled_is_build_fitted_with_one_factor() {
let plain = form(
"",
" label \"hi\" name=hi x=10 y=10 w=100 h=20 size=16\n",
);
let surface = Size::new(400, 200);
let mut one: Ui<Void> = Ui::new(surface, plain.theme().scaled(2.0));
let root = one.root();
let mut nothing = Anything;
let a = plain
.build_scaled(&mut one, root, 2.0, &mut nothing)
.expect("builds");
let mut two: Ui<Void> = Ui::new(surface, plain.theme().scaled(2.0));
let root = two.root();
let mut nothing = Anything;
let b = plain
.build_fitted(
&mut two,
root,
denise_forms::Placement {
x: 2.0,
y: 2.0,
rect: Rect::new(0, 0, 400, 200),
},
&mut nothing,
)
.expect("builds");
let of = |ui: &Ui<Void>, built: &denise_forms::Built| {
let id = built.node("hi").expect("named");
(ui.layout(id), ui.get_property(id, "size"))
};
assert_eq!(of(&one, &a), of(&two, &b));
assert_eq!(of(&one, &a).0, Some(Rect::new(20, 20, 200, 40)));
}
#[test]
fn building_a_form_the_old_way_is_still_the_old_way() {
let source = std::fs::read_to_string(
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../forms/reference.dform"),
)
.expect("the reference form");
let reference = Form::parse(&source).expect("parses");
let mut ui: Ui<Void> = Ui::new(reference.size(), reference.theme());
let root = ui.root();
let mut nothing = Anything;
let built = reference
.build(&mut ui, root, &mut nothing)
.expect("builds");
let volume = built.node("volume").expect("the reference form names it");
let was = ui.layout(volume).expect("laid out");
let mut same: Ui<Void> = Ui::new(reference.size(), reference.theme());
let root = same.root();
let mut nothing = Anything;
let built = reference
.build_scaled(&mut same, root, 1.0, &mut nothing)
.expect("builds");
assert_eq!(
same.layout(built.node("volume").expect("named")),
Some(was),
"1x is not the same as not scaling",
);
}