use appcui_proc_macro::*;
use super::App;
use super::Theme;
use super::Themes;
use super::ToolTip;
use crate::graphics::CharFlags;
use crate::graphics::Character;
use crate::graphics::Color;
use crate::graphics::Rect;
use crate::graphics::Size;
use crate::graphics::SpecialChar;
use crate::graphics::SurfaceTester;
use crate::input::Key;
use crate::input::KeyCode;
use crate::input::KeyModifier;
use crate::input::MouseButton;
use crate::system::Clipboard;
use crate::system::MouseButtonDownEvent;
use crate::system::MouseMoveEvent;
use crate::ui::command_bar::*;
use crate::ui::common::traits::*;
fn draw_tool_tip(size: Size, rect: Rect, txt: &str) -> SurfaceTester {
let mut tooltip = ToolTip::new();
let theme = Theme::new(Themes::Default);
let mut s = SurfaceTester::new(size.width, size.height);
tooltip.show(txt, &rect, s.size(), &theme);
s.clear(Character::new(' ', Color::White, Color::Black, CharFlags::None));
s.fill_rect(rect, Character::new('X', Color::White, Color::DarkRed, CharFlags::None));
tooltip.paint(&mut s, &theme);
s
}
#[test]
fn check_tooltip_single_line() {
let s = draw_tool_tip(Size::new(40, 6), Rect::new(2, 2, 10, 4), "A simple tooltip");
assert_eq!(s.compute_hash(), 0xA18B870B1B5423F6);
}
#[test]
fn check_tooltip_multi_line() {
let s = draw_tool_tip(Size::new(40, 10), Rect::new(2, 3, 10, 5), "A multi-line tooltip\nto show case");
assert_eq!(s.compute_hash(), 0x737C188B334A13C2);
}
#[test]
fn check_tooltip_multi_line_2() {
let s = draw_tool_tip(
Size::new(40, 15),
Rect::new(2, 4, 10, 5),
"A multi-line tooltip to show case in this example",
);
assert_eq!(s.compute_hash(), 0x8E67370E48B93A77);
}
#[test]
fn check_tooltip_multi_line_3() {
let s = draw_tool_tip(
Size::new(40, 15),
Rect::new(0, 4, 5, 5),
"A multi-line tooltip to show case in this example",
);
assert_eq!(s.compute_hash(), 0x6F0C45230D2BDDE7);
}
#[test]
fn check_tooltip_bottom_pos() {
let s = draw_tool_tip(
Size::new(40, 10),
Rect::new(3, 0, 10, 5),
"A multi-line tooltip to show case in this example",
);
assert_eq!(s.compute_hash(), 0xD12BB7D1C8BA1281);
}
#[test]
fn check_tooltip_bottom_pos_no_show() {
let s = draw_tool_tip(
Size::new(40, 10),
Rect::new(3, 0, 10, 7),
"A multi-line tooltip to show case in this example",
);
assert_eq!(s.compute_hash(), 0x9F6184450761DB25);
}
#[derive(Copy, Clone)]
struct Command {
value: u32,
}
impl TryFrom<u32> for Command {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(Self { value })
}
}
impl From<Command> for u32 {
fn from(value: Command) -> Self {
value.value
}
}
impl CommandID for Command {}
impl Command {
fn new(value: u32) -> Self {
Self { value }
}
}
fn prepare_command_bar(size: Size) -> CommandBar {
let mut c = CommandBar::new(size.width, size.height);
c.set(Key::new(KeyCode::F2, KeyModifier::None), "Save", Command::new(1));
c.set(Key::new(KeyCode::F3, KeyModifier::None), "Open", Command::new(2));
c.set(Key::new(KeyCode::F5, KeyModifier::None), "Run", Command::new(3));
c.set(Key::new(KeyCode::F7, KeyModifier::None), "Compile", Command::new(4));
c.set(Key::new(KeyCode::F8, KeyModifier::None), "Delete", Command::new(5));
c.set(Key::new(KeyCode::F2, KeyModifier::Alt), "Save As ...", Command::new(12345));
c.update_positions();
c
}
#[test]
fn check_command_bar_1() {
let mut s = SurfaceTester::new(60, 5);
let c = prepare_command_bar(s.size());
s.clear(Character::new('X', Color::Black, Color::DarkBlue, CharFlags::None));
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0xD466864BD254E538);
}
#[test]
fn check_command_bar_2() {
let mut s = SurfaceTester::new(60, 5);
let mut c = prepare_command_bar(s.size());
s.clear(Character::new('.', Color::Black, Color::DarkBlue, CharFlags::None));
c.set_key_modifier(KeyModifier::Alt);
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x940B30F3F39A2B3A);
}
#[test]
fn check_command_bar_hover() {
let mut s = SurfaceTester::new(60, 5);
let mut c = prepare_command_bar(s.size());
s.clear(Character::new(SpecialChar::Block50, Color::Black, Color::DarkBlue, CharFlags::None));
for x in 0..9 {
c.on_mouse_move(&MouseMoveEvent {
x,
y: 4,
button: MouseButton::None,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x6FFD6A9E00B06190);
}
c.on_mouse_move(&MouseMoveEvent {
x: 9,
y: 4,
button: MouseButton::None,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x8FE003D26FC257B8);
c.on_mouse_move(&MouseMoveEvent {
x: 10,
y: 4,
button: MouseButton::None,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x24738CE8FFD30F80);
c.on_mouse_move(&MouseMoveEvent {
x: 10,
y: 3,
button: MouseButton::None,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x8FE003D26FC257B8);
}
#[test]
fn check_command_bar_click() {
let mut s = SurfaceTester::new(60, 5);
let mut c = prepare_command_bar(s.size());
s.clear(Character::new(SpecialChar::Block50, Color::Black, Color::DarkBlue, CharFlags::None));
c.set_key_modifier(KeyModifier::Alt);
c.on_mouse_move(&MouseMoveEvent {
x: 9,
y: 4,
button: MouseButton::None,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0xF768DE602AA7C28A);
c.on_mouse_down(&MouseButtonDownEvent {
x: 9,
y: 4,
button: MouseButton::Left,
});
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0x66FEDFABE303DEF6);
let result = c.on_mouse_up().unwrap().command_id;
c.paint(&mut s, &Theme::new(Themes::Default));
assert_eq!(s.compute_hash(), 0xF768DE602AA7C28A);
assert_eq!(result, 12345);
}
#[test]
fn check_multiple_apps_started() {
let a = App::debug(60, 10, "").build().unwrap();
a.run();
let a = App::debug(50, 20, "").build().unwrap();
a.run();
}
#[test]
fn check_mouse_keymodifier_mouse() {
#[CustomControl(overwrite:OnPaint+OnMouseEvent, internal: true)]
struct TestControl {
txt: String,
}
impl TestControl {
fn new() -> Self {
Self {
base: ControlBase::new(layout!("d:f"), true),
txt: String::new(),
}
}
}
impl OnPaint for TestControl {
fn on_paint(&self, surface: &mut crate::prelude::Surface, _theme: &Theme) {
surface.clear(char!("' ',red,black"));
surface.write_string(0, 0, &self.txt, CharAttribute::new(Color::White, Color::Black, CharFlags::None), true);
}
}
impl OnMouseEvent for TestControl {
fn on_mouse_event(&mut self, event: &crate::prelude::MouseEvent) -> EventProcessStatus {
match event {
crate::prelude::MouseEvent::Enter => {}
crate::prelude::MouseEvent::Leave => {}
crate::prelude::MouseEvent::Over(_) => {}
crate::prelude::MouseEvent::Pressed(data) => {
self.txt = format!("Pressed: x:{},y:{}\nbutton:{:?},modif:{:?}", data.x, data.y, data.button, data.modifier);
}
crate::prelude::MouseEvent::Released(data) => {
self.txt = format!("Pressed: x:{},y:{}\nbutton:{:?},modif:{:?}", data.x, data.y, data.button, data.modifier);
}
crate::prelude::MouseEvent::DoubleClick(data) => {
self.txt = format!("Pressed: x:{},y:{}\nbutton:{:?},modif:{:?}", data.x, data.y, data.button, data.modifier);
}
crate::prelude::MouseEvent::Drag(data) => {
self.txt = format!("Pressed: x:{},y:{}\nbutton:{:?},modif:{:?}", data.x, data.y, data.button, data.modifier);
}
crate::prelude::MouseEvent::Wheel(_) => {}
}
EventProcessStatus::Processed
}
}
let script = "
Paint.Enable(false)
Paint('Initial state')
CheckHash(0x614245CC84C42969)
Mouse.Drag(1,1,3,3);
Paint('Simple Drag')
CheckHash(0x72F1BAC32695526E)
Key.Modifier(Ctrl)
Mouse.Drag(3,3,5,5);
Paint('Simple Drag (with ctrl - value 2)')
CheckHash(0x6595486EEC0578BC)
Key.Modifier(Ctrl+Shift)
Mouse.Drag(5,5,7,7);
Paint('Simple Drag (with ctrl+shift - value 6)')
CheckHash(0x81760858B7A9C498)
Key.Modifier(None)
Mouse.Drag(7,7,1,1);
Paint('Simple Drag (with no modifier - value 0)')
CheckHash(0x6959C1EA263F8E6E)
";
let mut a = App::debug(60, 10, script).build().unwrap();
let mut w = window!("Test,d:f");
w.add(TestControl::new());
a.add_window(w);
a.run();
}
#[test]
fn check_clipboard_api() {
let a = App::debug(60, 10, "Paint.Enable(false)").build().unwrap();
Clipboard::set_text("Hello, world!");
assert_eq!(Clipboard::text(), Some("Hello, world!".to_string()));
assert!(Clipboard::has_text());
Clipboard::clear();
assert_eq!(Clipboard::text(), None);
assert!(!Clipboard::has_text());
a.run();
}
#[test]
fn check_clipboard_api_without_app_initialization() {
Clipboard::set_text("Hello, world!");
assert_eq!(Clipboard::text(), None);
assert!(!Clipboard::has_text());
assert_eq!(Clipboard::text(), None);
Clipboard::clear();
assert_eq!(Clipboard::text(), None);
assert!(!Clipboard::has_text());
}
#[test]
fn check_app_create_with_title() {
let a = App::debug(60, 10, "Paint.Enable(false)").title("Some title").build().unwrap();
a.run();
}
#[test]
fn check_app_create_with_size() {
let a = App::debug(60, 10, "Paint.Enable(false)").size(Size::new(60, 10)).build().unwrap();
a.run();
}
#[test]
fn check_app_create_with_invalid_size() {
let a = App::debug(60, 10, "Paint.Enable(false)").size(Size::new(0, 0)).build();
assert!(a.is_err());
let err: crate::system::Error = a.err().unwrap();
assert_eq!(err.kind, crate::system::ErrorKind::InvalidParameter);
let desc = format!("{err}");
assert_eq!(desc, "Invalid size for a terminal (0x0). Both width and height must be bigger than 0 !");
}
#[test]
fn check_app_create_with_timers_count() {
let a = App::debug(60, 10, "Paint.Enable(false)").timers_count(10).build().unwrap();
a.run();
}
#[cfg(target_os = "windows")]
#[test]
fn check_create_app_with_default_terminal() {
let _ = App::new().build();
}
#[cfg(target_os = "windows")]
#[test]
fn check_create_app_with_windows_terminal() {
let _ = App::with_backend(crate::backend::Type::WindowsConsole).build();
}