diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/mod.rs index 5350db82d..a0b15a162 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/mod.rs @@ -10,6 +10,7 @@ pub use model::*; pub use persistence::*; pub use tree::*; pub use workflow::apply_batch_patch; +pub use workflow::batch::next_image_batch; pub(crate) use workflow::separate_ui_impl; #[cfg(test)] mod tests { diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/tree.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/tree.rs index 01c46b583..0b483d8e4 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/tree.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/tree.rs @@ -2,7 +2,6 @@ use super::model::*; use crate::ui_editor::component::{image::ImageComponent, Component}; use crate::ui_editor::layout::node::Node; use crate::ui_editor::state::State; -use crate::ui_editor::utils::NodeId; use std::collections::HashSet; fn is_unbound_image(node: &Node) -> bool { @@ -144,68 +143,6 @@ pub fn construct_separation_state(state: &State) -> SeparationState { } } -fn terminal_ids(state: &SeparationState) -> HashSet { - state - .bound - .iter() - .map(|n| n.node_id.clone()) - .chain(state.problematic_nodes.iter().map(|n| n.node_id.clone())) - .collect() -} - -fn collect_dfs_batch<'a>( - node: &'a SeparationNode, - is_root: bool, - root_extractable: bool, - terminal: &HashSet, - selected: &mut Vec<&'a SeparationNode>, - area: &mut u64, -) -> bool { - let is_target = matches!(node.kind, SeparationNodeKind::ImageTarget) - && (!is_root || root_extractable) - && !terminal.contains(&node.id); - if is_target { - let node_area = u64::from(node.width_px).saturating_mul(u64::from(node.height_px)); - let would_exceed = area.saturating_add(node_area) > IMAGE_EDIT_AREA_LIMIT_PX; - if selected.is_empty() || !would_exceed { - selected.push(node); - *area = area.saturating_add(node_area); - } else { - return true; - } - } - for child in &node.children { - if collect_dfs_batch(child, false, root_extractable, terminal, selected, area) { - return true; - } - } - false -} - -pub fn next_image_batch<'a>( - state: &SeparationState, - tree: &'a SeparationTree, -) -> Vec<&'a SeparationNode> { - let terminal = terminal_ids(state); - let mut selected = Vec::new(); - let mut area = 0; - collect_dfs_batch( - &tree.root, - true, - tree.root_extractable, - &terminal, - &mut selected, - &mut area, - ); - app_log!( - "ui_separation.batch_selected image_id={} image_nodes={} area_px={}", - tree.src_ui_design.as_str(), - selected.len(), - area - ); - selected -} - pub fn validate_binding_response( response: &BindingResp, batch: &[&SeparationNode], diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/batch.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/batch.rs new file mode 100644 index 000000000..487fc312c --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/batch.rs @@ -0,0 +1,65 @@ +use crate::ui_editor::commands::separation::model::*; +use crate::ui_editor::utils::NodeId; +use std::collections::HashSet; + +fn terminal_ids(state: &SeparationState) -> HashSet { + state + .bound + .iter() + .map(|n| n.node_id.clone()) + .chain(state.problematic_nodes.iter().map(|n| n.node_id.clone())) + .collect() +} + +fn collect_dfs_batch<'a>( + node: &'a SeparationNode, + is_root: bool, + root_extractable: bool, + terminal: &HashSet, + selected: &mut Vec<&'a SeparationNode>, + area: &mut u64, +) -> bool { + let is_target = matches!(node.kind, SeparationNodeKind::ImageTarget) + && (!is_root || root_extractable) + && !terminal.contains(&node.id); + if is_target { + let node_area = u64::from(node.width_px).saturating_mul(u64::from(node.height_px)); + let would_exceed = area.saturating_add(node_area) > IMAGE_EDIT_AREA_LIMIT_PX; + if selected.is_empty() || !would_exceed { + selected.push(node); + *area = area.saturating_add(node_area); + } else { + return true; + } + } + for child in &node.children { + if collect_dfs_batch(child, false, root_extractable, terminal, selected, area) { + return true; + } + } + false +} + +pub fn next_image_batch<'a>( + state: &SeparationState, + tree: &'a SeparationTree, +) -> Vec<&'a SeparationNode> { + let terminal = terminal_ids(state); + let mut selected = Vec::new(); + let mut area = 0; + collect_dfs_batch( + &tree.root, + true, + tree.root_extractable, + &terminal, + &mut selected, + &mut area, + ); + app_log!( + "ui_separation.batch_selected image_id={} image_nodes={} area_px={}", + tree.src_ui_design.as_str(), + selected.len(), + area + ); + selected +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/mod.rs index b6b245a8b..4bba6a8da 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/mod.rs @@ -1,3 +1,4 @@ +pub mod batch; mod binding; mod cut; mod extract; @@ -5,13 +6,13 @@ mod patch; pub use patch::apply_batch_patch; +use self::batch::next_image_batch; use super::model::*; use super::persistence::{ project_relative_path, read_separation_state, separation_dto, separation_sidecar_dir, separation_state_path, write_separation_state, }; use super::prompt::gen_extract_prompt; -use super::tree::next_image_batch; use crate::platform_session::current_platform_session; use crate::ui_editor::commands::utils::read_ui_reference_image_data_url; use crate::ui_editor::state::State; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/patch.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/patch.rs index c2fdd0e84..341416fd6 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/patch.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/patch.rs @@ -1,6 +1,7 @@ +use super::batch::next_image_batch; use crate::ui_editor::commands::separation::{ - next_image_batch, validate_binding_response, BindingDecision, BindingResp, BoundNode, - ProblematicNode, SeparationNode, SeparationState, MAX_REWORK_COUNT, + validate_binding_response, BindingDecision, BindingResp, BoundNode, ProblematicNode, + SeparationNode, SeparationState, MAX_REWORK_COUNT, }; use crate::ui_editor::utils::NodeId; use std::collections::HashMap;