finished proof of file load and save. port to multi-grid and multi-structure modality. remaining: selector for structure, selector for grid, exclusivity between the two. transform editor and node-data-editor (grid or light or structure nesting (test for infiniite loop!!))
This commit is contained in:
parent
51805dcbcb
commit
a67beb77bd
|
@ -2,14 +2,16 @@
|
|||
|
||||
use bevy::{diagnostic::FrameTimeDiagnosticsPlugin, prelude::*, window::WindowResolution};
|
||||
|
||||
use crate::vvlib::s_oct_asset::{self, OctAssetMarker, OctTreeAsset};
|
||||
use crate::vvlib::{
|
||||
s_oct_asset::{self, OctAssetMarker, OctTreeAsset},
|
||||
s_structure_asset::StructureAssetPlugin,
|
||||
};
|
||||
|
||||
mod s_editor_bevy_input_shim;
|
||||
pub mod s_editor_ui;
|
||||
mod s_orbit_camera;
|
||||
pub mod s_string_tree;
|
||||
pub mod s_ui_details;
|
||||
|
||||
pub mod s_ui_helpers_and_popup;
|
||||
|
||||
pub fn setup(app: &mut App) -> &mut App {
|
||||
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||
|
@ -21,7 +23,6 @@ pub fn setup(app: &mut App) -> &mut App {
|
|||
..default()
|
||||
}))
|
||||
.add_plugins(s_oct_asset::OctAssetPlugin)
|
||||
.init_asset::<s_oct_asset::OctTreeAsset>()
|
||||
.add_systems(Startup, crate::vvlib::s_fps_display::setup_fps_counter)
|
||||
.add_systems(
|
||||
Update,
|
||||
|
@ -31,6 +32,7 @@ pub fn setup(app: &mut App) -> &mut App {
|
|||
),
|
||||
)
|
||||
.add_plugins(FrameTimeDiagnosticsPlugin::default())
|
||||
.add_plugins(StructureAssetPlugin)
|
||||
.add_systems(Startup, startup);
|
||||
s_editor_ui::register_edit_ui(app)
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ use bevy::{
|
|||
math::Vec3,
|
||||
prelude::default,
|
||||
render::{camera::Camera, color::Color},
|
||||
transform::components::{GlobalTransform, Transform},
|
||||
utils::hashbrown::HashMap,
|
||||
transform::components::GlobalTransform,
|
||||
window::{PrimaryWindow, Window},
|
||||
};
|
||||
use bevy_egui::{
|
||||
|
@ -21,11 +20,8 @@ use bevy_egui::{
|
|||
use crate::{
|
||||
vvedit::s_editor_bevy_input_shim::keybind_codes::REMOVE_VOXEL,
|
||||
vvlib::{
|
||||
s_inputs::InputRegister,
|
||||
s_intersections::octtree_ray_overlap,
|
||||
s_obb::OBB,
|
||||
s_oct_asset::OctAssetMarker,
|
||||
s_structure_asset::{self, StructureAsset},
|
||||
s_inputs::InputRegister, s_intersections::octtree_ray_overlap, s_obb::OBB,
|
||||
s_oct_asset::OctAssetMarker, s_structure_asset::StructureAsset,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
|
@ -36,36 +32,44 @@ use crate::{
|
|||
use super::{
|
||||
s_editor_bevy_input_shim::setup_inputs,
|
||||
s_orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera},
|
||||
s_string_tree::StringTree,
|
||||
s_ui_details::*,
|
||||
s_ui_helpers_and_popup::*,
|
||||
};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
pub struct OctAssetEditData {
|
||||
path: String,
|
||||
id: Handle<OctTreeAsset>,
|
||||
has_changed_since_last_save: bool,
|
||||
pub struct GridEditData {
|
||||
pub path: String,
|
||||
pub id: Handle<OctTreeAsset>,
|
||||
pub has_changed_since_last_save: bool,
|
||||
}
|
||||
pub struct StructureEditData {
|
||||
pub path: String,
|
||||
pub id: Handle<StructureAsset>,
|
||||
pub has_changed_since_last_save: bool,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct EditWindowUIState {
|
||||
brush_color: Hsva,
|
||||
meshes: Vec<OctAssetEditData>,
|
||||
pub structure: StringTree,
|
||||
pub grids: Vec<GridEditData>,
|
||||
pub structures: Vec<StructureEditData>,
|
||||
pub egui: EditWindowEguiState,
|
||||
pub popup: PopupWindowMode,
|
||||
pub selected_structure_element: String,
|
||||
pub selected_structure: String,
|
||||
pub selected_grid: String,
|
||||
}
|
||||
impl Default for EditWindowUIState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
brush_color: Default::default(),
|
||||
meshes: Default::default(),
|
||||
structure: Default::default(),
|
||||
grids: Default::default(),
|
||||
structures: Default::default(),
|
||||
egui: Default::default(),
|
||||
popup: Default::default(),
|
||||
selected_structure_element: "".into(),
|
||||
selected_structure: "".into(),
|
||||
selected_grid: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,8 +77,9 @@ impl Default for EditWindowUIState {
|
|||
pub enum PopupWindowMode {
|
||||
#[default]
|
||||
None,
|
||||
EditStructureElement(String, String), // rename from and to, otherwise second string is unused
|
||||
CreateStructureElement(String, String), // node name, parent node
|
||||
EditStructureElement(String, String, String), // structure subject, rename from and to, otherwise second string is unused
|
||||
CreateStructureElement(String, String, String), // structure subject, node name, parent node
|
||||
LoadFile(String, i32, Vec<String>), // string is current selection from list discovered from disk, number is a timer for refreshing asset list via disk scan
|
||||
}
|
||||
impl PopupWindowMode {
|
||||
pub fn is_none(&self) -> bool {
|
||||
|
@ -103,7 +108,7 @@ impl Default for EditWindowEguiState {
|
|||
// refactor into hashmaps of the AssetId
|
||||
impl EditWindowUIState {
|
||||
pub fn name_from_handle(&self, id: Handle<OctTreeAsset>) -> Option<String> {
|
||||
for each in &self.meshes {
|
||||
for each in &self.grids {
|
||||
if &each.id == &id {
|
||||
return Some(each.path.clone());
|
||||
}
|
||||
|
@ -111,7 +116,7 @@ impl EditWindowUIState {
|
|||
None
|
||||
}
|
||||
pub fn has_changed_from_name(&self, name: &String) -> Option<bool> {
|
||||
for each in &self.meshes {
|
||||
for each in &self.grids {
|
||||
if &each.path == name {
|
||||
return Some(each.has_changed_since_last_save);
|
||||
}
|
||||
|
@ -119,7 +124,7 @@ impl EditWindowUIState {
|
|||
None
|
||||
}
|
||||
pub fn has_changed_from_handle(&self, id: Handle<OctTreeAsset>) -> Option<bool> {
|
||||
for each in &self.meshes {
|
||||
for each in &self.grids {
|
||||
if &each.id == &id {
|
||||
return Some(each.has_changed_since_last_save);
|
||||
}
|
||||
|
@ -127,7 +132,7 @@ impl EditWindowUIState {
|
|||
None
|
||||
}
|
||||
pub fn handle_from_name(&self, name: &String) -> Option<Handle<OctTreeAsset>> {
|
||||
for each in &self.meshes {
|
||||
for each in &self.grids {
|
||||
if &each.path == name {
|
||||
return Some(each.id.clone());
|
||||
}
|
||||
|
@ -141,7 +146,7 @@ impl EditWindowUIState {
|
|||
has_changed: bool,
|
||||
) -> bool {
|
||||
let mut match_count: usize = 0;
|
||||
for each in &self.meshes {
|
||||
for each in &self.grids {
|
||||
if &each.path == path {
|
||||
match_count += 1;
|
||||
} else if &each.id == &id {
|
||||
|
@ -149,7 +154,7 @@ impl EditWindowUIState {
|
|||
}
|
||||
}
|
||||
if match_count == 1 {
|
||||
for each in &mut self.meshes {
|
||||
for each in &mut self.grids {
|
||||
if &each.path == path {
|
||||
each.id = id.clone();
|
||||
each.has_changed_since_last_save = has_changed;
|
||||
|
@ -160,7 +165,7 @@ impl EditWindowUIState {
|
|||
}
|
||||
return true;
|
||||
} else if match_count == 0 {
|
||||
self.meshes.push(OctAssetEditData {
|
||||
self.grids.push(GridEditData {
|
||||
path: path.clone(),
|
||||
id,
|
||||
has_changed_since_last_save: has_changed,
|
||||
|
@ -178,8 +183,7 @@ pub fn register_edit_ui(
|
|||
) -> &mut bevy::prelude::App {
|
||||
app.insert_resource(EditWindowUIState {
|
||||
brush_color: egui_color_from(Color::RED),
|
||||
meshes: Vec::new(),
|
||||
structure: StringTree::new(),
|
||||
grids: Vec::new(),
|
||||
..default()
|
||||
});
|
||||
app.add_plugins(EguiPlugin);
|
||||
|
@ -196,29 +200,17 @@ pub fn startup_system_edit_ui(
|
|||
// formatting comment
|
||||
commands: Commands,
|
||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||
asset_server: ResMut<AssetServer>,
|
||||
) {
|
||||
spawn_camera(commands);
|
||||
shared_ui_state
|
||||
.structure
|
||||
.add_root_level(&String::from("example"));
|
||||
shared_ui_state
|
||||
.structure
|
||||
.add_root_level(&String::from("example2"));
|
||||
shared_ui_state
|
||||
.structure
|
||||
.add(&String::from("c1"), Some(&String::from("example")));
|
||||
shared_ui_state
|
||||
.structure
|
||||
.add(&String::from("c2"), Some(&String::from("c1")));
|
||||
let asset_test = StructureAsset {
|
||||
layout: shared_ui_state.structure.clone(),
|
||||
default_pose_positions: HashMap::<String, Transform>::new(),
|
||||
element_data: Default::default(),
|
||||
let str = "test.vvs";
|
||||
let handle = asset_server.load::<StructureAsset>(str);
|
||||
let data = StructureEditData {
|
||||
path: str.into(),
|
||||
id: handle,
|
||||
has_changed_since_last_save: false,
|
||||
};
|
||||
s_structure_asset::serialization::structures::write_latest_version(
|
||||
&"test.vvs".to_string(),
|
||||
&asset_test,
|
||||
);
|
||||
shared_ui_state.structures.push(data);
|
||||
}
|
||||
fn update_ui_scale_factor(
|
||||
mut egui_settings: ResMut<EguiSettings>,
|
||||
|
@ -234,7 +226,7 @@ pub fn edit_click_events(
|
|||
camera_query: Query<(&Camera, &GlobalTransform)>,
|
||||
oct_tree: Query<(&GlobalTransform, &OctAssetMarker)>,
|
||||
windows: Query<&Window>,
|
||||
mut oct_assets: ResMut<Assets<OctTreeAsset>>,
|
||||
mut grid_assets: ResMut<Assets<OctTreeAsset>>,
|
||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||
egui_settings: Res<EguiSettings>,
|
||||
) {
|
||||
|
@ -252,7 +244,7 @@ pub fn edit_click_events(
|
|||
continue;
|
||||
};
|
||||
let obb = OBB::from_transform(trans.compute_transform());
|
||||
let octtree = oct_assets.get_mut(oct.oct_handle.clone());
|
||||
let octtree = grid_assets.get_mut(oct.oct_handle.clone());
|
||||
if octtree.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
@ -373,10 +365,12 @@ pub fn update_asset_mesh_list(
|
|||
pub fn edit_window_ui(
|
||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||
mut contexts: EguiContexts,
|
||||
mut oct_assets: ResMut<Assets<OctTreeAsset>>,
|
||||
mut grid_assets: ResMut<Assets<OctTreeAsset>>,
|
||||
mut structure_assets: ResMut<Assets<StructureAsset>>,
|
||||
mut pairs: ResMut<MeshingOctTreePairs>,
|
||||
windows: Query<Entity, With<Window>>,
|
||||
window: Query<&Window>,
|
||||
mut asset_server: ResMut<AssetServer>,
|
||||
) {
|
||||
shared_ui_state.egui.windows.clear();
|
||||
let title = String::from("VVEdit");
|
||||
|
@ -407,12 +401,9 @@ pub fn edit_window_ui(
|
|||
} else {
|
||||
for window_entity in &windows {
|
||||
let ctx = contexts.ctx_for_window_mut(window_entity);
|
||||
let pos = ctx.memory(|memory| {
|
||||
if let PopupWindowMode::EditStructureElement(_, _) = shared_ui_state.popup {
|
||||
memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let pos = ctx.memory(|memory| match &shared_ui_state.popup {
|
||||
PopupWindowMode::None => None,
|
||||
_ => memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()),
|
||||
});
|
||||
if let Some(pos) = pos {
|
||||
shared_ui_state.egui.windows.push(pos);
|
||||
|
@ -430,6 +421,9 @@ pub fn edit_window_ui(
|
|||
}
|
||||
|
||||
response.show(contexts.ctx_mut(), |ui: &mut egui::Ui| {
|
||||
if ui.button("test directory list popup").clicked() {
|
||||
shared_ui_state.popup = PopupWindowMode::LoadFile("".into(), 0, Vec::new());
|
||||
}
|
||||
ui.label("This tool is in early development.");
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
ui.collapsing("Mesh Tools", |ui| {
|
||||
|
@ -445,11 +439,11 @@ pub fn edit_window_ui(
|
|||
);
|
||||
ui.label(label);
|
||||
let mut color_to_set: Option<Color> = None;
|
||||
for each in &shared_ui_state.meshes {
|
||||
for each in &shared_ui_state.grids {
|
||||
ui.vertical(|ui| {
|
||||
//color palette clickables.
|
||||
let handle = each.id.clone();
|
||||
let asset = oct_assets.get(handle);
|
||||
let asset = grid_assets.get(handle);
|
||||
if asset.is_some() {
|
||||
let list = {
|
||||
let eoct = asset.unwrap().model.read().unwrap();
|
||||
|
@ -496,7 +490,7 @@ pub fn edit_window_ui(
|
|||
//
|
||||
for pair in &mut pairs.handles {
|
||||
let id = pair.oct_handle.clone();
|
||||
let tree = oct_assets.get_mut(id);
|
||||
let tree = grid_assets.get_mut(id);
|
||||
if tree.is_some() {
|
||||
let tree = tree.unwrap();
|
||||
{
|
||||
|
@ -510,59 +504,94 @@ pub fn edit_window_ui(
|
|||
}
|
||||
}
|
||||
});
|
||||
ui.collapsing("Model Structure", |ui| {
|
||||
ui.vertical(|ui| {
|
||||
if ui.button("add element").clicked() {
|
||||
shared_ui_state.popup = PopupWindowMode::CreateStructureElement(
|
||||
"unnamed".to_owned(),
|
||||
"".to_owned(),
|
||||
);
|
||||
let mut selected_structure = false;
|
||||
let mut selection = None;
|
||||
if shared_ui_state.selected_structure != "" {
|
||||
for structure in &shared_ui_state.structures {
|
||||
if structure.path == shared_ui_state.selected_structure {
|
||||
let asset = structure_assets.get_mut(structure.id.clone());
|
||||
if asset.is_some() {
|
||||
selection = Some(&mut asset.unwrap().layout);
|
||||
selected_structure = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ui.separator();
|
||||
if shared_ui_state.selected_structure_element != "" {
|
||||
if ui.button("Edit Structure of Node").clicked() {
|
||||
let selection = shared_ui_state.selected_structure_element.clone();
|
||||
let mut should_close = false;
|
||||
if let PopupWindowMode::EditStructureElement(val, _) =
|
||||
&shared_ui_state.popup
|
||||
{
|
||||
if val == &selection {
|
||||
should_close = true;
|
||||
}
|
||||
}
|
||||
if should_close {
|
||||
shared_ui_state.popup = PopupWindowMode::None;
|
||||
} else {
|
||||
shared_ui_state.popup = PopupWindowMode::EditStructureElement(
|
||||
shared_ui_state.selected_structure_element.clone(),
|
||||
shared_ui_state.selected_structure_element.clone(),
|
||||
)
|
||||
}
|
||||
ui.label(
|
||||
"Tree Element Selection: ".to_owned()
|
||||
+ &shared_ui_state.selected_structure_element,
|
||||
}
|
||||
}
|
||||
if selected_structure {
|
||||
let selection = selection.unwrap();
|
||||
ui.collapsing("Model Structure", |ui| {
|
||||
ui.vertical(|ui| {
|
||||
if ui.button("add element").clicked() {
|
||||
shared_ui_state.popup = PopupWindowMode::CreateStructureElement(
|
||||
shared_ui_state.selected_structure.clone(),
|
||||
"unnamed".to_owned(),
|
||||
"".to_owned(),
|
||||
);
|
||||
}
|
||||
if ui.button("deselect").clicked() {
|
||||
shared_ui_state.selected_structure_element = "".into();
|
||||
}
|
||||
ui.separator();
|
||||
if shared_ui_state.selected_structure_element != "" {
|
||||
if ui.button("Edit Structure of Node").clicked() {
|
||||
let selection = shared_ui_state.selected_structure_element.clone();
|
||||
let mut should_close = false;
|
||||
if let PopupWindowMode::EditStructureElement(_, val, _) =
|
||||
&shared_ui_state.popup
|
||||
{
|
||||
if val == &selection {
|
||||
should_close = true;
|
||||
}
|
||||
}
|
||||
if should_close {
|
||||
shared_ui_state.popup = PopupWindowMode::None;
|
||||
} else {
|
||||
shared_ui_state.popup = PopupWindowMode::EditStructureElement(
|
||||
shared_ui_state.selected_structure.clone(),
|
||||
shared_ui_state.selected_structure_element.clone(),
|
||||
shared_ui_state.selected_structure_element.clone(),
|
||||
)
|
||||
}
|
||||
ui.label(
|
||||
"Tree Element Selection: ".to_owned()
|
||||
+ &shared_ui_state.selected_structure_element,
|
||||
);
|
||||
}
|
||||
if ui.button("deselect").clicked() {
|
||||
shared_ui_state.selected_structure_element = "".into();
|
||||
}
|
||||
ui.separator();
|
||||
}
|
||||
let mut string_selection =
|
||||
shared_ui_state.selected_structure_element.clone();
|
||||
|
||||
show_stringtree_selector(ui, selection, &mut string_selection);
|
||||
shared_ui_state.selected_structure_element = string_selection;
|
||||
})
|
||||
});
|
||||
}
|
||||
ui.collapsing("grid assets", |ui| {
|
||||
//
|
||||
for (id, _asset) in (&grid_assets).iter() {
|
||||
let path = asset_server.get_path(id.untyped());
|
||||
if let Some(path) = path {
|
||||
ui.label(path.to_string().as_str());
|
||||
}
|
||||
let mut string_selection = shared_ui_state.selected_structure_element.clone();
|
||||
show_stringtree_selector(
|
||||
ui,
|
||||
&mut shared_ui_state.structure,
|
||||
&mut string_selection,
|
||||
);
|
||||
shared_ui_state.selected_structure_element = string_selection;
|
||||
})
|
||||
}
|
||||
});
|
||||
ui.collapsing("structure assets", |ui| {
|
||||
//
|
||||
for (id, _asset) in (&structure_assets).iter() {
|
||||
let path = asset_server.get_path(id.untyped());
|
||||
if let Some(path) = path {
|
||||
ui.label(path.to_string().as_str());
|
||||
}
|
||||
}
|
||||
});
|
||||
if ui.button("Save Any Changes").clicked() {
|
||||
for each in &mut shared_ui_state.meshes {
|
||||
for each in &mut shared_ui_state.grids {
|
||||
if each.has_changed_since_last_save {
|
||||
let handle = each.id.clone();
|
||||
let path = each.path.clone() + ".vvg";
|
||||
let asset = oct_assets.get(handle);
|
||||
let asset = grid_assets.get(handle);
|
||||
if asset.is_some() {
|
||||
let result =
|
||||
crate::vvlib::s_oct_asset::serialization::meshes::write_latest_version(
|
||||
|
@ -578,5 +607,10 @@ pub fn edit_window_ui(
|
|||
}
|
||||
});
|
||||
});
|
||||
show_popup(&mut shared_ui_state, &mut contexts);
|
||||
show_popup(
|
||||
&mut shared_ui_state,
|
||||
&mut contexts,
|
||||
&mut asset_server,
|
||||
&mut structure_assets,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,255 +0,0 @@
|
|||
use std::mem;
|
||||
|
||||
use bevy::render::color::Color;
|
||||
use bevy_egui::{
|
||||
egui::{
|
||||
self,
|
||||
ecolor::{hsv_from_rgb, rgb_from_hsv},
|
||||
epaint::Hsva,
|
||||
},
|
||||
EguiContexts,
|
||||
};
|
||||
|
||||
use crate::vvlib::s_identifier_validation::{self, is_valid};
|
||||
|
||||
use super::{
|
||||
s_editor_ui::{EditWindowUIState, PopupWindowMode},
|
||||
s_string_tree::{StringTree, StringTreeElement},
|
||||
};
|
||||
|
||||
pub fn color_from(egui_color: Hsva) -> Color {
|
||||
let rgb = rgb_from_hsv((egui_color.h, egui_color.s, egui_color.v));
|
||||
return Color::rgb_from_array(rgb);
|
||||
}
|
||||
|
||||
pub fn egui_color_from(color: Color) -> Hsva {
|
||||
let x = hsv_from_rgb([color.r(), color.g(), color.b()]);
|
||||
|
||||
return Hsva::new(x.0, x.1, x.2, 1.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn round_trip_color() {
|
||||
use rand::Rng;
|
||||
let mut rng = rand::thread_rng();
|
||||
let min = 0.;
|
||||
let max = 1.;
|
||||
for _ in 0..10000 {
|
||||
let r = rng.gen_range(min..max);
|
||||
let g = rng.gen_range(min..max);
|
||||
let b = rng.gen_range(min..max);
|
||||
let mut color = Color::rgb(r, g, b);
|
||||
let mut egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
egui_color = egui_color_from(color);
|
||||
color = color_from(egui_color);
|
||||
assert_eq!((color.r() * 255.).floor(), (r * 255.).floor());
|
||||
assert_eq!((color.g() * 255.).floor(), (g * 255.).floor());
|
||||
assert_eq!((color.b() * 255.).floor(), (b * 255.).floor());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) {
|
||||
enum PopupStateChange {
|
||||
None,
|
||||
RemoveStructureElement(bool), //keep children(reparenting upward) or drop
|
||||
}
|
||||
let mut state_change = PopupStateChange::None;
|
||||
let mut change_state = None;
|
||||
let mut reparent = None;
|
||||
let mut rename_complete = false;
|
||||
let mut added_valid_name = false;
|
||||
match &mut state.popup {
|
||||
PopupWindowMode::None => return,
|
||||
PopupWindowMode::EditStructureElement(name, rename) => {
|
||||
//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 + "?");
|
||||
ui.horizontal(|ui| {
|
||||
//.
|
||||
ui.label("rename element: ");
|
||||
let mut rename_string = rename.clone();
|
||||
ui.text_edit_singleline(&mut rename_string);
|
||||
if s_identifier_validation::is_valid(rename_string.clone()) {
|
||||
*rename = rename_string;
|
||||
}
|
||||
if ui.button("Confirm and change name").clicked() {
|
||||
//.
|
||||
rename_complete = true;
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("remove and reparent to parent").clicked() {
|
||||
state_change = PopupStateChange::RemoveStructureElement(true);
|
||||
}
|
||||
if ui.button("remove and drop children").clicked() {
|
||||
state_change = PopupStateChange::RemoveStructureElement(false);
|
||||
}
|
||||
});
|
||||
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())
|
||||
&& !state.structure.is_upstream_of(&cur, &each)
|
||||
{
|
||||
if ui.button(&each).clicked() {
|
||||
reparent = Some((cur.clone(), each));
|
||||
change_state = Some(PopupWindowMode::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
if state.structure.parent_of(&cur).is_some() {
|
||||
if ui.button("None").clicked() {
|
||||
reparent = Some((cur.clone(), "".into()));
|
||||
change_state = Some(PopupWindowMode::None);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// todo: rename action. edit subject action (mesh, light), remove action (with, without reparenting)
|
||||
if ui.button("Cancel").clicked() {
|
||||
change_state = Some(PopupWindowMode::None);
|
||||
}
|
||||
});
|
||||
}
|
||||
PopupWindowMode::CreateStructureElement(name, parent) => {
|
||||
//
|
||||
let response = egui::Window::new("new structure element ".to_owned() + &name.clone())
|
||||
.id(state.egui.popup_identifier.unwrap());
|
||||
response.show(contexts.ctx_mut(), |ui| {
|
||||
ui.label("please name the new structure node.");
|
||||
let mut newname = name.clone();
|
||||
ui.text_edit_singleline(&mut newname);
|
||||
if is_valid(newname.clone()) && !state.structure.is_present(&newname) {
|
||||
*name = newname;
|
||||
}
|
||||
if ui.button("Confirm and add.").clicked() {
|
||||
added_valid_name = true;
|
||||
}
|
||||
ui.collapsing(
|
||||
"parent status: ".to_owned() + parent.clone().as_str(),
|
||||
|ui| {
|
||||
ui.vertical(|ui| {
|
||||
ui.radio_value(parent, "".into(), "Root level - no parent");
|
||||
for each in state.structure.list_of_elements() {
|
||||
ui.radio_value(parent, each.clone(), each.clone());
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
if change_state.is_some() {
|
||||
state.popup = change_state.unwrap();
|
||||
}
|
||||
if let Some((cur, next)) = reparent {
|
||||
if next != "" {
|
||||
state.structure.move_branch(&cur, &next);
|
||||
} else {
|
||||
state.structure.deparent(&cur);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if rename_complete {
|
||||
if let PopupWindowMode::EditStructureElement(old, new) = &state.popup {
|
||||
state.structure.rename(old, new);
|
||||
if &state.selected_structure_element == old {
|
||||
state.selected_structure_element = new.clone();
|
||||
}
|
||||
}
|
||||
state.popup = PopupWindowMode::None;
|
||||
}
|
||||
if added_valid_name {
|
||||
if let PopupWindowMode::CreateStructureElement(name, parent) = &state.popup {
|
||||
let par = if parent == "" { None } else { Some(parent) };
|
||||
state.structure.add(name, par);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
state.popup = PopupWindowMode::None;
|
||||
}
|
||||
match state_change {
|
||||
PopupStateChange::None => {} // nothing to do if state does not change
|
||||
PopupStateChange::RemoveStructureElement(keep_children) => {
|
||||
let mut consumed = PopupWindowMode::None;
|
||||
mem::swap(&mut state.popup, &mut consumed);
|
||||
if let PopupWindowMode::EditStructureElement(subject, _) = consumed {
|
||||
if keep_children {
|
||||
state.structure.remove_element_preserve_branch(&subject);
|
||||
} else {
|
||||
state.structure.remove_branch(&subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_stringtree_selector(ui: &mut egui::Ui, tree: &StringTree, selection: &mut String) {
|
||||
for each in &tree.root {
|
||||
match each {
|
||||
super::s_string_tree::StringTreeElement::None => {}
|
||||
super::s_string_tree::StringTreeElement::Element(name, children) => {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(">".to_owned());
|
||||
//ui.label(name.clone());
|
||||
ui.radio_value(selection, name.clone(), name.clone());
|
||||
});
|
||||
for each in children.as_ref() {
|
||||
show_child(ui, each, 1, selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn show_child(
|
||||
ui: &mut egui::Ui,
|
||||
subject: &StringTreeElement,
|
||||
depth: usize,
|
||||
selection: &mut String,
|
||||
) {
|
||||
match subject {
|
||||
StringTreeElement::None => {}
|
||||
StringTreeElement::Element(name, children) => {
|
||||
let mut prec = String::from("");
|
||||
for i in 0..depth {
|
||||
if i == 0 {
|
||||
prec = prec + "+";
|
||||
} else {
|
||||
prec = prec + "+";
|
||||
}
|
||||
}
|
||||
prec = prec + ">";
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(prec);
|
||||
ui.radio_value(selection, name.clone(), name.clone());
|
||||
});
|
||||
for each in children.as_ref() {
|
||||
show_child(ui, each, depth + 1, selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -384,6 +384,7 @@ pub struct OctAssetPlugin;
|
|||
impl Plugin for OctAssetPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_asset_loader::<OctLoader>();
|
||||
app.init_asset::<OctTreeAsset>();
|
||||
app.add_systems(Update, (attach_mesh_handle, oct_asset_to_mesh));
|
||||
app.insert_resource(MeshingOctTreePairs {
|
||||
handles: Vec::new(),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use bevy::{
|
||||
asset::{Asset, AssetLoader, AssetServer, AsyncReadExt, Handle},
|
||||
app::{App, Plugin},
|
||||
asset::{Asset, AssetApp, AssetLoader, AssetServer, AsyncReadExt, Handle},
|
||||
reflect::TypePath,
|
||||
transform::components::Transform,
|
||||
utils::{hashbrown::HashMap, thiserror},
|
||||
|
@ -76,6 +77,13 @@ impl ElementData {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct StructureAssetPlugin;
|
||||
impl Plugin for StructureAssetPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_asset_loader::<StructureLoader>();
|
||||
app.init_asset::<StructureAsset>();
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct StructureLoader {
|
||||
//can anything even be put in here?
|
||||
|
@ -454,7 +462,7 @@ pub mod serialization {
|
|||
}
|
||||
}
|
||||
// ^ NODE DATA SUCH AS RELIANT GRIDS (optional)
|
||||
Err(StructureLoadError::FileDataInvalid("".to_string()))
|
||||
return Ok(result);
|
||||
}
|
||||
pub fn save(asset: &StructureAsset) -> Option<Vec<u8>> {
|
||||
const NEWLINE: &str = "\n";
|
||||
|
|
Loading…
Reference in a new issue