nrelm 0.1.0

An idiomatic GUI library inspired by Elm and based on gtk3-rs
use crate::{RelmIterChildrenExt, RelmListBoxExt, RelmRemoveAllExt, run_gtk_test};
use gtk::prelude::{BoxExt, ContainerExt, FlowBoxExt, GridExt, ListBoxExt, WidgetExt};

#[derive(Default)]
struct TestWidgets(gtk::Label, gtk::Switch, gtk::Box);

impl TestWidgets {
    fn assert_parent(&self) {
        assert!(self.0.parent().is_some());
        assert!(self.1.parent().is_some());
        assert!(self.2.parent().is_some());
    }
}

fn same_widgets(
    first: Option<impl AsRef<gtk::Widget>>,
    second: Option<impl AsRef<gtk::Widget>>,
) -> bool {
    match (first, second) {
        (Some(first), Some(second)) => first.as_ref() == second.as_ref(),
        (None, None) => true,
        _ => false,
    }
}

#[test]
fn box_extension_traits() {
    run_gtk_test(|| {
        let gtk_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let widgets = TestWidgets::default();

        gtk_box.add(&widgets.1);
        gtk_box.pack_start(&widgets.0, true, true, 0);
        gtk_box.reorder_child(&widgets.0, 0);
        gtk_box.add(&widgets.2);

        widgets.assert_parent();

        let mut children = gtk_box.iter_children();
        assert!(same_widgets(children.next(), Some(&widgets.0)));
        assert!(same_widgets(children.next_back(), Some(&widgets.2)));
        assert!(same_widgets(children.next(), Some(&widgets.1)));
        assert_eq!(children.next(), None);
        assert_eq!(children.next_back(), None);

        gtk_box.remove_all();

        assert_eq!(gtk_box.iter_children().next(), None);
    });
}

#[test]
fn list_box_extension_traits() {
    run_gtk_test(|| {
        let list_box = gtk::ListBox::default();
        let widgets = TestWidgets::default();

        list_box.add(&widgets.1);
        list_box.prepend(&widgets.0);
        list_box.add(&widgets.2);

        widgets.assert_parent();

        assert_eq!(list_box.index_of_child(&widgets.0), Some(0));
        assert_eq!(list_box.index_of_child(&widgets.1), Some(1));
        assert_eq!(list_box.index_of_child(&widgets.2), Some(2));

        let mut rows = list_box.iter_children();
        assert!(same_widgets(rows.next_back(), widgets.2.parent()));
        assert!(same_widgets(rows.next(), widgets.0.parent()));
        assert!(same_widgets(rows.next(), widgets.1.parent()));
        assert_eq!(rows.next(), None);
        assert_eq!(rows.next_back(), None);

        list_box.remove_all();

        assert_eq!(list_box.iter_children().next(), None);

        list_box.add(&widgets.0);
        list_box.add(&widgets.1);
        list_box.add(&widgets.2);

        widgets.assert_parent();

        list_box.remove_row_of_child(&widgets.0);
        list_box.remove_row_of_child(&widgets.1);
        list_box.remove_row_of_child(&widgets.2);

        assert_eq!(list_box.iter_children().next(), None);

        assert_eq!(list_box.index_of_child(&widgets.0), None);
        assert_eq!(list_box.index_of_child(&widgets.1), None);
        assert_eq!(list_box.index_of_child(&widgets.2), None);
    });
}

#[test]
fn flow_box_extension_traits() {
    run_gtk_test(|| {
        let flow_box = gtk::FlowBox::default();
        let widgets = TestWidgets::default();

        flow_box.insert(&widgets.1, -1);
        flow_box.insert(&widgets.0, 0);
        flow_box.insert(&widgets.2, -1);

        widgets.assert_parent();

        let mut flow_children = flow_box.iter_children();
        assert!(same_widgets(flow_children.next(), widgets.0.parent()));
        assert!(same_widgets(flow_children.next(), widgets.1.parent()));
        assert!(same_widgets(flow_children.next(), widgets.2.parent()));
        assert_eq!(flow_children.next_back(), None);
        assert_eq!(flow_children.next(), None);

        flow_box.remove_all();

        assert_eq!(flow_box.iter_children().next(), None);
    });
}

#[test]
fn grid_extension_traits() {
    run_gtk_test(|| {
        let grid = gtk::Grid::default();
        let widgets = TestWidgets::default();

        grid.attach(&widgets.0, 0, 0, 1, 1);
        grid.attach(&widgets.2, 2, 2, 2, 2);
        grid.attach(&widgets.1, 1, 0, 1, 1);

        widgets.assert_parent();

        // GTK3 returns Grid children in reverse insertion order.
        let mut children = grid.iter_children();
        assert!(same_widgets(children.next(), Some(&widgets.1)));
        assert!(same_widgets(children.next(), Some(&widgets.2)));
        assert!(same_widgets(children.next(), Some(&widgets.0)));
        assert_eq!(children.next(), None);
        assert_eq!(children.next_back(), None);

        grid.remove_all();

        assert!(widgets.0.parent().is_none());
        assert!(widgets.1.parent().is_none());
        assert!(widgets.2.parent().is_none());
    });
}

#[test]
fn stack_extension_traits() {
    run_gtk_test(|| {
        let stack = gtk::Stack::default();
        let widgets = TestWidgets::default();

        stack.add(&widgets.0);
        stack.add(&widgets.1);
        stack.add(&widgets.2);

        widgets.assert_parent();

        let mut children = stack.iter_children();
        assert!(same_widgets(children.next(), Some(&widgets.0)));
        assert!(same_widgets(children.next(), Some(&widgets.1)));
        assert!(same_widgets(children.next(), Some(&widgets.2)));
        assert_eq!(children.next_back(), None);
        assert_eq!(children.next(), None);

        stack.remove_all();

        assert_eq!(stack.iter_children().next(), None);
    });
}