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 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;
|
mod s_editor_bevy_input_shim;
|
||||||
pub mod s_editor_ui;
|
pub mod s_editor_ui;
|
||||||
mod s_orbit_camera;
|
mod s_orbit_camera;
|
||||||
pub mod s_string_tree;
|
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 {
|
pub fn setup(app: &mut App) -> &mut App {
|
||||||
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
app.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||||
|
@ -21,7 +23,6 @@ pub fn setup(app: &mut App) -> &mut App {
|
||||||
..default()
|
..default()
|
||||||
}))
|
}))
|
||||||
.add_plugins(s_oct_asset::OctAssetPlugin)
|
.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(Startup, crate::vvlib::s_fps_display::setup_fps_counter)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
|
@ -31,6 +32,7 @@ pub fn setup(app: &mut App) -> &mut App {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.add_plugins(FrameTimeDiagnosticsPlugin::default())
|
.add_plugins(FrameTimeDiagnosticsPlugin::default())
|
||||||
|
.add_plugins(StructureAssetPlugin)
|
||||||
.add_systems(Startup, startup);
|
.add_systems(Startup, startup);
|
||||||
s_editor_ui::register_edit_ui(app)
|
s_editor_ui::register_edit_ui(app)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@ use bevy::{
|
||||||
math::Vec3,
|
math::Vec3,
|
||||||
prelude::default,
|
prelude::default,
|
||||||
render::{camera::Camera, color::Color},
|
render::{camera::Camera, color::Color},
|
||||||
transform::components::{GlobalTransform, Transform},
|
transform::components::GlobalTransform,
|
||||||
utils::hashbrown::HashMap,
|
|
||||||
window::{PrimaryWindow, Window},
|
window::{PrimaryWindow, Window},
|
||||||
};
|
};
|
||||||
use bevy_egui::{
|
use bevy_egui::{
|
||||||
|
@ -21,11 +20,8 @@ use bevy_egui::{
|
||||||
use crate::{
|
use crate::{
|
||||||
vvedit::s_editor_bevy_input_shim::keybind_codes::REMOVE_VOXEL,
|
vvedit::s_editor_bevy_input_shim::keybind_codes::REMOVE_VOXEL,
|
||||||
vvlib::{
|
vvlib::{
|
||||||
s_inputs::InputRegister,
|
s_inputs::InputRegister, s_intersections::octtree_ray_overlap, s_obb::OBB,
|
||||||
s_intersections::octtree_ray_overlap,
|
s_oct_asset::OctAssetMarker, s_structure_asset::StructureAsset,
|
||||||
s_obb::OBB,
|
|
||||||
s_oct_asset::OctAssetMarker,
|
|
||||||
s_structure_asset::{self, StructureAsset},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -36,36 +32,44 @@ use crate::{
|
||||||
use super::{
|
use super::{
|
||||||
s_editor_bevy_input_shim::setup_inputs,
|
s_editor_bevy_input_shim::setup_inputs,
|
||||||
s_orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera},
|
s_orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera},
|
||||||
s_string_tree::StringTree,
|
s_ui_helpers_and_popup::*,
|
||||||
s_ui_details::*,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub struct OctAssetEditData {
|
pub struct GridEditData {
|
||||||
path: String,
|
pub path: String,
|
||||||
id: Handle<OctTreeAsset>,
|
pub id: Handle<OctTreeAsset>,
|
||||||
has_changed_since_last_save: bool,
|
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)]
|
#[derive(Resource)]
|
||||||
pub struct EditWindowUIState {
|
pub struct EditWindowUIState {
|
||||||
brush_color: Hsva,
|
brush_color: Hsva,
|
||||||
meshes: Vec<OctAssetEditData>,
|
pub grids: Vec<GridEditData>,
|
||||||
pub structure: StringTree,
|
pub structures: Vec<StructureEditData>,
|
||||||
pub egui: EditWindowEguiState,
|
pub egui: EditWindowEguiState,
|
||||||
pub popup: PopupWindowMode,
|
pub popup: PopupWindowMode,
|
||||||
pub selected_structure_element: String,
|
pub selected_structure_element: String,
|
||||||
|
pub selected_structure: String,
|
||||||
|
pub selected_grid: String,
|
||||||
}
|
}
|
||||||
impl Default for EditWindowUIState {
|
impl Default for EditWindowUIState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
brush_color: Default::default(),
|
brush_color: Default::default(),
|
||||||
meshes: Default::default(),
|
grids: Default::default(),
|
||||||
structure: Default::default(),
|
structures: Default::default(),
|
||||||
egui: Default::default(),
|
egui: Default::default(),
|
||||||
popup: Default::default(),
|
popup: Default::default(),
|
||||||
selected_structure_element: "".into(),
|
selected_structure_element: "".into(),
|
||||||
|
selected_structure: "".into(),
|
||||||
|
selected_grid: "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,8 +77,9 @@ impl Default for EditWindowUIState {
|
||||||
pub enum PopupWindowMode {
|
pub enum PopupWindowMode {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
EditStructureElement(String, String), // rename from and to, otherwise second string is unused
|
EditStructureElement(String, String, String), // structure subject, rename from and to, otherwise second string is unused
|
||||||
CreateStructureElement(String, String), // node name, parent node
|
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 {
|
impl PopupWindowMode {
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
|
@ -103,7 +108,7 @@ impl Default for EditWindowEguiState {
|
||||||
// refactor into hashmaps of the AssetId
|
// refactor into hashmaps of the AssetId
|
||||||
impl EditWindowUIState {
|
impl EditWindowUIState {
|
||||||
pub fn name_from_handle(&self, id: Handle<OctTreeAsset>) -> Option<String> {
|
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 {
|
if &each.id == &id {
|
||||||
return Some(each.path.clone());
|
return Some(each.path.clone());
|
||||||
}
|
}
|
||||||
|
@ -111,7 +116,7 @@ impl EditWindowUIState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn has_changed_from_name(&self, name: &String) -> Option<bool> {
|
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 {
|
if &each.path == name {
|
||||||
return Some(each.has_changed_since_last_save);
|
return Some(each.has_changed_since_last_save);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +124,7 @@ impl EditWindowUIState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn has_changed_from_handle(&self, id: Handle<OctTreeAsset>) -> Option<bool> {
|
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 {
|
if &each.id == &id {
|
||||||
return Some(each.has_changed_since_last_save);
|
return Some(each.has_changed_since_last_save);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +132,7 @@ impl EditWindowUIState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn handle_from_name(&self, name: &String) -> Option<Handle<OctTreeAsset>> {
|
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 {
|
if &each.path == name {
|
||||||
return Some(each.id.clone());
|
return Some(each.id.clone());
|
||||||
}
|
}
|
||||||
|
@ -141,7 +146,7 @@ impl EditWindowUIState {
|
||||||
has_changed: bool,
|
has_changed: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut match_count: usize = 0;
|
let mut match_count: usize = 0;
|
||||||
for each in &self.meshes {
|
for each in &self.grids {
|
||||||
if &each.path == path {
|
if &each.path == path {
|
||||||
match_count += 1;
|
match_count += 1;
|
||||||
} else if &each.id == &id {
|
} else if &each.id == &id {
|
||||||
|
@ -149,7 +154,7 @@ impl EditWindowUIState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if match_count == 1 {
|
if match_count == 1 {
|
||||||
for each in &mut self.meshes {
|
for each in &mut self.grids {
|
||||||
if &each.path == path {
|
if &each.path == path {
|
||||||
each.id = id.clone();
|
each.id = id.clone();
|
||||||
each.has_changed_since_last_save = has_changed;
|
each.has_changed_since_last_save = has_changed;
|
||||||
|
@ -160,7 +165,7 @@ impl EditWindowUIState {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if match_count == 0 {
|
} else if match_count == 0 {
|
||||||
self.meshes.push(OctAssetEditData {
|
self.grids.push(GridEditData {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
id,
|
id,
|
||||||
has_changed_since_last_save: has_changed,
|
has_changed_since_last_save: has_changed,
|
||||||
|
@ -178,8 +183,7 @@ pub fn register_edit_ui(
|
||||||
) -> &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(),
|
grids: Vec::new(),
|
||||||
structure: StringTree::new(),
|
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
app.add_plugins(EguiPlugin);
|
app.add_plugins(EguiPlugin);
|
||||||
|
@ -196,29 +200,17 @@ pub fn startup_system_edit_ui(
|
||||||
// formatting comment
|
// formatting comment
|
||||||
commands: Commands,
|
commands: Commands,
|
||||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||||
|
asset_server: ResMut<AssetServer>,
|
||||||
) {
|
) {
|
||||||
spawn_camera(commands);
|
spawn_camera(commands);
|
||||||
shared_ui_state
|
let str = "test.vvs";
|
||||||
.structure
|
let handle = asset_server.load::<StructureAsset>(str);
|
||||||
.add_root_level(&String::from("example"));
|
let data = StructureEditData {
|
||||||
shared_ui_state
|
path: str.into(),
|
||||||
.structure
|
id: handle,
|
||||||
.add_root_level(&String::from("example2"));
|
has_changed_since_last_save: false,
|
||||||
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(),
|
|
||||||
};
|
};
|
||||||
s_structure_asset::serialization::structures::write_latest_version(
|
shared_ui_state.structures.push(data);
|
||||||
&"test.vvs".to_string(),
|
|
||||||
&asset_test,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
fn update_ui_scale_factor(
|
fn update_ui_scale_factor(
|
||||||
mut egui_settings: ResMut<EguiSettings>,
|
mut egui_settings: ResMut<EguiSettings>,
|
||||||
|
@ -234,7 +226,7 @@ pub fn edit_click_events(
|
||||||
camera_query: Query<(&Camera, &GlobalTransform)>,
|
camera_query: Query<(&Camera, &GlobalTransform)>,
|
||||||
oct_tree: Query<(&GlobalTransform, &OctAssetMarker)>,
|
oct_tree: Query<(&GlobalTransform, &OctAssetMarker)>,
|
||||||
windows: Query<&Window>,
|
windows: Query<&Window>,
|
||||||
mut oct_assets: ResMut<Assets<OctTreeAsset>>,
|
mut grid_assets: ResMut<Assets<OctTreeAsset>>,
|
||||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||||
egui_settings: Res<EguiSettings>,
|
egui_settings: Res<EguiSettings>,
|
||||||
) {
|
) {
|
||||||
|
@ -252,7 +244,7 @@ pub fn edit_click_events(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let obb = OBB::from_transform(trans.compute_transform());
|
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() {
|
if octtree.is_none() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -373,10 +365,12 @@ pub fn update_asset_mesh_list(
|
||||||
pub fn edit_window_ui(
|
pub fn edit_window_ui(
|
||||||
mut shared_ui_state: ResMut<EditWindowUIState>,
|
mut shared_ui_state: ResMut<EditWindowUIState>,
|
||||||
mut contexts: EguiContexts,
|
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>,
|
mut pairs: ResMut<MeshingOctTreePairs>,
|
||||||
windows: Query<Entity, With<Window>>,
|
windows: Query<Entity, With<Window>>,
|
||||||
window: Query<&Window>,
|
window: Query<&Window>,
|
||||||
|
mut asset_server: ResMut<AssetServer>,
|
||||||
) {
|
) {
|
||||||
shared_ui_state.egui.windows.clear();
|
shared_ui_state.egui.windows.clear();
|
||||||
let title = String::from("VVEdit");
|
let title = String::from("VVEdit");
|
||||||
|
@ -407,12 +401,9 @@ pub fn edit_window_ui(
|
||||||
} else {
|
} else {
|
||||||
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| match &shared_ui_state.popup {
|
||||||
if let PopupWindowMode::EditStructureElement(_, _) = shared_ui_state.popup {
|
PopupWindowMode::None => None,
|
||||||
memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap())
|
_ => memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()),
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if let Some(pos) = pos {
|
if let Some(pos) = pos {
|
||||||
shared_ui_state.egui.windows.push(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| {
|
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.");
|
ui.label("This tool is in early development.");
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.collapsing("Mesh Tools", |ui| {
|
ui.collapsing("Mesh Tools", |ui| {
|
||||||
|
@ -445,11 +439,11 @@ pub fn edit_window_ui(
|
||||||
);
|
);
|
||||||
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.grids {
|
||||||
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 = grid_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();
|
||||||
|
@ -496,7 +490,7 @@ pub fn edit_window_ui(
|
||||||
//
|
//
|
||||||
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 = grid_assets.get_mut(id);
|
||||||
if tree.is_some() {
|
if tree.is_some() {
|
||||||
let tree = tree.unwrap();
|
let tree = tree.unwrap();
|
||||||
{
|
{
|
||||||
|
@ -510,59 +504,94 @@ pub fn edit_window_ui(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.collapsing("Model Structure", |ui| {
|
let mut selected_structure = false;
|
||||||
ui.vertical(|ui| {
|
let mut selection = None;
|
||||||
if ui.button("add element").clicked() {
|
if shared_ui_state.selected_structure != "" {
|
||||||
shared_ui_state.popup = PopupWindowMode::CreateStructureElement(
|
for structure in &shared_ui_state.structures {
|
||||||
"unnamed".to_owned(),
|
if structure.path == shared_ui_state.selected_structure {
|
||||||
"".to_owned(),
|
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() {
|
if selected_structure {
|
||||||
let selection = shared_ui_state.selected_structure_element.clone();
|
let selection = selection.unwrap();
|
||||||
let mut should_close = false;
|
ui.collapsing("Model Structure", |ui| {
|
||||||
if let PopupWindowMode::EditStructureElement(val, _) =
|
ui.vertical(|ui| {
|
||||||
&shared_ui_state.popup
|
if ui.button("add element").clicked() {
|
||||||
{
|
shared_ui_state.popup = PopupWindowMode::CreateStructureElement(
|
||||||
if val == &selection {
|
shared_ui_state.selected_structure.clone(),
|
||||||
should_close = true;
|
"unnamed".to_owned(),
|
||||||
}
|
"".to_owned(),
|
||||||
}
|
|
||||||
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 ui.button("deselect").clicked() {
|
|
||||||
shared_ui_state.selected_structure_element = "".into();
|
|
||||||
}
|
|
||||||
ui.separator();
|
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,
|
ui.collapsing("structure assets", |ui| {
|
||||||
&mut shared_ui_state.structure,
|
//
|
||||||
&mut string_selection,
|
for (id, _asset) in (&structure_assets).iter() {
|
||||||
);
|
let path = asset_server.get_path(id.untyped());
|
||||||
shared_ui_state.selected_structure_element = string_selection;
|
if let Some(path) = path {
|
||||||
})
|
ui.label(path.to_string().as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if ui.button("Save Any Changes").clicked() {
|
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 {
|
if each.has_changed_since_last_save {
|
||||||
let handle = each.id.clone();
|
let handle = each.id.clone();
|
||||||
let path = each.path.clone() + ".vvg";
|
let path = each.path.clone() + ".vvg";
|
||||||
let asset = oct_assets.get(handle);
|
let asset = grid_assets.get(handle);
|
||||||
if asset.is_some() {
|
if asset.is_some() {
|
||||||
let result =
|
let result =
|
||||||
crate::vvlib::s_oct_asset::serialization::meshes::write_latest_version(
|
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 {
|
impl Plugin for OctAssetPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_asset_loader::<OctLoader>();
|
app.init_asset_loader::<OctLoader>();
|
||||||
|
app.init_asset::<OctTreeAsset>();
|
||||||
app.add_systems(Update, (attach_mesh_handle, oct_asset_to_mesh));
|
app.add_systems(Update, (attach_mesh_handle, oct_asset_to_mesh));
|
||||||
app.insert_resource(MeshingOctTreePairs {
|
app.insert_resource(MeshingOctTreePairs {
|
||||||
handles: Vec::new(),
|
handles: Vec::new(),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{Asset, AssetLoader, AssetServer, AsyncReadExt, Handle},
|
app::{App, Plugin},
|
||||||
|
asset::{Asset, AssetApp, AssetLoader, AssetServer, AsyncReadExt, Handle},
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
transform::components::Transform,
|
transform::components::Transform,
|
||||||
utils::{hashbrown::HashMap, thiserror},
|
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)]
|
#[derive(Default)]
|
||||||
pub struct StructureLoader {
|
pub struct StructureLoader {
|
||||||
//can anything even be put in here?
|
//can anything even be put in here?
|
||||||
|
@ -454,7 +462,7 @@ pub mod serialization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ^ NODE DATA SUCH AS RELIANT GRIDS (optional)
|
// ^ NODE DATA SUCH AS RELIANT GRIDS (optional)
|
||||||
Err(StructureLoadError::FileDataInvalid("".to_string()))
|
return Ok(result);
|
||||||
}
|
}
|
||||||
pub fn save(asset: &StructureAsset) -> Option<Vec<u8>> {
|
pub fn save(asset: &StructureAsset) -> Option<Vec<u8>> {
|
||||||
const NEWLINE: &str = "\n";
|
const NEWLINE: &str = "\n";
|
||||||
|
|
Loading…
Reference in a new issue