hgame 0.26.4

CG production management structs, e.g. of assets, personnels, progress, etc.
Documentation
use super::*;

// ----------------------------------------------------------------------------
#[derive(Debug, Clone)]
/// Multiple [`ProductionAsset`]s are usually created at the same time.
/// This is a helper for such usage, by allowing user to enter names of
/// many assets in a textfield, and to select a common [`Semantic`].
pub struct SemanticSeries {
    mode: MediaMode,

    #[cfg(feature = "gui")]
    /// Used to avoid [`egui::Id`] clashes.
    pub(crate) id_source: u8,

    /// Common `Semantic` for this series of [`ProductionAsset`]s.
    pub(crate) semantic: Semantic,

    /// String to be splitted into names of assets for creation. To be input
    /// by users as a text field.
    asset_names: String,

    /// Used to build asset subtrees.
    assets: Vec<ProductionAsset>,
}

impl Default for SemanticSeries {
    fn default() -> Self {
        Self {
            mode: Default::default(),
            #[cfg(feature = "gui")]
            id_source: 0,
            semantic: Semantic::Prop,
            asset_names: String::new(),
            assets: vec![],
        }
    }
}

fn asset_names_from_input(input: &String) -> Vec<String> {
    use mkutil::text::*;
    ascii_from_multiline(input, SPECIAL_CHARS, MAX_ASSET_NAME_LENGTH as usize)
}

impl SemanticSeries {
    pub fn from_semantic(semantic: Semantic) -> Self {
        Self {
            semantic,
            ..Default::default()
        }
    }

    pub fn with_assets(mut self, assets: Vec<ProductionAsset>) -> Self {
        self.assets = assets;
        self
    }

    #[cfg(feature = "gui")]
    pub fn with_id_source(id_source: u8) -> Self {
        Self {
            id_source,
            ..Default::default()
        }
    }

    /// Lists the `Semantic` and all input asset names.
    pub fn preview_name(&self) -> Option<String> {
        let asset_names = asset_names_from_input(&self.asset_names);

        if asset_names.is_empty() {
            None
        } else {
            Some(format!(
                "{}:\n{}",
                self.semantic.as_ref(),
                asset_names.join("\n")
            ))
        }
    }

    #[cfg(feature = "gui")]
    /// Makes a [`MkTree`] in the form of leaf group.
    pub fn into_tree(self, typ: &ProjectSource) -> MkTree<ProductionAsset> {
        MkTree::leaf_group(&self.semantic.to_string(), self.assets, typ)
    }

    pub fn assets_from_names(
        &self,
        project: &Project,
        criteria: &[&ObjectId],
    ) -> Vec<ProductionAsset> {
        match project.source() {
            ProjectSource::Offline => self.manual_assets_from_names(criteria),

            #[cfg(feature = "mongo")]
            ProjectSource::Mongo => self.mongo_assets_from_names(criteria),

            #[cfg(feature = "kitsu")]
            ProjectSource::Zou => self.kitsu_assets_from_names(criteria),
        }
    }

    fn standard_assets_from_names(&self, criteria: &[&ObjectId]) -> Vec<StandardAsset> {
        asset_names_from_input(&self.asset_names)
            .iter()
            .map(|n| StandardAsset::new(&self.semantic, n).with_criteria(criteria))
            .collect::<Vec<StandardAsset>>()
    }

    #[cfg(feature = "mongo")]
    fn mongo_assets_from_names(&self, criteria: &[&ObjectId]) -> Vec<ProductionAsset> {
        self.standard_assets_from_names(criteria)
            .into_iter()
            .map(|a| ProductionAsset::Mongo(a))
            .collect()
    }

    fn manual_assets_from_names(&self, criteria: &[&ObjectId]) -> Vec<ProductionAsset> {
        self.standard_assets_from_names(criteria)
            .into_iter()
            .map(|a| ProductionAsset::Manual(a))
            .collect()
    }

    #[cfg(feature = "kitsu")]
    fn kitsu_assets_from_names(&self, _criteria: &[&ObjectId]) -> Vec<ProductionAsset> {
        // TODO@kitsu
        error!("Adding assets for Kitsu project is unimplemented");
        vec![]
    }
}

impl ReadWriteSuggest for SemanticSeries {
    fn mode_mut(&mut self, mode: MediaMode) {
        self.mode = mode;
    }

    #[cfg(feature = "gui")]
    fn write_compose_ui(&mut self, ui: &mut egui::Ui) {
        egui::CollapsingHeader::new("Draft New Assets")
            .id_source(&self.id_source)
            .default_open(true)
            .show(ui, |ui| {
                criterion::semantic_options_ui(ui, &mut self.semantic);
                ui.horizontal(|ui| {
                    ui.label("Asset Name:");
                    ui.weak("(new line for multiple)");
                });
                ui.add(egui::TextEdit::multiline(&mut self.asset_names));
            });
    }

    fn write_suggest() -> Self {
        Self {
            mode: MediaMode::WriteSuggest,
            ..Default::default()
        }
    }

    fn with_mode(mut self, mode: MediaMode) -> Self {
        self.mode_mut(mode);
        self
    }

    fn mode(&self) -> &MediaMode {
        &self.mode
    }
}