diff --git a/src/vvedit/editor_ui.rs b/src/vvedit/editor_ui.rs index 791122f..fbf7509 100644 --- a/src/vvedit/editor_ui.rs +++ b/src/vvedit/editor_ui.rs @@ -17,7 +17,7 @@ use bevy_egui::{ self, color_picker, ecolor::{hsv_from_rgb, rgb_from_hsv}, epaint::Hsva, - Id, Pos2, Rect, Response, ScrollArea, + Id, Pos2, Rect, ScrollArea, }, EguiContexts, EguiPlugin, EguiSettings, }; @@ -39,6 +39,9 @@ use super::{ orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera}, ui_extensions::{StringTree, StringTreeElement}, }; + +use std::fmt::Write; + pub struct AssetEditData { path: String, id: Handle, @@ -51,6 +54,21 @@ pub struct EditWindowUIState { meshes: Vec, structure: StringTree, egui: EditWindowEguiState, + popup: PopupWindowData, +} +#[derive(Default)] +pub enum PopupWindowData { + #[default] + None, + StructureElement(String), +} +impl PopupWindowData { + pub fn is_none(&self) -> bool { + match self { + PopupWindowData::None => true, + _ => false, + } + } } #[derive(Clone)] @@ -140,7 +158,10 @@ impl EditWindowUIState { } } -pub fn register_edit_ui(app: &mut bevy::prelude::App) -> &mut bevy::prelude::App { +pub fn register_edit_ui( + //formatting comment + app: &mut bevy::prelude::App, +) -> &mut bevy::prelude::App { app.insert_resource(EditWindowUIState { brush_color: egui_color_from(Color::RED), meshes: Vec::new(), @@ -157,7 +178,11 @@ pub fn register_edit_ui(app: &mut bevy::prelude::App) -> &mut bevy::prelude::App app } -pub fn startup_system_edit_ui(commands: Commands, mut shared_ui_state: ResMut) { +pub fn startup_system_edit_ui( + // formatting comment + commands: Commands, + mut shared_ui_state: ResMut, +) { spawn_camera(commands); shared_ui_state .structure @@ -215,10 +240,8 @@ pub fn edit_click_events( octtree_ray_overlap(&eoct, &obb, ray.origin, ray.direction.normalize()) }; - dbg!(&shared_ui_state.egui.windows); let scale = egui_settings.scale_factor; let mod_cursor_pos = Pos2::new(cursor_pos.x / scale, cursor_pos.y / scale); - dbg!(&mod_cursor_pos); for rect in &shared_ui_state.egui.windows { if rect.contains(mod_cursor_pos) { return; @@ -362,10 +385,11 @@ pub fn edit_window_ui( for window_entity in &windows { let ctx = contexts.ctx_for_window_mut(window_entity); let pos = ctx.memory(|memory| { - if !memory.is_popup_open(shared_ui_state.egui.popup_identifier.unwrap()) { - return None; + if let PopupWindowData::StructureElement(_) = shared_ui_state.popup { + memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()) + } else { + None } - memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()) }); if let Some(pos) = pos { shared_ui_state.egui.windows.push(pos); @@ -383,86 +407,88 @@ pub fn edit_window_ui( } response.show(contexts.ctx_mut(), |ui: &mut egui::Ui| { + ui.label("This tool is in early development."); ScrollArea::vertical().show(ui, |ui| { - let mut label = String::from("Pre-Alpha"); - use std::fmt::Write; - writeln!(label, " Controls:").ok(); - writeln!(label, "click adds a voxel:").ok(); - writeln!(label, "R+click removes a voxel:").ok(); - writeln!(label, "E+click paints (edits) a voxel:").ok(); - color_picker::color_picker_hsva_2d( - ui, - &mut shared_ui_state.brush_color, - color_picker::Alpha::Opaque, - ); - ui.label(label); - let mut color_to_set: Option = None; - for each in &shared_ui_state.meshes { - ui.vertical(|ui| { - //color palette clickables. - let handle = each.id.clone(); - let asset = oct_assets.get(handle); - if asset.is_some() { - let list = { - let eoct = asset.unwrap().model.read().unwrap(); - eoct.collect_voxels() - }; + ui.collapsing("Mesh Tools", |ui| { + let mut label = String::from("Controls:"); + writeln!(label, "").ok(); + writeln!(label, "click adds a voxel:").ok(); + writeln!(label, "R+click removes a voxel:").ok(); + writeln!(label, "E+click paints (edits) a voxel:").ok(); + color_picker::color_picker_hsva_2d( + ui, + &mut shared_ui_state.brush_color, + color_picker::Alpha::Opaque, + ); + ui.label(label); + let mut color_to_set: Option = None; + for each in &shared_ui_state.meshes { + ui.vertical(|ui| { + //color palette clickables. + let handle = each.id.clone(); + let asset = oct_assets.get(handle); + if asset.is_some() { + let list = { + let eoct = asset.unwrap().model.read().unwrap(); + eoct.collect_voxels() + }; - let mut count: Vec<(Color, usize)> = Vec::new(); - fn eq(c1: &Color, c2: &mut Color) -> bool { - c1.r() == c2.r() && c1.g() == c2.g() && c1.b() == c2.b() - } - for (_, _, color) in &list { - let mut is_committed = false; - for (each_col, each_count) in &mut count { - if eq(color, each_col) { - *each_count += 1; - is_committed = true; - break; - } + let mut count: Vec<(Color, usize)> = Vec::new(); + fn eq(c1: &Color, c2: &mut Color) -> bool { + c1.r() == c2.r() && c1.g() == c2.g() && c1.b() == c2.b() } - if !is_committed { - count.push((color.clone(), 1)); - } - } - count.sort_by(|a, b| b.1.cmp(&a.1)); - if !count.is_empty() { - ui.label(each.path.clone()); - ui.horizontal_wrapped(|ui| { - for (color, count) in count { - let button = egui::Button::new(count.to_string()) - .fill(egui_color_from(color)); - if ui.add(button).clicked() { - color_to_set = Some(color); + for (_, _, color) in &list { + let mut is_committed = false; + for (each_col, each_count) in &mut count { + if eq(color, each_col) { + *each_count += 1; + is_committed = true; + break; } } - }); + if !is_committed { + count.push((color.clone(), 1)); + } + } + count.sort_by(|a, b| b.1.cmp(&a.1)); + if !count.is_empty() { + ui.label(each.path.clone()); + ui.horizontal_wrapped(|ui| { + for (color, count) in count { + let button = egui::Button::new(count.to_string()) + .fill(egui_color_from(color)); + if ui.add(button).clicked() { + color_to_set = Some(color); + } + } + }); + } } - } - }); - } - if let Some(color) = color_to_set { - shared_ui_state.brush_color = egui_color_from(color); - } - if ui.button("Add Origin Voxel").clicked() { - // - for pair in &mut pairs.handles { - let id = pair.oct_handle.clone(); - let tree = oct_assets.get_mut(id); - if tree.is_some() { - let tree = tree.unwrap(); - { - let mut eoct = tree.model.write().unwrap(); - eoct.set_voxel_at_location( - Vec3::ZERO, - color_from(shared_ui_state.brush_color), - ); + }); + } + if let Some(color) = color_to_set { + shared_ui_state.brush_color = egui_color_from(color); + } + if ui.button("Add Origin Voxel").clicked() { + // + for pair in &mut pairs.handles { + let id = pair.oct_handle.clone(); + let tree = oct_assets.get_mut(id); + if tree.is_some() { + let tree = tree.unwrap(); + { + let mut eoct = tree.model.write().unwrap(); + eoct.set_voxel_at_location( + Vec3::ZERO, + color_from(shared_ui_state.brush_color), + ); + } } } } - } - let response = ui.button("Save Any Changes"); - if response.clicked() { + }); + show_editable_stringtree(ui, &mut shared_ui_state); + if ui.button("Save Any Changes").clicked() { //save all files. for each in &mut shared_ui_state.meshes { if each.has_changed_since_last_save { @@ -477,40 +503,67 @@ pub fn edit_window_ui( ); if result { each.has_changed_since_last_save = false; - println!("{} saved to disk.", &path); } } } } } - show_editable_stringtree( - ui, - shared_ui_state.egui.clone(), - &mut shared_ui_state.structure, - &response, - ); }); }); + show_popup(&mut shared_ui_state, &mut contexts); } -pub fn show_editable_stringtree( - ui: &mut egui::Ui, - state: EditWindowEguiState, - tree: &mut StringTree, - response: &Response, -) { - egui::popup_below_widget(ui, state.popup_identifier.unwrap(), response, |ui| { - ScrollArea::vertical().show(ui, |ui| { - ui.vertical(|ui| { - for _ in 0..100 { - ui.label("filler"); +pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) { + let mut change_state = None; + let mut reparent = None; + match &state.popup { + PopupWindowData::None => return, + PopupWindowData::StructureElement(name) => { + //formatting comment + let response = egui::Window::new("edit structure element ".to_owned() + &name.clone()) + .id(state.egui.popup_identifier.unwrap()); + response.show(contexts.ctx_mut(), |ui| { + //formatting comment + let cur = name.clone(); + ui.label("what do you want to do with ".to_owned() + &name + "?"); + enum Tasks { + MoveElement, + RemoveElement, + DeleteElementWithChildren, + DeleteElementAndReparent, + } + ui.collapsing("Reparent to child of", |ui| { + ui.vertical(|ui| { + for each in state.structure.list_of_elements() { + if each != cur && Some(&each) != state.structure.parent_of(&cur.clone()) + { + if ui.button(&each).clicked() { + reparent = Some((cur.clone(), each)); + change_state = Some(PopupWindowData::None); + } + } + } + }); + }); + // todo: rename action. edit subject action (mesh, light), remove action (with, without reparenting) + if ui.button("Cancel").clicked() { + change_state = Some(PopupWindowData::None); } }); - }); - }); + } + } + if change_state.is_some() { + state.popup = change_state.unwrap(); + } + if let Some((cur, next)) = reparent { + state.structure.move_branch(&cur, &next); + } +} + +pub fn show_editable_stringtree(ui: &mut egui::Ui, state: &mut EditWindowUIState) { ui.collapsing("Model Structure", |ui| { ui.vertical(|ui| { - for each in &mut tree.root { + for each in &mut state.structure.root { match each { super::ui_extensions::StringTreeElement::None => {} super::ui_extensions::StringTreeElement::Element(name, children) => { @@ -518,14 +571,21 @@ pub fn show_editable_stringtree( ui.label(">".to_owned()); if ui.button(name.clone()).clicked() { // - - ui.memory_mut(|mem| { - mem.toggle_popup(state.popup_identifier.unwrap()) - }); + let mut should_close = false; + if let PopupWindowData::StructureElement(val) = &state.popup { + if val == name { + should_close = true; + } + } + if should_close { + state.popup = PopupWindowData::None; + } else { + state.popup = PopupWindowData::StructureElement(name.clone()) + } } }); - for each in children.as_mut() { - show_child(ui, each, 1); + for each in children.as_ref() { + show_child(ui, each, 1, &mut state.popup); } } } @@ -533,12 +593,15 @@ pub fn show_editable_stringtree( }); }); } -pub fn show_child(ui: &mut egui::Ui, subject: &mut StringTreeElement, depth: usize) { - // +pub fn show_child( + ui: &mut egui::Ui, + subject: &StringTreeElement, + depth: usize, + state: &mut PopupWindowData, +) { match subject { StringTreeElement::None => {} StringTreeElement::Element(name, children) => { - // let mut prec = String::from(""); for i in 0..depth { if i == 0 { @@ -550,10 +613,22 @@ pub fn show_child(ui: &mut egui::Ui, subject: &mut StringTreeElement, depth: usi prec = prec + ">"; ui.horizontal(|ui| { ui.label(prec); - ui.button(name.clone()).clicked(); + if ui.button(name.clone()).clicked() { + let mut should_close = false; + if let PopupWindowData::StructureElement(val) = state { + if val == name { + should_close = true; + } + } + if should_close { + *state = PopupWindowData::None; + } else { + *state = PopupWindowData::StructureElement(name.clone()) + } + } }); - for each in children.as_mut() { - show_child(ui, each, depth + 1); + for each in children.as_ref() { + show_child(ui, each, depth + 1, state); } } } diff --git a/src/vvedit/ui_extensions.rs b/src/vvedit/ui_extensions.rs index 6986fa2..98dd480 100644 --- a/src/vvedit/ui_extensions.rs +++ b/src/vvedit/ui_extensions.rs @@ -263,6 +263,28 @@ impl StringTree { } false } */ + + pub fn list_of_elements(&self) -> Vec { + let mut list: Vec = Vec::new(); + let mut to_search = Vec::new(); + for each in &self.root { + to_search.push(each); + } + while !to_search.is_empty() { + let next = to_search.pop(); + if let Some(next) = next { + if let Some(name) = next.name_of() { + list.push(name.clone()); + } + if let StringTreeElement::Element(_, children) = next { + for each in children.as_ref() { + to_search.push(each); + } + } + } + } + return list; + } } #[test] pub fn test_string_tree() {