use crossterm::event::KeyCode;
use photon_ui::{
Anchor,
Component,
Focusable,
Overlay,
OverlayConstraints,
OverlayPosition,
RenderError,
Rendered,
TUI,
events::Event,
terminal::TestTerminal,
tui::Rect,
};
struct DummyComponent {
focused: bool,
render_result: Vec<String>,
}
impl DummyComponent {
fn new(lines: Vec<String>) -> Self {
Self {
focused: false,
render_result: lines,
}
}
}
impl Focusable for DummyComponent {
fn focused(&self) -> bool {
self.focused
}
fn set_focused(&mut self, focused: bool) {
self.focused = focused;
}
}
impl Component for DummyComponent {
fn render(&self, _width: u16) -> Result<Rendered, RenderError> {
Ok(Rendered {
lines: self.render_result.clone(),
cursor: None,
images: Vec::new(),
})
}
fn as_focusable(&self) -> Option<&dyn Focusable> {
Some(self)
}
fn as_focusable_mut(&mut self) -> Option<&mut dyn Focusable> {
Some(self)
}
}
#[test]
fn tui_mount_sets_focus() {
let term = TestTerminal::new(80, 24);
let mut tui = TUI::new(Box::new(term));
tui.mount(Box::new(DummyComponent::new(vec!["a".into()])));
assert!(tui.terminal().size().is_ok());
}
#[test]
fn tui_set_focus_switches() {
let term = TestTerminal::new(80, 24);
let mut tui = TUI::new(Box::new(term));
let mut c1 = DummyComponent::new(vec!["a".into()]);
let mut c2 = DummyComponent::new(vec!["b".into()]);
c1.set_focused(true);
tui.mount(Box::new(c1));
tui.mount(Box::new(c2));
}
#[test]
fn tui_render_frame() {
let term = TestTerminal::new(80, 24);
let mut tui = TUI::new(Box::new(term));
tui.mount(Box::new(DummyComponent::new(vec!["hello".into()])));
tui.render_frame().unwrap();
}
#[test]
fn tui_handle_input() {
let term = TestTerminal::new(80, 24);
let mut tui = TUI::new(Box::new(term));
tui.mount(Box::new(DummyComponent::new(vec!["a".into()])));
tui.handle_input(&Event::Key(crossterm::event::KeyEvent::new(
KeyCode::Char('x'),
crossterm::event::KeyModifiers::empty(),
)));
}
#[test]
fn overlay_anchor_center() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Anchor(Anchor::Center),
constraints: OverlayConstraints {
min_width: 10,
max_height: 5,
margin: 1,
offset_x: 0,
offset_y: 0,
visible: None,
},
};
let rect = overlay.compute_position(80, 24, 20, 3).unwrap();
assert_eq!(rect.y, (24 - 3) / 2);
assert_eq!(rect.x, (80 - 20) / 2);
assert_eq!(rect.width, 20);
assert_eq!(rect.height, 3);
}
#[test]
fn overlay_anchor_top_left() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Anchor(Anchor::TopLeft),
constraints: OverlayConstraints {
min_width: 5,
max_height: 5,
margin: 2,
offset_x: 0,
offset_y: 0,
visible: None,
},
};
let rect = overlay.compute_position(80, 24, 10, 3).unwrap();
assert_eq!(rect.y, 2);
assert_eq!(rect.x, 2);
}
#[test]
fn overlay_at_position() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::At(5, 10),
constraints: OverlayConstraints {
min_width: 1,
max_height: 10,
margin: 0,
offset_x: 0,
offset_y: 0,
visible: None,
},
};
let rect = overlay.compute_position(80, 24, 10, 3).unwrap();
assert_eq!(rect.y, 5);
assert_eq!(rect.x, 10);
}
#[test]
fn overlay_percent_position() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Percent("50%".into(), "50%".into()),
constraints: OverlayConstraints {
min_width: 1,
max_height: 10,
margin: 0,
offset_x: 0,
offset_y: 0,
visible: None,
},
};
let rect = overlay.compute_position(100, 100, 10, 10).unwrap();
assert_eq!(rect.y, 50);
assert_eq!(rect.x, 50);
}
#[test]
fn overlay_not_visible() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Anchor(Anchor::Center),
constraints: OverlayConstraints {
min_width: 1,
max_height: 10,
margin: 0,
offset_x: 0,
offset_y: 0,
visible: Some(|_w, _h| false),
},
};
assert!(overlay.compute_position(80, 24, 10, 3).is_none());
}
#[test]
fn overlay_with_offset() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Anchor(Anchor::TopLeft),
constraints: OverlayConstraints {
min_width: 1,
max_height: 10,
margin: 0,
offset_x: 5,
offset_y: 3,
visible: None,
},
};
let rect = overlay.compute_position(80, 24, 10, 3).unwrap();
assert_eq!(rect.y, 3);
assert_eq!(rect.x, 5);
}
#[test]
fn overlay_clamped_to_terminal() {
let overlay = Overlay {
content: Box::new(DummyComponent::new(vec!["test".into()])),
position: OverlayPosition::Anchor(Anchor::BottomRight),
constraints: OverlayConstraints {
min_width: 100,
max_height: 10,
margin: 0,
offset_x: 0,
offset_y: 0,
visible: None,
},
};
let rect = overlay.compute_position(80, 24, 10, 3).unwrap();
assert!(rect.width <= 80);
assert!(rect.height <= 24);
}