use eframe::emath::Vec2;
use egui::{
Align, Button, Checkbox, DragValue, Frame, Id, Label, Layout, ScrollArea, TextEdit, Ui,
};
use egui_flex::{Flex, FlexAlign, FlexAlignContent, FlexItem, FlexJustify, Size, item};
use egui_kittest::wgpu::WgpuTestRenderer;
use egui_kittest::{Harness, TestRenderer};
use rstest::rstest;
use std::cell::Cell;
fn snapshot_name() -> String {
let thread = std::thread::current();
let thread_name = thread.name().unwrap();
thread_name.replace("::", "_")
}
fn should_be_stable(harness: &mut Harness) {
let first = WgpuTestRenderer::new().render(&harness.ctx, harness.output());
for _ in 0..6 {
harness.run_ok();
let second = WgpuTestRenderer::new().render(&harness.ctx, harness.output());
#[allow(clippy::manual_assert)]
if first != second {
panic!("Is not stable");
}
}
}
#[rstest]
fn test_justify(
#[values(false, true)] grow: bool,
#[values(
FlexAlign::Start,
FlexAlign::Center,
FlexAlign::End,
FlexAlign::Stretch
)]
align: FlexAlign,
) {
let justify_values = [
FlexJustify::Start,
FlexJustify::Center,
FlexJustify::End,
FlexJustify::SpaceBetween,
FlexJustify::SpaceAround,
FlexJustify::SpaceEvenly,
];
let app = |ui: &mut Ui| {
ui.label(format!("align: {align:?}, grow: {grow}"));
for justify in &justify_values {
ui.group(|ui| {
ui.label(format!("{justify:?}"));
let mut flex = egui_flex::Flex::horizontal()
.height(40.0)
.align_items(align);
if grow {
flex = flex.grow_items(1.0);
}
flex.justify(*justify).w_full().show(ui, |flex| {
for _ in 0..3 {
flex.add(item(), Button::new("Label"));
}
});
});
}
};
let mut harness = Harness::new_ui(app);
harness.snapshot(snapshot_name());
}
#[test]
fn test_insert_remove() {
let show = Cell::new(false);
let mut harness = Harness::new_ui(|ui| {
Flex::horizontal()
.w_full()
.grow_items(1.0)
.show(ui, |flex| {
flex.add(item(), Label::new("Label"));
if show.get() {
flex.add(item(), Label::new("New\nLabel\nMultiline"));
}
flex.add(item(), Label::new("Label 2"));
});
});
let mut results = vec![];
results.push(harness.try_snapshot("test_insert_remove_0"));
show.set(true);
harness.run();
results.push(harness.try_snapshot("test_insert_remove_1"));
show.set(false);
harness.run();
results.push(harness.try_snapshot("test_insert_remove_2"));
for result in results {
result.unwrap();
}
}
#[rstest]
fn test_size(
#[values(
None,
Some(Size::Points(100.0)),
Some(Size::Percent(0.5)),
Some(Size::Percent(1.0))
)]
width: Option<Size>,
#[values(
None,
Some(Size::Points(100.0)),
Some(Size::Percent(0.5)),
Some(Size::Percent(1.0))
)]
height: Option<Size>,
) {
let mut harness = Harness::new_ui(|ui| {
ui.group(|ui| {
let mut flex = Flex::horizontal();
if let Some(width) = width {
flex = flex.width(width);
}
if let Some(height) = height {
flex = flex.height(height);
}
flex.justify(FlexJustify::Center)
.align_items(FlexAlign::Center)
.show(ui, |flex| {
flex.add(item(), Button::new("Button"));
});
});
});
harness.snapshot(snapshot_name());
}
#[test]
fn basis_stabilize() {
let mut harness = Harness::new_ui(|ui| {
Flex::horizontal()
.justify(FlexJustify::Center)
.wrap(false)
.show(ui, |flex| {
flex.add(item(), Button::new("Button 1"));
flex.add(
item(),
Label::new("Button 12398983274892379847239847293873489"),
);
});
Flex::horizontal().grow_items(1.0).show(ui, |flex| {
flex.add_flex(
item().basis(100.0),
Flex::horizontal().justify(FlexJustify::Center),
|flex| {
flex.add(item(), Button::new("Button 1"));
flex.add(
item(),
Label::new("Button 12398983274892379847239847293873489"),
);
},
);
flex.add(item().basis(200.0), Button::new("Button 2"));
});
});
should_be_stable(&mut harness);
harness.snapshot("basis_stabilize");
}
#[test]
fn nested() {
let mut harness = Harness::new_ui(|ui| {
ui.spacing_mut().item_spacing = Vec2::splat(10.0);
let frame = Frame::group(ui.style());
Flex::horizontal()
.align_content(FlexAlignContent::Start)
.grow_items(1.0)
.show(ui, |flex| {
flex.add_flex(
FlexItem::new().frame(frame),
Flex::vertical()
.align_content(FlexAlignContent::Stretch)
.h_full()
.grow_items(1.0),
|flex| {
flex.add(FlexItem::new(), Button::new("btn"));
flex.add(
FlexItem::new().grow(0.0),
TextEdit::singleline(&mut String::new()).desired_width(100.0),
);
flex.add(FlexItem::new(), DragValue::new(&mut 0.0));
flex.add(FlexItem::new(), Checkbox::new(&mut false, "Checkbox"));
},
);
flex.add(FlexItem::new().grow(1.0), Button::new("Single Button"));
flex.add_flex(
FlexItem::new().grow(1.0).frame(frame),
Flex::vertical()
.align_content(FlexAlignContent::Stretch)
.grow_items(1.0)
.h_full(),
|flex| {
flex.add(FlexItem::new().grow(1.0), Button::new("btn"));
flex.add(FlexItem::new(), Button::new("Very long button"));
},
);
flex.add_flex(
FlexItem::new().grow(1.0).frame(frame),
Flex::vertical()
.align_content(FlexAlignContent::Stretch)
.grow_items(1.0),
|flex| {
flex.add_flex(
FlexItem::new().grow(1.0).frame(frame),
Flex::horizontal()
.align_content(FlexAlignContent::Stretch)
.grow_items(1.0),
|flex| {
flex.add(FlexItem::new().grow(1.0), Button::new("btn"));
flex.add(FlexItem::new(), Button::new("Very long button"));
flex.add_flex(
FlexItem::new().grow(1.0).frame(frame),
Flex::vertical()
.align_content(FlexAlignContent::Stretch)
.grow_items(1.0),
|flex| {
flex.add(FlexItem::new().grow(1.0), Button::new("btn"));
flex.add(FlexItem::new(), Button::new("Very long button"));
},
);
},
);
flex.add(FlexItem::new().grow(1.0), Button::new("btn"));
flex.add(FlexItem::new(), Button::new("Very long button"));
flex.add(FlexItem::new(), Button::new("btn"));
},
);
});
Flex::vertical().show(ui, |flex| {
flex.add_flex(
FlexItem::new().frame(frame),
Flex::horizontal()
.align_content(FlexAlignContent::Start)
.grow_items(1.0),
|flex| {
flex.add(FlexItem::new().grow(1.0), Button::new("btn"));
flex.add(FlexItem::new(), Button::new("Very long button"));
},
);
});
});
should_be_stable(&mut harness);
harness.snapshot("nested");
}
#[test]
fn egui_justify_interaction() {
let mut harness = Harness::new_ui(|ui| {
ui.group(|ui| {
ui.label("vertical_centered_justified");
ui.vertical_centered_justified(|ui| {
_ = ui.button("Justified normal button");
Flex::vertical().show(ui, |flex| {
flex.add(item(), Button::new("Justified flex button (vertical)"));
});
Flex::horizontal().show(ui, |flex| {
flex.add(
item().grow(1.0),
Button::new("Justified flex button (horizontal)"),
);
});
});
});
ui.group(|ui| {
ui.label("vertical normal");
_ = ui.button("Non-justified normal button");
Flex::horizontal().show(ui, |flex| {
flex.add(item().grow(1.0), Button::new("Non-justified flex button"));
});
});
});
should_be_stable(&mut harness);
harness.snapshot("egui_justify_interaction");
}
#[test]
pub fn chat() {
let mut harness = Harness::builder().with_size([300.0, 200.0]).build_ui(|ui| {
Flex::vertical()
.h_full()
.w_full()
.align_content(FlexAlignContent::Stretch)
.show(ui, |flex| {
flex.add_ui(FlexItem::new().grow(1.0).basis(0.0), |ui| {
ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| {
ui.set_width(ui.available_width());
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.label("Messages");
ui.with_layout(Layout::right_to_left(Align::Min), |ui| {
ui.label("My message");
});
});
});
let frame = Frame::NONE
.inner_margin(8.0);
flex.add_flex(
FlexItem::new().frame(frame),
Flex::horizontal().w_full(),
|flex| {
flex.add_flex(item().grow(1.0), Flex::horizontal(), |flex| {
flex.add(
item().grow(1.0).basis(0.0),
TextEdit::singleline(&mut String::new()),
);
flex.add(item(), Button::new("Send"));
});
},
);
});
});
should_be_stable(&mut harness);
harness.snapshot("chat");
}
#[test]
fn truncate_shrink() {
let texts = ["Hello", "Helloooooooooooooooooooooooooooooooo"];
let text_index = Cell::new(0);
let mut harness = Harness::builder().with_size([300.0, 600.0]).build_ui(|ui| {
let text = texts[text_index.get()];
ui.group(|ui| {
ui.set_max_width(140.0);
ui.set_max_height(80.0);
ui.separator();
Flex::vertical().w_full().h_full().show(ui, |flex| {
let frame = Frame::group(flex.ui().style());
flex.add_flex(item().frame(frame), Flex::horizontal(), |flex| {
flex.add(
item().shrink().grow(1.0).content_id(Id::new(text)),
Button::new(text).truncate(),
);
flex.add(item(), Button::new("World!").wrap());
});
});
});
Flex::horizontal().w_full().show(ui, |flex| {
flex.add_flex(item().shrink(), Flex::horizontal(), |flex| {
flex.add(item().shrink(), Button::new(text).wrap());
});
flex.add(item(), Button::new("World!"));
});
ui.add(Button::new("Helloooooooooooooooooooooo").truncate());
Flex::horizontal().w_full().show(ui, |flex| {
flex.add_ui(item().shrink(), |ui| {
ui.add(Button::new(text).wrap());
});
flex.add(item(), Button::new("World!"));
});
Flex::horizontal().w_full().show(ui, |flex| {
flex.add(item().shrink(), Button::new(text).wrap());
flex.add(item(), Button::new("World!"));
});
});
let mut results = vec![];
harness.run();
should_be_stable(&mut harness);
results.push(harness.try_snapshot("truncate_shrink_0_short"));
text_index.set(1);
harness.run();
harness.run();
should_be_stable(&mut harness);
results.push(harness.try_snapshot("truncate_shrink_1_long"));
text_index.set(0);
harness.run();
harness.run();
should_be_stable(&mut harness);
results.push(harness.try_snapshot("truncate_shrink_2_short"));
for result in results {
result.unwrap();
}
}