basic stringtree movement

This commit is contained in:
Lillian Vixe 2024-04-25 03:54:37 -07:00
parent a9d346c411
commit 18a93e44df
2 changed files with 209 additions and 112 deletions

View file

@ -17,7 +17,7 @@ use bevy_egui::{
self, color_picker, self, color_picker,
ecolor::{hsv_from_rgb, rgb_from_hsv}, ecolor::{hsv_from_rgb, rgb_from_hsv},
epaint::Hsva, epaint::Hsva,
Id, Pos2, Rect, Response, ScrollArea, Id, Pos2, Rect, ScrollArea,
}, },
EguiContexts, EguiPlugin, EguiSettings, EguiContexts, EguiPlugin, EguiSettings,
}; };
@ -39,6 +39,9 @@ use super::{
orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera}, orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera},
ui_extensions::{StringTree, StringTreeElement}, ui_extensions::{StringTree, StringTreeElement},
}; };
use std::fmt::Write;
pub struct AssetEditData { pub struct AssetEditData {
path: String, path: String,
id: Handle<OctTreeAsset>, id: Handle<OctTreeAsset>,
@ -51,6 +54,21 @@ pub struct EditWindowUIState {
meshes: Vec<AssetEditData>, meshes: Vec<AssetEditData>,
structure: StringTree, structure: StringTree,
egui: EditWindowEguiState, 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)] #[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 { app.insert_resource(EditWindowUIState {
brush_color: egui_color_from(Color::RED), brush_color: egui_color_from(Color::RED),
meshes: Vec::new(), meshes: Vec::new(),
@ -157,7 +178,11 @@ pub fn register_edit_ui(app: &mut bevy::prelude::App) -> &mut bevy::prelude::App
app app
} }
pub fn startup_system_edit_ui(commands: Commands, mut shared_ui_state: ResMut<EditWindowUIState>) { pub fn startup_system_edit_ui(
// formatting comment
commands: Commands,
mut shared_ui_state: ResMut<EditWindowUIState>,
) {
spawn_camera(commands); spawn_camera(commands);
shared_ui_state shared_ui_state
.structure .structure
@ -215,10 +240,8 @@ pub fn edit_click_events(
octtree_ray_overlap(&eoct, &obb, ray.origin, ray.direction.normalize()) octtree_ray_overlap(&eoct, &obb, ray.origin, ray.direction.normalize())
}; };
dbg!(&shared_ui_state.egui.windows);
let scale = egui_settings.scale_factor; let scale = egui_settings.scale_factor;
let mod_cursor_pos = Pos2::new(cursor_pos.x / scale, cursor_pos.y / scale); 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 { for rect in &shared_ui_state.egui.windows {
if rect.contains(mod_cursor_pos) { if rect.contains(mod_cursor_pos) {
return; return;
@ -362,10 +385,11 @@ pub fn edit_window_ui(
for window_entity in &windows { for window_entity in &windows {
let ctx = contexts.ctx_for_window_mut(window_entity); let ctx = contexts.ctx_for_window_mut(window_entity);
let pos = ctx.memory(|memory| { let pos = ctx.memory(|memory| {
if !memory.is_popup_open(shared_ui_state.egui.popup_identifier.unwrap()) { if let PopupWindowData::StructureElement(_) = shared_ui_state.popup {
return None; 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 { if let Some(pos) = pos {
shared_ui_state.egui.windows.push(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| { response.show(contexts.ctx_mut(), |ui: &mut egui::Ui| {
ui.label("This tool is in early development.");
ScrollArea::vertical().show(ui, |ui| { ScrollArea::vertical().show(ui, |ui| {
let mut label = String::from("Pre-Alpha"); ui.collapsing("Mesh Tools", |ui| {
use std::fmt::Write; let mut label = String::from("Controls:");
writeln!(label, " Controls:").ok(); writeln!(label, "").ok();
writeln!(label, "click adds a voxel:").ok(); writeln!(label, "click adds a voxel:").ok();
writeln!(label, "R+click removes a voxel:").ok(); writeln!(label, "R+click removes a voxel:").ok();
writeln!(label, "E+click paints (edits) a voxel:").ok(); writeln!(label, "E+click paints (edits) a voxel:").ok();
color_picker::color_picker_hsva_2d( color_picker::color_picker_hsva_2d(
ui, ui,
&mut shared_ui_state.brush_color, &mut shared_ui_state.brush_color,
color_picker::Alpha::Opaque, color_picker::Alpha::Opaque,
); );
ui.label(label); ui.label(label);
let mut color_to_set: Option<Color> = None; let mut color_to_set: Option<Color> = None;
for each in &shared_ui_state.meshes { for each in &shared_ui_state.meshes {
ui.vertical(|ui| { ui.vertical(|ui| {
//color palette clickables. //color palette clickables.
let handle = each.id.clone(); let handle = each.id.clone();
let asset = oct_assets.get(handle); let asset = oct_assets.get(handle);
if asset.is_some() { if asset.is_some() {
let list = { let list = {
let eoct = asset.unwrap().model.read().unwrap(); let eoct = asset.unwrap().model.read().unwrap();
eoct.collect_voxels() eoct.collect_voxels()
}; };
let mut count: Vec<(Color, usize)> = Vec::new(); let mut count: Vec<(Color, usize)> = Vec::new();
fn eq(c1: &Color, c2: &mut Color) -> bool { fn eq(c1: &Color, c2: &mut Color) -> bool {
c1.r() == c2.r() && c1.g() == c2.g() && c1.b() == c2.b() 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;
}
} }
if !is_committed { for (_, _, color) in &list {
count.push((color.clone(), 1)); let mut is_committed = false;
} for (each_col, each_count) in &mut count {
} if eq(color, each_col) {
count.sort_by(|a, b| b.1.cmp(&a.1)); *each_count += 1;
if !count.is_empty() { is_committed = true;
ui.label(each.path.clone()); break;
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 !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 {
if let Some(color) = color_to_set { shared_ui_state.brush_color = egui_color_from(color);
shared_ui_state.brush_color = egui_color_from(color); }
} if ui.button("Add Origin Voxel").clicked() {
if ui.button("Add Origin Voxel").clicked() { //
// for pair in &mut pairs.handles {
for pair in &mut pairs.handles { let id = pair.oct_handle.clone();
let id = pair.oct_handle.clone(); let tree = oct_assets.get_mut(id);
let tree = oct_assets.get_mut(id); if tree.is_some() {
if tree.is_some() { let tree = tree.unwrap();
let tree = tree.unwrap(); {
{ let mut eoct = tree.model.write().unwrap();
let mut eoct = tree.model.write().unwrap(); eoct.set_voxel_at_location(
eoct.set_voxel_at_location( Vec3::ZERO,
Vec3::ZERO, color_from(shared_ui_state.brush_color),
color_from(shared_ui_state.brush_color), );
); }
} }
} }
} }
} });
let response = ui.button("Save Any Changes"); show_editable_stringtree(ui, &mut shared_ui_state);
if response.clicked() { if ui.button("Save Any Changes").clicked() {
//save all files. //save all files.
for each in &mut shared_ui_state.meshes { for each in &mut shared_ui_state.meshes {
if each.has_changed_since_last_save { if each.has_changed_since_last_save {
@ -477,40 +503,67 @@ pub fn edit_window_ui(
); );
if result { if result {
each.has_changed_since_last_save = false; 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( pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
ui: &mut egui::Ui, let mut change_state = None;
state: EditWindowEguiState, let mut reparent = None;
tree: &mut StringTree, match &state.popup {
response: &Response, PopupWindowData::None => return,
) { PopupWindowData::StructureElement(name) => {
egui::popup_below_widget(ui, state.popup_identifier.unwrap(), response, |ui| { //formatting comment
ScrollArea::vertical().show(ui, |ui| { let response = egui::Window::new("edit structure element ".to_owned() + &name.clone())
ui.vertical(|ui| { .id(state.egui.popup_identifier.unwrap());
for _ in 0..100 { response.show(contexts.ctx_mut(), |ui| {
ui.label("filler"); //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.collapsing("Model Structure", |ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
for each in &mut tree.root { for each in &mut state.structure.root {
match each { match each {
super::ui_extensions::StringTreeElement::None => {} super::ui_extensions::StringTreeElement::None => {}
super::ui_extensions::StringTreeElement::Element(name, children) => { super::ui_extensions::StringTreeElement::Element(name, children) => {
@ -518,14 +571,21 @@ pub fn show_editable_stringtree(
ui.label(">".to_owned()); ui.label(">".to_owned());
if ui.button(name.clone()).clicked() { if ui.button(name.clone()).clicked() {
// //
let mut should_close = false;
ui.memory_mut(|mem| { if let PopupWindowData::StructureElement(val) = &state.popup {
mem.toggle_popup(state.popup_identifier.unwrap()) 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() { for each in children.as_ref() {
show_child(ui, each, 1); 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 { match subject {
StringTreeElement::None => {} StringTreeElement::None => {}
StringTreeElement::Element(name, children) => { StringTreeElement::Element(name, children) => {
//
let mut prec = String::from(""); let mut prec = String::from("");
for i in 0..depth { for i in 0..depth {
if i == 0 { if i == 0 {
@ -550,10 +613,22 @@ pub fn show_child(ui: &mut egui::Ui, subject: &mut StringTreeElement, depth: usi
prec = prec + ">"; prec = prec + ">";
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label(prec); 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() { for each in children.as_ref() {
show_child(ui, each, depth + 1); show_child(ui, each, depth + 1, state);
} }
} }
} }

View file

@ -263,6 +263,28 @@ impl StringTree {
} }
false false
} */ } */
pub fn list_of_elements(&self) -> Vec<String> {
let mut list: Vec<String> = 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] #[test]
pub fn test_string_tree() { pub fn test_string_tree() {