widget-forge 0.1.0

A Widget Based Application Engine for Ascii-Forge
Documentation
use crate::{prelude::*, widget::conditional_widgets::ConditionalWidgets};

use ascii_forge::prelude::*;

use std::{collections::HashSet, io, time::Duration};

pub struct Scene<D> {
    window: Window,
    data: D,
    widgets: Vec<Box<dyn Widget<D>>>,
    special_widgets: Vec<Box<dyn SpecialWidget<D>>>,
}

impl<D: 'static> Scene<D> {
    pub fn new(window: Window, data: D) -> Self {
        Self {
            window,
            data,
            widgets: vec![],
            special_widgets: vec![],
        }
    }

    pub fn data(&self) -> &D {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut D {
        &mut self.data
    }

    pub fn insert_widget(&mut self, widget: impl Widget<D> + 'static) -> &mut Self {
        self.widgets.push(Box::new(widget));
        self
    }

    pub fn insert_widgets(&mut self, set: impl WidgetSet<D>) -> &mut Self {
        set.insert(self);
        self
    }

    pub fn insert_special_widget(&mut self, widget: impl SpecialWidget<D> + 'static) -> &mut Self {
        self.special_widgets.push(Box::new(widget));
        self
    }

    pub fn insert_conditional_widgets(
        &mut self,
        cond: impl Fn(&mut Window, &mut D) -> bool + 'static,
        widgets: impl WidgetSet<D>,
    ) -> &mut Self {
        let start = self.widgets.len();
        widgets.insert(self);
        let end = self.widgets.len();

        self.insert_special_widget(ConditionalWidgets::new(cond, (start..end).collect()));
        self
    }

    pub fn take_all(self) -> (Window, D) {
        (self.window, self.data)
    }

    pub fn update(&mut self) {
        let mut updated = HashSet::default();
        for special in &mut self.special_widgets {
            special.update(
                &mut self.window,
                &mut self.data,
                &mut self.widgets,
                &mut updated,
            );
        }
        for (i, widget) in self.widgets.iter_mut().enumerate() {
            if updated.contains(&i) {
                continue;
            }

            widget.update(&mut self.window, &mut self.data);
        }
    }

    pub fn run(
        &mut self,
        update_millis: u64,
        run_cond: impl Fn(&mut Self) -> bool,
    ) -> io::Result<&mut Self> {
        while run_cond(self) {
            self.update();

            self.window.update(Duration::from_millis(update_millis))?;
        }
        Ok(self)
    }
}