mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
Merge branch 'FyroxEngine:master' into tiles
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
name: audit
|
||||
|
||||
# This is a separate file so it can have a separate badge in readme
|
||||
# and therefore spread awareness of cargo audit a tiny bit.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
schedule:
|
||||
# Runs at 15:00 UTC on Fri
|
||||
- cron: "0 15 * * 5"
|
||||
workflow_dispatch:
|
||||
# This allows running it on any branch manually:
|
||||
# https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# Actions-rs/install is unmaintained but works for now.
|
||||
# Alternatives for when it breaks:
|
||||
# - dtolnay/install - not a full replacement - only supports crates he uses (not audit currently)
|
||||
# - baptiste0928/cargo-install - looks like it just compiles the crate and then caches it for subsequent runs
|
||||
# - just `cargo install` and caching it
|
||||
- uses: actions-rs/[email protected]
|
||||
with:
|
||||
crate: cargo-audit
|
||||
version: latest
|
||||
- run: cargo audit --version
|
||||
# RUSTSEC-2020-0097: xcb - Soundness issue with base::Error
|
||||
# RUSTSEC-2022-0048: xml-rs is Unmaintained
|
||||
# For more info: https://github.com/FyroxEngine/Fyrox/issues/208
|
||||
- run: cargo audit --deny warnings --ignore RUSTSEC-2020-0097 --ignore RUSTSEC-2022-0048 --ignore RUSTSEC-2021-0140
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
[](https://github.com/FyroxEngine/Fyrox/blob/master/LICENSE.md)
|
||||
[](https://github.com/FyroxEngine/Fyrox/actions/workflows/ci.yml)
|
||||
[](https://github.com/FyroxEngine/Fyrox/actions/workflows/audit.yml)
|
||||
[](https://deps.rs/repo/github/FyroxEngine/Fyrox)
|
||||
[](https://crates.io/crates/fyrox)
|
||||
[](https://docs.rs/Fyrox/)
|
||||
|
||||
@@ -37,9 +37,8 @@ use crate::fyrox::{
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
inspector::editors::make_property_editors_container, message::MessageSender, MSG_SYNC_FLAG,
|
||||
};
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{message::MessageSender, MSG_SYNC_FLAG};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -39,7 +39,7 @@ use crate::{
|
||||
text::TextBuilder,
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
BuildContext, Control, HorizontalAlignment, RcUiNodeHandle, Thickness, UiNode,
|
||||
UserInterface, BRUSH_DARKER, BRUSH_DARKEST,
|
||||
UserInterface,
|
||||
},
|
||||
material::Material,
|
||||
scene::tilemap::tileset::TileSet,
|
||||
@@ -47,6 +47,8 @@ use crate::{
|
||||
message::MessageSender,
|
||||
Message,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
@@ -254,14 +256,14 @@ fn make_tooltip(ctx: &mut BuildContext, text: &str) -> RcUiNodeHandle {
|
||||
let handle = BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_visibility(false)
|
||||
.with_foreground(BRUSH_DARKEST)
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_DARKEST))
|
||||
.with_background(Brush::Solid(Color::opaque(230, 230, 230)))
|
||||
.with_max_size(Vector2::new(300.0, f32::INFINITY))
|
||||
.with_child(
|
||||
TextBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.with_foreground(BRUSH_DARKER),
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_DARKER)),
|
||||
)
|
||||
.with_wrap(WrapMode::Letter)
|
||||
.with_text(text)
|
||||
@@ -337,7 +339,7 @@ impl AssetItemBuilder {
|
||||
.add_row(Row::auto())
|
||||
.build(ctx),
|
||||
)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
path,
|
||||
preview,
|
||||
selected: false,
|
||||
@@ -347,3 +349,18 @@ impl AssetItemBuilder {
|
||||
ctx.add_node(UiNode::new(item))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::asset::item::AssetItemBuilder;
|
||||
use fyrox::asset::manager::ResourceManager;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
let rm = ResourceManager::new(Default::default());
|
||||
test_widget_deletion(|ctx| {
|
||||
AssetItemBuilder::new(WidgetBuilder::new()).build(rm, Default::default(), ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ use crate::{
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
BuildContext, HorizontalAlignment, Orientation, RcUiNodeHandle, Thickness, UiNode,
|
||||
UserInterface, VerticalAlignment, BRUSH_DARK,
|
||||
UserInterface, VerticalAlignment,
|
||||
},
|
||||
resource::{model::Model, texture::Texture},
|
||||
scene::sound::SoundBuffer,
|
||||
@@ -74,6 +74,8 @@ use crate::{
|
||||
utils::window_content,
|
||||
Message, Mode,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
@@ -620,7 +622,7 @@ impl AssetBrowser {
|
||||
ctx,
|
||||
18.0,
|
||||
18.0,
|
||||
load_image(include_bytes!("../../resources/reimport.png")),
|
||||
load_image!("../../resources/reimport.png"),
|
||||
"Refresh",
|
||||
Some(1),
|
||||
);
|
||||
@@ -659,7 +661,7 @@ impl AssetBrowser {
|
||||
.with_child(
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(BRUSH_DARK)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARK))
|
||||
.with_child({
|
||||
folder_browser = FileBrowserBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
@@ -819,7 +821,7 @@ impl AssetBrowser {
|
||||
WidgetBuilder::new().with_context_menu(self.context_menu.menu.clone()),
|
||||
)
|
||||
.with_icon(if is_dir {
|
||||
load_image(include_bytes!("../../resources/folder.png"))
|
||||
load_image!("../../resources/folder.png")
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@@ -924,9 +926,7 @@ impl AssetBrowser {
|
||||
let asset_item = AssetItemBuilder::new(
|
||||
WidgetBuilder::new().with_context_menu(self.context_menu.menu.clone()),
|
||||
)
|
||||
.with_icon(load_image(include_bytes!(
|
||||
"../../resources/folder_return.png"
|
||||
)))
|
||||
.with_icon(load_image!("../../resources/folder_return.png"))
|
||||
.with_path(parent_path)
|
||||
.build(
|
||||
resource_manager.clone(),
|
||||
|
||||
@@ -285,7 +285,7 @@ impl AssetPreviewGenerator for SoundPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/sound.png"))
|
||||
load_image!("../../../resources/sound.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ impl AssetPreviewGenerator for ModelPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/model.png"))
|
||||
load_image!("../../../resources/model.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ impl AssetPreviewGenerator for SurfaceDataPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/model.png"))
|
||||
load_image!("../../../resources/model.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ impl AssetPreviewGenerator for ShaderPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/shader.png"))
|
||||
load_image!("../../../resources/shader.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@ impl AssetPreviewGenerator for MaterialPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/material.png"))
|
||||
load_image!("../../../resources/material.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +570,7 @@ impl AssetPreviewGenerator for HrirPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/hrir.png"))
|
||||
load_image!("../../../resources/hrir.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ impl AssetPreviewGenerator for CurvePreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/curve.png"))
|
||||
load_image!("../../../resources/curve.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +678,7 @@ impl AssetPreviewGenerator for FontPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/font.png"))
|
||||
load_image!("../../../resources/font.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,6 +713,6 @@ impl AssetPreviewGenerator for UserInterfacePreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/ui.png"))
|
||||
load_image!("../../../resources/ui.png")
|
||||
}
|
||||
}
|
||||
|
||||
+21
-8
@@ -35,11 +35,13 @@ use crate::fyrox::{
|
||||
utils::make_simple_tooltip,
|
||||
widget::{Widget, WidgetBuilder},
|
||||
BuildContext, Control, HorizontalAlignment, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_LIGHTER,
|
||||
VerticalAlignment,
|
||||
},
|
||||
scene::sound::{AudioBus, AudioBusGraph},
|
||||
};
|
||||
use crate::gui::make_dropdown_list_option;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -136,12 +138,12 @@ fn make_items(buses: &[(Handle<AudioBus>, String)], ctx: &mut BuildContext) -> V
|
||||
|
||||
fn make_effect_names(names: &[String], ctx: &mut BuildContext) -> Vec<Handle<UiNode>> {
|
||||
if names.is_empty() {
|
||||
vec![
|
||||
TextBuilder::new(WidgetBuilder::new().with_foreground(BRUSH_LIGHTER))
|
||||
.with_text("No Effects")
|
||||
.with_horizontal_text_alignment(HorizontalAlignment::Center)
|
||||
.build(ctx),
|
||||
]
|
||||
vec![TextBuilder::new(
|
||||
WidgetBuilder::new().with_foreground(ctx.style.get_or_default(Style::BRUSH_LIGHTER)),
|
||||
)
|
||||
.with_text("No Effects")
|
||||
.with_horizontal_text_alignment(HorizontalAlignment::Center)
|
||||
.build(ctx)]
|
||||
} else {
|
||||
names
|
||||
.iter()
|
||||
@@ -281,7 +283,7 @@ impl AudioBusViewBuilder {
|
||||
))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
bus: self.bus,
|
||||
parent_bus_selector,
|
||||
possible_parent_buses: self
|
||||
@@ -295,3 +297,14 @@ impl AudioBusViewBuilder {
|
||||
ctx.add_node(UiNode::new(view))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::audio::bus::AudioBusViewBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| AudioBusViewBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::inspector::editors::resource::{ResourceFieldBuilder, ResourceFieldMessage};
|
||||
use crate::{
|
||||
audio::bus::{AudioBusView, AudioBusViewBuilder, AudioBusViewMessage},
|
||||
command::CommandGroup,
|
||||
@@ -41,7 +42,6 @@ use crate::{
|
||||
scene::sound::{AudioBus, AudioBusGraph, DistanceModel, HrirSphereResourceData, Renderer},
|
||||
},
|
||||
gui::make_dropdown_list_option,
|
||||
inspector::editors::resource::{ResourceFieldBuilder, ResourceFieldMessage},
|
||||
message::MessageSender,
|
||||
scene::{
|
||||
commands::{
|
||||
|
||||
+3
-2
@@ -31,10 +31,11 @@ use crate::fyrox::{
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
BRUSH_DARKEST,
|
||||
},
|
||||
};
|
||||
use crate::{message::MessageSender, Message};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
io::{BufRead, BufReader},
|
||||
process::ChildStderr,
|
||||
@@ -78,7 +79,7 @@ impl BuildWindow {
|
||||
WidgetBuilder::new()
|
||||
.on_row(1)
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.with_background(BRUSH_DARKEST)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARKEST))
|
||||
.with_child({
|
||||
scroll_viewer =
|
||||
ScrollViewerBuilder::new(WidgetBuilder::new())
|
||||
|
||||
+44
-39
@@ -18,23 +18,23 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::graph::SceneGraph;
|
||||
use crate::fyrox::gui::{HorizontalAlignment, Thickness};
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
engine::Engine,
|
||||
gui::{
|
||||
check_box::{CheckBoxBuilder, CheckBoxMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, Orientation, UiNode, VerticalAlignment,
|
||||
},
|
||||
scene::{camera::Camera, node::Node},
|
||||
};
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::pool::Handle,
|
||||
engine::Engine,
|
||||
graph::SceneGraph,
|
||||
gui::{
|
||||
check_box::{CheckBoxBuilder, CheckBoxMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, Orientation, UiNode, VerticalAlignment,
|
||||
},
|
||||
gui::{HorizontalAlignment, Thickness},
|
||||
scene::{camera::Camera, node::Node},
|
||||
},
|
||||
scene::{GameScene, Selection},
|
||||
send_sync_message, Message,
|
||||
};
|
||||
@@ -49,31 +49,36 @@ pub struct CameraPreviewControlPanel {
|
||||
impl CameraPreviewControlPanel {
|
||||
pub fn new(scene_viewer_frame: Handle<UiNode>, ctx: &mut BuildContext) -> Self {
|
||||
let preview;
|
||||
let window = WindowBuilder::new(WidgetBuilder::new().with_name("CameraPanel"))
|
||||
.with_title(WindowTitle::text("Camera Preview"))
|
||||
.with_content(
|
||||
StackPanelBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_child({
|
||||
preview = CheckBoxBuilder::new(WidgetBuilder::new())
|
||||
.with_content(
|
||||
TextBuilder::new(
|
||||
WidgetBuilder::new().with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_text("Preview")
|
||||
.with_vertical_text_alignment(VerticalAlignment::Center)
|
||||
.build(ctx),
|
||||
let window = WindowBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(200.0)
|
||||
.with_height(50.0)
|
||||
.with_name("CameraPanel"),
|
||||
)
|
||||
.with_title(WindowTitle::text("Camera Preview"))
|
||||
.with_content(
|
||||
StackPanelBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_child({
|
||||
preview = CheckBoxBuilder::new(WidgetBuilder::new())
|
||||
.with_content(
|
||||
TextBuilder::new(
|
||||
WidgetBuilder::new().with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.build(ctx);
|
||||
preview
|
||||
}),
|
||||
)
|
||||
.with_orientation(Orientation::Vertical)
|
||||
.build(ctx),
|
||||
.with_text("Preview")
|
||||
.with_vertical_text_alignment(VerticalAlignment::Center)
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
preview
|
||||
}),
|
||||
)
|
||||
.open(false)
|
||||
.build(ctx);
|
||||
.with_orientation(Orientation::Vertical)
|
||||
.build(ctx),
|
||||
)
|
||||
.open(false)
|
||||
.build(ctx);
|
||||
|
||||
Self {
|
||||
window,
|
||||
|
||||
@@ -67,7 +67,7 @@ impl CommandStackViewer {
|
||||
ctx,
|
||||
20.0,
|
||||
20.0,
|
||||
load_image(include_bytes!("../../resources/undo.png")),
|
||||
load_image!("../../resources/undo.png"),
|
||||
"Undo The Command",
|
||||
Some(0),
|
||||
);
|
||||
@@ -78,7 +78,7 @@ impl CommandStackViewer {
|
||||
ctx,
|
||||
20.0,
|
||||
20.0,
|
||||
load_image(include_bytes!("../../resources/redo.png")),
|
||||
load_image!("../../resources/redo.png"),
|
||||
"Redo The Command",
|
||||
Some(1),
|
||||
);
|
||||
@@ -89,7 +89,7 @@ impl CommandStackViewer {
|
||||
ctx,
|
||||
20.0,
|
||||
20.0,
|
||||
load_image(include_bytes!("../../resources/clear.png")),
|
||||
load_image!("../../resources/clear.png"),
|
||||
"Clear Command Stack\nChanges history will be erased.",
|
||||
Some(2),
|
||||
);
|
||||
|
||||
@@ -48,7 +48,7 @@ use crate::{
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_DARKER, BRUSH_LIGHT,
|
||||
VerticalAlignment,
|
||||
},
|
||||
},
|
||||
gui::make_dropdown_list_option,
|
||||
@@ -57,6 +57,8 @@ use crate::{
|
||||
};
|
||||
use cargo_metadata::{camino::Utf8Path, Metadata};
|
||||
use fyrox::graph::SceneGraph;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fmt::{Display, Formatter},
|
||||
@@ -826,7 +828,7 @@ impl ExportWindow {
|
||||
WidgetBuilder::new()
|
||||
.on_row(3)
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.with_background(BRUSH_LIGHT)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_LIGHT))
|
||||
.with_child(
|
||||
ScrollViewerBuilder::new(
|
||||
WidgetBuilder::new().with_margin(Thickness::uniform(2.0)),
|
||||
@@ -862,7 +864,7 @@ impl ExportWindow {
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.on_row(1)
|
||||
.with_background(BRUSH_DARKER)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARKER))
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.with_child({
|
||||
log_scroll_viewer = ScrollViewerBuilder::new(
|
||||
|
||||
+11
-8
@@ -195,17 +195,20 @@ impl SceneRenderPass for HighlightRenderPass {
|
||||
{
|
||||
let render_pass_name = ImmutableString::new("Forward");
|
||||
|
||||
let mut render_bundle_storage = RenderDataBundleStorage::default();
|
||||
let observer_info = ObserverInfo {
|
||||
observer_position: ctx.camera.global_position(),
|
||||
z_near: ctx.camera.projection().z_near(),
|
||||
z_far: ctx.camera.projection().z_far(),
|
||||
view_matrix: ctx.camera.view_matrix(),
|
||||
projection_matrix: ctx.camera.projection_matrix(),
|
||||
};
|
||||
|
||||
let mut render_bundle_storage =
|
||||
RenderDataBundleStorage::new_empty(observer_info.clone());
|
||||
|
||||
let frustum = ctx.camera.frustum();
|
||||
let mut render_context = RenderContext {
|
||||
observer_info: &ObserverInfo {
|
||||
observer_position: ctx.camera.global_position(),
|
||||
z_near: ctx.camera.projection().z_near(),
|
||||
z_far: ctx.camera.projection().z_far(),
|
||||
view_matrix: ctx.camera.view_matrix(),
|
||||
projection_matrix: ctx.camera.projection_matrix(),
|
||||
},
|
||||
observer_info: &observer_info,
|
||||
frustum: Some(&frustum),
|
||||
storage: &mut render_bundle_storage,
|
||||
graph: &ctx.scene.graph,
|
||||
|
||||
@@ -37,17 +37,18 @@ use crate::{
|
||||
message::{KeyCode, UiMessage},
|
||||
utils::make_simple_tooltip,
|
||||
widget::WidgetBuilder,
|
||||
BuildContext, Thickness, UiNode, BRUSH_BRIGHT_BLUE, BRUSH_DARKER, BRUSH_LIGHT,
|
||||
BRUSH_LIGHTER, BRUSH_LIGHTEST,
|
||||
BuildContext, Thickness, UiNode,
|
||||
},
|
||||
scene::{camera::Projection, graph::Graph, node::Node},
|
||||
},
|
||||
load_image,
|
||||
load_image_internal,
|
||||
message::MessageSender,
|
||||
scene::{controller::SceneController, Selection},
|
||||
settings::Settings,
|
||||
Engine, Message,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::any::Any;
|
||||
|
||||
pub mod gizmo;
|
||||
@@ -211,15 +212,17 @@ pub fn make_interaction_mode_button(
|
||||
)
|
||||
.with_back(
|
||||
DecoratorBuilder::new(
|
||||
BorderBuilder::new(WidgetBuilder::new().with_foreground(BRUSH_DARKER))
|
||||
.with_pad_by_corner_radius(false)
|
||||
.with_corner_radius(4.0)
|
||||
.with_stroke_thickness(Thickness::uniform(1.0)),
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new().with_foreground(ctx.style.get_or_default(Style::BRUSH_DARKER)),
|
||||
)
|
||||
.with_pad_by_corner_radius(false)
|
||||
.with_corner_radius(4.0)
|
||||
.with_stroke_thickness(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_normal_brush(BRUSH_LIGHT)
|
||||
.with_hover_brush(BRUSH_LIGHTER)
|
||||
.with_pressed_brush(BRUSH_LIGHTEST)
|
||||
.with_selected_brush(BRUSH_BRIGHT_BLUE)
|
||||
.with_normal_brush(ctx.style.get_or_default(Style::BRUSH_LIGHT))
|
||||
.with_hover_brush(ctx.style.get_or_default(Style::BRUSH_LIGHTER))
|
||||
.with_pressed_brush(ctx.style.get_or_default(Style::BRUSH_LIGHTEST))
|
||||
.with_selected_brush(ctx.style.get_or_default(Style::BRUSH_BRIGHT_BLUE))
|
||||
.with_selected(selected)
|
||||
.build(ctx),
|
||||
)
|
||||
@@ -231,7 +234,7 @@ pub fn make_interaction_mode_button(
|
||||
.with_width(23.0)
|
||||
.with_height(23.0),
|
||||
)
|
||||
.with_opt_texture(load_image(image))
|
||||
.with_opt_texture(load_image_internal(image))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx)
|
||||
|
||||
+87
-275
@@ -30,29 +30,23 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod absm;
|
||||
pub mod animation;
|
||||
pub mod asset;
|
||||
pub mod audio;
|
||||
pub mod build;
|
||||
pub mod camera;
|
||||
pub mod command;
|
||||
pub mod configurator;
|
||||
pub mod curve_editor;
|
||||
pub mod export;
|
||||
pub mod gui;
|
||||
pub mod highlight;
|
||||
pub mod inspector;
|
||||
pub mod interaction;
|
||||
pub mod light;
|
||||
pub mod log;
|
||||
pub mod material;
|
||||
pub mod menu;
|
||||
pub mod mesh;
|
||||
pub mod message;
|
||||
pub mod overlay;
|
||||
pub mod particle;
|
||||
pub mod physics;
|
||||
pub mod plugin;
|
||||
pub mod plugins;
|
||||
pub mod preview;
|
||||
@@ -66,16 +60,14 @@ pub mod world;
|
||||
|
||||
pub use fyrox;
|
||||
|
||||
use crate::plugins::path_fixer::PathFixerPlugin;
|
||||
use crate::{
|
||||
absm::AbsmEditor,
|
||||
animation::AnimationEditor,
|
||||
asset::AssetBrowser,
|
||||
audio::{preview::AudioPreviewPanel, AudioPanel},
|
||||
build::BuildWindow,
|
||||
camera::panel::CameraPreviewControlPanel,
|
||||
command::{panel::CommandStackViewer, Command, CommandTrait},
|
||||
configurator::Configurator,
|
||||
curve_editor::CurveEditorWindow,
|
||||
export::ExportWindow,
|
||||
fyrox::{
|
||||
asset::{io::FsResourceIo, manager::ResourceManager, untyped::UntypedResource},
|
||||
@@ -84,6 +76,7 @@ use crate::{
|
||||
color::Color,
|
||||
futures::executor::block_on,
|
||||
log::{Log, MessageKind},
|
||||
parking_lot::Mutex,
|
||||
pool::Handle,
|
||||
task::TaskPool,
|
||||
uuid::Uuid,
|
||||
@@ -132,7 +125,6 @@ use crate::{
|
||||
window::{Icon, WindowAttributes},
|
||||
},
|
||||
highlight::HighlightRenderPass,
|
||||
inspector::InspectorPlugin,
|
||||
interaction::{
|
||||
move_mode::MoveInteractionMode,
|
||||
navmesh::{EditNavmeshMode, NavmeshPanel},
|
||||
@@ -143,15 +135,17 @@ use crate::{
|
||||
},
|
||||
light::LightPanel,
|
||||
log::LogPanel,
|
||||
material::MaterialEditor,
|
||||
menu::{Menu, MenuContext, Panels},
|
||||
mesh::{MeshControlPanel, SurfaceDataViewer},
|
||||
message::MessageSender,
|
||||
overlay::OverlayRenderPass,
|
||||
particle::ParticleSystemPreviewControlPanel,
|
||||
physics::ColliderControlPanel,
|
||||
plugin::EditorPlugin,
|
||||
plugins::collider::ColliderShapePlugin,
|
||||
plugin::{EditorPlugin, EditorPluginsContainer},
|
||||
plugins::{
|
||||
absm::AbsmEditorPlugin, animation::AnimationEditorPlugin, collider::ColliderPlugin,
|
||||
curve_editor::CurveEditorPlugin, material::MaterialPlugin, ragdoll::RagdollPlugin,
|
||||
settings::SettingsPlugin, stats::UiStatisticsPlugin, tilemap::TileMapEditorPlugin,
|
||||
},
|
||||
scene::{
|
||||
commands::{
|
||||
make_delete_selection_command, ChangeSelectionCommand, GameSceneContext, PasteCommand,
|
||||
@@ -169,9 +163,12 @@ use crate::{
|
||||
commands::graph::PasteWidgetCommand, menu::WidgetContextMenu,
|
||||
utils::UiSceneWorldViewerDataProvider, UiScene,
|
||||
},
|
||||
utils::{doc::DocWindow, path_fixer::PathFixer, ragdoll::RagdollWizard},
|
||||
utils::doc::DocWindow,
|
||||
world::{graph::menu::SceneNodeContextMenu, graph::EditorSceneWrapper, WorldViewer},
|
||||
};
|
||||
use fyrox::gui::constructor::new_widget_constructor_container;
|
||||
pub use message::Message;
|
||||
use plugins::inspector::InspectorPlugin;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
@@ -187,10 +184,6 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::plugin::EditorPluginsContainer;
|
||||
use crate::plugins::tilemap::TileMapEditorPlugin;
|
||||
pub use message::Message;
|
||||
|
||||
pub const FIXED_TIMESTEP: f32 = 1.0 / 60.0;
|
||||
pub const MSG_SYNC_FLAG: u64 = 1;
|
||||
|
||||
@@ -199,19 +192,52 @@ pub fn send_sync_message(ui: &UserInterface, mut msg: UiMessage) {
|
||||
ui.send_message(msg);
|
||||
}
|
||||
|
||||
pub fn load_texture(data: &[u8]) -> Option<TextureResource> {
|
||||
TextureResource::load_from_memory(
|
||||
Default::default(),
|
||||
data,
|
||||
TextureImportOptions::default()
|
||||
.with_compression(CompressionOptions::NoCompression)
|
||||
.with_minification_filter(TextureMinificationFilter::Linear),
|
||||
)
|
||||
.ok()
|
||||
lazy_static! {
|
||||
static ref EDITOR_TEXTURE_CACHE: Mutex<FxHashMap<usize, TextureResource>> = Default::default();
|
||||
}
|
||||
|
||||
pub fn load_image(data: &[u8]) -> Option<UntypedResource> {
|
||||
Some(load_texture(data)?.into())
|
||||
pub fn load_texture_internal(data: &[u8]) -> Option<TextureResource> {
|
||||
let mut cache = EDITOR_TEXTURE_CACHE.lock();
|
||||
|
||||
// Editor use data that is embedded in the binary, so each such piece of data will have fixed
|
||||
// location in memory. This fact allows us to cache the resources and skip redundant loading if
|
||||
// they're already loaded.
|
||||
let id = data.as_ptr() as usize;
|
||||
|
||||
if let Some(existing) = cache.get(&id) {
|
||||
Some(existing.clone())
|
||||
} else {
|
||||
let texture = TextureResource::load_from_memory(
|
||||
Default::default(),
|
||||
data,
|
||||
TextureImportOptions::default()
|
||||
.with_compression(CompressionOptions::NoCompression)
|
||||
.with_minification_filter(TextureMinificationFilter::Linear),
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
cache.insert(id, texture.clone());
|
||||
|
||||
Some(texture)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_image_internal(data: &[u8]) -> Option<UntypedResource> {
|
||||
Some(load_texture_internal(data)?.into())
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! load_texture {
|
||||
($file:expr $(,)?) => {
|
||||
$crate::load_texture_internal(include_bytes!($file))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! load_image {
|
||||
($file:expr $(,)?) => {
|
||||
$crate::load_image_internal(include_bytes!($file))
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@@ -261,7 +287,8 @@ pub fn make_save_file_selector(
|
||||
FileSelectorBuilder::new(
|
||||
WindowBuilder::new(WidgetBuilder::new().with_width(300.0).with_height(400.0))
|
||||
.with_title(WindowTitle::text("Save Scene As"))
|
||||
.open(false),
|
||||
.open(false)
|
||||
.with_remove_on_close(true),
|
||||
)
|
||||
.with_mode(FileBrowserMode::Save { default_file_name })
|
||||
.with_path("./")
|
||||
@@ -506,15 +533,10 @@ pub struct Editor {
|
||||
pub validation_message_box: Handle<UiNode>,
|
||||
pub navmesh_panel: NavmeshPanel,
|
||||
pub settings: Settings,
|
||||
pub path_fixer: PathFixer,
|
||||
pub material_editor: MaterialEditor,
|
||||
pub curve_editor: CurveEditorWindow,
|
||||
pub audio_panel: AudioPanel,
|
||||
pub absm_editor: AbsmEditor,
|
||||
pub mode: Mode,
|
||||
pub build_window: BuildWindow,
|
||||
pub scene_settings: SceneSettingsWindow,
|
||||
pub animation_editor: AnimationEditor,
|
||||
pub particle_system_control_panel: ParticleSystemPreviewControlPanel,
|
||||
pub camera_control_panel: CameraPreviewControlPanel,
|
||||
pub mesh_control_panel: MeshControlPanel,
|
||||
@@ -527,15 +549,14 @@ pub struct Editor {
|
||||
pub focused: bool,
|
||||
pub update_loop_state: UpdateLoopState,
|
||||
pub is_suspended: bool,
|
||||
pub ragdoll_wizard: RagdollWizard,
|
||||
pub scene_node_context_menu: Rc<RefCell<SceneNodeContextMenu>>,
|
||||
pub widget_context_menu: Rc<RefCell<WidgetContextMenu>>,
|
||||
pub collider_control_panel: ColliderControlPanel,
|
||||
pub overlay_pass: Option<Rc<RefCell<OverlayRenderPass>>>,
|
||||
pub highlighter: Option<Rc<RefCell<HighlightRenderPass>>>,
|
||||
pub export_window: Option<ExportWindow>,
|
||||
pub statistics_window: Option<StatisticsWindow>,
|
||||
pub surface_data_viewer: Option<SurfaceDataViewer>,
|
||||
pub processed_ui_messages: usize,
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
@@ -587,7 +608,7 @@ impl Editor {
|
||||
resource_manager: ResourceManager::new(task_pool.clone()),
|
||||
serialization_context,
|
||||
task_pool,
|
||||
widget_constructors: Arc::new(Default::default()),
|
||||
widget_constructors: Arc::new(new_widget_constructor_container()),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -612,27 +633,28 @@ impl Editor {
|
||||
let menu = Menu::new(&mut engine, message_sender.clone(), &settings);
|
||||
let light_panel = LightPanel::new(&mut engine, message_sender.clone());
|
||||
let audio_panel = AudioPanel::new(&mut engine, message_sender.clone());
|
||||
let material_editor = MaterialEditor::new(&mut engine, message_sender.clone());
|
||||
|
||||
let ctx = &mut engine.user_interfaces.first_mut().build_ctx();
|
||||
let navmesh_panel = NavmeshPanel::new(scene_viewer.frame(), ctx, message_sender.clone());
|
||||
let scene_node_context_menu = Rc::new(RefCell::new(SceneNodeContextMenu::new(ctx)));
|
||||
let widget_context_menu = Rc::new(RefCell::new(WidgetContextMenu::new(ctx)));
|
||||
let scene_node_context_menu = Rc::new(RefCell::new(SceneNodeContextMenu::new(
|
||||
&engine.serialization_context,
|
||||
&engine.widget_constructors,
|
||||
ctx,
|
||||
)));
|
||||
let widget_context_menu = Rc::new(RefCell::new(WidgetContextMenu::new(
|
||||
&engine.widget_constructors,
|
||||
ctx,
|
||||
)));
|
||||
let world_outliner = WorldViewer::new(ctx, message_sender.clone(), &settings);
|
||||
let command_stack_viewer = CommandStackViewer::new(ctx, message_sender.clone());
|
||||
let log = LogPanel::new(ctx, log_message_receiver);
|
||||
let inspector_plugin = InspectorPlugin::new(ctx, message_sender.clone());
|
||||
let animation_editor = AnimationEditor::new(ctx);
|
||||
let absm_editor = AbsmEditor::new(ctx, message_sender.clone());
|
||||
let particle_system_control_panel =
|
||||
ParticleSystemPreviewControlPanel::new(scene_viewer.frame(), ctx);
|
||||
let camera_control_panel = CameraPreviewControlPanel::new(scene_viewer.frame(), ctx);
|
||||
let mesh_control_panel = MeshControlPanel::new(scene_viewer.frame(), ctx);
|
||||
let audio_preview_panel = AudioPreviewPanel::new(scene_viewer.frame(), ctx);
|
||||
let collider_control_panel = ColliderControlPanel::new(scene_viewer.frame(), ctx);
|
||||
let doc_window = DocWindow::new(ctx);
|
||||
let node_removal_dialog = NodeRemovalDialog::new(ctx);
|
||||
let ragdoll_wizard = RagdollWizard::new(ctx, message_sender.clone());
|
||||
let scene_settings = SceneSettingsWindow::new(ctx, message_sender.clone());
|
||||
|
||||
let docking_manager;
|
||||
@@ -754,19 +776,14 @@ impl Editor {
|
||||
.build(ctx)
|
||||
}))
|
||||
.with_floating_windows(vec![
|
||||
animation_editor.window,
|
||||
absm_editor.window,
|
||||
particle_system_control_panel.window,
|
||||
camera_control_panel.window,
|
||||
mesh_control_panel.window,
|
||||
audio_preview_panel.window,
|
||||
collider_control_panel.window,
|
||||
navmesh_panel.window,
|
||||
doc_window.window,
|
||||
light_panel.window,
|
||||
menu.file_menu.settings.window,
|
||||
scene_settings.window,
|
||||
material_editor.window,
|
||||
])
|
||||
.build(ctx);
|
||||
docking_manager
|
||||
@@ -797,14 +814,8 @@ impl Editor {
|
||||
.with_buttons(MessageBoxButtons::Ok)
|
||||
.build(ctx);
|
||||
|
||||
let path_fixer = PathFixer::new(ctx);
|
||||
|
||||
let curve_editor = CurveEditorWindow::new(ctx);
|
||||
|
||||
let save_scene_dialog = SaveSceneConfirmationDialog::new(ctx);
|
||||
|
||||
let build_window = BuildWindow::new(ctx);
|
||||
|
||||
if let Some(layout) = settings.windows.layout.as_ref() {
|
||||
engine
|
||||
.user_interfaces
|
||||
@@ -818,7 +829,6 @@ impl Editor {
|
||||
|
||||
let editor = Self {
|
||||
docking_manager,
|
||||
animation_editor,
|
||||
engine,
|
||||
navmesh_panel,
|
||||
scene_viewer,
|
||||
@@ -837,9 +847,6 @@ impl Editor {
|
||||
command_stack_viewer,
|
||||
validation_message_box,
|
||||
settings,
|
||||
path_fixer,
|
||||
material_editor,
|
||||
curve_editor,
|
||||
audio_panel,
|
||||
save_scene_dialog,
|
||||
mode: Mode::Edit,
|
||||
@@ -847,7 +854,6 @@ impl Editor {
|
||||
clock: Instant::now(),
|
||||
lag: 0.0,
|
||||
},
|
||||
absm_editor,
|
||||
build_window,
|
||||
scene_settings,
|
||||
particle_system_control_panel,
|
||||
@@ -857,8 +863,16 @@ impl Editor {
|
||||
node_removal_dialog,
|
||||
doc_window,
|
||||
plugins: EditorPluginsContainer::new()
|
||||
.with(ColliderShapePlugin::default())
|
||||
.with(ColliderPlugin::default())
|
||||
.with(TileMapEditorPlugin::default())
|
||||
.with(MaterialPlugin::default())
|
||||
.with(RagdollPlugin::default())
|
||||
.with(SettingsPlugin::default())
|
||||
.with(AnimationEditorPlugin::default())
|
||||
.with(AbsmEditorPlugin::default())
|
||||
.with(UiStatisticsPlugin::default())
|
||||
.with(CurveEditorPlugin::default())
|
||||
.with(PathFixerPlugin::default())
|
||||
.with(inspector_plugin),
|
||||
// Apparently, some window managers (like Wayland), does not send `Focused` event after the window
|
||||
// was created. So we must assume that the editor is focused by default, otherwise editor's thread
|
||||
@@ -866,15 +880,14 @@ impl Editor {
|
||||
focused: true,
|
||||
update_loop_state: UpdateLoopState::default(),
|
||||
is_suspended: false,
|
||||
ragdoll_wizard,
|
||||
scene_node_context_menu,
|
||||
widget_context_menu,
|
||||
collider_control_panel,
|
||||
overlay_pass: None,
|
||||
highlighter: None,
|
||||
export_window: None,
|
||||
statistics_window: None,
|
||||
surface_data_viewer: None,
|
||||
processed_ui_messages: 0,
|
||||
};
|
||||
|
||||
if let Some(data) = startup_data {
|
||||
@@ -1189,13 +1202,8 @@ impl Editor {
|
||||
navmesh_panel: self.navmesh_panel.window,
|
||||
audio_panel: self.audio_panel.window,
|
||||
configurator_window: self.configurator.window,
|
||||
path_fixer: self.path_fixer.window,
|
||||
curve_editor: &self.curve_editor,
|
||||
absm_editor: &self.absm_editor,
|
||||
command_stack_panel: self.command_stack_viewer.window,
|
||||
scene_settings: &self.scene_settings,
|
||||
animation_editor: &self.animation_editor,
|
||||
ragdoll_wizard: &self.ragdoll_wizard,
|
||||
export_window: &mut self.export_window,
|
||||
statistics_window: &mut self.statistics_window,
|
||||
},
|
||||
@@ -1216,13 +1224,6 @@ impl Editor {
|
||||
self.asset_browser
|
||||
.handle_ui_message(message, engine, self.message_sender.clone());
|
||||
self.command_stack_viewer.handle_ui_message(message);
|
||||
self.curve_editor.handle_ui_message(message, engine);
|
||||
self.path_fixer.handle_ui_message(
|
||||
message,
|
||||
engine.user_interfaces.first_mut(),
|
||||
engine.serialization_context.clone(),
|
||||
engine.resource_manager.clone(),
|
||||
);
|
||||
self.scene_viewer.handle_ui_message(
|
||||
message,
|
||||
engine,
|
||||
@@ -1249,32 +1250,6 @@ impl Editor {
|
||||
|
||||
if let Some(current_scene_entry) = current_scene_entry {
|
||||
if let Some(game_scene) = current_scene_entry.controller.downcast_mut::<GameScene>() {
|
||||
let graph = &mut engine.scenes[game_scene.scene].graph;
|
||||
self.animation_editor.handle_ui_message(
|
||||
message,
|
||||
¤t_scene_entry.selection,
|
||||
graph,
|
||||
game_scene.scene_content_root,
|
||||
engine.user_interfaces.first_mut(),
|
||||
&engine.resource_manager,
|
||||
&self.message_sender,
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.handle_ui_message(
|
||||
message,
|
||||
&self.message_sender,
|
||||
¤t_scene_entry.selection,
|
||||
graph,
|
||||
engine.user_interfaces.first_mut(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.ragdoll_wizard.handle_ui_message(
|
||||
message,
|
||||
engine.user_interfaces.first_mut(),
|
||||
graph,
|
||||
game_scene,
|
||||
&self.message_sender,
|
||||
);
|
||||
self.particle_system_control_panel.handle_ui_message(
|
||||
message,
|
||||
¤t_scene_entry.selection,
|
||||
@@ -1294,13 +1269,6 @@ impl Editor {
|
||||
engine,
|
||||
&self.message_sender,
|
||||
);
|
||||
self.collider_control_panel.handle_ui_message(
|
||||
message,
|
||||
engine,
|
||||
game_scene,
|
||||
¤t_scene_entry.selection,
|
||||
&self.message_sender,
|
||||
);
|
||||
self.audio_preview_panel.handle_ui_message(
|
||||
message,
|
||||
¤t_scene_entry.selection,
|
||||
@@ -1368,25 +1336,6 @@ impl Editor {
|
||||
.handle_ui_message(message, game_scene, engine);
|
||||
} else if let Some(ui_scene) = current_scene_entry.controller.downcast_mut::<UiScene>()
|
||||
{
|
||||
let ui_root = ui_scene.ui.root();
|
||||
self.animation_editor.handle_ui_message(
|
||||
message,
|
||||
¤t_scene_entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
ui_root,
|
||||
engine.user_interfaces.first_mut(),
|
||||
&engine.resource_manager,
|
||||
&self.message_sender,
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.handle_ui_message(
|
||||
message,
|
||||
&self.message_sender,
|
||||
¤t_scene_entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
engine.user_interfaces.first_mut(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.world_viewer.handle_ui_message(
|
||||
message,
|
||||
&mut UiSceneWorldViewerDataProvider {
|
||||
@@ -1408,9 +1357,6 @@ impl Editor {
|
||||
&self.message_sender,
|
||||
);
|
||||
}
|
||||
|
||||
self.material_editor
|
||||
.handle_ui_message(message, engine, &self.message_sender);
|
||||
}
|
||||
|
||||
if let Some(MessageBoxMessage::Close(result)) = message.data() {
|
||||
@@ -1613,16 +1559,6 @@ impl Editor {
|
||||
);
|
||||
|
||||
if let Some(game_scene) = current_scene_entry.controller.downcast_mut::<GameScene>() {
|
||||
self.animation_editor.sync_to_model(
|
||||
¤t_scene_entry.selection,
|
||||
engine.user_interfaces.first_mut(),
|
||||
&engine.scenes[game_scene.scene].graph,
|
||||
);
|
||||
self.absm_editor.sync_to_model(
|
||||
¤t_scene_entry.selection,
|
||||
&engine.scenes[game_scene.scene].graph,
|
||||
engine.user_interfaces.first_mut(),
|
||||
);
|
||||
self.scene_settings.sync_to_model(game_scene, engine);
|
||||
let sender = &self.message_sender;
|
||||
self.world_viewer.sync_to_model(
|
||||
@@ -1638,8 +1574,7 @@ impl Editor {
|
||||
engine.user_interfaces.first_mut(),
|
||||
&self.settings,
|
||||
);
|
||||
self.material_editor
|
||||
.sync_to_model(engine.user_interfaces.first_mut());
|
||||
|
||||
self.audio_panel
|
||||
.sync_to_model(¤t_scene_entry.selection, game_scene, engine);
|
||||
self.navmesh_panel.sync_to_model(
|
||||
@@ -1649,16 +1584,6 @@ impl Editor {
|
||||
);
|
||||
} else if let Some(ui_scene) = current_scene_entry.controller.downcast_mut::<UiScene>()
|
||||
{
|
||||
self.animation_editor.sync_to_model(
|
||||
¤t_scene_entry.selection,
|
||||
engine.user_interfaces.first_mut(),
|
||||
&ui_scene.ui,
|
||||
);
|
||||
self.absm_editor.sync_to_model(
|
||||
¤t_scene_entry.selection,
|
||||
&ui_scene.ui,
|
||||
engine.user_interfaces.first_mut(),
|
||||
);
|
||||
self.world_viewer.sync_to_model(
|
||||
&UiSceneWorldViewerDataProvider {
|
||||
ui: &mut ui_scene.ui,
|
||||
@@ -1782,31 +1707,10 @@ impl Editor {
|
||||
.leave_preview_mode(game_scene, engine);
|
||||
self.audio_preview_panel
|
||||
.leave_preview_mode(game_scene, engine);
|
||||
self.animation_editor.try_leave_preview_mode(
|
||||
&mut engine.scenes[game_scene.scene].graph,
|
||||
engine.user_interfaces.first(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.try_leave_preview_mode(
|
||||
&entry.selection,
|
||||
&mut engine.scenes[game_scene.scene].graph,
|
||||
engine.user_interfaces.first_mut(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
self.animation_editor.try_leave_preview_mode(
|
||||
&mut ui_scene.ui,
|
||||
self.engine.user_interfaces.first(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.try_leave_preview_mode(
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_plugin!(self.plugins => on_leave_preview_mode(self));
|
||||
}
|
||||
|
||||
pub fn is_in_preview_mode(&mut self) -> bool {
|
||||
@@ -1833,8 +1737,6 @@ impl Editor {
|
||||
self.particle_system_control_panel.is_in_preview_mode()
|
||||
|| self.camera_control_panel.is_in_preview_mode()
|
||||
|| self.audio_preview_panel.is_in_preview_mode()
|
||||
|| self.animation_editor.is_in_preview_mode()
|
||||
|| self.absm_editor.is_in_preview_mode()
|
||||
|| self.light_panel.is_in_preview_mode()
|
||||
|| self.export_window.is_some()
|
||||
|| is_any_plugin_in_preview_mode
|
||||
@@ -2024,8 +1926,6 @@ impl Editor {
|
||||
}
|
||||
|
||||
self.world_viewer.clear(ui);
|
||||
self.animation_editor.clear(ui);
|
||||
self.absm_editor.clear(ui);
|
||||
|
||||
self.poll_ui_messages();
|
||||
|
||||
@@ -2033,6 +1933,9 @@ impl Editor {
|
||||
|
||||
self.scene_viewer
|
||||
.on_current_scene_changed(self.scenes.current_scene_entry_mut(), &mut self.engine);
|
||||
|
||||
for_each_plugin!(self.plugins => on_scene_changed(self));
|
||||
|
||||
self.sync_to_model();
|
||||
self.poll_ui_messages();
|
||||
}
|
||||
@@ -2120,22 +2023,6 @@ impl Editor {
|
||||
));
|
||||
}
|
||||
|
||||
fn open_material_editor(&mut self, material: MaterialResource) {
|
||||
let engine = &mut self.engine;
|
||||
|
||||
self.material_editor.set_material(Some(material), engine);
|
||||
|
||||
engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
.send_message(WindowMessage::open(
|
||||
self.material_editor.window,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
fn poll_ui_messages(&mut self) -> usize {
|
||||
let mut processed = 0;
|
||||
|
||||
@@ -2251,7 +2138,6 @@ impl Editor {
|
||||
self.handle_modes();
|
||||
|
||||
self.log.update(&self.settings, &mut self.engine);
|
||||
self.material_editor.update(&mut self.engine);
|
||||
self.asset_browser
|
||||
.update(&mut self.engine, &self.message_sender);
|
||||
if let Some(export_window) = self.export_window.as_mut() {
|
||||
@@ -2270,20 +2156,9 @@ impl Editor {
|
||||
}
|
||||
|
||||
self.light_panel.update(game_scene, &mut self.engine);
|
||||
self.animation_editor.update(
|
||||
&entry.selection,
|
||||
self.engine.user_interfaces.first(),
|
||||
&self.engine.scenes[game_scene.scene].graph,
|
||||
);
|
||||
self.audio_preview_panel
|
||||
.update(&entry.selection, game_scene, &self.engine);
|
||||
self.scene_viewer.update(game_scene, &mut self.engine);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_ref::<UiScene>() {
|
||||
self.animation_editor.update(
|
||||
&entry.selection,
|
||||
self.engine.user_interfaces.first(),
|
||||
&ui_scene.ui,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2291,11 +2166,13 @@ impl Editor {
|
||||
overlay_pass.borrow_mut().pictogram_size = self.settings.debugging.pictogram_size;
|
||||
}
|
||||
|
||||
self.processed_ui_messages = 0;
|
||||
let mut iterations = 1;
|
||||
while iterations > 0 {
|
||||
iterations -= 1;
|
||||
|
||||
let ui_messages_processed_count = self.poll_ui_messages();
|
||||
self.processed_ui_messages += ui_messages_processed_count;
|
||||
|
||||
let mut needs_sync = false;
|
||||
|
||||
@@ -2304,8 +2181,6 @@ impl Editor {
|
||||
for_each_plugin!(self.plugins => on_message(&message, self));
|
||||
|
||||
editor_messages_processed_count += 1;
|
||||
self.path_fixer
|
||||
.handle_message(&message, self.engine.user_interfaces.first());
|
||||
|
||||
self.save_scene_dialog
|
||||
.handle_message(&message, &self.message_sender);
|
||||
@@ -2330,47 +2205,13 @@ impl Editor {
|
||||
game_scene,
|
||||
&mut self.engine,
|
||||
);
|
||||
self.collider_control_panel.handle_message(
|
||||
&message,
|
||||
&self.engine,
|
||||
game_scene,
|
||||
&entry.selection,
|
||||
);
|
||||
self.audio_preview_panel.handle_message(
|
||||
&message,
|
||||
&entry.selection,
|
||||
game_scene,
|
||||
&mut self.engine,
|
||||
);
|
||||
self.animation_editor.handle_message(
|
||||
&message,
|
||||
&mut self.engine.scenes[game_scene.scene].graph,
|
||||
self.engine.user_interfaces.first(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.handle_message(
|
||||
&message,
|
||||
&entry.selection,
|
||||
&mut self.engine.scenes[game_scene.scene].graph,
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
self.animation_editor.handle_message(
|
||||
&message,
|
||||
&mut ui_scene.ui,
|
||||
self.engine.user_interfaces.first(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
self.absm_editor.handle_message(
|
||||
&message,
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
needs_sync |=
|
||||
entry
|
||||
.controller
|
||||
@@ -2425,14 +2266,6 @@ impl Editor {
|
||||
self.configure(working_directory);
|
||||
needs_sync = true;
|
||||
}
|
||||
Message::OpenSettings => {
|
||||
self.menu.file_menu.settings.open(
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
&self.settings,
|
||||
&self.message_sender,
|
||||
);
|
||||
}
|
||||
Message::OpenMaterialEditor(material) => self.open_material_editor(material),
|
||||
Message::OpenNodeRemovalDialog => {
|
||||
if let Some(entry) = self.scenes.current_scene_entry_ref() {
|
||||
// TODO
|
||||
@@ -2491,13 +2324,6 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::OpenAnimationEditor => {
|
||||
self.animation_editor
|
||||
.open(self.engine.user_interfaces.first());
|
||||
}
|
||||
Message::OpenAbsmEditor => {
|
||||
self.absm_editor.open(self.engine.user_interfaces.first())
|
||||
}
|
||||
Message::ShowDocumentation(doc) => {
|
||||
self.doc_window
|
||||
.open(doc, self.engine.user_interfaces.first());
|
||||
@@ -2558,20 +2384,6 @@ impl Editor {
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(game_scene) = controller.downcast_ref::<GameScene>() {
|
||||
self.absm_editor.update(
|
||||
&entry.selection,
|
||||
&mut self.engine.scenes[game_scene.scene].graph,
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
);
|
||||
} else if let Some(ui_scene) = controller.downcast_mut::<UiScene>() {
|
||||
self.absm_editor.update(
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
self.engine.user_interfaces.first_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(interaction_mode) = entry
|
||||
.current_interaction_mode
|
||||
.and_then(|current_mode| entry.interaction_modes.get_mut(¤t_mode))
|
||||
|
||||
+2
-4
@@ -38,10 +38,8 @@ use crate::fyrox::{
|
||||
CancellationToken, Lightmap, LightmapGenerationError, LightmapInputData, ProgressIndicator,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
inspector::editors::make_property_editors_container, message::MessageSender, scene::GameScene,
|
||||
Engine, MSG_SYNC_FLAG,
|
||||
};
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{message::MessageSender, scene::GameScene, Engine, MSG_SYNC_FLAG};
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ impl LogPanel {
|
||||
ctx,
|
||||
24.0,
|
||||
24.0,
|
||||
load_image(include_bytes!("../resources/clear.png")),
|
||||
load_image!("../resources/clear.png"),
|
||||
"Clear the log.",
|
||||
Some(0),
|
||||
);
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode},
|
||||
scene::{
|
||||
animation::{absm::prelude::*, prelude::*},
|
||||
base::BaseBuilder,
|
||||
node::Node,
|
||||
},
|
||||
};
|
||||
use crate::menu::create_menu_item;
|
||||
|
||||
pub struct AnimationMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
create_animation_player: Handle<UiNode>,
|
||||
create_absm: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl AnimationMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let create_animation_player;
|
||||
let create_absm;
|
||||
|
||||
let menu = create_menu_item(
|
||||
"Animation",
|
||||
vec![
|
||||
{
|
||||
create_animation_player = create_menu_item("Animation Player", vec![], ctx);
|
||||
create_animation_player
|
||||
},
|
||||
{
|
||||
create_absm = create_menu_item("Animation Blending State Machine", vec![], ctx);
|
||||
create_absm
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
|
||||
Self {
|
||||
menu,
|
||||
create_animation_player,
|
||||
create_absm,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(&mut self, message: &UiMessage) -> Option<Node> {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.create_animation_player {
|
||||
let node =
|
||||
AnimationPlayerBuilder::new(BaseBuilder::new().with_name("Animation Player"))
|
||||
.build_node();
|
||||
Some(node)
|
||||
} else if message.destination() == self.create_absm {
|
||||
let mut machine = Machine::default();
|
||||
|
||||
let mut layer = MachineLayer::new();
|
||||
layer.set_name("Base Layer");
|
||||
|
||||
machine.add_layer(layer);
|
||||
|
||||
let node = AnimationBlendingStateMachineBuilder::new(
|
||||
BaseBuilder::new().with_name("Animation Blending State Machine"),
|
||||
)
|
||||
.with_machine(machine)
|
||||
.build_node();
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
-407
@@ -20,49 +20,17 @@
|
||||
|
||||
use crate::{
|
||||
command::{Command, CommandGroup},
|
||||
create_terrain_layer_material,
|
||||
fyrox::{
|
||||
asset::untyped::ResourceKind,
|
||||
core::{
|
||||
algebra::{Matrix4, Vector3},
|
||||
math::TriangleDefinition,
|
||||
pool::Handle,
|
||||
},
|
||||
core::{algebra::Vector3, pool::Handle},
|
||||
engine::{Engine, SerializationContext},
|
||||
fxhash::FxHashMap,
|
||||
gui::{
|
||||
menu::MenuItemMessage, message::MessageDirection, message::UiMessage,
|
||||
widget::WidgetMessage, BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
material::{Material, MaterialResource},
|
||||
resource::texture::PLACEHOLDER,
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
camera::CameraBuilder,
|
||||
decal::DecalBuilder,
|
||||
light::{
|
||||
directional::DirectionalLightBuilder, point::PointLightBuilder,
|
||||
spot::SpotLightBuilder, BaseLightBuilder,
|
||||
},
|
||||
mesh::{
|
||||
surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
|
||||
MeshBuilder,
|
||||
},
|
||||
navmesh::NavigationalMeshBuilder,
|
||||
node::Node,
|
||||
particle_system::{
|
||||
emitter::{base::BaseEmitterBuilder, sphere::SphereEmitterBuilder},
|
||||
ParticleSystemBuilder,
|
||||
},
|
||||
pivot::PivotBuilder,
|
||||
sound::{listener::ListenerBuilder, SoundBuilder},
|
||||
sprite::SpriteBuilder,
|
||||
terrain::{Layer, TerrainBuilder},
|
||||
},
|
||||
utils::navmesh::Navmesh,
|
||||
},
|
||||
menu::{
|
||||
animation::AnimationMenu, create_menu_item, create_root_menu_item, dim2::Dim2Menu,
|
||||
physics::PhysicsMenu, physics2d::Physics2dMenu, ui::UiMenu,
|
||||
scene::node::Node,
|
||||
},
|
||||
menu::{create_menu_item, create_root_menu_item, ui::UiMenu},
|
||||
message::MessageSender,
|
||||
scene::{
|
||||
commands::graph::{AddNodeCommand, MoveNodeCommand},
|
||||
@@ -72,7 +40,11 @@ use crate::{
|
||||
ui_scene::UiScene,
|
||||
Mode,
|
||||
};
|
||||
use fyrox::engine::Engine;
|
||||
use fyrox::core::log::Log;
|
||||
use fyrox::graph::constructor::{VariantConstructor, VariantResult};
|
||||
use fyrox::gui::constructor::WidgetConstructorContainer;
|
||||
use fyrox::gui::menu::SortingPredicate;
|
||||
use fyrox::scene::graph::Graph;
|
||||
|
||||
pub struct CreateEntityRootMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
@@ -80,10 +52,21 @@ pub struct CreateEntityRootMenu {
|
||||
}
|
||||
|
||||
impl CreateEntityRootMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let (sub_menus, root_items) = CreateEntityMenu::new(ctx);
|
||||
pub fn new(
|
||||
serialization_context: &SerializationContext,
|
||||
widget_constructors_container: &WidgetConstructorContainer,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let sub_menus =
|
||||
CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
|
||||
|
||||
let menu = create_root_menu_item("Create", root_items, ctx);
|
||||
let menu = create_root_menu_item("Create", sub_menus.root_items.clone(), ctx);
|
||||
|
||||
ctx.inner().send_message(MenuItemMessage::sort(
|
||||
menu,
|
||||
MessageDirection::ToWidget,
|
||||
SortingPredicate::sort_by_text(),
|
||||
));
|
||||
|
||||
Self { menu, sub_menus }
|
||||
}
|
||||
@@ -94,11 +77,11 @@ impl CreateEntityRootMenu {
|
||||
sender: &MessageSender,
|
||||
controller: &mut dyn SceneController,
|
||||
selection: &Selection,
|
||||
engine: &Engine,
|
||||
engine: &mut Engine,
|
||||
) {
|
||||
if let Some(node) = self
|
||||
.sub_menus
|
||||
.handle_ui_message(message, sender, controller, selection)
|
||||
.handle_ui_message(message, sender, controller, selection, engine)
|
||||
{
|
||||
if let Some(game_scene) = controller.downcast_ref::<GameScene>() {
|
||||
let scene = &engine.scenes[game_scene.scene];
|
||||
@@ -134,203 +117,59 @@ impl CreateEntityRootMenu {
|
||||
}
|
||||
|
||||
pub struct CreateEntityMenu {
|
||||
create_pivot: Handle<UiNode>,
|
||||
create_cube: Handle<UiNode>,
|
||||
create_cone: Handle<UiNode>,
|
||||
create_sphere: Handle<UiNode>,
|
||||
create_cylinder: Handle<UiNode>,
|
||||
create_quad: Handle<UiNode>,
|
||||
create_decal: Handle<UiNode>,
|
||||
create_point_light: Handle<UiNode>,
|
||||
create_spot_light: Handle<UiNode>,
|
||||
create_directional_light: Handle<UiNode>,
|
||||
create_navmesh: Handle<UiNode>,
|
||||
create_terrain: Handle<UiNode>,
|
||||
create_camera: Handle<UiNode>,
|
||||
create_sprite: Handle<UiNode>,
|
||||
create_particle_system: Handle<UiNode>,
|
||||
create_listener: Handle<UiNode>,
|
||||
create_sound_source: Handle<UiNode>,
|
||||
physics_menu: PhysicsMenu,
|
||||
physics2d_menu: Physics2dMenu,
|
||||
dim2_menu: Dim2Menu,
|
||||
animation_menu: AnimationMenu,
|
||||
ui_menu: UiMenu,
|
||||
|
||||
mesh_menu: Handle<UiNode>,
|
||||
sound_menu: Handle<UiNode>,
|
||||
light_menu: Handle<UiNode>,
|
||||
}
|
||||
|
||||
fn placeholder_material() -> MaterialResource {
|
||||
let mut material = Material::standard();
|
||||
material.bind("diffuseTexture", PLACEHOLDER.resource());
|
||||
MaterialResource::new_ok(ResourceKind::Embedded, material)
|
||||
pub root_items: Vec<Handle<UiNode>>,
|
||||
constructor_views: FxHashMap<Handle<UiNode>, VariantConstructor<Node, Graph>>,
|
||||
}
|
||||
|
||||
impl CreateEntityMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> (Self, Vec<Handle<UiNode>>) {
|
||||
let create_cube;
|
||||
let create_cone;
|
||||
let create_sphere;
|
||||
let create_cylinder;
|
||||
let create_quad;
|
||||
let create_point_light;
|
||||
let create_spot_light;
|
||||
let create_directional_light;
|
||||
let create_camera;
|
||||
let create_sprite;
|
||||
let create_decal;
|
||||
let create_navmesh;
|
||||
let create_particle_system;
|
||||
let create_terrain;
|
||||
let create_pivot;
|
||||
let create_sound_source;
|
||||
let create_listener;
|
||||
let physics_menu = PhysicsMenu::new(ctx);
|
||||
let physics2d_menu = Physics2dMenu::new(ctx);
|
||||
let dim2_menu = Dim2Menu::new(ctx);
|
||||
let animation_menu = AnimationMenu::new(ctx);
|
||||
let mesh_menu;
|
||||
let sound_menu;
|
||||
let light_menu;
|
||||
pub fn new(
|
||||
serialization_context: &SerializationContext,
|
||||
widget_constructor_container: &WidgetConstructorContainer,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let ui_menu = UiMenu::new(widget_constructor_container, "UI", ctx);
|
||||
|
||||
let ui_menu = UiMenu::new(UiMenu::default_entries(), "UI", ctx);
|
||||
let mut root_items = vec![ui_menu.menu];
|
||||
let mut groups = FxHashMap::default();
|
||||
let mut constructor_views = FxHashMap::default();
|
||||
let constructors = serialization_context.node_constructors.map();
|
||||
for constructor in constructors.values() {
|
||||
for variant in constructor.variants.iter() {
|
||||
let item = create_menu_item(&variant.name, vec![], ctx);
|
||||
constructor_views.insert(item, variant.constructor.clone());
|
||||
if constructor.group.is_empty() {
|
||||
root_items.push(item);
|
||||
} else {
|
||||
let group = *groups.entry(constructor.group).or_insert_with(|| {
|
||||
let group = create_menu_item(constructor.group, vec![], ctx);
|
||||
root_items.push(group);
|
||||
group
|
||||
});
|
||||
ctx.sender()
|
||||
.send(MenuItemMessage::add_item(
|
||||
group,
|
||||
MessageDirection::ToWidget,
|
||||
item,
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let items = vec![
|
||||
ui_menu.menu,
|
||||
{
|
||||
create_pivot = create_menu_item("Pivot", vec![], ctx);
|
||||
create_pivot
|
||||
},
|
||||
{
|
||||
mesh_menu = create_menu_item(
|
||||
"Mesh",
|
||||
vec![
|
||||
{
|
||||
create_cube = create_menu_item("Cube", vec![], ctx);
|
||||
create_cube
|
||||
},
|
||||
{
|
||||
create_sphere = create_menu_item("Sphere", vec![], ctx);
|
||||
create_sphere
|
||||
},
|
||||
{
|
||||
create_cylinder = create_menu_item("Cylinder", vec![], ctx);
|
||||
create_cylinder
|
||||
},
|
||||
{
|
||||
create_cone = create_menu_item("Cone", vec![], ctx);
|
||||
create_cone
|
||||
},
|
||||
{
|
||||
create_quad = create_menu_item("Quad", vec![], ctx);
|
||||
create_quad
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
mesh_menu
|
||||
},
|
||||
{
|
||||
sound_menu = create_menu_item(
|
||||
"Sound",
|
||||
vec![
|
||||
{
|
||||
create_sound_source = create_menu_item("Source", vec![], ctx);
|
||||
create_sound_source
|
||||
},
|
||||
{
|
||||
create_listener = create_menu_item("Listener", vec![], ctx);
|
||||
create_listener
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
sound_menu
|
||||
},
|
||||
{
|
||||
light_menu = create_menu_item(
|
||||
"Light",
|
||||
vec![
|
||||
{
|
||||
create_directional_light =
|
||||
create_menu_item("Directional Light", vec![], ctx);
|
||||
create_directional_light
|
||||
},
|
||||
{
|
||||
create_spot_light = create_menu_item("Spot Light", vec![], ctx);
|
||||
create_spot_light
|
||||
},
|
||||
{
|
||||
create_point_light = create_menu_item("Point Light", vec![], ctx);
|
||||
create_point_light
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
light_menu
|
||||
},
|
||||
physics_menu.menu,
|
||||
physics2d_menu.menu,
|
||||
dim2_menu.menu,
|
||||
animation_menu.menu,
|
||||
{
|
||||
create_camera = create_menu_item("Camera", vec![], ctx);
|
||||
create_camera
|
||||
},
|
||||
{
|
||||
create_sprite = create_menu_item("Sprite (3D)", vec![], ctx);
|
||||
create_sprite
|
||||
},
|
||||
{
|
||||
create_particle_system = create_menu_item("Particle System", vec![], ctx);
|
||||
create_particle_system
|
||||
},
|
||||
{
|
||||
create_terrain = create_menu_item("Terrain", vec![], ctx);
|
||||
create_terrain
|
||||
},
|
||||
{
|
||||
create_decal = create_menu_item("Decal", vec![], ctx);
|
||||
create_decal
|
||||
},
|
||||
{
|
||||
create_navmesh = create_menu_item("Navmesh", vec![], ctx);
|
||||
create_navmesh
|
||||
},
|
||||
];
|
||||
for root_item in root_items.iter() {
|
||||
ctx.inner().send_message(MenuItemMessage::sort(
|
||||
*root_item,
|
||||
MessageDirection::ToWidget,
|
||||
SortingPredicate::sort_by_text(),
|
||||
))
|
||||
}
|
||||
|
||||
(
|
||||
Self {
|
||||
create_cube,
|
||||
create_cone,
|
||||
create_sphere,
|
||||
create_cylinder,
|
||||
create_quad,
|
||||
create_point_light,
|
||||
create_spot_light,
|
||||
create_directional_light,
|
||||
create_camera,
|
||||
create_sprite,
|
||||
create_particle_system,
|
||||
create_pivot,
|
||||
create_terrain,
|
||||
create_sound_source,
|
||||
create_listener,
|
||||
create_navmesh,
|
||||
create_decal,
|
||||
physics_menu,
|
||||
physics2d_menu,
|
||||
dim2_menu,
|
||||
animation_menu,
|
||||
ui_menu,
|
||||
mesh_menu,
|
||||
light_menu,
|
||||
sound_menu,
|
||||
},
|
||||
items,
|
||||
)
|
||||
Self {
|
||||
ui_menu,
|
||||
constructor_views,
|
||||
root_items,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_scene_changed(&self, controller: &dyn SceneController, ui: &UserInterface) {
|
||||
@@ -342,24 +181,13 @@ impl CreateEntityMenu {
|
||||
is_ui_scene,
|
||||
));
|
||||
|
||||
for widget in [
|
||||
self.mesh_menu,
|
||||
self.light_menu,
|
||||
self.create_camera,
|
||||
self.create_sprite,
|
||||
self.create_particle_system,
|
||||
self.create_pivot,
|
||||
self.create_terrain,
|
||||
self.sound_menu,
|
||||
self.create_navmesh,
|
||||
self.create_decal,
|
||||
self.physics_menu.menu,
|
||||
self.physics2d_menu.menu,
|
||||
self.dim2_menu.menu,
|
||||
self.animation_menu.menu,
|
||||
] {
|
||||
for widget in self.root_items.iter() {
|
||||
if *widget == self.ui_menu.menu {
|
||||
continue;
|
||||
}
|
||||
|
||||
ui.send_message(WidgetMessage::enabled(
|
||||
widget,
|
||||
*widget,
|
||||
MessageDirection::ToWidget,
|
||||
!is_ui_scene,
|
||||
));
|
||||
@@ -372,168 +200,24 @@ impl CreateEntityMenu {
|
||||
sender: &MessageSender,
|
||||
controller: &mut dyn SceneController,
|
||||
selection: &Selection,
|
||||
engine: &mut Engine,
|
||||
) -> Option<Node> {
|
||||
if let Some(ui_scene) = controller.downcast_mut::<UiScene>() {
|
||||
self.ui_menu
|
||||
.handle_ui_message(sender, message, ui_scene, selection);
|
||||
} else if let Some(game_scene) = controller.downcast_mut::<GameScene>() {
|
||||
let graph = &mut engine.scenes[game_scene.scene].graph;
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if let Some(constructor) = self.constructor_views.get(&message.destination()) {
|
||||
if let VariantResult::Owned(node) = constructor(graph) {
|
||||
return Some(node);
|
||||
} else {
|
||||
Log::err("Unsupported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.physics_menu
|
||||
.handle_ui_message(message)
|
||||
.or_else(|| self.physics2d_menu.handle_ui_message(message))
|
||||
.or_else(|| self.dim2_menu.handle_ui_message(message))
|
||||
.or_else(|| self.animation_menu.handle_ui_message(message))
|
||||
.or_else(|| {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.create_cube {
|
||||
Some(
|
||||
MeshBuilder::new(BaseBuilder::new().with_name("Cube"))
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
|
||||
ResourceKind::Embedded,
|
||||
SurfaceData::make_cube(Matrix4::identity()),
|
||||
))
|
||||
.with_material(placeholder_material())
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_spot_light {
|
||||
Some(
|
||||
SpotLightBuilder::new(BaseLightBuilder::new(
|
||||
BaseBuilder::new().with_name("SpotLight"),
|
||||
))
|
||||
.with_distance(10.0)
|
||||
.with_hotspot_cone_angle(45.0f32.to_radians())
|
||||
.with_falloff_angle_delta(2.0f32.to_radians())
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_pivot {
|
||||
Some(PivotBuilder::new(BaseBuilder::new().with_name("Pivot")).build_node())
|
||||
} else if message.destination() == self.create_point_light {
|
||||
Some(
|
||||
PointLightBuilder::new(BaseLightBuilder::new(
|
||||
BaseBuilder::new().with_name("PointLight"),
|
||||
))
|
||||
.with_radius(10.0)
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_directional_light {
|
||||
Some(
|
||||
DirectionalLightBuilder::new(BaseLightBuilder::new(
|
||||
BaseBuilder::new().with_name("DirectionalLight"),
|
||||
))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_cone {
|
||||
Some(
|
||||
MeshBuilder::new(BaseBuilder::new().with_name("Cone"))
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
|
||||
ResourceKind::Embedded,
|
||||
SurfaceData::make_cone(16, 0.5, 1.0, &Matrix4::identity()),
|
||||
))
|
||||
.with_material(placeholder_material())
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_cylinder {
|
||||
Some(
|
||||
MeshBuilder::new(BaseBuilder::new().with_name("Cylinder"))
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
|
||||
ResourceKind::Embedded,
|
||||
SurfaceData::make_cylinder(
|
||||
16,
|
||||
0.5,
|
||||
1.0,
|
||||
true,
|
||||
&Matrix4::identity(),
|
||||
),
|
||||
))
|
||||
.with_material(placeholder_material())
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_sphere {
|
||||
Some(
|
||||
MeshBuilder::new(BaseBuilder::new().with_name("Sphere"))
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
|
||||
ResourceKind::Embedded,
|
||||
SurfaceData::make_sphere(16, 16, 0.5, &Matrix4::identity()),
|
||||
))
|
||||
.with_material(placeholder_material())
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_quad {
|
||||
Some(
|
||||
MeshBuilder::new(BaseBuilder::new().with_name("Quad"))
|
||||
.with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
|
||||
ResourceKind::Embedded,
|
||||
SurfaceData::make_quad(&Matrix4::identity()),
|
||||
))
|
||||
.with_material(placeholder_material())
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_camera {
|
||||
Some(
|
||||
CameraBuilder::new(BaseBuilder::new().with_name("Camera")).build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_navmesh {
|
||||
let navmesh = Navmesh::new(
|
||||
vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])],
|
||||
vec![
|
||||
Vector3::new(-1.0, 0.0, 1.0),
|
||||
Vector3::new(1.0, 0.0, 1.0),
|
||||
Vector3::new(1.0, 0.0, -1.0),
|
||||
Vector3::new(-1.0, 0.0, -1.0),
|
||||
],
|
||||
);
|
||||
Some(
|
||||
NavigationalMeshBuilder::new(BaseBuilder::new().with_name("Navmesh"))
|
||||
.with_navmesh(navmesh)
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_sprite {
|
||||
Some(
|
||||
SpriteBuilder::new(BaseBuilder::new().with_name("Sprite")).build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_sound_source {
|
||||
Some(SoundBuilder::new(BaseBuilder::new().with_name("Sound")).build_node())
|
||||
} else if message.destination() == self.create_particle_system {
|
||||
Some(
|
||||
ParticleSystemBuilder::new(
|
||||
BaseBuilder::new().with_name("ParticleSystem"),
|
||||
)
|
||||
.with_emitters(vec![SphereEmitterBuilder::new(
|
||||
BaseEmitterBuilder::new()
|
||||
.with_max_particles(100)
|
||||
.resurrect_particles(true),
|
||||
)
|
||||
.with_radius(1.0)
|
||||
.build()])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_terrain {
|
||||
Some(
|
||||
TerrainBuilder::new(BaseBuilder::new().with_name("Terrain"))
|
||||
.with_layers(vec![Layer {
|
||||
material: create_terrain_layer_material(),
|
||||
..Default::default()
|
||||
}])
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_decal {
|
||||
Some(DecalBuilder::new(BaseBuilder::new().with_name("Decal")).build_node())
|
||||
} else if message.destination() == self.create_listener {
|
||||
Some(
|
||||
ListenerBuilder::new(BaseBuilder::new().with_name("Listener"))
|
||||
.build_node(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::pool::Handle,
|
||||
gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode},
|
||||
scene::{
|
||||
base::BaseBuilder, dim2::rectangle::RectangleBuilder, node::Node,
|
||||
tilemap::TileMapBuilder,
|
||||
},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
};
|
||||
|
||||
pub struct Dim2Menu {
|
||||
pub menu: Handle<UiNode>,
|
||||
create_sprite: Handle<UiNode>,
|
||||
create_tile_map: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl Dim2Menu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let create_sprite;
|
||||
let create_tile_map;
|
||||
|
||||
let menu = create_menu_item(
|
||||
"2D",
|
||||
vec![
|
||||
{
|
||||
create_sprite = create_menu_item("Rectangle (2D Sprite)", vec![], ctx);
|
||||
create_sprite
|
||||
},
|
||||
{
|
||||
create_tile_map = create_menu_item("Tile Map", vec![], ctx);
|
||||
create_tile_map
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
|
||||
Self {
|
||||
menu,
|
||||
create_sprite,
|
||||
create_tile_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(&mut self, message: &UiMessage) -> Option<Node> {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.create_sprite {
|
||||
let node =
|
||||
RectangleBuilder::new(BaseBuilder::new().with_name("Sprite (2D)")).build_node();
|
||||
Some(node)
|
||||
} else if message.destination() == self.create_tile_map {
|
||||
let node =
|
||||
TileMapBuilder::new(BaseBuilder::new().with_name("Tile Map")).build_node();
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,10 @@ use crate::{
|
||||
|
||||
pub struct EditMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
undo: Handle<UiNode>,
|
||||
redo: Handle<UiNode>,
|
||||
copy: Handle<UiNode>,
|
||||
paste: Handle<UiNode>,
|
||||
pub undo: Handle<UiNode>,
|
||||
pub redo: Handle<UiNode>,
|
||||
pub copy: Handle<UiNode>,
|
||||
pub paste: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl EditMenu {
|
||||
|
||||
+7
-29
@@ -36,27 +36,25 @@ use crate::{
|
||||
menu::{create_menu_item, create_menu_item_shortcut, create_root_menu_item},
|
||||
message::MessageSender,
|
||||
scene::container::EditorSceneEntry,
|
||||
settings::{recent::RecentFiles, Settings, SettingsWindow},
|
||||
settings::{recent::RecentFiles, Settings},
|
||||
Engine, Message, Mode, Panels, SaveSceneConfirmationDialogAction,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct FileMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
new_scene: Handle<UiNode>,
|
||||
new_ui_scene: Handle<UiNode>,
|
||||
pub new_scene: Handle<UiNode>,
|
||||
pub new_ui_scene: Handle<UiNode>,
|
||||
pub save: Handle<UiNode>,
|
||||
pub save_as: Handle<UiNode>,
|
||||
pub save_all: Handle<UiNode>,
|
||||
load: Handle<UiNode>,
|
||||
pub load: Handle<UiNode>,
|
||||
pub close_scene: Handle<UiNode>,
|
||||
exit: Handle<UiNode>,
|
||||
pub open_settings: Handle<UiNode>,
|
||||
configure: Handle<UiNode>,
|
||||
pub exit: Handle<UiNode>,
|
||||
pub configure: Handle<UiNode>,
|
||||
pub save_file_selector: Handle<UiNode>,
|
||||
pub load_file_selector: Handle<UiNode>,
|
||||
configure_message: Handle<UiNode>,
|
||||
pub settings: SettingsWindow,
|
||||
pub configure_message: Handle<UiNode>,
|
||||
pub recent_files_container: Handle<UiNode>,
|
||||
pub recent_files: Vec<Handle<UiNode>>,
|
||||
pub open_scene_settings: Handle<UiNode>,
|
||||
@@ -83,7 +81,6 @@ impl FileMenu {
|
||||
let save_all;
|
||||
let close_scene;
|
||||
let load;
|
||||
let open_settings;
|
||||
let open_scene_settings;
|
||||
let configure;
|
||||
let exit;
|
||||
@@ -135,10 +132,6 @@ impl FileMenu {
|
||||
close_scene = create_menu_item_shortcut("Close Scene", "Ctrl+Q", vec![], ctx);
|
||||
close_scene
|
||||
},
|
||||
{
|
||||
open_settings = create_menu_item("Editor Settings...", vec![], ctx);
|
||||
open_settings
|
||||
},
|
||||
{
|
||||
open_scene_settings = create_menu_item("Scene Settings...", vec![], ctx);
|
||||
open_scene_settings
|
||||
@@ -183,10 +176,8 @@ impl FileMenu {
|
||||
close_scene,
|
||||
load,
|
||||
exit,
|
||||
open_settings,
|
||||
configure,
|
||||
configure_message,
|
||||
settings: SettingsWindow::new(engine),
|
||||
recent_files_container,
|
||||
recent_files,
|
||||
open_scene_settings,
|
||||
@@ -243,9 +234,6 @@ impl FileMenu {
|
||||
settings: &mut Settings,
|
||||
panels: &mut Panels,
|
||||
) {
|
||||
self.settings
|
||||
.handle_message(message, engine, settings, sender);
|
||||
|
||||
if let Some(FileSelectorMessage::Commit(path)) = message.data::<FileSelectorMessage>() {
|
||||
if message.destination() == self.save_file_selector {
|
||||
if let Some(game_scene) = entry {
|
||||
@@ -254,13 +242,6 @@ impl FileMenu {
|
||||
path: path.to_owned(),
|
||||
});
|
||||
}
|
||||
engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
.send_message(WidgetMessage::remove(
|
||||
self.save_file_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.save_file_selector = Handle::NONE;
|
||||
} else if message.destination() == self.load_file_selector {
|
||||
sender.send(Message::LoadScene(path.to_owned()));
|
||||
@@ -336,9 +317,6 @@ impl FileMenu {
|
||||
ExportWindow::new(&mut engine.user_interfaces.first_mut().build_ctx());
|
||||
export_window.open(engine.user_interfaces.first());
|
||||
*panels.export_window = Some(export_window);
|
||||
} else if message.destination() == self.open_settings {
|
||||
self.settings
|
||||
.open(engine.user_interfaces.first_mut(), settings, sender);
|
||||
} else if message.destination() == self.open_scene_settings {
|
||||
panels.scene_settings.open(engine.user_interfaces.first());
|
||||
} else if let Some(recent_file) = self
|
||||
|
||||
@@ -26,8 +26,8 @@ use crate::menu::{create_menu_item, create_root_menu_item};
|
||||
|
||||
pub struct HelpMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
open_book: Handle<UiNode>,
|
||||
open_api_reference: Handle<UiNode>,
|
||||
pub open_book: Handle<UiNode>,
|
||||
pub open_api_reference: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl HelpMenu {
|
||||
|
||||
+12
-19
@@ -19,7 +19,6 @@
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::{
|
||||
animation::AnimationEditor,
|
||||
export::ExportWindow,
|
||||
fyrox::{
|
||||
core::{algebra::Vector2, pool::Handle},
|
||||
@@ -39,32 +38,27 @@ use crate::{
|
||||
send_sync_message,
|
||||
settings::Settings,
|
||||
stats::StatisticsWindow,
|
||||
utils::ragdoll::RagdollWizard,
|
||||
AbsmEditor, CurveEditorWindow, Engine, Mode, SceneSettingsWindow,
|
||||
Engine, Mode, SceneSettingsWindow,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub mod animation;
|
||||
pub mod create;
|
||||
pub mod dim2;
|
||||
pub mod edit;
|
||||
pub mod file;
|
||||
pub mod help;
|
||||
pub mod physics;
|
||||
pub mod physics2d;
|
||||
pub mod ui;
|
||||
pub mod utils;
|
||||
pub mod view;
|
||||
|
||||
pub struct Menu {
|
||||
pub menu: Handle<UiNode>,
|
||||
create_entity_menu: CreateEntityRootMenu,
|
||||
edit_menu: EditMenu,
|
||||
pub create_entity_menu: CreateEntityRootMenu,
|
||||
pub edit_menu: EditMenu,
|
||||
pub file_menu: FileMenu,
|
||||
view_menu: ViewMenu,
|
||||
message_sender: MessageSender,
|
||||
utils_menu: UtilsMenu,
|
||||
help_menu: HelpMenu,
|
||||
pub view_menu: ViewMenu,
|
||||
pub message_sender: MessageSender,
|
||||
pub utils_menu: UtilsMenu,
|
||||
pub help_menu: HelpMenu,
|
||||
}
|
||||
|
||||
pub struct Panels<'b> {
|
||||
@@ -78,12 +72,7 @@ pub struct Panels<'b> {
|
||||
pub world_outliner_window: Handle<UiNode>,
|
||||
pub asset_window: Handle<UiNode>,
|
||||
pub configurator_window: Handle<UiNode>,
|
||||
pub path_fixer: Handle<UiNode>,
|
||||
pub curve_editor: &'b CurveEditorWindow,
|
||||
pub absm_editor: &'b AbsmEditor,
|
||||
pub scene_settings: &'b SceneSettingsWindow,
|
||||
pub animation_editor: &'b AnimationEditor,
|
||||
pub ragdoll_wizard: &'b RagdollWizard,
|
||||
pub export_window: &'b mut Option<ExportWindow>,
|
||||
pub statistics_window: &'b mut Option<StatisticsWindow>,
|
||||
}
|
||||
@@ -133,7 +122,11 @@ impl Menu {
|
||||
pub fn new(engine: &mut Engine, message_sender: MessageSender, settings: &Settings) -> Self {
|
||||
let file_menu = FileMenu::new(engine, settings);
|
||||
let ctx = &mut engine.user_interfaces.first_mut().build_ctx();
|
||||
let create_entity_menu = CreateEntityRootMenu::new(ctx);
|
||||
let create_entity_menu = CreateEntityRootMenu::new(
|
||||
&engine.serialization_context,
|
||||
&engine.widget_constructors,
|
||||
ctx,
|
||||
);
|
||||
let edit_menu = EditMenu::new(ctx);
|
||||
let view_menu = ViewMenu::new(ctx);
|
||||
let utils_menu = UtilsMenu::new(ctx);
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode},
|
||||
scene::{
|
||||
base::BaseBuilder, collider::*, joint::*, node::Node, ragdoll::RagdollBuilder,
|
||||
rigidbody::RigidBodyBuilder,
|
||||
},
|
||||
};
|
||||
use crate::menu::create_menu_item;
|
||||
|
||||
pub struct PhysicsMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
create_rigid_body: Handle<UiNode>,
|
||||
create_revolute_joint: Handle<UiNode>,
|
||||
create_ball_joint: Handle<UiNode>,
|
||||
create_prismatic_joint: Handle<UiNode>,
|
||||
create_fixed_joint: Handle<UiNode>,
|
||||
create_collider: Handle<UiNode>,
|
||||
create_ragdoll: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl PhysicsMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let create_rigid_body;
|
||||
let create_collider;
|
||||
let create_revolute_joint;
|
||||
let create_ball_joint;
|
||||
let create_prismatic_joint;
|
||||
let create_fixed_joint;
|
||||
let create_ragdoll;
|
||||
let menu = create_menu_item(
|
||||
"Physics",
|
||||
vec![
|
||||
{
|
||||
create_rigid_body = create_menu_item("Rigid Body", vec![], ctx);
|
||||
create_rigid_body
|
||||
},
|
||||
{
|
||||
create_collider = create_menu_item("Collider", vec![], ctx);
|
||||
create_collider
|
||||
},
|
||||
{
|
||||
create_revolute_joint = create_menu_item("Revolute Joint", vec![], ctx);
|
||||
create_revolute_joint
|
||||
},
|
||||
{
|
||||
create_ball_joint = create_menu_item("Ball Joint", vec![], ctx);
|
||||
create_ball_joint
|
||||
},
|
||||
{
|
||||
create_prismatic_joint = create_menu_item("Prismatic Joint", vec![], ctx);
|
||||
create_prismatic_joint
|
||||
},
|
||||
{
|
||||
create_fixed_joint = create_menu_item("Fixed Joint", vec![], ctx);
|
||||
create_fixed_joint
|
||||
},
|
||||
{
|
||||
create_ragdoll = create_menu_item("Ragdoll", vec![], ctx);
|
||||
create_ragdoll
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
|
||||
Self {
|
||||
menu,
|
||||
create_rigid_body,
|
||||
create_revolute_joint,
|
||||
create_ball_joint,
|
||||
create_prismatic_joint,
|
||||
create_fixed_joint,
|
||||
create_collider,
|
||||
create_ragdoll,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(&mut self, message: &UiMessage) -> Option<Node> {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.create_rigid_body {
|
||||
Some(RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body")).build_node())
|
||||
} else if message.destination() == self.create_revolute_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Revolute Joint"))
|
||||
.with_params(JointParams::RevoluteJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_ball_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Ball Joint"))
|
||||
.with_params(JointParams::BallJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_prismatic_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Prismatic Joint"))
|
||||
.with_params(JointParams::PrismaticJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_fixed_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Fixed Joint"))
|
||||
.with_params(JointParams::FixedJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination == self.create_collider {
|
||||
Some(
|
||||
ColliderBuilder::new(BaseBuilder::new().with_name("Collider"))
|
||||
.with_shape(ColliderShape::Cuboid(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination == self.create_ragdoll {
|
||||
Some(RagdollBuilder::new(BaseBuilder::new().with_name("Ragdoll")).build_node())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode},
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
dim2::{collider::*, joint::*, rigidbody::RigidBodyBuilder},
|
||||
node::Node,
|
||||
},
|
||||
};
|
||||
use crate::menu::create_menu_item;
|
||||
|
||||
pub struct Physics2dMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
create_rigid_body: Handle<UiNode>,
|
||||
create_ball_joint: Handle<UiNode>,
|
||||
create_prismatic_joint: Handle<UiNode>,
|
||||
create_fixed_joint: Handle<UiNode>,
|
||||
create_collider: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl Physics2dMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let create_rigid_body;
|
||||
let create_collider;
|
||||
let create_ball_joint;
|
||||
let create_prismatic_joint;
|
||||
let create_fixed_joint;
|
||||
let menu = create_menu_item(
|
||||
"Physics 2D",
|
||||
vec![
|
||||
{
|
||||
create_rigid_body = create_menu_item("Rigid Body", vec![], ctx);
|
||||
create_rigid_body
|
||||
},
|
||||
{
|
||||
create_collider = create_menu_item("Collider", vec![], ctx);
|
||||
create_collider
|
||||
},
|
||||
{
|
||||
create_ball_joint = create_menu_item("Ball Joint", vec![], ctx);
|
||||
create_ball_joint
|
||||
},
|
||||
{
|
||||
create_prismatic_joint = create_menu_item("Prismatic Joint", vec![], ctx);
|
||||
create_prismatic_joint
|
||||
},
|
||||
{
|
||||
create_fixed_joint = create_menu_item("Fixed Joint", vec![], ctx);
|
||||
create_fixed_joint
|
||||
},
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
|
||||
Self {
|
||||
menu,
|
||||
create_rigid_body,
|
||||
create_ball_joint,
|
||||
create_prismatic_joint,
|
||||
create_fixed_joint,
|
||||
create_collider,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(&mut self, message: &UiMessage) -> Option<Node> {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.create_rigid_body {
|
||||
Some(
|
||||
RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body 2D"))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_ball_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Ball Joint 2D"))
|
||||
.with_params(JointParams::BallJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_prismatic_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Prismatic Joint 2D"))
|
||||
.with_params(JointParams::PrismaticJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination() == self.create_fixed_joint {
|
||||
Some(
|
||||
JointBuilder::new(BaseBuilder::new().with_name("Fixed Joint 2D"))
|
||||
.with_params(JointParams::FixedJoint(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else if message.destination == self.create_collider {
|
||||
Some(
|
||||
ColliderBuilder::new(BaseBuilder::new().with_name("Collider 2D"))
|
||||
.with_shape(ColliderShape::Cuboid(Default::default()))
|
||||
.build_node(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
-218
@@ -18,231 +18,73 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::gui::selector::SelectorBuilder;
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
fxhash::FxHashMap,
|
||||
gui::{
|
||||
absm::{AbsmEventProviderBuilder, AnimationBlendingStateMachineBuilder},
|
||||
animation::AnimationPlayerBuilder,
|
||||
border::BorderBuilder,
|
||||
button::ButtonBuilder,
|
||||
canvas::CanvasBuilder,
|
||||
check_box::CheckBoxBuilder,
|
||||
decorator::DecoratorBuilder,
|
||||
dropdown_list::DropdownListBuilder,
|
||||
expander::ExpanderBuilder,
|
||||
grid::GridBuilder,
|
||||
image::ImageBuilder,
|
||||
list_view::ListViewBuilder,
|
||||
menu::MenuItemMessage,
|
||||
menu::{MenuBuilder, MenuItemBuilder},
|
||||
message::UiMessage,
|
||||
messagebox::MessageBoxBuilder,
|
||||
nine_patch::NinePatchBuilder,
|
||||
numeric::NumericUpDownBuilder,
|
||||
path::PathEditorBuilder,
|
||||
popup::PopupBuilder,
|
||||
progress_bar::ProgressBarBuilder,
|
||||
screen::ScreenBuilder,
|
||||
scroll_bar::ScrollBarBuilder,
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
searchbar::SearchBarBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
tab_control::TabControlBuilder,
|
||||
text::TextBuilder,
|
||||
text_box::TextBoxBuilder,
|
||||
tree::{TreeBuilder, TreeRootBuilder},
|
||||
uuid::UuidEditorBuilder,
|
||||
vector_image::VectorImageBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::WindowBuilder,
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
BuildContext, UiNode,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::{log::Log, pool::Handle},
|
||||
fxhash::FxHashMap,
|
||||
graph::constructor::{VariantConstructor, VariantResult},
|
||||
gui::{
|
||||
constructor::WidgetConstructorContainer, menu::MenuItemMessage,
|
||||
message::MessageDirection, message::UiMessage, BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
scene::Selection,
|
||||
ui_scene::{commands::graph::AddWidgetCommand, UiScene},
|
||||
};
|
||||
use fyrox::gui::menu::SortingPredicate;
|
||||
|
||||
pub struct UiMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
constructors: FxHashMap<Handle<UiNode>, UiMenuEntry>,
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct UiMenuEntry {
|
||||
pub name: String,
|
||||
pub constructor: Box<dyn FnMut(&str, &mut BuildContext) -> Handle<UiNode>>,
|
||||
}
|
||||
|
||||
impl UiMenuEntry {
|
||||
pub fn new<P, F>(name: P, constructor: F) -> Self
|
||||
where
|
||||
P: AsRef<str>,
|
||||
F: FnMut(&str, &mut BuildContext) -> Handle<UiNode> + 'static,
|
||||
{
|
||||
Self {
|
||||
name: name.as_ref().to_owned(),
|
||||
constructor: Box::new(constructor),
|
||||
}
|
||||
}
|
||||
constructor_views: FxHashMap<Handle<UiNode>, VariantConstructor<UiNode, UserInterface>>,
|
||||
}
|
||||
|
||||
impl UiMenu {
|
||||
pub fn default_entries() -> Vec<UiMenuEntry> {
|
||||
vec![
|
||||
UiMenuEntry::new("Screen", |name, ctx| {
|
||||
ScreenBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Button", |name, ctx| {
|
||||
ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(100.0)
|
||||
.with_height(20.0)
|
||||
.with_name(name),
|
||||
)
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Border", |name, ctx| {
|
||||
BorderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Image", |name, ctx| {
|
||||
ImageBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_height(32.0)
|
||||
.with_width(32.0)
|
||||
.with_name(name),
|
||||
)
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Canvas", |name, ctx| {
|
||||
CanvasBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Grid", |name, ctx| {
|
||||
GridBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("CheckBox", |name, ctx| {
|
||||
CheckBoxBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Decorator", |name, ctx| {
|
||||
DecoratorBuilder::new(BorderBuilder::new(WidgetBuilder::new().with_name(name)))
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("DropdownList", |name, ctx| {
|
||||
DropdownListBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Expander", |name, ctx| {
|
||||
ExpanderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("ListView", |name, ctx| {
|
||||
ListViewBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Menu", |name, ctx| {
|
||||
MenuBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("MenuItem", |name, ctx| {
|
||||
MenuItemBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("MessageBox", |name, ctx| {
|
||||
MessageBoxBuilder::new(WindowBuilder::new(WidgetBuilder::new().with_name(name)))
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("NinePatch", |name, ctx| {
|
||||
NinePatchBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("NumericUpDownF32", |name, ctx| {
|
||||
NumericUpDownBuilder::<f32>::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("NumericUpDownI32", |name, ctx| {
|
||||
NumericUpDownBuilder::<i32>::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("PathEditor", |name, ctx| {
|
||||
PathEditorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Popup", |name, ctx| {
|
||||
PopupBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("ProgressBar", |name, ctx| {
|
||||
ProgressBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("ScrollBar", |name, ctx| {
|
||||
ScrollBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("ScrollViewer", |name, ctx| {
|
||||
ScrollViewerBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("SearchBar", |name, ctx| {
|
||||
SearchBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("StackPanel", |name, ctx| {
|
||||
StackPanelBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("TabControl", |name, ctx| {
|
||||
TabControlBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Text", |name, ctx| {
|
||||
TextBuilder::new(WidgetBuilder::new().with_name(name))
|
||||
.with_text("Text")
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("TextBox", |name, ctx| {
|
||||
TextBoxBuilder::new(WidgetBuilder::new().with_name(name))
|
||||
.with_text("Text")
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Tree", |name, ctx| {
|
||||
TreeBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("TreeRoot", |name, ctx| {
|
||||
TreeRootBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("UuidEditor", |name, ctx| {
|
||||
UuidEditorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("VectorImage", |name, ctx| {
|
||||
VectorImageBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Window", |name, ctx| {
|
||||
WindowBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("WrapPanel", |name, ctx| {
|
||||
WrapPanelBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("AnimationPlayer", |name, ctx| {
|
||||
AnimationPlayerBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("AnimationBlendingStateMachine", |name, ctx| {
|
||||
AnimationBlendingStateMachineBuilder::new(WidgetBuilder::new().with_name(name))
|
||||
.build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("AbsmEventProvider", |name, ctx| {
|
||||
AbsmEventProviderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
UiMenuEntry::new("Selector", |name, ctx| {
|
||||
SelectorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx)
|
||||
}),
|
||||
]
|
||||
}
|
||||
pub fn new(
|
||||
constructors: &WidgetConstructorContainer,
|
||||
name: &str,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let mut root_items = vec![];
|
||||
let mut groups = FxHashMap::default();
|
||||
let mut constructor_views = FxHashMap::default();
|
||||
let constructors = constructors.map();
|
||||
for constructor in constructors.values() {
|
||||
for variant in constructor.variants.iter() {
|
||||
let item = create_menu_item(&variant.name, vec![], ctx);
|
||||
constructor_views.insert(item, variant.constructor.clone());
|
||||
if constructor.group.is_empty() {
|
||||
root_items.push(item);
|
||||
} else {
|
||||
let group = *groups.entry(constructor.group).or_insert_with(|| {
|
||||
let group = create_menu_item(constructor.group, vec![], ctx);
|
||||
root_items.push(group);
|
||||
group
|
||||
});
|
||||
ctx.inner().send_message(MenuItemMessage::add_item(
|
||||
group,
|
||||
MessageDirection::ToWidget,
|
||||
item,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(entries: Vec<UiMenuEntry>, name: &str, ctx: &mut BuildContext) -> Self {
|
||||
let items = entries
|
||||
.iter()
|
||||
.map(|e| create_menu_item(&e.name, Default::default(), ctx))
|
||||
.collect::<Vec<_>>();
|
||||
let menu = create_menu_item(name, root_items.clone(), ctx);
|
||||
|
||||
let constructors = entries
|
||||
.into_iter()
|
||||
.zip(items.iter().cloned())
|
||||
.map(|(entry, node)| (node, entry))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
for root_item in root_items.iter().chain(&[menu]) {
|
||||
ctx.inner().send_message(MenuItemMessage::sort(
|
||||
*root_item,
|
||||
MessageDirection::ToWidget,
|
||||
SortingPredicate::sort_by_text(),
|
||||
))
|
||||
}
|
||||
|
||||
let menu = create_menu_item(name, items, ctx);
|
||||
|
||||
Self { menu, constructors }
|
||||
Self {
|
||||
menu,
|
||||
constructor_views,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(
|
||||
@@ -253,15 +95,18 @@ impl UiMenu {
|
||||
selection: &Selection,
|
||||
) {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if let Some(entry) = self.constructors.get_mut(&message.destination()) {
|
||||
let ui_node_handle = (entry.constructor)(&entry.name, &mut scene.ui.build_ctx());
|
||||
let sub_graph = scene.ui.take_reserve_sub_graph(ui_node_handle);
|
||||
let parent = if let Some(selection) = selection.as_ui() {
|
||||
selection.widgets.first().cloned().unwrap_or_default()
|
||||
if let Some(constructor) = self.constructor_views.get_mut(&message.destination()) {
|
||||
if let VariantResult::Handle(ui_node_handle) = constructor(&mut scene.ui) {
|
||||
let sub_graph = scene.ui.take_reserve_sub_graph(ui_node_handle);
|
||||
let parent = if let Some(selection) = selection.as_ui() {
|
||||
selection.widgets.first().cloned().unwrap_or_default()
|
||||
} else {
|
||||
Handle::NONE
|
||||
};
|
||||
sender.do_command(AddWidgetCommand::new(sub_graph, parent, true));
|
||||
} else {
|
||||
Handle::NONE
|
||||
};
|
||||
sender.do_command(AddWidgetCommand::new(sub_graph, parent, true));
|
||||
Log::err("Unsupported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-67
@@ -18,74 +18,34 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
asset::core::pool::Handle,
|
||||
gui::{
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
window::WindowMessage,
|
||||
BuildContext, UiNode, UserInterface,
|
||||
use crate::{
|
||||
fyrox::{
|
||||
asset::core::pool::Handle,
|
||||
gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode, UserInterface},
|
||||
},
|
||||
menu::{create_menu_item, create_root_menu_item, Panels},
|
||||
stats::StatisticsWindow,
|
||||
};
|
||||
use crate::menu::{create_menu_item, create_root_menu_item, Panels};
|
||||
use crate::stats::StatisticsWindow;
|
||||
|
||||
pub struct UtilsMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
open_path_fixer: Handle<UiNode>,
|
||||
open_curve_editor: Handle<UiNode>,
|
||||
absm_editor: Handle<UiNode>,
|
||||
animation_editor: Handle<UiNode>,
|
||||
ragdoll_wizard: Handle<UiNode>,
|
||||
rendering_statistics: Handle<UiNode>,
|
||||
pub rendering_statistics: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl UtilsMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let open_path_fixer;
|
||||
let open_curve_editor;
|
||||
let absm_editor;
|
||||
let animation_editor;
|
||||
let ragdoll_wizard;
|
||||
let rendering_statistics;
|
||||
let menu = create_root_menu_item(
|
||||
"Utils",
|
||||
vec![
|
||||
{
|
||||
open_path_fixer = create_menu_item("Path Fixer", vec![], ctx);
|
||||
open_path_fixer
|
||||
},
|
||||
{
|
||||
open_curve_editor = create_menu_item("Curve Editor", vec![], ctx);
|
||||
open_curve_editor
|
||||
},
|
||||
{
|
||||
absm_editor = create_menu_item("ABSM Editor", vec![], ctx);
|
||||
absm_editor
|
||||
},
|
||||
{
|
||||
animation_editor = create_menu_item("Animation Editor", vec![], ctx);
|
||||
animation_editor
|
||||
},
|
||||
{
|
||||
ragdoll_wizard = create_menu_item("Ragdoll Wizard", vec![], ctx);
|
||||
ragdoll_wizard
|
||||
},
|
||||
{
|
||||
rendering_statistics = create_menu_item("Rendering Statistics", vec![], ctx);
|
||||
rendering_statistics
|
||||
},
|
||||
],
|
||||
vec![{
|
||||
rendering_statistics = create_menu_item("Rendering Statistics", vec![], ctx);
|
||||
rendering_statistics
|
||||
}],
|
||||
ctx,
|
||||
);
|
||||
|
||||
Self {
|
||||
menu,
|
||||
open_path_fixer,
|
||||
open_curve_editor,
|
||||
absm_editor,
|
||||
animation_editor,
|
||||
ragdoll_wizard,
|
||||
rendering_statistics,
|
||||
}
|
||||
}
|
||||
@@ -97,22 +57,7 @@ impl UtilsMenu {
|
||||
ui: &mut UserInterface,
|
||||
) {
|
||||
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
if message.destination() == self.open_path_fixer {
|
||||
ui.send_message(WindowMessage::open_modal(
|
||||
panels.path_fixer,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
} else if message.destination() == self.open_curve_editor {
|
||||
panels.curve_editor.open(ui);
|
||||
} else if message.destination() == self.absm_editor {
|
||||
panels.absm_editor.open(ui);
|
||||
} else if message.destination() == self.animation_editor {
|
||||
panels.animation_editor.open(ui);
|
||||
} else if message.destination() == self.ragdoll_wizard {
|
||||
panels.ragdoll_wizard.open(ui);
|
||||
} else if message.destination() == self.rendering_statistics {
|
||||
if message.destination() == self.rendering_statistics {
|
||||
*panels.statistics_window = Some(StatisticsWindow::new(
|
||||
&mut ui.build_ctx(),
|
||||
panels.scene_frame,
|
||||
|
||||
+10
-10
@@ -36,16 +36,16 @@ use crate::{
|
||||
|
||||
pub struct ViewMenu {
|
||||
pub menu: Handle<UiNode>,
|
||||
inspector: Handle<UiNode>,
|
||||
world_viewer: Handle<UiNode>,
|
||||
asset_browser: Handle<UiNode>,
|
||||
light_panel: Handle<UiNode>,
|
||||
log_panel: Handle<UiNode>,
|
||||
nav_mesh: Handle<UiNode>,
|
||||
audio: Handle<UiNode>,
|
||||
command_stack: Handle<UiNode>,
|
||||
save_layout: Handle<UiNode>,
|
||||
load_layout: Handle<UiNode>,
|
||||
pub inspector: Handle<UiNode>,
|
||||
pub world_viewer: Handle<UiNode>,
|
||||
pub asset_browser: Handle<UiNode>,
|
||||
pub light_panel: Handle<UiNode>,
|
||||
pub log_panel: Handle<UiNode>,
|
||||
pub nav_mesh: Handle<UiNode>,
|
||||
pub audio: Handle<UiNode>,
|
||||
pub command_stack: Handle<UiNode>,
|
||||
pub save_layout: Handle<UiNode>,
|
||||
pub load_layout: Handle<UiNode>,
|
||||
}
|
||||
|
||||
fn switch_window_state(window: Handle<UiNode>, ui: &UserInterface, center: bool) {
|
||||
|
||||
@@ -34,6 +34,7 @@ use crate::{
|
||||
SaveSceneConfirmationDialogAction,
|
||||
};
|
||||
use fyrox::scene::tilemap::tileset::TileSetResource;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{path::PathBuf, sync::mpsc::Sender};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -61,7 +62,6 @@ pub enum Message {
|
||||
Exit {
|
||||
force: bool,
|
||||
},
|
||||
OpenSettings,
|
||||
OpenAnimationEditor,
|
||||
OpenAbsmEditor,
|
||||
OpenMaterialEditor(MaterialResource),
|
||||
@@ -108,6 +108,13 @@ pub enum Message {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MessageSender(pub Sender<Message>);
|
||||
|
||||
impl Default for MessageSender {
|
||||
fn default() -> Self {
|
||||
let (rx, _) = channel();
|
||||
Self(rx)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for MessageSender {}
|
||||
unsafe impl Sync for MessageSender {}
|
||||
|
||||
|
||||
@@ -72,6 +72,11 @@ pub trait EditorPlugin: BaseEditorPlugin {
|
||||
/// [`crate::Mode::Edit`].
|
||||
fn on_mode_changed(&mut self, #[allow(unused_variables)] editor: &mut Editor) {}
|
||||
|
||||
/// This method is called when active scene was changed. It could happen if a user opens or loads
|
||||
/// a new scene, closes existing scene so the active scene changes to previous in the list of
|
||||
/// scenes (if any).
|
||||
fn on_scene_changed(&mut self, #[allow(unused_variables)] editor: &mut Editor) {}
|
||||
|
||||
/// This method is called when a UI message was extracted from the message queue. It should be used to react to user
|
||||
/// changes, for example a user could click a button, then a [`fyrox::gui::button::ButtonMessage::Click`] will be
|
||||
/// passed to this method. It then can be used to perform some other action.
|
||||
@@ -97,6 +102,12 @@ pub trait EditorPlugin: BaseEditorPlugin {
|
||||
/// about suspension.
|
||||
fn on_resumed(&mut self, #[allow(unused_variables)] editor: &mut Editor) {}
|
||||
|
||||
/// This method is called when the editor leaves preview mode. Usually this method is used to
|
||||
/// rollback scene changes to the state in which scene objects were before entering the preview
|
||||
/// mode. This method is typically called by the editor before execution of any command and before
|
||||
/// saving (to prevent "leakage" of preview mode changes into the saved scene).
|
||||
fn on_leave_preview_mode(&mut self, #[allow(unused_variables)] editor: &mut Editor) {}
|
||||
|
||||
/// This method is used to tell the editor, whether your plugin is in preview mode or not. Preview mode is a special
|
||||
/// state of the editor, when it modifies a content of some scene every frame and discards these changes when the
|
||||
/// preview mode is disabled.
|
||||
|
||||
@@ -47,22 +47,19 @@ use crate::fyrox::{
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, Control, HorizontalAlignment, RcUiNodeHandle, Thickness, UiNode,
|
||||
UserInterface, VerticalAlignment, BRUSH_DARK, BRUSH_LIGHT, BRUSH_LIGHTEST,
|
||||
UserInterface, VerticalAlignment,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
command::blend::{
|
||||
AddBlendSpacePointCommand, RemoveBlendSpacePointCommand,
|
||||
SetBlendSpacePointPositionCommand,
|
||||
},
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
use crate::plugins::absm::{
|
||||
command::blend::{
|
||||
AddBlendSpacePointCommand, RemoveBlendSpacePointCommand, SetBlendSpacePointPositionCommand,
|
||||
},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
send_sync_message,
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
};
|
||||
use crate::{menu::create_menu_item, message::MessageSender, send_sync_message};
|
||||
use fyrox::gui::menu::ContextMenuBuilder;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
cell::Cell,
|
||||
fmt::{Debug, Formatter},
|
||||
@@ -175,7 +172,7 @@ fn make_points<P: Iterator<Item = Vector2<f32>>>(
|
||||
BlendSpaceFieldPointBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_context_menu(context_menu.clone())
|
||||
.with_background(BRUSH_LIGHTEST)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_LIGHTEST))
|
||||
.with_foreground(Brush::Solid(Color::WHITE))
|
||||
.with_desired_position(p),
|
||||
i,
|
||||
@@ -532,14 +529,14 @@ impl BlendSpaceFieldBuilder {
|
||||
.with_clip_to_bounds(false)
|
||||
.with_preview_messages(true)
|
||||
.with_context_menu(menu.clone())
|
||||
.build(),
|
||||
.build(ctx),
|
||||
points: Default::default(),
|
||||
min_values: self.min_values,
|
||||
max_values: self.max_values,
|
||||
snap_step: self.snap_step,
|
||||
point_positions: Default::default(),
|
||||
triangles: Default::default(),
|
||||
grid_brush: BRUSH_LIGHT,
|
||||
grid_brush: ctx.style.get_or_default(Style::BRUSH_LIGHT),
|
||||
sampling_point: Vector2::new(0.25, 0.5),
|
||||
drag_context: None,
|
||||
field_context_menu: ContextMenu {
|
||||
@@ -635,7 +632,7 @@ impl BlendSpaceFieldPointBuilder {
|
||||
)
|
||||
.with_width(10.0)
|
||||
.with_height(10.0)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
selected: false,
|
||||
};
|
||||
|
||||
@@ -661,8 +658,8 @@ impl BlendSpaceEditor {
|
||||
.on_row(0)
|
||||
.on_column(1)
|
||||
.with_margin(Thickness::uniform(15.0))
|
||||
.with_foreground(BRUSH_LIGHTEST)
|
||||
.with_background(BRUSH_DARK),
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_LIGHTEST))
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARK)),
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
@@ -970,3 +967,17 @@ impl BlendSpaceEditor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::blendspace::{BlendSpaceFieldBuilder, BlendSpaceFieldPointBuilder};
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
BlendSpaceFieldPointBuilder::new(WidgetBuilder::new(), 0).build(ctx)
|
||||
});
|
||||
test_widget_deletion(|ctx| BlendSpaceFieldBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
@@ -39,36 +39,34 @@ use crate::fyrox::{
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
connection::{self, Connection},
|
||||
node::AbsmBaseNode,
|
||||
segment::SegmentMessage,
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
socket::{Socket, SocketDirection, SocketMessage},
|
||||
transition::{self, TransitionView},
|
||||
},
|
||||
utils::fetch_node_screen_center_ui,
|
||||
use crate::plugins::absm::{
|
||||
connection::{self, Connection},
|
||||
node::AbsmBaseNode,
|
||||
segment::SegmentMessage,
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
socket::{Socket, SocketDirection, SocketMessage},
|
||||
transition::{self, TransitionView},
|
||||
};
|
||||
use crate::utils::fetch_node_screen_center_ui;
|
||||
use std::{
|
||||
cell::Cell,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Visit, Reflect, Default)]
|
||||
pub(super) struct Entry {
|
||||
pub(crate) struct Entry {
|
||||
pub node: Handle<UiNode>,
|
||||
pub initial_position: Vector2<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Visit, Reflect, Default)]
|
||||
pub(super) struct DragContext {
|
||||
pub(crate) struct DragContext {
|
||||
initial_cursor_position: Vector2<f32>,
|
||||
entries: Vec<Entry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Visit, Reflect)]
|
||||
pub(super) enum Mode {
|
||||
pub(crate) enum Mode {
|
||||
Normal,
|
||||
Drag {
|
||||
drag_context: DragContext,
|
||||
@@ -86,7 +84,7 @@ pub(super) enum Mode {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(super) enum AbsmCanvasMessage {
|
||||
pub(crate) enum AbsmCanvasMessage {
|
||||
SwitchMode(Mode),
|
||||
CommitTransition {
|
||||
source_node: Handle<UiNode>,
|
||||
@@ -641,7 +639,7 @@ impl AbsmCanvasBuilder {
|
||||
.widget_builder
|
||||
.with_preview_messages(true)
|
||||
.with_clip_to_bounds(false)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
selection: Default::default(),
|
||||
view_position: Default::default(),
|
||||
initial_view_position: Default::default(),
|
||||
@@ -655,3 +653,14 @@ impl AbsmCanvasBuilder {
|
||||
ctx.add_node(UiNode::new(canvas))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::canvas::AbsmCanvasBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| AbsmCanvasBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,9 @@ use crate::fyrox::{
|
||||
node::blendspace::BlendSpacePoint, BlendPose, IndexedBlendInput, PoseNode,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::command::fetch_machine;
|
||||
use crate::{
|
||||
absm::command::fetch_machine, command::CommandTrait, define_push_element_to_collection_command,
|
||||
command::CommandTrait, define_push_element_to_collection_command,
|
||||
define_set_collection_element_command,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
@@ -32,7 +32,8 @@ use crate::fyrox::{
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{absm::segment::Segment, utils::fetch_node_screen_center};
|
||||
use crate::plugins::absm::segment::Segment;
|
||||
use crate::utils::fetch_node_screen_center;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
const PICKED_BRUSH: Brush = Brush::Solid(Color::opaque(100, 100, 100));
|
||||
@@ -146,21 +147,23 @@ impl ConnectionBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self, canvas: Handle<UiNode>, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
let canvas_ref = &ctx[canvas];
|
||||
let canvas_ref = ctx.try_get_node(canvas);
|
||||
|
||||
let connection = Connection {
|
||||
widget: self
|
||||
.widget_builder
|
||||
.with_foreground(NORMAL_BRUSH)
|
||||
.with_clip_to_bounds(false)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
segment: Segment {
|
||||
source: self.source_socket,
|
||||
source_pos: canvas_ref
|
||||
.screen_to_local(fetch_node_screen_center(self.source_socket, ctx)),
|
||||
.map(|c| c.screen_to_local(fetch_node_screen_center(self.source_socket, ctx)))
|
||||
.unwrap_or_default(),
|
||||
dest: self.dest_socket,
|
||||
dest_pos: canvas_ref
|
||||
.screen_to_local(fetch_node_screen_center(self.dest_socket, ctx)),
|
||||
.map(|c| c.screen_to_local(fetch_node_screen_center(self.dest_socket, ctx)))
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
source_node: self.source_node,
|
||||
dest_node: self.dest_node,
|
||||
@@ -169,3 +172,16 @@ impl ConnectionBuilder {
|
||||
ctx.add_node(UiNode::new(connection))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::connection::ConnectionBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
ConnectionBuilder::new(WidgetBuilder::new()).build(Default::default(), ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -39,21 +39,25 @@ use crate::fyrox::{
|
||||
BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
blendspace::BlendSpaceEditor,
|
||||
command::blend::{AddBlendSpacePointCommand, AddInputCommand, AddPoseSourceCommand},
|
||||
node::{AbsmNode, AbsmNodeMessage},
|
||||
parameter::ParameterPanel,
|
||||
selection::AbsmSelection,
|
||||
state_graph::StateGraphViewer,
|
||||
state_viewer::StateViewer,
|
||||
toolbar::{Toolbar, ToolbarAction},
|
||||
},
|
||||
message::MessageSender,
|
||||
scene::Selection,
|
||||
Message,
|
||||
use crate::menu::create_menu_item;
|
||||
use crate::plugin::EditorPlugin;
|
||||
use crate::plugins::absm::{
|
||||
blendspace::BlendSpaceEditor,
|
||||
command::blend::{AddBlendSpacePointCommand, AddInputCommand, AddPoseSourceCommand},
|
||||
node::{AbsmNode, AbsmNodeMessage},
|
||||
parameter::ParameterPanel,
|
||||
selection::AbsmSelection,
|
||||
state_graph::StateGraphViewer,
|
||||
state_viewer::StateViewer,
|
||||
toolbar::{Toolbar, ToolbarAction},
|
||||
};
|
||||
use crate::scene::GameScene;
|
||||
use crate::ui_scene::UiScene;
|
||||
use crate::{message::MessageSender, scene::Selection, Editor, Message};
|
||||
use fyrox::core::some_or_return;
|
||||
use fyrox::gui::dock::DockingManagerMessage;
|
||||
use fyrox::gui::menu::MenuItemMessage;
|
||||
use fyrox::gui::widget::WidgetMessage;
|
||||
use std::{any::Any, fmt::Debug};
|
||||
|
||||
mod blendspace;
|
||||
@@ -197,6 +201,8 @@ pub struct AbsmEditor {
|
||||
}
|
||||
|
||||
impl AbsmEditor {
|
||||
const WINDOW_NAME: &'static str = "AsbmEditor";
|
||||
|
||||
pub fn new(ctx: &mut BuildContext, sender: MessageSender) -> Self {
|
||||
let state_graph_viewer = StateGraphViewer::new(ctx);
|
||||
let state_viewer = StateViewer::new(ctx);
|
||||
@@ -249,7 +255,7 @@ impl AbsmEditor {
|
||||
|
||||
let window = WindowBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_name("AsbmEditor")
|
||||
.with_name(Self::WINDOW_NAME)
|
||||
.with_width(800.0)
|
||||
.with_height(500.0),
|
||||
)
|
||||
@@ -392,6 +398,22 @@ impl AbsmEditor {
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy(self, ui: &UserInterface, docking_manager: Handle<UiNode>) {
|
||||
ui.send_message(DockingManagerMessage::remove_floating_window(
|
||||
docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
self.window,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.blend_space_editor.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn sync_to_model<P, G, N>(
|
||||
&mut self,
|
||||
editor_selection: &Selection,
|
||||
@@ -686,3 +708,208 @@ impl AbsmEditor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AbsmEditorPlugin {
|
||||
absm_editor: Option<AbsmEditor>,
|
||||
open_absm_editor: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl AbsmEditorPlugin {
|
||||
fn get_or_create_absm_editor(
|
||||
&mut self,
|
||||
ui: &mut UserInterface,
|
||||
sender: &MessageSender,
|
||||
) -> &mut AbsmEditor {
|
||||
self.absm_editor
|
||||
.get_or_insert_with(|| AbsmEditor::new(&mut ui.build_ctx(), sender.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for AbsmEditorPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(layout) = editor.settings.windows.layout.as_ref() {
|
||||
if layout.has_window(AbsmEditor::WINDOW_NAME) {
|
||||
self.get_or_create_absm_editor(ui, &editor.message_sender);
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_absm_editor = create_menu_item("ABSM Editor", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_absm_editor,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_sync_to_model(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_mut());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let graph = &editor.engine.scenes[game_scene.scene].graph;
|
||||
absm_editor.sync_to_model(&entry.selection, graph, ui);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
absm_editor.sync_to_model(&entry.selection, &ui_scene.ui, ui);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_scene_changed(&mut self, editor: &mut Editor) {
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_mut());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
absm_editor.clear(ui);
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_absm_editor {
|
||||
editor.message_sender.send(Message::OpenAbsmEditor);
|
||||
}
|
||||
}
|
||||
|
||||
let mut absm_editor = some_or_return!(self.absm_editor.take());
|
||||
|
||||
if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == absm_editor.window {
|
||||
self.on_leave_preview_mode(editor);
|
||||
|
||||
absm_editor.destroy(
|
||||
editor.engine.user_interfaces.first(),
|
||||
editor.docking_manager,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(entry) = editor.scenes.current_scene_entry_mut() {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let graph = &mut editor.engine.scenes[game_scene.scene].graph;
|
||||
absm_editor.handle_ui_message(
|
||||
message,
|
||||
&editor.message_sender,
|
||||
&entry.selection,
|
||||
graph,
|
||||
ui,
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
absm_editor.handle_ui_message(
|
||||
message,
|
||||
&editor.message_sender,
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
ui,
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.absm_editor = Some(absm_editor);
|
||||
}
|
||||
|
||||
fn on_leave_preview_mode(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let engine = &mut editor.engine;
|
||||
absm_editor.try_leave_preview_mode(
|
||||
&entry.selection,
|
||||
&mut engine.scenes[game_scene.scene].graph,
|
||||
engine.user_interfaces.first_mut(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
absm_editor.try_leave_preview_mode(
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
editor.engine.user_interfaces.first_mut(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_in_preview_mode(&self, _editor: &Editor) -> bool {
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_ref(), false);
|
||||
absm_editor.is_in_preview_mode()
|
||||
}
|
||||
|
||||
fn on_update(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_ref::<GameScene>() {
|
||||
absm_editor.update(
|
||||
&entry.selection,
|
||||
&mut editor.engine.scenes[game_scene.scene].graph,
|
||||
editor.engine.user_interfaces.first_mut(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
absm_editor.update(
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
editor.engine.user_interfaces.first_mut(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_message(&mut self, message: &Message, editor: &mut Editor) {
|
||||
if let Message::OpenAbsmEditor = message {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let absm_editor = self.get_or_create_absm_editor(ui, &editor.message_sender);
|
||||
|
||||
absm_editor.open(ui);
|
||||
|
||||
ui.send_message(DockingManagerMessage::add_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
absm_editor.window,
|
||||
));
|
||||
|
||||
self.on_sync_to_model(editor);
|
||||
}
|
||||
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let absm_editor = some_or_return!(self.absm_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
absm_editor.handle_message(
|
||||
message,
|
||||
&entry.selection,
|
||||
&mut editor.engine.scenes[game_scene.scene].graph,
|
||||
editor.engine.user_interfaces.first_mut(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
absm_editor.handle_message(
|
||||
message,
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
editor.engine.user_interfaces.first_mut(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::AbsmEditor;
|
||||
use fyrox::core::algebra::Vector2;
|
||||
use fyrox::core::pool::Handle;
|
||||
use fyrox::gui::UserInterface;
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
let screen_size = Vector2::new(100.0, 100.0);
|
||||
let mut ui = UserInterface::new(screen_size);
|
||||
let editor = AbsmEditor::new(&mut ui.build_ctx(), Default::default());
|
||||
editor.destroy(&ui, Handle::NONE);
|
||||
ui.update(screen_size, 1.0 / 60.0, &Default::default());
|
||||
while ui.poll_message().is_some() {}
|
||||
// Only root node must be alive.
|
||||
assert_eq!(ui.nodes().alive_count(), 1);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,6 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::absm::{
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
BORDER_COLOR, NORMAL_BACKGROUND, SELECTED_BACKGROUND,
|
||||
};
|
||||
use crate::fyrox::{
|
||||
core::{
|
||||
color::Color, pool::Handle, reflect::prelude::*, type_traits::prelude::*, uuid::uuid,
|
||||
@@ -42,6 +38,10 @@ use crate::fyrox::{
|
||||
VerticalAlignment,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::{
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
BORDER_COLOR, NORMAL_BACKGROUND, SELECTED_BACKGROUND,
|
||||
};
|
||||
use std::{
|
||||
fmt::{Debug, Formatter},
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -496,7 +496,7 @@ where
|
||||
.build(ctx);
|
||||
|
||||
let node = AbsmNode {
|
||||
widget: self.widget_builder.with_child(background).build(),
|
||||
widget: self.widget_builder.with_child(background).build(ctx),
|
||||
background,
|
||||
selectable: Default::default(),
|
||||
model_handle: self.model_handle,
|
||||
@@ -516,3 +516,15 @@ where
|
||||
ctx.add_node(UiNode::new(node))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::node::AbsmNodeBuilder;
|
||||
use fyrox::scene::node::Node;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| AbsmNodeBuilder::<Node>::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,10 @@ use crate::fyrox::{
|
||||
BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::command::fetch_machine;
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{
|
||||
absm::command::fetch_machine, command::make_command,
|
||||
inspector::editors::make_property_editors_container, message::MessageSender, Message,
|
||||
MessageDirection, MSG_SYNC_FLAG,
|
||||
command::make_command, message::MessageSender, Message, MessageDirection, MSG_SYNC_FLAG,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -227,7 +227,7 @@ impl SocketBuilder {
|
||||
.build(ctx);
|
||||
|
||||
let socket = Socket {
|
||||
widget: self.widget_builder.with_child(grid).build(),
|
||||
widget: self.widget_builder.with_child(grid).build(ctx),
|
||||
click_position: Default::default(),
|
||||
parent_node: self.parent_node,
|
||||
direction: self.direction,
|
||||
@@ -239,3 +239,14 @@ impl SocketBuilder {
|
||||
ctx.add_node(UiNode::new(socket))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::socket::SocketBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| SocketBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
+11
-12
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use super::fetch_state_node_model_handle;
|
||||
use crate::fyrox::{
|
||||
core::pool::Handle,
|
||||
generic_animation::machine::{Machine, State, Transition},
|
||||
@@ -31,17 +32,17 @@ use crate::fyrox::{
|
||||
BuildContext, RcUiNodeHandle, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
canvas::{AbsmCanvas, AbsmCanvasMessage, Mode},
|
||||
command::{
|
||||
AddStateCommand, AddTransitionCommand, DeleteStateCommand, DeleteTransitionCommand,
|
||||
SetMachineEntryStateCommand,
|
||||
},
|
||||
node::{AbsmNode, AbsmNodeMessage},
|
||||
selection::SelectedEntity,
|
||||
transition::TransitionView,
|
||||
use crate::plugins::absm::{
|
||||
canvas::{AbsmCanvas, AbsmCanvasMessage, Mode},
|
||||
command::{
|
||||
AddStateCommand, AddTransitionCommand, DeleteStateCommand, DeleteTransitionCommand,
|
||||
SetMachineEntryStateCommand,
|
||||
},
|
||||
node::{AbsmNode, AbsmNodeMessage},
|
||||
selection::SelectedEntity,
|
||||
transition::TransitionView,
|
||||
};
|
||||
use crate::{
|
||||
command::{Command, CommandGroup},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
@@ -50,8 +51,6 @@ use crate::{
|
||||
use fyrox::gui::menu::ContextMenuBuilder;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::fetch_state_node_model_handle;
|
||||
|
||||
pub struct CanvasContextMenu {
|
||||
create_state: Handle<UiNode>,
|
||||
connect_all_nodes: Handle<UiNode>,
|
||||
@@ -31,17 +31,17 @@ use crate::fyrox::{
|
||||
BuildContext, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::{
|
||||
canvas::{AbsmCanvas, AbsmCanvasBuilder, AbsmCanvasMessage},
|
||||
command::{AddTransitionCommand, MoveStateNodeCommand},
|
||||
fetch_selection,
|
||||
node::{AbsmNode, AbsmNodeBuilder, AbsmNodeMessage},
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
state_graph::context::{CanvasContextMenu, NodeContextMenu, TransitionContextMenu},
|
||||
transition::{TransitionBuilder, TransitionMessage, TransitionView},
|
||||
NORMAL_BACKGROUND, NORMAL_ROOT_COLOR, SELECTED_BACKGROUND, SELECTED_ROOT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
canvas::{AbsmCanvas, AbsmCanvasBuilder, AbsmCanvasMessage},
|
||||
command::{AddTransitionCommand, MoveStateNodeCommand},
|
||||
fetch_selection,
|
||||
node::{AbsmNode, AbsmNodeBuilder, AbsmNodeMessage},
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
state_graph::context::{CanvasContextMenu, NodeContextMenu, TransitionContextMenu},
|
||||
transition::{TransitionBuilder, TransitionMessage, TransitionView},
|
||||
NORMAL_BACKGROUND, NORMAL_ROOT_COLOR, SELECTED_BACKGROUND, SELECTED_ROOT_COLOR,
|
||||
},
|
||||
command::{Command, CommandGroup},
|
||||
message::MessageSender,
|
||||
scene::{commands::ChangeSelectionCommand, Selection},
|
||||
+11
-11
@@ -35,19 +35,19 @@ use crate::fyrox::{
|
||||
BuildContext, RcUiNodeHandle, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
command::{
|
||||
blend::{
|
||||
SetBlendAnimationByIndexInputPoseSourceCommand,
|
||||
SetBlendAnimationsPoseSourceCommand, SetBlendSpacePoseSourceCommand,
|
||||
},
|
||||
AddPoseNodeCommand, DeletePoseNodeCommand, SetStateRootPoseCommand,
|
||||
use crate::plugins::absm::{
|
||||
command::{
|
||||
blend::{
|
||||
SetBlendAnimationByIndexInputPoseSourceCommand, SetBlendAnimationsPoseSourceCommand,
|
||||
SetBlendSpacePoseSourceCommand,
|
||||
},
|
||||
connection::Connection,
|
||||
node::AbsmNode,
|
||||
selection::SelectedEntity,
|
||||
AddPoseNodeCommand, DeletePoseNodeCommand, SetStateRootPoseCommand,
|
||||
},
|
||||
connection::Connection,
|
||||
node::AbsmNode,
|
||||
selection::SelectedEntity,
|
||||
};
|
||||
use crate::{
|
||||
command::{Command, CommandGroup},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
@@ -38,24 +38,24 @@ use crate::fyrox::{
|
||||
},
|
||||
};
|
||||
use crate::message::MessageSender;
|
||||
use crate::{
|
||||
absm::{
|
||||
canvas::{AbsmCanvasBuilder, AbsmCanvasMessage},
|
||||
command::{
|
||||
blend::{
|
||||
SetBlendAnimationByIndexInputPoseSourceCommand,
|
||||
SetBlendAnimationsPoseSourceCommand, SetBlendSpacePoseSourceCommand,
|
||||
},
|
||||
MovePoseNodeCommand,
|
||||
use crate::plugins::absm::{
|
||||
canvas::{AbsmCanvasBuilder, AbsmCanvasMessage},
|
||||
command::{
|
||||
blend::{
|
||||
SetBlendAnimationByIndexInputPoseSourceCommand, SetBlendAnimationsPoseSourceCommand,
|
||||
SetBlendSpacePoseSourceCommand,
|
||||
},
|
||||
connection::{Connection, ConnectionBuilder},
|
||||
fetch_selection,
|
||||
node::{AbsmNode, AbsmNodeBuilder, AbsmNodeMessage},
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
socket::{Socket, SocketBuilder, SocketDirection},
|
||||
state_viewer::context::{CanvasContextMenu, ConnectionContextMenu, NodeContextMenu},
|
||||
NORMAL_BACKGROUND, NORMAL_ROOT_COLOR, SELECTED_BACKGROUND, SELECTED_ROOT_COLOR,
|
||||
MovePoseNodeCommand,
|
||||
},
|
||||
connection::{Connection, ConnectionBuilder},
|
||||
fetch_selection,
|
||||
node::{AbsmNode, AbsmNodeBuilder, AbsmNodeMessage},
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
socket::{Socket, SocketBuilder, SocketDirection},
|
||||
state_viewer::context::{CanvasContextMenu, ConnectionContextMenu, NodeContextMenu},
|
||||
NORMAL_BACKGROUND, NORMAL_ROOT_COLOR, SELECTED_BACKGROUND, SELECTED_ROOT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
scene::{commands::ChangeSelectionCommand, Selection},
|
||||
send_sync_message,
|
||||
};
|
||||
@@ -36,16 +36,15 @@ use crate::fyrox::{
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, Orientation, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
BRUSH_BRIGHT,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::{
|
||||
animation_container_ref,
|
||||
command::{AddLayerCommand, RemoveLayerCommand, SetLayerMaskCommand, SetLayerNameCommand},
|
||||
fetch_selection, machine_container_ref,
|
||||
selection::AbsmSelection,
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
animation_container_ref,
|
||||
command::{AddLayerCommand, RemoveLayerCommand, SetLayerMaskCommand, SetLayerNameCommand},
|
||||
fetch_selection, machine_container_ref,
|
||||
selection::AbsmSelection,
|
||||
},
|
||||
command::{Command, CommandGroup},
|
||||
gui::make_dropdown_list_option,
|
||||
load_image,
|
||||
@@ -57,6 +56,8 @@ use crate::{
|
||||
},
|
||||
send_sync_message,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
|
||||
pub struct Toolbar {
|
||||
pub panel: Handle<UiNode>,
|
||||
@@ -156,9 +157,9 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_BRIGHT)),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!("../../resources/filter.png")))
|
||||
.with_opt_texture(load_image!("../../../resources/filter.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -39,13 +39,11 @@ use crate::fyrox::{
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
segment::Segment,
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
},
|
||||
utils::fetch_node_center,
|
||||
use crate::plugins::absm::{
|
||||
segment::Segment,
|
||||
selectable::{Selectable, SelectableMessage},
|
||||
};
|
||||
use crate::utils::fetch_node_center;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
const PICKED_COLOR: Color = Color::opaque(100, 100, 100);
|
||||
@@ -203,7 +201,7 @@ impl TransitionBuilder {
|
||||
.with_foreground(NORMAL_BRUSH.clone())
|
||||
.with_clip_to_bounds(false)
|
||||
.with_need_update(true)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
segment: Segment {
|
||||
source: self.source,
|
||||
source_pos: fetch_node_center(self.source, ctx),
|
||||
@@ -218,3 +216,16 @@ impl TransitionBuilder {
|
||||
ctx.add_node(UiNode::new(transition))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::absm::transition::TransitionBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
TransitionBuilder::new(WidgetBuilder::new()).build(Default::default(), ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ use crate::fyrox::{
|
||||
},
|
||||
graph::{BaseSceneGraph, SceneGraphNode},
|
||||
};
|
||||
use crate::plugins::animation::selection::AnimationSelection;
|
||||
use crate::{
|
||||
animation::selection::AnimationSelection,
|
||||
command::{CommandContext, CommandTrait},
|
||||
scene::{commands::GameSceneContext, Selection},
|
||||
ui_scene::commands::UiSceneContext,
|
||||
@@ -19,7 +19,36 @@
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::{
|
||||
animation::{
|
||||
command::{Command, CommandGroup},
|
||||
fyrox::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{
|
||||
algebra::Vector2, color::Color, log::Log, math::curve::Curve, math::Rect,
|
||||
pool::ErasedHandle, pool::Handle, some_or_return, uuid::Uuid,
|
||||
variable::InheritableVariable,
|
||||
},
|
||||
fxhash::FxHashSet,
|
||||
generic_animation::{signal::AnimationSignal, AnimationContainer},
|
||||
graph::{BaseSceneGraph, PrefabData, SceneGraph, SceneGraphNode},
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
brush::Brush,
|
||||
check_box::CheckBoxMessage,
|
||||
curve::{CurveEditorBuilder, CurveEditorMessage, HighlightZone},
|
||||
dock::DockingManagerMessage,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
resource::model::AnimationSource,
|
||||
},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
plugin::EditorPlugin,
|
||||
plugins::animation::{
|
||||
command::{
|
||||
AddAnimationSignal, MoveAnimationSignal, RemoveAnimationSignal,
|
||||
ReplaceTrackCurveCommand,
|
||||
@@ -30,35 +59,13 @@ use crate::{
|
||||
toolbar::{Toolbar, ToolbarAction},
|
||||
track::TrackList,
|
||||
},
|
||||
command::{Command, CommandGroup},
|
||||
fyrox::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{
|
||||
algebra::Vector2, log::Log, math::Rect, pool::ErasedHandle, pool::Handle, uuid::Uuid,
|
||||
variable::InheritableVariable,
|
||||
},
|
||||
fxhash::FxHashSet,
|
||||
generic_animation::{signal::AnimationSignal, AnimationContainer},
|
||||
graph::{BaseSceneGraph, PrefabData, SceneGraph, SceneGraphNode},
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
check_box::CheckBoxMessage,
|
||||
curve::{CurveEditorBuilder, CurveEditorMessage, HighlightZone},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
message::{MessageDirection, UiMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, UiNode, UserInterface, BRUSH_DARK, BRUSH_PRIMARY,
|
||||
},
|
||||
resource::model::AnimationSource,
|
||||
},
|
||||
message::MessageSender,
|
||||
scene::{commands::ChangeSelectionCommand, Selection},
|
||||
send_sync_message, Message,
|
||||
scene::{commands::ChangeSelectionCommand, GameScene, Selection},
|
||||
send_sync_message,
|
||||
ui_scene::UiScene,
|
||||
Editor, Message,
|
||||
};
|
||||
use fyrox::core::color::Color;
|
||||
use fyrox::core::math::curve::Curve;
|
||||
use fyrox::gui::brush::Brush;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::any::{Any, TypeId};
|
||||
|
||||
pub mod command;
|
||||
@@ -194,6 +201,8 @@ where
|
||||
}
|
||||
|
||||
impl AnimationEditor {
|
||||
const WINDOW_NAME: &'static str = "AnimationEditor";
|
||||
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
let curve_editor;
|
||||
let ruler;
|
||||
@@ -225,7 +234,9 @@ impl AnimationEditor {
|
||||
.with_child({
|
||||
curve_editor = CurveEditorBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(BRUSH_DARK)
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_DARK),
|
||||
)
|
||||
.on_row(1),
|
||||
)
|
||||
.with_show_x_values(false)
|
||||
@@ -263,7 +274,7 @@ impl AnimationEditor {
|
||||
|
||||
let window = WindowBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_name("AnimationEditor")
|
||||
.with_name(Self::WINDOW_NAME)
|
||||
.with_width(600.0)
|
||||
.with_height(500.0),
|
||||
)
|
||||
@@ -634,6 +645,19 @@ impl AnimationEditor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self, ui: &UserInterface, docking_manager: Handle<UiNode>) {
|
||||
self.toolbar.destroy(ui);
|
||||
ui.send_message(DockingManagerMessage::remove_floating_window(
|
||||
docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
self.window,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, ui: &UserInterface) {
|
||||
self.toolbar.clear(ui);
|
||||
self.track_list.clear(ui);
|
||||
@@ -706,7 +730,7 @@ impl AnimationEditor {
|
||||
animation.time_slice().end - animation.time_slice().start,
|
||||
200000.0,
|
||||
),
|
||||
brush: BRUSH_PRIMARY,
|
||||
brush: ui.style.get_or_default(Style::BRUSH_PRIMARY),
|
||||
}],
|
||||
),
|
||||
);
|
||||
@@ -899,3 +923,205 @@ impl AnimationEditor {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AnimationEditorPlugin {
|
||||
animation_editor: Option<AnimationEditor>,
|
||||
open_animation_editor: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl AnimationEditorPlugin {
|
||||
fn get_or_create_animation_editor(&mut self, ui: &mut UserInterface) -> &mut AnimationEditor {
|
||||
self.animation_editor
|
||||
.get_or_insert_with(|| AnimationEditor::new(&mut ui.build_ctx()))
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for AnimationEditorPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(layout) = editor.settings.windows.layout.as_ref() {
|
||||
if layout.has_window(AnimationEditor::WINDOW_NAME) {
|
||||
self.get_or_create_animation_editor(ui);
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_animation_editor = create_menu_item("Animation Editor", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_animation_editor,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_sync_to_model(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_mut());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let graph = &editor.engine.scenes[game_scene.scene].graph;
|
||||
animation_editor.sync_to_model(&entry.selection, ui, graph);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
animation_editor.sync_to_model(&entry.selection, ui, &ui_scene.ui);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_scene_changed(&mut self, editor: &mut Editor) {
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_mut());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
animation_editor.clear(ui);
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_animation_editor {
|
||||
editor.message_sender.send(Message::OpenAnimationEditor);
|
||||
}
|
||||
}
|
||||
|
||||
let mut animation_editor = some_or_return!(self.animation_editor.take());
|
||||
|
||||
if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == animation_editor.window {
|
||||
self.on_leave_preview_mode(editor);
|
||||
|
||||
animation_editor.destroy(
|
||||
editor.engine.user_interfaces.first(),
|
||||
editor.docking_manager,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(entry) = editor.scenes.current_scene_entry_mut() {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let graph = &mut editor.engine.scenes[game_scene.scene].graph;
|
||||
animation_editor.handle_ui_message(
|
||||
message,
|
||||
&entry.selection,
|
||||
graph,
|
||||
game_scene.scene_content_root,
|
||||
ui,
|
||||
&editor.engine.resource_manager,
|
||||
&editor.message_sender,
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
let ui_root = ui_scene.ui.root();
|
||||
animation_editor.handle_ui_message(
|
||||
message,
|
||||
&entry.selection,
|
||||
&mut ui_scene.ui,
|
||||
ui_root,
|
||||
ui,
|
||||
&editor.engine.resource_manager,
|
||||
&editor.message_sender,
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.animation_editor = Some(animation_editor);
|
||||
}
|
||||
|
||||
fn on_leave_preview_mode(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
let engine = &mut editor.engine;
|
||||
animation_editor.try_leave_preview_mode(
|
||||
&mut engine.scenes[game_scene.scene].graph,
|
||||
engine.user_interfaces.first(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
animation_editor.try_leave_preview_mode(
|
||||
&mut ui_scene.ui,
|
||||
editor.engine.user_interfaces.first(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_in_preview_mode(&self, _editor: &Editor) -> bool {
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_ref(), false);
|
||||
animation_editor.is_in_preview_mode()
|
||||
}
|
||||
|
||||
fn on_update(&mut self, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_ref::<GameScene>() {
|
||||
animation_editor.update(
|
||||
&entry.selection,
|
||||
editor.engine.user_interfaces.first(),
|
||||
&editor.engine.scenes[game_scene.scene].graph,
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_ref::<UiScene>() {
|
||||
animation_editor.update(
|
||||
&entry.selection,
|
||||
editor.engine.user_interfaces.first(),
|
||||
&ui_scene.ui,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_message(&mut self, message: &Message, editor: &mut Editor) {
|
||||
if let Message::OpenAnimationEditor = message {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let animation_editor = self.get_or_create_animation_editor(ui);
|
||||
|
||||
animation_editor.open(ui);
|
||||
|
||||
ui.send_message(DockingManagerMessage::add_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
animation_editor.window,
|
||||
));
|
||||
|
||||
self.on_sync_to_model(editor);
|
||||
}
|
||||
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let animation_editor = some_or_return!(self.animation_editor.as_mut());
|
||||
if let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() {
|
||||
animation_editor.handle_message(
|
||||
message,
|
||||
&mut editor.engine.scenes[game_scene.scene].graph,
|
||||
editor.engine.user_interfaces.first(),
|
||||
game_scene.graph_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
} else if let Some(ui_scene) = entry.controller.downcast_mut::<UiScene>() {
|
||||
animation_editor.handle_message(
|
||||
message,
|
||||
&mut ui_scene.ui,
|
||||
editor.engine.user_interfaces.first(),
|
||||
ui_scene.ui_update_switches.node_overrides.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::animation::AnimationEditor;
|
||||
use fyrox::core::algebra::Vector2;
|
||||
use fyrox::core::pool::Handle;
|
||||
use fyrox::gui::UserInterface;
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
let screen_size = Vector2::new(100.0, 100.0);
|
||||
let mut ui = UserInterface::new(screen_size);
|
||||
let editor = AnimationEditor::new(&mut ui.build_ctx());
|
||||
editor.destroy(&ui, Handle::NONE);
|
||||
ui.update(screen_size, 1.0 / 60.0, &Default::default());
|
||||
while ui.poll_message().is_some() {}
|
||||
// Only root node must be alive.
|
||||
assert_eq!(ui.nodes().alive_count(), 1);
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,14 @@ use crate::fyrox::{
|
||||
popup::{Placement, PopupMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
BuildContext, Control, RcUiNodeHandle, UiNode, UserInterface, BRUSH_BRIGHT, BRUSH_DARKER,
|
||||
BRUSH_LIGHTER, BRUSH_LIGHTEST,
|
||||
BuildContext, Control, RcUiNodeHandle, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use crate::menu::create_menu_item;
|
||||
use fyrox::gui::curve::{CurveTransformCell, STANDARD_GRID_SIZE};
|
||||
use fyrox::gui::menu::ContextMenuBuilder;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
@@ -263,9 +264,9 @@ impl Control for Ruler {
|
||||
Vector2::new(x, local_bounds.h()),
|
||||
]);
|
||||
let brush = if signal.selected {
|
||||
BRUSH_BRIGHT
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT)
|
||||
} else {
|
||||
BRUSH_LIGHTEST
|
||||
ctx.style.get_or_default(Style::BRUSH_LIGHTEST)
|
||||
};
|
||||
ctx.commit(self.clip_bounds(), brush, CommandTexture::None, None);
|
||||
}
|
||||
@@ -459,9 +460,9 @@ impl RulerBuilder {
|
||||
.widget_builder
|
||||
.with_preview_messages(true)
|
||||
.with_context_menu(context_menu.menu.clone())
|
||||
.with_background(BRUSH_DARKER)
|
||||
.with_foreground(BRUSH_LIGHTER)
|
||||
.build(),
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARKER))
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_LIGHTER))
|
||||
.build(ctx),
|
||||
transform: Default::default(),
|
||||
text: RefCell::new(FormattedTextBuilder::new(ctx.default_font()).build()),
|
||||
value: self.value,
|
||||
@@ -473,3 +474,14 @@ impl RulerBuilder {
|
||||
ctx.add_node(UiNode::new(ruler))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::animation::ruler::RulerBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| RulerBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
@@ -36,10 +36,12 @@ use crate::fyrox::{
|
||||
draw::{CommandTexture, Draw, DrawingContext},
|
||||
message::{MessageDirection, UiMessage},
|
||||
widget::{Widget, WidgetBuilder},
|
||||
BuildContext, Control, UiNode, UserInterface, BRUSH_BRIGHT,
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use fyrox::gui::curve::CurveTransformCell;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -141,8 +143,8 @@ impl ThumbBuilder {
|
||||
widget: self
|
||||
.widget_builder
|
||||
.with_hit_test_visibility(false)
|
||||
.with_foreground(BRUSH_BRIGHT)
|
||||
.build(),
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_BRIGHT))
|
||||
.build(ctx),
|
||||
transform: CurveTransformCell::default(),
|
||||
position: 0.0,
|
||||
};
|
||||
@@ -150,3 +152,14 @@ impl ThumbBuilder {
|
||||
ctx.add_node(UiNode::new(ruler))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::animation::thumb::ThumbBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| ThumbBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
@@ -45,20 +45,20 @@ use crate::fyrox::{
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_BRIGHT, BRUSH_LIGHT,
|
||||
VerticalAlignment,
|
||||
},
|
||||
resource::model::AnimationSource,
|
||||
};
|
||||
use crate::{
|
||||
animation::{
|
||||
command::{
|
||||
AddAnimationCommand, RemoveAnimationCommand, ReplaceAnimationCommand,
|
||||
SetAnimationEnabledCommand, SetAnimationLoopingCommand, SetAnimationNameCommand,
|
||||
SetAnimationRootMotionSettingsCommand, SetAnimationSpeedCommand,
|
||||
SetAnimationTimeSliceCommand,
|
||||
},
|
||||
selection::AnimationSelection,
|
||||
use crate::plugins::animation::{
|
||||
command::{
|
||||
AddAnimationCommand, RemoveAnimationCommand, ReplaceAnimationCommand,
|
||||
SetAnimationEnabledCommand, SetAnimationLoopingCommand, SetAnimationNameCommand,
|
||||
SetAnimationRootMotionSettingsCommand, SetAnimationSpeedCommand,
|
||||
SetAnimationTimeSliceCommand,
|
||||
},
|
||||
selection::AnimationSelection,
|
||||
};
|
||||
use crate::{
|
||||
command::{Command, CommandGroup},
|
||||
gui::make_dropdown_list_option_universal,
|
||||
load_image,
|
||||
@@ -70,6 +70,8 @@ use crate::{
|
||||
},
|
||||
send_sync_message,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::path::Path;
|
||||
|
||||
enum ImportMode {
|
||||
@@ -329,6 +331,13 @@ impl RootMotionDropdownArea {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self, ui: &UserInterface) {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.popup,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn sync_to_model<G, N>(
|
||||
&self,
|
||||
animation: &Animation<Handle<N>>,
|
||||
@@ -417,7 +426,7 @@ impl Toolbar {
|
||||
let panel = BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.with_foreground(BRUSH_LIGHT)
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_LIGHT))
|
||||
.with_child(
|
||||
StackPanelBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
@@ -468,11 +477,11 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/import.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/import.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -498,11 +507,13 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/reimport.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!(
|
||||
"../../../resources/reimport.png"
|
||||
))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -527,11 +538,11 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/rename.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/rename.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -582,11 +593,11 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/copy.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/copy.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -638,11 +649,11 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/speed.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/speed.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child({
|
||||
@@ -666,11 +677,11 @@ impl Toolbar {
|
||||
.with_width(18.0)
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(BRUSH_BRIGHT),
|
||||
.with_background(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/time.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/time.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child({
|
||||
@@ -751,7 +762,9 @@ impl Toolbar {
|
||||
.with_content(
|
||||
VectorImageBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_foreground(BRUSH_BRIGHT)
|
||||
.with_foreground(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
)
|
||||
.with_tooltip(make_simple_tooltip(ctx, "Play/Pause")),
|
||||
)
|
||||
.with_primitives(vec![
|
||||
@@ -782,9 +795,9 @@ impl Toolbar {
|
||||
.with_tooltip(make_simple_tooltip(ctx, "Stop Playback")),
|
||||
)
|
||||
.with_content(
|
||||
VectorImageBuilder::new(
|
||||
WidgetBuilder::new().with_foreground(BRUSH_BRIGHT),
|
||||
)
|
||||
VectorImageBuilder::new(WidgetBuilder::new().with_foreground(
|
||||
ctx.style.get_or_default(Style::BRUSH_BRIGHT),
|
||||
))
|
||||
.with_primitives(vec![Primitive::RectangleFilled {
|
||||
rect: Rect::new(0.0, 0.0, 16.0, 16.0),
|
||||
}])
|
||||
@@ -808,7 +821,7 @@ impl Toolbar {
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
let file_selector = FileSelectorBuilder::new(
|
||||
let import_file_selector = FileSelectorBuilder::new(
|
||||
WindowBuilder::new(WidgetBuilder::new().with_width(300.0).with_height(400.0))
|
||||
.open(false)
|
||||
.with_title(WindowTitle::text("Select Animation To Import")),
|
||||
@@ -842,7 +855,7 @@ impl Toolbar {
|
||||
import,
|
||||
reimport,
|
||||
node_selector,
|
||||
import_file_selector: file_selector,
|
||||
import_file_selector,
|
||||
selected_import_root: Default::default(),
|
||||
looping,
|
||||
enabled,
|
||||
@@ -852,6 +865,18 @@ impl Toolbar {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self, ui: &UserInterface) {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.node_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.import_file_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.root_motion_dropdown_area.destroy(ui);
|
||||
}
|
||||
|
||||
pub fn handle_ui_message<G, N>(
|
||||
&mut self,
|
||||
message: &UiMessage,
|
||||
@@ -20,15 +20,15 @@
|
||||
|
||||
#![allow(clippy::manual_map)]
|
||||
|
||||
use crate::{
|
||||
animation::{
|
||||
animation_container_ref,
|
||||
command::{
|
||||
AddTrackCommand, RemoveTrackCommand, SetTrackEnabledCommand, SetTrackTargetCommand,
|
||||
SetTrackValueBindingCommand,
|
||||
},
|
||||
selection::{AnimationSelection, SelectedEntity},
|
||||
use crate::plugins::animation::{
|
||||
animation_container_ref,
|
||||
command::{
|
||||
AddTrackCommand, RemoveTrackCommand, SetTrackEnabledCommand, SetTrackTargetCommand,
|
||||
SetTrackValueBindingCommand,
|
||||
},
|
||||
selection::{AnimationSelection, SelectedEntity},
|
||||
};
|
||||
use crate::{
|
||||
command::{Command, CommandGroup},
|
||||
fyrox::{
|
||||
core::{
|
||||
@@ -72,7 +72,7 @@ use crate::{
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, Control, Orientation, RcUiNodeHandle, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_BRIGHT, BRUSH_TEXT,
|
||||
VerticalAlignment,
|
||||
},
|
||||
resource::texture::TextureBytes,
|
||||
},
|
||||
@@ -92,8 +92,11 @@ use crate::{
|
||||
send_sync_message, utils,
|
||||
};
|
||||
use fyrox::generic_animation::track::TrackBinding;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use fyrox::renderer::framework::DrawParameters;
|
||||
use fyrox::scene::mesh::buffer::{TriangleBuffer, VertexBuffer};
|
||||
use fyrox::scene::sound::Samples;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp::Ordering,
|
||||
@@ -369,7 +372,7 @@ impl Control for TrackView {
|
||||
self.name_text,
|
||||
MessageDirection::ToWidget,
|
||||
if result.is_ok() {
|
||||
BRUSH_TEXT
|
||||
ui.style.get_or_default(Style::BRUSH_TEXT)
|
||||
} else {
|
||||
Brush::Solid(Color::RED)
|
||||
},
|
||||
@@ -547,13 +550,11 @@ impl Toolbar {
|
||||
.with_content(
|
||||
ImageBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(BRUSH_BRIGHT)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_BRIGHT))
|
||||
.with_width(16.0)
|
||||
.with_height(16.0),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/collapse.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/collapse.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -569,11 +570,11 @@ impl Toolbar {
|
||||
.with_content(
|
||||
ImageBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(BRUSH_BRIGHT)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_BRIGHT))
|
||||
.with_width(16.0)
|
||||
.with_height(16.0),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!("../../resources/expand.png")))
|
||||
.with_opt_texture(load_image!("../../../resources/expand.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -675,9 +676,7 @@ impl TrackList {
|
||||
ctx,
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/property_track.png"
|
||||
)),
|
||||
load_image!("../../../resources/property_track.png"),
|
||||
"Add Property Track.\n\
|
||||
Create generic property binding to a numeric property.",
|
||||
Some(0),
|
||||
@@ -689,9 +688,7 @@ impl TrackList {
|
||||
ctx,
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/position_track.png"
|
||||
)),
|
||||
load_image!("../../../resources/position_track.png"),
|
||||
"Add Position Track.\n\
|
||||
Creates a binding to a local position of a node. \
|
||||
Such binding is much more performant than generic \
|
||||
@@ -705,7 +702,7 @@ impl TrackList {
|
||||
ctx,
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!("../../resources/scaling_track.png")),
|
||||
load_image!("../../../resources/scaling_track.png"),
|
||||
"Add Scale Track.\n\
|
||||
Creates a binding to a local scale of a node. \
|
||||
Such binding is much more performant than generic \
|
||||
@@ -719,9 +716,7 @@ impl TrackList {
|
||||
ctx,
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/rotation_track.png"
|
||||
)),
|
||||
load_image!("../../../resources/rotation_track.png"),
|
||||
"Add Rotation Track.\n\
|
||||
Creates a binding to a local rotation of a node. \
|
||||
Such binding is much more performant than generic \
|
||||
@@ -879,7 +874,7 @@ impl TrackList {
|
||||
match self.property_binding_mode {
|
||||
PropertyBindingMode::Generic => {
|
||||
self.property_selector =
|
||||
Self::open_property_selector(graph, (*first).into(), ui);
|
||||
Self::open_property_selector(graph, (*first).into(), None, ui);
|
||||
}
|
||||
PropertyBindingMode::Position => {
|
||||
sender.do_command(AddTrackCommand::new(
|
||||
@@ -1103,6 +1098,7 @@ impl TrackList {
|
||||
fn open_property_selector<G, N>(
|
||||
graph: &G,
|
||||
node: Handle<N>,
|
||||
existing_binding: Option<&ValueBinding>,
|
||||
ui: &mut UserInterface,
|
||||
) -> Handle<UiNode>
|
||||
where
|
||||
@@ -1121,6 +1117,7 @@ impl TrackList {
|
||||
&& type_id != TypeId::of::<TriangleBuffer>()
|
||||
// Makes no sense to animate drawing parameters.
|
||||
&& type_id != TypeId::of::<DrawParameters>()
|
||||
&& type_id != TypeId::of::<Samples>()
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1147,6 +1144,21 @@ impl TrackList {
|
||||
|
||||
UnitQuaternion<f32>
|
||||
})))
|
||||
.with_selected_property_paths(
|
||||
existing_binding
|
||||
.and_then(|binding| {
|
||||
if let ValueBinding::Property { name, value_type } = binding {
|
||||
Some(vec![PropertyDescriptorData {
|
||||
name: name.to_string(),
|
||||
path: name.to_string(),
|
||||
type_id: value_type.into_type_id(),
|
||||
}])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.with_property_descriptors(descriptors)
|
||||
.build(&mut ui.build_ctx());
|
||||
|
||||
@@ -1174,10 +1186,25 @@ impl TrackList {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(binding) = animation.track_bindings().get(&first_selected_track) {
|
||||
self.context_menu.property_rebinding_selector =
|
||||
Self::open_property_selector(graph, binding.target(), ui);
|
||||
}
|
||||
let tracks_data_state = animation.tracks_data().state();
|
||||
let Some(tracks_data) = tracks_data_state.data_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(binding) = animation.track_bindings().get(&first_selected_track) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(track) = tracks_data
|
||||
.tracks
|
||||
.iter()
|
||||
.find(|track| track.id() == first_selected_track)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.context_menu.property_rebinding_selector =
|
||||
Self::open_property_selector(graph, binding.target(), Some(track.value_binding()), ui);
|
||||
}
|
||||
|
||||
fn rebind_property<G, N>(
|
||||
@@ -1615,3 +1642,17 @@ impl TrackList {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::animation::track::TrackViewBuilder;
|
||||
use fyrox::gui::tree::TreeBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
TrackViewBuilder::new(TreeBuilder::new(WidgetBuilder::new())).build(ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ mod cuboid;
|
||||
mod cuboid2d;
|
||||
mod cylinder;
|
||||
mod dummy;
|
||||
mod panel;
|
||||
mod segment;
|
||||
mod segment2d;
|
||||
mod triangle;
|
||||
@@ -45,19 +46,29 @@ use crate::{
|
||||
math::{plane::Plane, Matrix4Ext},
|
||||
pool::Handle,
|
||||
reflect::Reflect,
|
||||
some_or_return,
|
||||
type_traits::prelude::*,
|
||||
Uuid,
|
||||
},
|
||||
engine::Engine,
|
||||
graph::{BaseSceneGraph, SceneGraph, SceneGraphNode},
|
||||
gui::{BuildContext, UiNode},
|
||||
gui::{
|
||||
dock::DockingManagerMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
BuildContext, UiNode,
|
||||
},
|
||||
material::{
|
||||
shader::{ShaderResource, ShaderResourceExtension},
|
||||
Material, MaterialResource,
|
||||
},
|
||||
scene::{
|
||||
base::BaseBuilder, collider::Collider, collider::ColliderShape, dim2, node::Node,
|
||||
sprite::SpriteBuilder, Scene,
|
||||
base::BaseBuilder,
|
||||
collider::{Collider, ColliderShape},
|
||||
dim2,
|
||||
node::Node,
|
||||
sprite::Sprite,
|
||||
sprite::SpriteBuilder,
|
||||
Scene,
|
||||
},
|
||||
},
|
||||
interaction::{
|
||||
@@ -71,14 +82,13 @@ use crate::{
|
||||
ball::BallShapeGizmo, ball2d::Ball2DShapeGizmo, capsule::CapsuleShapeGizmo,
|
||||
capsule2d::Capsule2DShapeGizmo, cone::ConeShapeGizmo, cuboid::CuboidShapeGizmo,
|
||||
cuboid2d::Cuboid2DShapeGizmo, cylinder::CylinderShapeGizmo, dummy::DummyShapeGizmo,
|
||||
segment::SegmentShapeGizmo, segment2d::Segment2DShapeGizmo, triangle::TriangleShapeGizmo,
|
||||
triangle2d::Triangle2DShapeGizmo,
|
||||
panel::ColliderControlPanel, segment::SegmentShapeGizmo, segment2d::Segment2DShapeGizmo,
|
||||
triangle::TriangleShapeGizmo, triangle2d::Triangle2DShapeGizmo,
|
||||
},
|
||||
scene::{commands::GameSceneContext, controller::SceneController, GameScene, Selection},
|
||||
settings::Settings,
|
||||
Editor, Message,
|
||||
};
|
||||
use fyrox::scene::sprite::Sprite;
|
||||
|
||||
fn try_get_collider_shape(collider: Handle<Node>, scene: &Scene) -> Option<ColliderShape> {
|
||||
scene
|
||||
@@ -272,7 +282,7 @@ fn make_handle(scene: &mut Scene, root: Handle<Node>, visible: bool) -> Handle<N
|
||||
|
||||
material.bind(
|
||||
"diffuseTexture",
|
||||
load_texture(include_bytes!("../../../resources/circle.png")),
|
||||
load_texture!("../../../resources/circle.png"),
|
||||
);
|
||||
|
||||
let handle = SpriteBuilder::new(BaseBuilder::new().with_visibility(visible))
|
||||
@@ -662,21 +672,28 @@ impl InteractionMode for ColliderShapeInteractionMode {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ColliderShapePlugin {}
|
||||
pub struct ColliderPlugin {
|
||||
panel: Option<ColliderControlPanel>,
|
||||
}
|
||||
|
||||
impl EditorPlugin for ColliderPlugin {
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let game_scene = some_or_return!(entry.controller.downcast_mut::<GameScene>());
|
||||
let panel = some_or_return!(self.panel.as_mut());
|
||||
panel.handle_ui_message(
|
||||
message,
|
||||
&editor.engine,
|
||||
game_scene,
|
||||
&entry.selection,
|
||||
&editor.message_sender,
|
||||
);
|
||||
}
|
||||
|
||||
impl EditorPlugin for ColliderShapePlugin {
|
||||
fn on_message(&mut self, message: &Message, editor: &mut Editor) {
|
||||
let Some(entry) = editor.scenes.current_scene_entry_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(selection) = entry.selection.as_graph() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(game_scene) = entry.controller.downcast_mut::<GameScene>() else {
|
||||
return;
|
||||
};
|
||||
let entry = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let selection = some_or_return!(entry.selection.as_graph());
|
||||
let game_scene = some_or_return!(entry.controller.downcast_mut::<GameScene>());
|
||||
|
||||
let scene = &mut editor.engine.scenes[game_scene.scene];
|
||||
|
||||
@@ -688,36 +705,50 @@ impl EditorPlugin for ColliderShapePlugin {
|
||||
mode.shape_gizmo.destroy(scene);
|
||||
}
|
||||
|
||||
for node_handle in selection.nodes().iter() {
|
||||
if let Some(collider) = scene.graph.try_get(*node_handle) {
|
||||
if collider.component_ref::<Collider>().is_none()
|
||||
&& collider
|
||||
.component_ref::<dim2::collider::Collider>()
|
||||
.is_none()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let first_selected_collider = selection.nodes().iter().find(|h| {
|
||||
scene.graph.has_component::<Collider>(**h)
|
||||
|| scene.graph.has_component::<dim2::collider::Collider>(**h)
|
||||
});
|
||||
|
||||
let shape_gizmo = make_shape_gizmo(
|
||||
*node_handle,
|
||||
scene,
|
||||
game_scene.editor_objects_root,
|
||||
false,
|
||||
);
|
||||
if let Some(first_selected_collider) = first_selected_collider {
|
||||
let shape_gizmo = make_shape_gizmo(
|
||||
*first_selected_collider,
|
||||
scene,
|
||||
game_scene.editor_objects_root,
|
||||
false,
|
||||
);
|
||||
|
||||
let move_gizmo = MoveGizmo::new(game_scene, &mut editor.engine);
|
||||
let move_gizmo = MoveGizmo::new(game_scene, &mut editor.engine);
|
||||
|
||||
entry.interaction_modes.add(ColliderShapeInteractionMode {
|
||||
collider: *node_handle,
|
||||
shape_gizmo,
|
||||
move_gizmo,
|
||||
drag_context: None,
|
||||
selected_handle: Default::default(),
|
||||
message_sender: editor.message_sender.clone(),
|
||||
});
|
||||
entry.interaction_modes.add(ColliderShapeInteractionMode {
|
||||
collider: *first_selected_collider,
|
||||
shape_gizmo,
|
||||
move_gizmo,
|
||||
drag_context: None,
|
||||
selected_handle: Default::default(),
|
||||
message_sender: editor.message_sender.clone(),
|
||||
});
|
||||
|
||||
break;
|
||||
if self.panel.is_none() {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let panel =
|
||||
ColliderControlPanel::new(editor.scene_viewer.frame(), &mut ui.build_ctx());
|
||||
ui.send_message(DockingManagerMessage::add_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
panel.window,
|
||||
));
|
||||
panel.open(ui);
|
||||
self.panel = Some(panel);
|
||||
}
|
||||
} else if let Some(panel) = self.panel.take() {
|
||||
let ui = editor.engine.user_interfaces.first();
|
||||
ui.send_message(DockingManagerMessage::remove_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
panel.window,
|
||||
));
|
||||
panel.destroy(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,30 +18,28 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::command::{Command, CommandGroup, SetPropertyCommand};
|
||||
use crate::fyrox::graph::{BaseSceneGraph, SceneGraph};
|
||||
use crate::fyrox::{
|
||||
core::{algebra::Vector3, pool::Handle, reflect::Reflect},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
utils::make_simple_tooltip,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Thickness, UiNode, VerticalAlignment,
|
||||
},
|
||||
scene::{
|
||||
collider::{Collider, ColliderShape},
|
||||
node::Node,
|
||||
},
|
||||
};
|
||||
use crate::scene::commands::GameSceneContext;
|
||||
use crate::{
|
||||
command::{Command, CommandGroup, SetPropertyCommand},
|
||||
fyrox::{
|
||||
core::{algebra::Vector3, pool::Handle, reflect::Reflect},
|
||||
engine::Engine,
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
utils::make_simple_tooltip,
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
},
|
||||
scene::{
|
||||
collider::{Collider, ColliderShape},
|
||||
node::Node,
|
||||
},
|
||||
},
|
||||
message::MessageSender,
|
||||
scene::{GameScene, Selection},
|
||||
Message,
|
||||
scene::{commands::GameSceneContext, GameScene, Selection},
|
||||
};
|
||||
|
||||
pub struct ColliderControlPanel {
|
||||
@@ -81,6 +79,7 @@ impl ColliderControlPanel {
|
||||
.with_height(50.0)
|
||||
.with_name("ColliderControlPanel"),
|
||||
)
|
||||
.open(false)
|
||||
.with_title(WindowTitle::text("Collider Control Panel"))
|
||||
.with_content(
|
||||
StackPanelBuilder::new(
|
||||
@@ -109,49 +108,24 @@ impl ColliderControlPanel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_message(
|
||||
&self,
|
||||
message: &Message,
|
||||
engine: &Engine,
|
||||
game_scene: &GameScene,
|
||||
selection: &Selection,
|
||||
) {
|
||||
if let Message::SelectionChanged { .. } = message {
|
||||
let mut collider_selected = false;
|
||||
pub fn open(&self, ui: &UserInterface) {
|
||||
ui.send_message(WindowMessage::open_and_align(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
self.scene_frame,
|
||||
HorizontalAlignment::Right,
|
||||
VerticalAlignment::Top,
|
||||
Thickness::uniform(1.0),
|
||||
false,
|
||||
false,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(selection) = selection.as_graph() {
|
||||
for selected in selection.nodes() {
|
||||
let scene = &engine.scenes[game_scene.scene];
|
||||
|
||||
collider_selected =
|
||||
scene.graph.try_get_of_type::<Collider>(*selected).is_some();
|
||||
}
|
||||
}
|
||||
|
||||
if collider_selected {
|
||||
engine
|
||||
.user_interfaces
|
||||
.first()
|
||||
.send_message(WindowMessage::open_and_align(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
self.scene_frame,
|
||||
HorizontalAlignment::Right,
|
||||
VerticalAlignment::Top,
|
||||
Thickness::uniform(1.0),
|
||||
false,
|
||||
false,
|
||||
));
|
||||
} else {
|
||||
engine
|
||||
.user_interfaces
|
||||
.first()
|
||||
.send_message(WindowMessage::close(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
}
|
||||
pub fn destroy(self, ui: &UserInterface) {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(
|
||||
@@ -18,36 +18,39 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
asset::{untyped::ResourceKind, Resource},
|
||||
core::{
|
||||
color::Color, futures::executor::block_on, math::curve::Curve, pool::Handle,
|
||||
type_traits::prelude::*, visitor::prelude::*,
|
||||
},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
brush::Brush,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
curve::{CurveEditorBuilder, CurveEditorMessage},
|
||||
file_browser::{FileBrowserMode, FileSelectorMessage},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
menu::{MenuBuilder, MenuItemBuilder, MenuItemContent, MenuItemMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
messagebox::{MessageBoxBuilder, MessageBoxResult},
|
||||
stack_panel::StackPanelBuilder,
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
resource::curve::{CurveResource, CurveResourceState},
|
||||
};
|
||||
use crate::{
|
||||
command::{Command, CommandContext, CommandStack, CommandTrait},
|
||||
fyrox::{
|
||||
asset::{untyped::ResourceKind, Resource},
|
||||
core::{
|
||||
color::Color, futures::executor::block_on, math::curve::Curve, pool::Handle,
|
||||
type_traits::prelude::*, visitor::prelude::*,
|
||||
},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
brush::Brush,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
curve::{CurveEditorBuilder, CurveEditorMessage},
|
||||
file_browser::{FileBrowserMode, FileSelectorMessage},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
menu::{MenuBuilder, MenuItemBuilder, MenuItemContent, MenuItemMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
messagebox::{MessageBoxBuilder, MessageBoxResult},
|
||||
stack_panel::StackPanelBuilder,
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
resource::curve::{CurveResource, CurveResourceState},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
plugin::EditorPlugin,
|
||||
send_sync_message,
|
||||
utils::create_file_selector,
|
||||
MessageBoxButtons, MessageBoxMessage, MSG_SYNC_FLAG,
|
||||
Editor, MessageBoxButtons, MessageBoxMessage, MSG_SYNC_FLAG,
|
||||
};
|
||||
use fyrox::core::some_or_return;
|
||||
use std::{fmt::Debug, path::PathBuf};
|
||||
|
||||
#[derive(Debug, ComponentProvider)]
|
||||
@@ -277,6 +280,7 @@ impl CurveEditorWindow {
|
||||
.add_column(Column::stretch())
|
||||
.build(ctx),
|
||||
)
|
||||
.with_remove_on_close(true)
|
||||
.with_title(WindowTitle::text("Curve Editor"))
|
||||
.build(ctx);
|
||||
|
||||
@@ -301,9 +305,23 @@ impl CurveEditorWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&mut self, ui: &UserInterface) {
|
||||
self.clear(ui);
|
||||
|
||||
fn destroy(self, ui: &UserInterface) {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.cancel_message_box,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.save_changes_message_box,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.load_file_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.save_file_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
@@ -381,27 +399,6 @@ impl CurveEditorWindow {
|
||||
));
|
||||
}
|
||||
|
||||
fn clear(&mut self, ui: &UserInterface) {
|
||||
self.path = Default::default();
|
||||
self.backup = Default::default();
|
||||
self.command_stack.clear(&mut CurveEditorContext {});
|
||||
self.curve_resource = None;
|
||||
self.sync_title(ui);
|
||||
ui.send_message(WidgetMessage::enabled(
|
||||
self.curve_editor,
|
||||
MessageDirection::ToWidget,
|
||||
false,
|
||||
));
|
||||
send_sync_message(
|
||||
ui,
|
||||
CurveEditorMessage::sync(
|
||||
self.curve_editor,
|
||||
MessageDirection::ToWidget,
|
||||
Default::default(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn revert(&self) {
|
||||
if let Some(curve_resource) = self.curve_resource.as_ref() {
|
||||
curve_resource.data_ref().curve = self.backup.clone();
|
||||
@@ -423,7 +420,7 @@ impl CurveEditorWindow {
|
||||
));
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(&mut self, message: &UiMessage, engine: &mut Engine) {
|
||||
pub fn handle_ui_message(mut self, message: &UiMessage, engine: &mut Engine) -> Option<Self> {
|
||||
let ui = &engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(ButtonMessage::Click) = message.data() {
|
||||
@@ -436,7 +433,8 @@ impl CurveEditorWindow {
|
||||
None,
|
||||
));
|
||||
} else {
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
} else if message.destination() == self.ok {
|
||||
if self.modified && self.curve_resource.is_some() {
|
||||
@@ -449,10 +447,12 @@ impl CurveEditorWindow {
|
||||
));
|
||||
} else {
|
||||
self.save();
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
} else if let Some(CurveEditorMessage::Sync(curve)) = message.data() {
|
||||
@@ -525,14 +525,16 @@ impl CurveEditorWindow {
|
||||
match result {
|
||||
MessageBoxResult::No => {
|
||||
self.revert();
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
MessageBoxResult::Yes => {
|
||||
if self.path == PathBuf::default() {
|
||||
self.open_save_file_dialog(ui);
|
||||
} else {
|
||||
self.save();
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@@ -540,9 +542,52 @@ impl CurveEditorWindow {
|
||||
} else if message.destination() == self.cancel_message_box {
|
||||
if let MessageBoxResult::Yes = result {
|
||||
self.revert();
|
||||
self.close(ui);
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CurveEditorPlugin {
|
||||
curve_editor_window: Option<CurveEditorWindow>,
|
||||
open_curve_editor: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl CurveEditorPlugin {
|
||||
fn on_open_curve_editor_clicked(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
let curve_editor = self
|
||||
.curve_editor_window
|
||||
.get_or_insert_with(|| CurveEditorWindow::new(ctx));
|
||||
curve_editor.open(ui);
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for CurveEditorPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_curve_editor = create_menu_item("Curve Editor", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_curve_editor,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_curve_editor {
|
||||
self.on_open_curve_editor_clicked(editor)
|
||||
}
|
||||
}
|
||||
let curve_editor = some_or_return!(self.curve_editor_window.take());
|
||||
self.curve_editor_window = curve_editor.handle_ui_message(message, &mut editor.engine);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -38,7 +38,8 @@ use crate::fyrox::{
|
||||
widget::WidgetBuilder,
|
||||
},
|
||||
};
|
||||
use crate::{gui::make_dropdown_list_option_universal, inspector::EditorEnvironment, Message};
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use crate::{gui::make_dropdown_list_option_universal, Message};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
fmt::{Debug, Formatter},
|
||||
+12
-1
@@ -184,7 +184,7 @@ impl FontFieldBuilder {
|
||||
.build(ctx);
|
||||
text_preview
|
||||
})
|
||||
.build();
|
||||
.build(ctx);
|
||||
|
||||
let editor = FontField {
|
||||
widget,
|
||||
@@ -245,3 +245,14 @@ impl PropertyEditorDefinition for FontPropertyEditorDefinition {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::inspector::editors::font::FontFieldBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| FontFieldBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
}
|
||||
}
|
||||
+25
-10
@@ -48,12 +48,14 @@ use crate::fyrox::{
|
||||
scene::node::Node,
|
||||
};
|
||||
use crate::{
|
||||
load_image,
|
||||
load_image_internal,
|
||||
message::MessageSender,
|
||||
scene::selector::{HierarchyNode, NodeSelectorMessage, NodeSelectorWindowBuilder},
|
||||
world::graph::item::SceneItem,
|
||||
Message, UiMessage, UiNode, UserInterface, VerticalAlignment,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
fmt::Debug,
|
||||
@@ -170,14 +172,14 @@ impl Control for HandlePropertyEditor {
|
||||
));
|
||||
|
||||
let color = if self.value.is_none() {
|
||||
Color::ORANGE
|
||||
Brush::Solid(Color::ORANGE)
|
||||
} else {
|
||||
fyrox::gui::COLOR_FOREGROUND
|
||||
ui.style.get_or_default(Style::BRUSH_FOREGROUND)
|
||||
};
|
||||
ui.send_message(WidgetMessage::foreground(
|
||||
self.text,
|
||||
MessageDirection::ToWidget,
|
||||
Brush::Solid(color),
|
||||
color,
|
||||
));
|
||||
} else {
|
||||
ui.send_message(TextMessage::text(
|
||||
@@ -292,7 +294,7 @@ fn make_icon(data: &[u8], color: Color, ctx: &mut BuildContext) -> Handle<UiNode
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_background(Brush::Solid(color)),
|
||||
)
|
||||
.with_opt_texture(load_image(data))
|
||||
.with_opt_texture(load_image_internal(data))
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
@@ -338,7 +340,7 @@ impl HandlePropertyEditorBuilder {
|
||||
.on_column(1),
|
||||
)
|
||||
.with_content(make_icon(
|
||||
include_bytes!("../../../resources/pick.png"),
|
||||
include_bytes!("../../../../resources/pick.png"),
|
||||
Color::opaque(0, 180, 0),
|
||||
ctx,
|
||||
))
|
||||
@@ -354,7 +356,7 @@ impl HandlePropertyEditorBuilder {
|
||||
.on_column(2),
|
||||
)
|
||||
.with_content(make_icon(
|
||||
include_bytes!("../../../resources/locate.png"),
|
||||
include_bytes!("../../../../resources/locate.png"),
|
||||
Color::opaque(180, 180, 180),
|
||||
ctx,
|
||||
))
|
||||
@@ -370,7 +372,7 @@ impl HandlePropertyEditorBuilder {
|
||||
.on_column(3),
|
||||
)
|
||||
.with_content(make_icon(
|
||||
include_bytes!("../../../resources/select_in_wv.png"),
|
||||
include_bytes!("../../../../resources/select_in_wv.png"),
|
||||
Color::opaque(180, 180, 180),
|
||||
ctx,
|
||||
))
|
||||
@@ -386,7 +388,7 @@ impl HandlePropertyEditorBuilder {
|
||||
.on_column(4),
|
||||
)
|
||||
.with_content(make_icon(
|
||||
include_bytes!("../../../resources/cross.png"),
|
||||
include_bytes!("../../../../resources/cross.png"),
|
||||
Color::opaque(180, 0, 0),
|
||||
ctx,
|
||||
))
|
||||
@@ -412,7 +414,7 @@ impl HandlePropertyEditorBuilder {
|
||||
.with_preview_messages(true)
|
||||
.with_allow_drop(true)
|
||||
.with_child(grid)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
text,
|
||||
value: self.value,
|
||||
sender: self.sender,
|
||||
@@ -521,3 +523,16 @@ fn request_name_sync(sender: &MessageSender, editor: Handle<UiNode>, handle: Era
|
||||
handle,
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::inspector::editors::handle::HandlePropertyEditorBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
HandlePropertyEditorBuilder::new(WidgetBuilder::new(), Default::default()).build(ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,23 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::inspector::editors::{
|
||||
animation::{
|
||||
AnimationContainerPropertyEditorDefinition, AnimationPropertyEditorDefinition,
|
||||
MachinePropertyEditorDefinition,
|
||||
},
|
||||
font::FontPropertyEditorDefinition,
|
||||
handle::{EntityKind, NodeHandlePropertyEditorDefinition},
|
||||
resource::ResourceFieldPropertyEditorDefinition,
|
||||
script::ScriptPropertyEditorDefinition,
|
||||
spritesheet::SpriteSheetFramesContainerEditorDefinition,
|
||||
surface::SurfaceDataPropertyEditorDefinition,
|
||||
texture::TexturePropertyEditorDefinition,
|
||||
};
|
||||
use crate::{
|
||||
fyrox::{
|
||||
asset::{untyped::UntypedResource, Resource},
|
||||
core::{
|
||||
parking_lot::Mutex,
|
||||
pool::{ErasedHandle, Handle},
|
||||
},
|
||||
core::pool::{ErasedHandle, Handle},
|
||||
gui::{
|
||||
self,
|
||||
font::FontResource,
|
||||
@@ -38,10 +48,7 @@ use crate::{
|
||||
},
|
||||
UiNode, UserInterface,
|
||||
},
|
||||
material::{
|
||||
shader::{Shader, ShaderResource},
|
||||
MaterialResource,
|
||||
},
|
||||
material::shader::{Shader, ShaderResource},
|
||||
renderer::framework::PolygonFillMode,
|
||||
resource::{
|
||||
curve::{CurveResource, CurveResourceState},
|
||||
@@ -77,6 +84,7 @@ use crate::{
|
||||
BatchingMode, RenderPath,
|
||||
},
|
||||
node::Node,
|
||||
particle_system::CoordinateSystem,
|
||||
particle_system::{
|
||||
emitter::{
|
||||
base::BaseEmitter, cuboid::CuboidEmitter, cylinder::CylinderEmitter,
|
||||
@@ -97,34 +105,18 @@ use crate::{
|
||||
SoundBufferResource, Status,
|
||||
},
|
||||
terrain::{Chunk, Layer},
|
||||
tilemap::brush::{TileMapBrush, TileMapBrushResource},
|
||||
tilemap::tileset::TileCollider,
|
||||
tilemap::{tileset::TileSet, Tile},
|
||||
transform::Transform,
|
||||
},
|
||||
},
|
||||
inspector::editors::{
|
||||
animation::{
|
||||
AnimationContainerPropertyEditorDefinition, AnimationPropertyEditorDefinition,
|
||||
MachinePropertyEditorDefinition,
|
||||
},
|
||||
font::FontPropertyEditorDefinition,
|
||||
handle::{EntityKind, NodeHandlePropertyEditorDefinition},
|
||||
material::MaterialPropertyEditorDefinition,
|
||||
resource::ResourceFieldPropertyEditorDefinition,
|
||||
script::ScriptPropertyEditorDefinition,
|
||||
spritesheet::SpriteSheetFramesContainerEditorDefinition,
|
||||
surface::SurfaceDataPropertyEditorDefinition,
|
||||
texture::TexturePropertyEditorDefinition,
|
||||
},
|
||||
message::MessageSender,
|
||||
};
|
||||
use fyrox::scene::particle_system::CoordinateSystem;
|
||||
use fyrox::scene::tilemap::brush::{TileMapBrush, TileMapBrushResource};
|
||||
use fyrox::scene::tilemap::tileset::TileCollider;
|
||||
|
||||
pub mod animation;
|
||||
pub mod font;
|
||||
pub mod handle;
|
||||
pub mod material;
|
||||
pub mod resource;
|
||||
pub mod script;
|
||||
pub mod spritesheet;
|
||||
@@ -228,11 +220,6 @@ pub fn make_property_editors_container(sender: MessageSender) -> PropertyEditorD
|
||||
container.register_inheritable_vec_collection::<Option<TextureResource>>();
|
||||
container.register_inheritable_vec_collection::<Option<UntypedResource>>();
|
||||
|
||||
container.insert(MaterialPropertyEditorDefinition {
|
||||
sender: Mutex::new(sender.clone()),
|
||||
});
|
||||
container.insert(InheritablePropertyEditorDefinition::<MaterialResource>::new());
|
||||
|
||||
container.insert(InheritablePropertyEditorDefinition::<Handle<Node>>::new());
|
||||
container.register_inheritable_vec_collection::<Handle<Node>>();
|
||||
container.insert(NodeHandlePropertyEditorDefinition::new(
|
||||
+23
-8
@@ -45,10 +45,8 @@ use crate::fyrox::{
|
||||
BuildContext, Control, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
asset::item::AssetItem, inspector::EditorEnvironment, load_image, message::MessageSender,
|
||||
Message,
|
||||
};
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use crate::{asset::item::AssetItem, load_image, message::MessageSender, Message};
|
||||
use fyrox::core::PhantomDataSendSync;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
@@ -286,9 +284,9 @@ where
|
||||
.with_height(16.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../../resources/sound_source.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!(
|
||||
"../../../../resources/sound_source.png"
|
||||
))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child({
|
||||
@@ -321,7 +319,7 @@ where
|
||||
.build(ctx),
|
||||
)
|
||||
.with_allow_drop(true)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
name,
|
||||
resource_manager,
|
||||
resource: self.resource,
|
||||
@@ -421,3 +419,20 @@ where
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::plugins::inspector::editors::resource::ResourceFieldBuilder;
|
||||
use fyrox::asset::manager::ResourceManager;
|
||||
use fyrox::resource::model::Model;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
ResourceFieldBuilder::<Model>::new(WidgetBuilder::new(), Default::default())
|
||||
.build(ctx, ResourceManager::new(Default::default()))
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -48,9 +48,9 @@ use crate::fyrox::{
|
||||
},
|
||||
script::Script,
|
||||
};
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use crate::{
|
||||
gui::make_dropdown_list_option,
|
||||
inspector::EditorEnvironment,
|
||||
send_sync_message,
|
||||
settings::{general::ScriptEditor, SettingsData},
|
||||
DropdownListBuilder, MSG_SYNC_FLAG,
|
||||
@@ -265,7 +265,7 @@ impl ScriptPropertyEditorBuilder {
|
||||
.widget_builder
|
||||
.with_preview_messages(true)
|
||||
.with_child(inspector)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
selected_script_uuid: script_uuid,
|
||||
variant_selector,
|
||||
open_in_ide_button,
|
||||
+2
-2
@@ -42,7 +42,7 @@ use crate::fyrox::{
|
||||
},
|
||||
scene::animation::spritesheet::prelude::*,
|
||||
};
|
||||
use crate::inspector::editors::spritesheet::window::SpriteSheetFramesEditorWindow;
|
||||
use crate::plugins::inspector::editors::spritesheet::window::SpriteSheetFramesEditorWindow;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -134,7 +134,7 @@ impl SpriteSheetFramesPropertyEditor {
|
||||
.build(ctx);
|
||||
|
||||
ctx.add_node(UiNode::new(Self {
|
||||
widget: WidgetBuilder::new().with_child(grid).build(),
|
||||
widget: WidgetBuilder::new().with_child(grid).build(ctx),
|
||||
edit_button,
|
||||
container,
|
||||
}))
|
||||
+1
-1
@@ -44,7 +44,7 @@ use crate::fyrox::{
|
||||
},
|
||||
scene::animation::spritesheet::prelude::*,
|
||||
};
|
||||
use crate::inspector::editors::spritesheet::SpriteSheetFramesPropertyEditorMessage;
|
||||
use crate::plugins::inspector::editors::spritesheet::SpriteSheetFramesPropertyEditorMessage;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{mpsc::Sender, Arc},
|
||||
+2
-2
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use crate::{
|
||||
asset::item::AssetItem,
|
||||
fyrox::{
|
||||
@@ -45,7 +46,6 @@ use crate::{
|
||||
},
|
||||
scene::mesh::surface::{SurfaceData, SurfaceResource},
|
||||
},
|
||||
inspector::EditorEnvironment,
|
||||
message::MessageSender,
|
||||
Message,
|
||||
};
|
||||
@@ -185,7 +185,7 @@ impl SurfaceDataPropertyEditor {
|
||||
.build(ctx),
|
||||
)
|
||||
.with_allow_drop(true)
|
||||
.build();
|
||||
.build(ctx);
|
||||
|
||||
let editor = Self {
|
||||
widget,
|
||||
+3
-2
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::asset::item::AssetItem;
|
||||
use crate::fyrox::graph::BaseSceneGraph;
|
||||
use crate::fyrox::{
|
||||
asset::manager::ResourceManager,
|
||||
@@ -42,7 +43,7 @@ use crate::fyrox::{
|
||||
},
|
||||
resource::texture::{Texture, TextureResource},
|
||||
};
|
||||
use crate::{asset::item::AssetItem, inspector::EditorEnvironment};
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
fmt::{Debug, Formatter},
|
||||
@@ -161,7 +162,7 @@ impl TextureEditorBuilder {
|
||||
.build(ctx);
|
||||
image
|
||||
})
|
||||
.build();
|
||||
.build(ctx);
|
||||
|
||||
let editor = TextureEditor {
|
||||
widget,
|
||||
@@ -18,8 +18,9 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::absm::animation_container_ref;
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{
|
||||
absm::animation_container_ref,
|
||||
fyrox::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{
|
||||
@@ -47,7 +48,6 @@ use crate::{
|
||||
scene::SceneContainer,
|
||||
},
|
||||
gui::make_image_button_with_tooltip,
|
||||
inspector::editors::make_property_editors_container,
|
||||
load_image,
|
||||
message::MessageSender,
|
||||
plugin::EditorPlugin,
|
||||
@@ -207,7 +207,7 @@ impl InspectorPlugin {
|
||||
ctx,
|
||||
18.0,
|
||||
18.0,
|
||||
load_image(include_bytes!("../../resources/doc.png")),
|
||||
load_image!("../../../resources/doc.png"),
|
||||
"Open Documentation",
|
||||
Some(0),
|
||||
);
|
||||
@@ -248,7 +248,7 @@ impl MaterialFieldEditorBuilder {
|
||||
.add_column(Column::auto())
|
||||
.build(ctx),
|
||||
)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
edit,
|
||||
sender,
|
||||
material,
|
||||
@@ -309,3 +309,20 @@ impl PropertyEditorDefinition for MaterialPropertyEditorDefinition {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::plugins::material::editor::MaterialFieldEditorBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
MaterialFieldEditorBuilder::new(WidgetBuilder::new()).build(
|
||||
ctx,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,15 +18,20 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::inspector::{
|
||||
editors::resource::{ResourceFieldBuilder, ResourceFieldMessage},
|
||||
InspectorPlugin,
|
||||
};
|
||||
use crate::{
|
||||
asset::item::AssetItem,
|
||||
fyrox::{
|
||||
asset::untyped::ResourceKind,
|
||||
core::{
|
||||
algebra::{Matrix4, SMatrix, Vector2, Vector3, Vector4},
|
||||
algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
|
||||
color::Color,
|
||||
parking_lot::Mutex,
|
||||
pool::Handle,
|
||||
some_or_continue, some_or_return,
|
||||
sstorage::ImmutableString,
|
||||
},
|
||||
fxhash::FxHashMap,
|
||||
@@ -35,8 +40,10 @@ use crate::{
|
||||
border::BorderBuilder,
|
||||
check_box::{CheckBoxBuilder, CheckBoxMessage},
|
||||
color::{ColorFieldBuilder, ColorFieldMessage},
|
||||
dock::DockingManagerMessage,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
image::{Image, ImageBuilder, ImageMessage},
|
||||
inspector::editors::inherit::InheritablePropertyEditorDefinition,
|
||||
list_view::{ListView, ListViewBuilder, ListViewMessage},
|
||||
matrix::{MatrixEditorBuilder, MatrixEditorMessage},
|
||||
menu::{ContextMenuBuilder, MenuItemBuilder, MenuItemContent, MenuItemMessage},
|
||||
@@ -46,17 +53,15 @@ use crate::{
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
vec::{
|
||||
Vec2EditorBuilder, Vec2EditorMessage, Vec3EditorBuilder, Vec3EditorMessage,
|
||||
Vec4EditorBuilder, Vec4EditorMessage,
|
||||
},
|
||||
vec::{Vec2EditorMessage, Vec3EditorMessage, Vec4EditorMessage},
|
||||
vec::{VecEditorBuilder, VecEditorMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowTitle},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, RcUiNodeHandle, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
},
|
||||
material::{
|
||||
shader::{Shader, ShaderResourceKind},
|
||||
MaterialProperty, MaterialResource, MaterialResourceBinding,
|
||||
MaterialProperty, MaterialResource, MaterialResourceBinding, MaterialTextureBinding,
|
||||
},
|
||||
renderer::framework::gpu_program::{ShaderProperty, ShaderPropertyKind},
|
||||
resource::texture::Texture,
|
||||
@@ -68,18 +73,20 @@ use crate::{
|
||||
},
|
||||
},
|
||||
},
|
||||
inspector::editors::resource::{ResourceFieldBuilder, ResourceFieldMessage},
|
||||
message::MessageSender,
|
||||
plugin::EditorPlugin,
|
||||
plugins::material::editor::MaterialPropertyEditorDefinition,
|
||||
preview::PreviewPanel,
|
||||
scene::commands::material::{
|
||||
SetMaterialBindingCommand, SetMaterialPropertyGroupPropertyValueCommand,
|
||||
SetMaterialShaderCommand,
|
||||
},
|
||||
send_sync_message, Engine, Message,
|
||||
send_sync_message, Editor, Engine, Message,
|
||||
};
|
||||
use fyrox::material::MaterialTextureBinding;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod editor;
|
||||
|
||||
struct TextureContextMenu {
|
||||
popup: RcUiNodeHandle,
|
||||
show_in_asset_browser: Handle<UiNode>,
|
||||
@@ -147,11 +154,7 @@ pub struct MaterialEditor {
|
||||
texture_context_menu: TextureContextMenu,
|
||||
}
|
||||
|
||||
fn create_item_container(
|
||||
ctx: &mut BuildContext,
|
||||
name: &str,
|
||||
item: Handle<UiNode>,
|
||||
) -> Handle<UiNode> {
|
||||
fn make_item_container(ctx: &mut BuildContext, name: &str, item: Handle<UiNode>) -> Handle<UiNode> {
|
||||
ctx[item].set_column(1);
|
||||
|
||||
GridBuilder::new(
|
||||
@@ -171,79 +174,7 @@ fn create_item_container(
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_array_view<T, B>(
|
||||
ctx: &mut BuildContext,
|
||||
value: &[T],
|
||||
mut item_builder: B,
|
||||
) -> Handle<UiNode>
|
||||
where
|
||||
T: Clone,
|
||||
B: FnMut(&mut BuildContext, T) -> Handle<UiNode>,
|
||||
{
|
||||
ListViewBuilder::new(WidgetBuilder::new())
|
||||
.with_items(value.iter().map(|v| item_builder(ctx, v.clone())).collect())
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_float_view(ctx: &mut BuildContext, value: f32) -> Handle<UiNode> {
|
||||
NumericUpDownBuilder::<f32>::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_int_view(ctx: &mut BuildContext, value: i32) -> Handle<UiNode> {
|
||||
NumericUpDownBuilder::<i32>::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.with_precision(0)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_uint_view(ctx: &mut BuildContext, value: u32) -> Handle<UiNode> {
|
||||
NumericUpDownBuilder::<u32>::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.with_precision(0)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_vec2_view(ctx: &mut BuildContext, value: Vector2<f32>) -> Handle<UiNode> {
|
||||
Vec2EditorBuilder::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_vec3_view(ctx: &mut BuildContext, value: Vector3<f32>) -> Handle<UiNode> {
|
||||
Vec3EditorBuilder::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_vec4_view(ctx: &mut BuildContext, value: Vector4<f32>) -> Handle<UiNode> {
|
||||
Vec4EditorBuilder::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(value)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn create_mat_view<const R: usize, const C: usize>(
|
||||
ctx: &mut BuildContext,
|
||||
value: SMatrix<f32, R, C>,
|
||||
) -> Handle<UiNode> {
|
||||
MatrixEditorBuilder::<R, C, f32>::new(WidgetBuilder::new())
|
||||
.with_value(value)
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn sync_array<T, B>(ui: &UserInterface, handle: Handle<UiNode>, array: &[T], mut message_builder: B)
|
||||
where
|
||||
T: Clone,
|
||||
B: FnMut(&T, Handle<UiNode>) -> UiMessage,
|
||||
{
|
||||
let views = &**ui.try_get_of_type::<ListView>(handle).unwrap().items;
|
||||
for (item, view) in array.iter().zip(views) {
|
||||
send_sync_message(ui, message_builder(item, *view))
|
||||
}
|
||||
}
|
||||
|
||||
fn pad_vec<T: Default + Clone>(v: &[T], max_len: usize) -> Vec<T> {
|
||||
fn pad_vec<T: UiView>(v: &[T], max_len: usize) -> Vec<T> {
|
||||
let mut vec = v.to_vec();
|
||||
for _ in v.len()..max_len {
|
||||
vec.push(T::default());
|
||||
@@ -251,6 +182,102 @@ fn pad_vec<T: Default + Clone>(v: &[T], max_len: usize) -> Vec<T> {
|
||||
vec
|
||||
}
|
||||
|
||||
fn make_array_view(
|
||||
ctx: &mut BuildContext,
|
||||
value: &[impl UiView],
|
||||
max_len: usize,
|
||||
) -> Handle<UiNode> {
|
||||
let value = pad_vec(value, max_len);
|
||||
ListViewBuilder::new(WidgetBuilder::new())
|
||||
.with_items(value.into_iter().map(|v| v.make_view(ctx)).collect())
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn sync_array(ui: &UserInterface, handle: Handle<UiNode>, array: &[impl UiView]) {
|
||||
let views = &**ui.try_get_of_type::<ListView>(handle).unwrap().items;
|
||||
for (item, view) in array.iter().zip(views) {
|
||||
send_sync_message(ui, item.into_message(*view))
|
||||
}
|
||||
}
|
||||
|
||||
trait UiView: Default + Copy {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage;
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode>;
|
||||
fn send(self, ui: &UserInterface, item: Handle<UiNode>) {
|
||||
send_sync_message(ui, self.into_message(item))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! numeric_ui_view {
|
||||
($($ty:ty),*) => {
|
||||
$(impl UiView for $ty {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage {
|
||||
NumericUpDownMessage::value(item, MessageDirection::ToWidget, self)
|
||||
}
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
NumericUpDownBuilder::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(self)
|
||||
.build(ctx)
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
numeric_ui_view!(f32, u32, i32);
|
||||
|
||||
macro_rules! vec_ui_view {
|
||||
($($ty:ty),*) => {
|
||||
$(impl UiView for $ty {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage {
|
||||
VecEditorMessage::value(item, MessageDirection::ToWidget, self)
|
||||
}
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
VecEditorBuilder::new(WidgetBuilder::new().with_height(24.0))
|
||||
.with_value(self)
|
||||
.build(ctx)
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
vec_ui_view!(Vector2<f32>, Vector3<f32>, Vector4<f32>);
|
||||
|
||||
macro_rules! mat_ui_view {
|
||||
($($ty:ty),*) => {
|
||||
$(impl UiView for $ty {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage {
|
||||
MatrixEditorMessage::value(item, MessageDirection::ToWidget, self)
|
||||
}
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
MatrixEditorBuilder::new(WidgetBuilder::new())
|
||||
.with_value(self)
|
||||
.build(ctx)
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
mat_ui_view!(Matrix2<f32>, Matrix3<f32>, Matrix4<f32>);
|
||||
|
||||
impl UiView for bool {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage {
|
||||
CheckBoxMessage::checked(item, MessageDirection::ToWidget, Some(self))
|
||||
}
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
CheckBoxBuilder::new(WidgetBuilder::new())
|
||||
.checked(Some(self))
|
||||
.build(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl UiView for Color {
|
||||
fn into_message(self, item: Handle<UiNode>) -> UiMessage {
|
||||
ColorFieldMessage::color(item, MessageDirection::ToWidget, self)
|
||||
}
|
||||
fn make_view(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
ColorFieldBuilder::new(WidgetBuilder::new())
|
||||
.with_color(self)
|
||||
.build(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl MaterialEditor {
|
||||
pub fn new(engine: &mut Engine, sender: MessageSender) -> Self {
|
||||
let mut preview = PreviewPanel::new(engine, 350, 400);
|
||||
@@ -338,6 +365,20 @@ impl MaterialEditor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self, docking_manager: Handle<UiNode>, engine: &mut Engine) {
|
||||
self.preview.destroy(engine);
|
||||
let ui = engine.user_interfaces.first();
|
||||
ui.send_message(DockingManagerMessage::remove_floating_window(
|
||||
docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
self.window,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn set_material(&mut self, material: Option<MaterialResource>, engine: &mut Engine) {
|
||||
self.material = material;
|
||||
|
||||
@@ -365,19 +406,13 @@ impl MaterialEditor {
|
||||
);
|
||||
}
|
||||
|
||||
let Some(material) = self.material.clone() else {
|
||||
return;
|
||||
};
|
||||
let material = some_or_return!(self.material.clone());
|
||||
|
||||
let mut material_state = material.state();
|
||||
let Some(material) = material_state.data() else {
|
||||
return;
|
||||
};
|
||||
let material = some_or_return!(material_state.data());
|
||||
|
||||
let mut shader_state = material.shader().state();
|
||||
let Some(shader) = shader_state.data() else {
|
||||
return;
|
||||
};
|
||||
let shader = some_or_return!(shader_state.data());
|
||||
|
||||
for resource in shader.definition.resources.iter() {
|
||||
if resource.is_built_in() {
|
||||
@@ -396,7 +431,7 @@ impl MaterialEditor {
|
||||
.build(&mut ui.build_ctx());
|
||||
ResourceView {
|
||||
name: resource.name.clone(),
|
||||
container: create_item_container(
|
||||
container: make_item_container(
|
||||
&mut ui.build_ctx(),
|
||||
resource.name.as_str(),
|
||||
editor,
|
||||
@@ -435,55 +470,34 @@ impl MaterialEditor {
|
||||
let property_containers = group
|
||||
.iter()
|
||||
.map(|property| {
|
||||
use ShaderPropertyKind as Kind;
|
||||
let item = match &property.kind {
|
||||
ShaderPropertyKind::Float(value) => create_float_view(ctx, *value),
|
||||
ShaderPropertyKind::FloatArray { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_float_view)
|
||||
}
|
||||
ShaderPropertyKind::Int(value) => create_int_view(ctx, *value),
|
||||
ShaderPropertyKind::IntArray { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_int_view)
|
||||
}
|
||||
ShaderPropertyKind::UInt(value) => create_uint_view(ctx, *value),
|
||||
ShaderPropertyKind::UIntArray { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_uint_view)
|
||||
}
|
||||
ShaderPropertyKind::Vector2(value) => create_vec2_view(ctx, *value),
|
||||
ShaderPropertyKind::Vector2Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_vec2_view)
|
||||
}
|
||||
ShaderPropertyKind::Vector3(value) => create_vec3_view(ctx, *value),
|
||||
ShaderPropertyKind::Vector3Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_vec3_view)
|
||||
}
|
||||
ShaderPropertyKind::Vector4(value) => create_vec4_view(ctx, *value),
|
||||
ShaderPropertyKind::Vector4Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_vec4_view)
|
||||
}
|
||||
ShaderPropertyKind::Matrix2(value) => create_mat_view(ctx, *value),
|
||||
ShaderPropertyKind::Matrix2Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_mat_view)
|
||||
}
|
||||
ShaderPropertyKind::Matrix3(value) => create_mat_view(ctx, *value),
|
||||
ShaderPropertyKind::Matrix3Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_mat_view)
|
||||
}
|
||||
ShaderPropertyKind::Matrix4(value) => create_mat_view(ctx, *value),
|
||||
ShaderPropertyKind::Matrix4Array { value, max_len } => {
|
||||
create_array_view(ctx, &pad_vec(value, *max_len), create_mat_view)
|
||||
}
|
||||
ShaderPropertyKind::Bool(value) => CheckBoxBuilder::new(WidgetBuilder::new())
|
||||
.checked(Some(*value))
|
||||
Kind::Float(value) => value.make_view(ctx),
|
||||
Kind::FloatArray { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Int(value) => value.make_view(ctx),
|
||||
Kind::IntArray { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::UInt(value) => value.make_view(ctx),
|
||||
Kind::UIntArray { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Vector2(value) => value.make_view(ctx),
|
||||
Kind::Vector2Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Vector3(value) => value.make_view(ctx),
|
||||
Kind::Vector3Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Vector4(value) => value.make_view(ctx),
|
||||
Kind::Vector4Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Matrix2(value) => value.make_view(ctx),
|
||||
Kind::Matrix2Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Matrix3(value) => value.make_view(ctx),
|
||||
Kind::Matrix3Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Matrix4(value) => value.make_view(ctx),
|
||||
Kind::Matrix4Array { value, max_len } => make_array_view(ctx, value, *max_len),
|
||||
Kind::Bool(value) => value.make_view(ctx),
|
||||
Kind::Color { r, g, b, a } => ColorFieldBuilder::new(WidgetBuilder::new())
|
||||
.with_color(Color::from_rgba(*r, *g, *b, *a))
|
||||
.build(ctx),
|
||||
ShaderPropertyKind::Color { r, g, b, a } => {
|
||||
ColorFieldBuilder::new(WidgetBuilder::new())
|
||||
.with_color(Color::from_rgba(*r, *g, *b, *a))
|
||||
.build(ctx)
|
||||
}
|
||||
};
|
||||
|
||||
property_views.push(item);
|
||||
create_item_container(ctx, &property.name, item)
|
||||
make_item_container(ctx, &property.name, item)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -493,7 +507,7 @@ impl MaterialEditor {
|
||||
.build(ctx);
|
||||
|
||||
ResourceView {
|
||||
container: create_item_container(ctx, name.as_str(), panel),
|
||||
container: make_item_container(ctx, name.as_str(), panel),
|
||||
name,
|
||||
kind: ResourceViewKind::PropertyGroup {
|
||||
property_views: group
|
||||
@@ -522,14 +536,10 @@ impl MaterialEditor {
|
||||
};
|
||||
|
||||
let mut material_state = material.state();
|
||||
let Some(material) = material_state.data() else {
|
||||
return;
|
||||
};
|
||||
let material = some_or_return!(material_state.data());
|
||||
|
||||
for (binding_name, binding_value) in material.bindings() {
|
||||
let Some(view) = self.find_resource_view(binding_name) else {
|
||||
continue;
|
||||
};
|
||||
let view = some_or_continue!(self.find_resource_view(binding_name));
|
||||
match binding_value {
|
||||
MaterialResourceBinding::Texture(ref binding) => send_sync_message(
|
||||
ui,
|
||||
@@ -550,187 +560,40 @@ impl MaterialEditor {
|
||||
.unwrap_or_else(|| panic!("Property not found {}", property_name));
|
||||
|
||||
match property_value {
|
||||
MaterialProperty::Float(value) => {
|
||||
send_sync_message(
|
||||
ui,
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
),
|
||||
);
|
||||
}
|
||||
MaterialProperty::FloatArray(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Int(value) => {
|
||||
send_sync_message(
|
||||
ui,
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value as f32,
|
||||
),
|
||||
);
|
||||
}
|
||||
MaterialProperty::IntArray(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value as f32,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::UInt(value) => {
|
||||
send_sync_message(
|
||||
ui,
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value as f32,
|
||||
),
|
||||
);
|
||||
}
|
||||
MaterialProperty::UIntArray(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
NumericUpDownMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value as f32,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Vector2(value) => send_sync_message(
|
||||
ui,
|
||||
Vec2EditorMessage::value(item, MessageDirection::ToWidget, *value),
|
||||
),
|
||||
MaterialProperty::Vector2Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
Vec2EditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Vector3(value) => send_sync_message(
|
||||
ui,
|
||||
Vec3EditorMessage::value(item, MessageDirection::ToWidget, *value),
|
||||
),
|
||||
MaterialProperty::Vector3Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
Vec3EditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Vector4(value) => send_sync_message(
|
||||
ui,
|
||||
Vec4EditorMessage::value(item, MessageDirection::ToWidget, *value),
|
||||
),
|
||||
MaterialProperty::Vector4Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
Vec4EditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Matrix2(value) => send_sync_message(
|
||||
ui,
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
),
|
||||
),
|
||||
MaterialProperty::Matrix2Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Matrix3(value) => send_sync_message(
|
||||
ui,
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
),
|
||||
),
|
||||
MaterialProperty::Matrix3Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Matrix4(value) => send_sync_message(
|
||||
ui,
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
),
|
||||
),
|
||||
MaterialProperty::Matrix4Array(value) => {
|
||||
sync_array(ui, item, value, |value, item| {
|
||||
MatrixEditorMessage::value(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
)
|
||||
})
|
||||
}
|
||||
MaterialProperty::Bool(value) => {
|
||||
send_sync_message(
|
||||
ui,
|
||||
CheckBoxMessage::checked(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
Some(*value),
|
||||
),
|
||||
);
|
||||
}
|
||||
MaterialProperty::Color(value) => {
|
||||
send_sync_message(
|
||||
ui,
|
||||
ColorFieldMessage::color(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
*value,
|
||||
),
|
||||
);
|
||||
}
|
||||
MaterialProperty::Float(value) => value.send(ui, item),
|
||||
MaterialProperty::FloatArray(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Int(value) => value.send(ui, item),
|
||||
MaterialProperty::IntArray(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::UInt(value) => value.send(ui, item),
|
||||
MaterialProperty::UIntArray(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Vector2(value) => value.send(ui, item),
|
||||
MaterialProperty::Vector2Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Vector3(value) => value.send(ui, item),
|
||||
MaterialProperty::Vector3Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Vector4(value) => value.send(ui, item),
|
||||
MaterialProperty::Vector4Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Matrix2(value) => value.send(ui, item),
|
||||
MaterialProperty::Matrix2Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Matrix3(value) => value.send(ui, item),
|
||||
MaterialProperty::Matrix3Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Matrix4(value) => value.send(ui, item),
|
||||
MaterialProperty::Matrix4Array(value) => sync_array(ui, item, value),
|
||||
MaterialProperty::Bool(value) => value.send(ui, item),
|
||||
MaterialProperty::Color(value) => value.send(ui, item),
|
||||
}
|
||||
}
|
||||
|
||||
send_sync_message(
|
||||
ui,
|
||||
ResourceFieldMessage::value(
|
||||
self.shader,
|
||||
MessageDirection::ToWidget,
|
||||
Some(material.shader().clone()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_sync_message(
|
||||
ui,
|
||||
ResourceFieldMessage::value(
|
||||
self.shader,
|
||||
MessageDirection::ToWidget,
|
||||
Some(material.shader().clone()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(
|
||||
@@ -739,9 +602,7 @@ impl MaterialEditor {
|
||||
engine: &mut Engine,
|
||||
sender: &MessageSender,
|
||||
) {
|
||||
let Some(material) = self.material.clone() else {
|
||||
return;
|
||||
};
|
||||
let material = some_or_return!(self.material.clone());
|
||||
|
||||
self.preview.handle_message(message, engine);
|
||||
|
||||
@@ -756,13 +617,11 @@ impl MaterialEditor {
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if let Some(PopupMessage::Placement(Placement::Cursor(target))) =
|
||||
message.data::<PopupMessage>()
|
||||
{
|
||||
} else if let Some(PopupMessage::Placement(Placement::Cursor(target))) = message.data() {
|
||||
if message.destination() == self.texture_context_menu.popup.handle() {
|
||||
self.texture_context_menu.target = *target;
|
||||
}
|
||||
} else if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
|
||||
} else if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.texture_context_menu.show_in_asset_browser
|
||||
&& self.texture_context_menu.target.is_some()
|
||||
{
|
||||
@@ -800,7 +659,7 @@ impl MaterialEditor {
|
||||
for resource_view in self.resource_views.iter() {
|
||||
match resource_view.kind {
|
||||
ResourceViewKind::Sampler => {
|
||||
if let Some(WidgetMessage::Drop(handle)) = message.data::<WidgetMessage>() {
|
||||
if let Some(WidgetMessage::Drop(handle)) = message.data() {
|
||||
if let Some(asset_item) = engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
@@ -834,50 +693,7 @@ impl MaterialEditor {
|
||||
if *property_view == message.destination()
|
||||
&& message.direction() == MessageDirection::FromWidget
|
||||
{
|
||||
let property_value =
|
||||
if let Some(NumericUpDownMessage::<f32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Float(*value))
|
||||
} else if let Some(NumericUpDownMessage::<i32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Int(*value))
|
||||
} else if let Some(NumericUpDownMessage::<u32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::UInt(*value))
|
||||
} else if let Some(Vec2EditorMessage::Value(value)) = message.data()
|
||||
{
|
||||
Some(MaterialProperty::Vector2(*value))
|
||||
} else if let Some(Vec3EditorMessage::Value(value)) = message.data()
|
||||
{
|
||||
Some(MaterialProperty::Vector3(*value))
|
||||
} else if let Some(Vec4EditorMessage::Value(value)) = message.data()
|
||||
{
|
||||
Some(MaterialProperty::Vector4(*value))
|
||||
} else if let Some(ColorFieldMessage::Color(color)) = message.data()
|
||||
{
|
||||
Some(MaterialProperty::Color(*color))
|
||||
} else if let Some(MatrixEditorMessage::<2, 2, f32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Matrix2(*value))
|
||||
} else if let Some(MatrixEditorMessage::<3, 3, f32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Matrix3(*value))
|
||||
} else if let Some(MatrixEditorMessage::<4, 4, f32>::Value(value)) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Matrix4(*value))
|
||||
} else if let Some(CheckBoxMessage::Check(Some(value))) =
|
||||
message.data()
|
||||
{
|
||||
Some(MaterialProperty::Bool(*value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let property_value = try_extract_message_value(message);
|
||||
|
||||
if let Some(property_value) = property_value {
|
||||
sender.do_command(
|
||||
@@ -900,3 +716,98 @@ impl MaterialEditor {
|
||||
self.preview.update(engine)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_extract_message_value(message: &UiMessage) -> Option<MaterialProperty> {
|
||||
if let Some(NumericUpDownMessage::<f32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Float(*value))
|
||||
} else if let Some(NumericUpDownMessage::<i32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Int(*value))
|
||||
} else if let Some(NumericUpDownMessage::<u32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::UInt(*value))
|
||||
} else if let Some(Vec2EditorMessage::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Vector2(*value))
|
||||
} else if let Some(Vec3EditorMessage::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Vector3(*value))
|
||||
} else if let Some(Vec4EditorMessage::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Vector4(*value))
|
||||
} else if let Some(ColorFieldMessage::Color(color)) = message.data() {
|
||||
Some(MaterialProperty::Color(*color))
|
||||
} else if let Some(MatrixEditorMessage::<2, 2, f32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Matrix2(*value))
|
||||
} else if let Some(MatrixEditorMessage::<3, 3, f32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Matrix3(*value))
|
||||
} else if let Some(MatrixEditorMessage::<4, 4, f32>::Value(value)) = message.data() {
|
||||
Some(MaterialProperty::Matrix4(*value))
|
||||
} else if let Some(CheckBoxMessage::Check(Some(value))) = message.data() {
|
||||
Some(MaterialProperty::Bool(*value))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MaterialPlugin {
|
||||
material_editor: Option<MaterialEditor>,
|
||||
}
|
||||
|
||||
impl EditorPlugin for MaterialPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let container = &editor.plugins.get_mut::<InspectorPlugin>().property_editors;
|
||||
container.insert(MaterialPropertyEditorDefinition {
|
||||
sender: Mutex::new(editor.message_sender.clone()),
|
||||
});
|
||||
container.insert(InheritablePropertyEditorDefinition::<MaterialResource>::new());
|
||||
}
|
||||
|
||||
fn on_sync_to_model(&mut self, editor: &mut Editor) {
|
||||
let material_editor = some_or_return!(self.material_editor.as_mut());
|
||||
material_editor.sync_to_model(editor.engine.user_interfaces.first_mut());
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
let mut material_editor = some_or_return!(self.material_editor.take());
|
||||
|
||||
material_editor.handle_ui_message(message, &mut editor.engine, &editor.message_sender);
|
||||
|
||||
if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == material_editor.window {
|
||||
material_editor.destroy(editor.docking_manager, &mut editor.engine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.material_editor = Some(material_editor);
|
||||
}
|
||||
|
||||
fn on_update(&mut self, editor: &mut Editor) {
|
||||
let material_editor = some_or_return!(self.material_editor.as_mut());
|
||||
material_editor.update(&mut editor.engine);
|
||||
}
|
||||
|
||||
fn on_message(&mut self, message: &Message, editor: &mut Editor) {
|
||||
let Message::OpenMaterialEditor(material) = message else {
|
||||
return;
|
||||
};
|
||||
|
||||
let engine = &mut editor.engine;
|
||||
|
||||
let material_editor = self
|
||||
.material_editor
|
||||
.get_or_insert_with(|| MaterialEditor::new(engine, editor.message_sender.clone()));
|
||||
|
||||
material_editor.set_material(Some(material.clone()), engine);
|
||||
|
||||
let ui = engine.user_interfaces.first_mut();
|
||||
ui.send_message(WindowMessage::open(
|
||||
material_editor.window,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
ui.send_message(DockingManagerMessage::add_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
material_editor.window,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -18,5 +18,14 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
pub mod absm;
|
||||
pub mod animation;
|
||||
pub mod collider;
|
||||
pub mod curve_editor;
|
||||
pub mod inspector;
|
||||
pub mod material;
|
||||
pub mod path_fixer;
|
||||
pub mod ragdoll;
|
||||
pub mod settings;
|
||||
pub mod stats;
|
||||
pub mod tilemap;
|
||||
|
||||
@@ -21,34 +21,40 @@
|
||||
//! Special utility that allows you to fix paths to resources. It is very useful if you've
|
||||
//! moved a resource in a file system, but a scene has old path.
|
||||
|
||||
use crate::fyrox::asset::untyped::ResourceKind;
|
||||
use crate::fyrox::graph::{BaseSceneGraph, SceneGraph};
|
||||
use crate::fyrox::{
|
||||
asset::{manager::ResourceManager, untyped::UntypedResource},
|
||||
core::{
|
||||
color::Color, futures::executor::block_on, pool::Handle, replace_slashes, visitor::Visitor,
|
||||
use crate::{
|
||||
fyrox::{
|
||||
asset::{manager::ResourceManager, untyped::ResourceKind, untyped::UntypedResource},
|
||||
core::{
|
||||
color::Color, futures::executor::block_on, pool::Handle, replace_slashes,
|
||||
some_or_return, visitor::Visitor,
|
||||
},
|
||||
engine::SerializationContext,
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
brush::Brush,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
decorator::DecoratorBuilder,
|
||||
file_browser::{FileSelectorBuilder, FileSelectorMessage},
|
||||
formatted_text::WrapMode,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
list_view::{ListView, ListViewBuilder, ListViewMessage},
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::{Text, TextBuilder, TextMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment,
|
||||
},
|
||||
scene::{Scene, SceneLoader},
|
||||
},
|
||||
engine::SerializationContext,
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
brush::Brush,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
decorator::DecoratorBuilder,
|
||||
file_browser::{FileSelectorBuilder, FileSelectorMessage},
|
||||
formatted_text::WrapMode,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
list_view::{ListView, ListViewBuilder, ListViewMessage},
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::{Text, TextBuilder, TextMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment,
|
||||
},
|
||||
scene::{Scene, SceneLoader},
|
||||
make_scene_file_filter,
|
||||
menu::create_menu_item,
|
||||
plugin::EditorPlugin,
|
||||
Editor, Message,
|
||||
};
|
||||
use crate::{make_scene_file_filter, Message};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
@@ -74,7 +80,10 @@ pub struct PathFixer {
|
||||
|
||||
fn find_file(name: &Path) -> Vec<PathBuf> {
|
||||
let mut files = Vec::new();
|
||||
for dir in fyrox::walkdir::WalkDir::new(".").into_iter().flatten() {
|
||||
for dir in fyrox::walkdir::WalkDir::new("../../..")
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
let path = dir.path();
|
||||
if let Some(file_name) = path.file_name() {
|
||||
if file_name == name {
|
||||
@@ -216,6 +225,7 @@ impl PathFixer {
|
||||
.add_column(Column::stretch())
|
||||
.build(ctx),
|
||||
)
|
||||
.with_remove_on_close(true)
|
||||
.build(ctx);
|
||||
|
||||
Self {
|
||||
@@ -269,13 +279,24 @@ impl PathFixer {
|
||||
));
|
||||
}
|
||||
|
||||
fn destroy(self, ui: &UserInterface) {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.new_path_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.scene_selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(
|
||||
&mut self,
|
||||
mut self,
|
||||
message: &UiMessage,
|
||||
ui: &mut UserInterface,
|
||||
serialization_context: Arc<SerializationContext>,
|
||||
resource_manager: ResourceManager,
|
||||
) {
|
||||
) -> Option<Self> {
|
||||
if let Some(FileSelectorMessage::Commit(path)) = message.data::<FileSelectorMessage>() {
|
||||
if message.destination() == self.scene_selector {
|
||||
let message;
|
||||
@@ -492,7 +513,14 @@ impl PathFixer {
|
||||
self.selection.is_some(),
|
||||
));
|
||||
}
|
||||
} else if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == self.window {
|
||||
self.destroy(ui);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(self)
|
||||
}
|
||||
|
||||
pub fn handle_message(&mut self, message: &Message, ui: &UserInterface) {
|
||||
@@ -509,4 +537,63 @@ impl PathFixer {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn open(&self, ui: &UserInterface) {
|
||||
ui.send_message(WindowMessage::open_modal(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PathFixerPlugin {
|
||||
path_fixer: Option<PathFixer>,
|
||||
open_path_fixer: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl PathFixerPlugin {
|
||||
fn on_open_curve_editor_clicked(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
let path_fixer = self.path_fixer.get_or_insert_with(|| PathFixer::new(ctx));
|
||||
path_fixer.open(ui);
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for PathFixerPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_path_fixer = create_menu_item("Path Fixer", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_path_fixer,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_path_fixer {
|
||||
self.on_open_curve_editor_clicked(editor)
|
||||
}
|
||||
}
|
||||
let path_fixer = some_or_return!(self.path_fixer.take());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
self.path_fixer = path_fixer.handle_ui_message(
|
||||
message,
|
||||
ui,
|
||||
editor.engine.serialization_context.clone(),
|
||||
editor.engine.resource_manager.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
fn on_message(&mut self, message: &Message, editor: &mut Editor) {
|
||||
let path_fixer = some_or_return!(self.path_fixer.as_mut());
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
path_fixer.handle_message(message, ui);
|
||||
}
|
||||
}
|
||||
@@ -18,51 +18,54 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::command::{Command, CommandGroup};
|
||||
use crate::fyrox::graph::{BaseSceneGraph, SceneGraph};
|
||||
use crate::fyrox::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector3},
|
||||
log::Log,
|
||||
math::Matrix4Ext,
|
||||
pool::Handle,
|
||||
reflect::prelude::*,
|
||||
},
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
inspector::{InspectorBuilder, InspectorContext, InspectorMessage, PropertyAction},
|
||||
message::{MessageDirection, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
utils::make_simple_tooltip,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
collider::{ColliderBuilder, ColliderShape, InteractionGroups},
|
||||
graph::Graph,
|
||||
joint::{BallJoint, JointBuilder, JointParams, RevoluteJoint},
|
||||
node::Node,
|
||||
ragdoll::{Limb, RagdollBuilder},
|
||||
rigidbody::{RigidBodyBuilder, RigidBodyType},
|
||||
transform::TransformBuilder,
|
||||
},
|
||||
};
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{
|
||||
inspector::editors::make_property_editors_container,
|
||||
command::{Command, CommandGroup},
|
||||
fyrox::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector3},
|
||||
log::Log,
|
||||
math::Matrix4Ext,
|
||||
pool::Handle,
|
||||
reflect::prelude::*,
|
||||
some_or_return,
|
||||
},
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
inspector::{InspectorBuilder, InspectorContext, InspectorMessage, PropertyAction},
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
utils::make_simple_tooltip,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
scene::{
|
||||
base::BaseBuilder,
|
||||
collider::{ColliderBuilder, ColliderShape, InteractionGroups},
|
||||
graph::Graph,
|
||||
joint::{BallJoint, JointBuilder, JointParams, RevoluteJoint},
|
||||
node::Node,
|
||||
ragdoll::{Limb, RagdollBuilder},
|
||||
rigidbody::{RigidBodyBuilder, RigidBodyType},
|
||||
transform::TransformBuilder,
|
||||
},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
plugin::EditorPlugin,
|
||||
scene::{
|
||||
commands::{graph::AddModelCommand, ChangeSelectionCommand},
|
||||
GameScene, Selection,
|
||||
},
|
||||
world::graph::selection::GraphSelection,
|
||||
MSG_SYNC_FLAG,
|
||||
Editor, MSG_SYNC_FLAG,
|
||||
};
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
#[derive(Reflect, Debug)]
|
||||
pub struct RagdollPreset {
|
||||
@@ -743,7 +746,7 @@ impl RagdollPreset {
|
||||
try_make_ball_joint(
|
||||
right_up_leg,
|
||||
hips,
|
||||
"RagdollLeftUpLegHipsBallJoint",
|
||||
"RagdollRightUpLegHipsBallJoint",
|
||||
Some(BallJointLimits {
|
||||
x: (-80.0f32).to_radians()..80.0f32.to_radians(),
|
||||
y: (-80.0f32).to_radians()..80.0f32.to_radians(),
|
||||
@@ -1219,3 +1222,48 @@ impl RagdollWizard {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RagdollPlugin {
|
||||
ragdoll_wizard: Option<RagdollWizard>,
|
||||
open_ragdoll_wizard: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl RagdollPlugin {
|
||||
fn on_open_ragdoll_wizard_clicked(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
let wizard = self
|
||||
.ragdoll_wizard
|
||||
.get_or_insert_with(|| RagdollWizard::new(ctx, editor.message_sender.clone()));
|
||||
wizard.open(ui);
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for RagdollPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_ragdoll_wizard = create_menu_item("Ragdoll Wizard", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_ragdoll_wizard,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_ragdoll_wizard {
|
||||
self.on_open_ragdoll_wizard_clicked(editor)
|
||||
}
|
||||
}
|
||||
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let wizard = some_or_return!(self.ragdoll_wizard.as_mut());
|
||||
let current_scene = some_or_return!(editor.scenes.current_scene_entry_mut());
|
||||
let game_scene = some_or_return!(current_scene.controller.downcast_mut::<GameScene>());
|
||||
let graph = &mut editor.engine.scenes[game_scene.scene].graph;
|
||||
wizard.handle_ui_message(message, ui, graph, game_scene, &editor.message_sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! Settings window plugin.
|
||||
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::{log::Log, pool::Handle, some_or_return},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
dock::DockingManagerMessage,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
inspector::{
|
||||
editors::{
|
||||
collection::VecCollectionPropertyEditorDefinition,
|
||||
enumeration::EnumPropertyEditorDefinition,
|
||||
inspectable::InspectablePropertyEditorDefinition,
|
||||
key::HotKeyPropertyEditorDefinition, PropertyEditorDefinitionContainer,
|
||||
},
|
||||
InspectorBuilder, InspectorContext, InspectorMessage, PropertyAction,
|
||||
},
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
renderer::{CsmSettings, QualitySettings, ShadowMapPrecision},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
message::MessageSender,
|
||||
plugin::EditorPlugin,
|
||||
settings::{
|
||||
build::{BuildCommand, BuildProfile, BuildSettings, EnvironmentVariable},
|
||||
camera::CameraSettings,
|
||||
debugging::DebuggingSettings,
|
||||
general::{GeneralSettings, ScriptEditor},
|
||||
graphics::GraphicsSettings,
|
||||
keys::{KeyBindings, TerrainKeyBindings},
|
||||
model::ModelSettings,
|
||||
move_mode::MoveInteractionModeSettings,
|
||||
navmesh::NavmeshSettings,
|
||||
rotate_mode::RotateInteractionModeSettings,
|
||||
selection::SelectionSettings,
|
||||
Settings,
|
||||
},
|
||||
Editor, MSG_SYNC_FLAG,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn make_property_editors_container(
|
||||
sender: MessageSender,
|
||||
) -> Arc<PropertyEditorDefinitionContainer> {
|
||||
let container = crate::plugins::inspector::editors::make_property_editors_container(sender);
|
||||
|
||||
container.insert(InspectablePropertyEditorDefinition::<GeneralSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<GraphicsSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<SelectionSettings>::new());
|
||||
container.insert(EnumPropertyEditorDefinition::<ShadowMapPrecision>::new());
|
||||
container.insert(EnumPropertyEditorDefinition::<ScriptEditor>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<DebuggingSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<CsmSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<QualitySettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<CameraSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<
|
||||
MoveInteractionModeSettings,
|
||||
>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<
|
||||
RotateInteractionModeSettings,
|
||||
>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<ModelSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<NavmeshSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<KeyBindings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<TerrainKeyBindings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildSettings>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<EnvironmentVariable>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<EnvironmentVariable>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<BuildProfile>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildProfile>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<BuildCommand>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildCommand>::new());
|
||||
container.insert(HotKeyPropertyEditorDefinition);
|
||||
Arc::new(container)
|
||||
}
|
||||
|
||||
pub struct SettingsWindow {
|
||||
pub window: Handle<UiNode>,
|
||||
ok: Handle<UiNode>,
|
||||
default: Handle<UiNode>,
|
||||
inspector: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl SettingsWindow {
|
||||
pub fn new(engine: &mut Engine) -> Self {
|
||||
let ok;
|
||||
let default;
|
||||
|
||||
let ctx = &mut engine.user_interfaces.first_mut().build_ctx();
|
||||
|
||||
let inspector = InspectorBuilder::new(WidgetBuilder::new()).build(ctx);
|
||||
|
||||
let window = WindowBuilder::new(WidgetBuilder::new().with_width(500.0).with_height(600.0))
|
||||
.open(false)
|
||||
.with_title(WindowTitle::text("Settings"))
|
||||
.with_content(
|
||||
GridBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_child(
|
||||
ScrollViewerBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.on_row(0),
|
||||
)
|
||||
.with_content(inspector)
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child(
|
||||
StackPanelBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.on_row(1)
|
||||
.with_horizontal_alignment(HorizontalAlignment::Right)
|
||||
.with_child({
|
||||
default = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(80.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_text("Default")
|
||||
.build(ctx);
|
||||
default
|
||||
})
|
||||
.with_child({
|
||||
ok = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(80.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_text("OK")
|
||||
.build(ctx);
|
||||
ok
|
||||
}),
|
||||
)
|
||||
.with_orientation(Orientation::Horizontal)
|
||||
.build(ctx),
|
||||
),
|
||||
)
|
||||
.add_row(Row::stretch())
|
||||
.add_row(Row::strict(25.0))
|
||||
.add_column(Column::stretch())
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
Self {
|
||||
window,
|
||||
ok,
|
||||
default,
|
||||
inspector,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&self, ui: &mut UserInterface, settings: &Settings, sender: &MessageSender) {
|
||||
ui.send_message(WindowMessage::open(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
|
||||
self.sync_to_model(ui, settings, sender);
|
||||
}
|
||||
|
||||
fn sync_to_model(&self, ui: &mut UserInterface, settings: &Settings, sender: &MessageSender) {
|
||||
let context = InspectorContext::from_object(
|
||||
&**settings,
|
||||
&mut ui.build_ctx(),
|
||||
make_property_editors_container(sender.clone()),
|
||||
None,
|
||||
MSG_SYNC_FLAG,
|
||||
0,
|
||||
true,
|
||||
Default::default(),
|
||||
150.0,
|
||||
);
|
||||
ui.send_message(InspectorMessage::context(
|
||||
self.inspector,
|
||||
MessageDirection::ToWidget,
|
||||
context,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn handle_ui_message(
|
||||
self,
|
||||
message: &UiMessage,
|
||||
engine: &mut Engine,
|
||||
settings: &mut Settings,
|
||||
sender: &MessageSender,
|
||||
docking_manager: Handle<UiNode>,
|
||||
) -> Option<Self> {
|
||||
let ui = engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(ButtonMessage::Click) = message.data::<ButtonMessage>() {
|
||||
if message.destination() == self.ok {
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
} else if message.destination() == self.default {
|
||||
**settings = Default::default();
|
||||
|
||||
self.sync_to_model(ui, settings, sender);
|
||||
}
|
||||
} else if let Some(InspectorMessage::PropertyChanged(property_changed)) = message.data() {
|
||||
if message.destination() == self.inspector {
|
||||
PropertyAction::from_field_kind(&property_changed.value).apply(
|
||||
&property_changed.path(),
|
||||
&mut **settings,
|
||||
&mut Log::verify,
|
||||
);
|
||||
}
|
||||
} else if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == self.window {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
ui.send_message(DockingManagerMessage::remove_floating_window(
|
||||
docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
self.window,
|
||||
));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let graphics_context = engine.graphics_context.as_initialized_mut();
|
||||
|
||||
if settings.graphics.quality != graphics_context.renderer.get_quality_settings() {
|
||||
if let Err(e) = graphics_context
|
||||
.renderer
|
||||
.set_quality_settings(&settings.graphics.quality)
|
||||
{
|
||||
Log::err(format!(
|
||||
"An error occurred at attempt to set new graphics settings: {e:?}"
|
||||
));
|
||||
} else {
|
||||
Log::info("New graphics quality settings were successfully set!");
|
||||
}
|
||||
}
|
||||
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SettingsPlugin {
|
||||
window: Option<SettingsWindow>,
|
||||
open_settings: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl SettingsPlugin {
|
||||
fn on_open_settings_clicked(&mut self, editor: &mut Editor) {
|
||||
let window = self
|
||||
.window
|
||||
.get_or_insert_with(|| SettingsWindow::new(&mut editor.engine));
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
window.open(ui, &editor.settings, &editor.message_sender);
|
||||
ui.send_message(DockingManagerMessage::add_floating_window(
|
||||
editor.docking_manager,
|
||||
MessageDirection::ToWidget,
|
||||
window.window,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
impl EditorPlugin for SettingsPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_settings = create_menu_item("Editor Settings...", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.file_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_settings,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_settings {
|
||||
self.on_open_settings_clicked(editor);
|
||||
}
|
||||
}
|
||||
|
||||
let window = some_or_return!(self.window.take());
|
||||
self.window = window.handle_ui_message(
|
||||
message,
|
||||
&mut editor.engine,
|
||||
&mut editor.settings,
|
||||
&editor.message_sender,
|
||||
editor.docking_manager,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::pool::Handle,
|
||||
gui::{
|
||||
menu::MenuItemMessage,
|
||||
message::{MessageDirection, UiMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::{TextBuilder, TextMessage},
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage},
|
||||
HorizontalAlignment, Thickness, UiNode, VerticalAlignment,
|
||||
},
|
||||
},
|
||||
menu::create_menu_item,
|
||||
plugin::EditorPlugin,
|
||||
Editor,
|
||||
};
|
||||
use fyrox::gui::window::WindowTitle;
|
||||
|
||||
/// Editor UI statistics, useful to track number of active widgets and memory consumption.
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UiStatisticsPlugin {
|
||||
window: Handle<UiNode>,
|
||||
text: Handle<UiNode>,
|
||||
open_ui_stats: Handle<UiNode>,
|
||||
}
|
||||
|
||||
impl EditorPlugin for UiStatisticsPlugin {
|
||||
fn on_start(&mut self, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.open_ui_stats = create_menu_item("Editor UI Statistics", vec![], ctx);
|
||||
ui.send_message(MenuItemMessage::add_item(
|
||||
editor.menu.utils_menu.menu,
|
||||
MessageDirection::ToWidget,
|
||||
self.open_ui_stats,
|
||||
));
|
||||
}
|
||||
|
||||
fn on_ui_message(&mut self, message: &mut UiMessage, editor: &mut Editor) {
|
||||
let ui = editor.engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(MenuItemMessage::Click) = message.data() {
|
||||
if message.destination() == self.open_ui_stats && self.window.is_none() {
|
||||
let ctx = &mut ui.build_ctx();
|
||||
self.text =
|
||||
TextBuilder::new(WidgetBuilder::new().with_margin(Thickness::uniform(1.0)))
|
||||
.build(ctx);
|
||||
self.window =
|
||||
WindowBuilder::new(WidgetBuilder::new().with_width(200.0).with_height(100.0))
|
||||
.with_title(WindowTitle::text("Editor UI Statistics"))
|
||||
.with_content(
|
||||
StackPanelBuilder::new(WidgetBuilder::new().with_child(self.text))
|
||||
.build(ctx),
|
||||
)
|
||||
.open(false)
|
||||
.build(ctx);
|
||||
|
||||
ui.send_message(WindowMessage::open_and_align(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
editor.scene_viewer.frame(),
|
||||
HorizontalAlignment::Right,
|
||||
VerticalAlignment::Bottom,
|
||||
Thickness::uniform(1.0),
|
||||
false,
|
||||
true,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(WindowMessage::Close) = message.data() {
|
||||
if message.destination() == self.window {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.window = Handle::NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_update(&mut self, editor: &mut Editor) {
|
||||
if self.window.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let ui = editor.engine.user_interfaces.first();
|
||||
|
||||
let total_memory = ui
|
||||
.nodes()
|
||||
.iter()
|
||||
.fold(0, |acc, node| acc + node.self_size());
|
||||
|
||||
ui.send_message(TextMessage::text(
|
||||
self.text,
|
||||
MessageDirection::ToWidget,
|
||||
format!(
|
||||
"Widget Count: {}\nMemory Used: {:.3} Mb.\n\
|
||||
Drawing Commands: {}\nProcessed Messages: {}\n",
|
||||
ui.nodes().alive_count(),
|
||||
total_memory as f32 / (1024.0 * 1024.0),
|
||||
ui.get_drawing_context().get_commands().len(),
|
||||
editor.processed_ui_messages
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ mod preview;
|
||||
pub mod tile_set_import;
|
||||
pub mod tileset;
|
||||
|
||||
use crate::inspector::InspectorPlugin;
|
||||
use crate::plugins::inspector::InspectorPlugin;
|
||||
use crate::{
|
||||
command::SetPropertyCommand,
|
||||
fyrox::{
|
||||
|
||||
@@ -18,34 +18,32 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::tilemap::tileset::TileSetTileView;
|
||||
use crate::{
|
||||
absm::selectable::{Selectable, SelectableMessage},
|
||||
fyrox::{
|
||||
core::{
|
||||
algebra::{Matrix3, Point2, Vector2},
|
||||
color::Color,
|
||||
math::{OptionRect, Rect},
|
||||
pool::Handle,
|
||||
reflect::prelude::*,
|
||||
type_traits::prelude::*,
|
||||
visitor::prelude::*,
|
||||
},
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
gui::{
|
||||
brush::Brush,
|
||||
define_constructor, define_widget_deref,
|
||||
draw::{CommandTexture, Draw, DrawingContext},
|
||||
message::{KeyCode, MessageDirection, MouseButton, UiMessage},
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
scene::tilemap::{
|
||||
brush::{BrushTile, TileMapBrush},
|
||||
tileset::TileSetResource,
|
||||
},
|
||||
use crate::fyrox::{
|
||||
core::{
|
||||
algebra::{Matrix3, Point2, Vector2},
|
||||
color::Color,
|
||||
math::{OptionRect, Rect},
|
||||
pool::Handle,
|
||||
reflect::prelude::*,
|
||||
type_traits::prelude::*,
|
||||
visitor::prelude::*,
|
||||
},
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
gui::{
|
||||
brush::Brush,
|
||||
define_constructor, define_widget_deref,
|
||||
draw::{CommandTexture, Draw, DrawingContext},
|
||||
message::{KeyCode, MessageDirection, MouseButton, UiMessage},
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
},
|
||||
scene::tilemap::{
|
||||
brush::{BrushTile, TileMapBrush},
|
||||
tileset::TileSetResource,
|
||||
},
|
||||
};
|
||||
use crate::plugins::absm::selectable::{Selectable, SelectableMessage};
|
||||
use crate::plugins::tilemap::tileset::TileSetTileView;
|
||||
use fyrox::scene::tilemap::tileset::TileDefinitionHandle;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
@@ -513,7 +511,7 @@ impl PaletteWidgetBuilder {
|
||||
.with_allow_drop(true)
|
||||
.with_clip_to_bounds(false)
|
||||
.with_children(self.tiles.iter().cloned())
|
||||
.build(),
|
||||
.build(ctx),
|
||||
tiles: self.tiles,
|
||||
view_position: Default::default(),
|
||||
zoom: 1.0,
|
||||
@@ -640,7 +638,7 @@ impl BrushTileViewBuilder {
|
||||
|
||||
pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
ctx.add_node(UiNode::new(BrushTileView {
|
||||
widget: self.widget_builder.build(),
|
||||
widget: self.widget_builder.build(ctx),
|
||||
selectable: Default::default(),
|
||||
definition_handle: self.definition_id,
|
||||
local_position: self.local_position,
|
||||
|
||||
@@ -41,8 +41,7 @@ use crate::{
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_BRIGHT_BLUE, BRUSH_DARKER, BRUSH_LIGHT, BRUSH_LIGHTER,
|
||||
BRUSH_LIGHTEST,
|
||||
VerticalAlignment,
|
||||
},
|
||||
scene::{
|
||||
node::Node,
|
||||
@@ -70,6 +69,8 @@ use crate::{
|
||||
scene::{commands::GameSceneContext, container::EditorSceneEntry},
|
||||
Message,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
|
||||
pub struct TileMapPanel {
|
||||
pub window: Handle<UiNode>,
|
||||
@@ -138,15 +139,17 @@ fn make_drawing_mode_button(
|
||||
)
|
||||
.with_back(
|
||||
DecoratorBuilder::new(
|
||||
BorderBuilder::new(WidgetBuilder::new().with_foreground(BRUSH_DARKER))
|
||||
.with_pad_by_corner_radius(false)
|
||||
.with_corner_radius(4.0)
|
||||
.with_stroke_thickness(Thickness::uniform(1.0)),
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new().with_foreground(ctx.style.get_or_default(Style::BRUSH_DARKER)),
|
||||
)
|
||||
.with_pad_by_corner_radius(false)
|
||||
.with_corner_radius(4.0)
|
||||
.with_stroke_thickness(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_selected_brush(BRUSH_BRIGHT_BLUE)
|
||||
.with_normal_brush(BRUSH_LIGHT)
|
||||
.with_hover_brush(BRUSH_LIGHTER)
|
||||
.with_pressed_brush(BRUSH_LIGHTEST)
|
||||
.with_selected_brush(ctx.style.get_or_default(Style::BRUSH_BRIGHT_BLUE))
|
||||
.with_normal_brush(ctx.style.get_or_default(Style::BRUSH_LIGHT))
|
||||
.with_hover_brush(ctx.style.get_or_default(Style::BRUSH_LIGHTER))
|
||||
.with_pressed_brush(ctx.style.get_or_default(Style::BRUSH_LIGHTEST))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_content(
|
||||
@@ -194,7 +197,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/brush.png")),
|
||||
load_image!("../../../resources/brush.png"),
|
||||
"Draw with active brush.",
|
||||
Some(0),
|
||||
);
|
||||
@@ -202,7 +205,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/eraser.png")),
|
||||
load_image!("../../../resources/eraser.png"),
|
||||
"Erase with active brush.",
|
||||
Some(1),
|
||||
);
|
||||
@@ -210,7 +213,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/fill.png")),
|
||||
load_image!("../../../resources/fill.png"),
|
||||
"Flood fill with random tiles from current brush.",
|
||||
Some(2),
|
||||
);
|
||||
@@ -218,7 +221,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/pipette.png")),
|
||||
load_image!("../../../resources/pipette.png"),
|
||||
"Pick tiles for drawing from the tile map.",
|
||||
Some(3),
|
||||
);
|
||||
@@ -226,7 +229,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/rect_fill.png")),
|
||||
load_image!("../../../resources/rect_fill.png"),
|
||||
"Fill the rectangle using the current brush.",
|
||||
Some(4),
|
||||
);
|
||||
@@ -234,7 +237,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/nine_slice.png")),
|
||||
load_image!("../../../resources/nine_slice.png"),
|
||||
"Draw rectangles with fixed corners, but stretchable sides.",
|
||||
Some(5),
|
||||
);
|
||||
@@ -242,7 +245,7 @@ impl TileMapPanel {
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
load_image(include_bytes!("../../../resources/line.png")),
|
||||
load_image!("../../../resources/line.png"),
|
||||
"Draw a line using random tiles from the given brush.",
|
||||
Some(6),
|
||||
);
|
||||
|
||||
@@ -93,6 +93,6 @@ impl AssetPreviewGenerator for TileSetPreview {
|
||||
_resource: &UntypedResource,
|
||||
_resource_manager: &ResourceManager,
|
||||
) -> Option<UntypedResource> {
|
||||
load_image(include_bytes!("../../../resources/tile_set.png"))
|
||||
load_image!("../../../resources/tile_set.png")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::inspector::EditorEnvironment;
|
||||
use crate::{
|
||||
asset::item::AssetItem,
|
||||
command::{make_command, Command, CommandGroup},
|
||||
@@ -55,7 +56,6 @@ use crate::{
|
||||
resource::texture::Texture,
|
||||
scene::tilemap::tileset::{TileDefinition, TileSet, TileSetResource},
|
||||
},
|
||||
inspector::EditorEnvironment,
|
||||
message::MessageSender,
|
||||
plugins::tilemap::{
|
||||
commands::{AddTileCommand, RemoveTileCommand},
|
||||
@@ -554,7 +554,7 @@ impl TileSetTileViewBuilder {
|
||||
.widget_builder
|
||||
.with_allow_drag(true)
|
||||
.with_child(decorator)
|
||||
.build(),
|
||||
.build(ctx),
|
||||
definition_handle: tile_handle,
|
||||
image,
|
||||
}))
|
||||
|
||||
@@ -217,9 +217,9 @@ impl PreviewPanel {
|
||||
.with_height(18.0)
|
||||
.with_margin(Thickness::uniform(2.0)),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
.with_opt_texture(load_image!(
|
||||
"../resources/fit.png"
|
||||
)))
|
||||
))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
+10
-9
@@ -18,12 +18,17 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::plugins::absm::{
|
||||
command::fetch_machine,
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
};
|
||||
use crate::plugins::animation::{
|
||||
self, command::fetch_animations_container, selection::AnimationSelection,
|
||||
};
|
||||
use crate::plugins::inspector::{
|
||||
editors::handle::HandlePropertyEditorMessage, handlers::node::SceneNodePropertyChangedHandler,
|
||||
};
|
||||
use crate::{
|
||||
absm::{
|
||||
command::fetch_machine,
|
||||
selection::{AbsmSelection, SelectedEntity},
|
||||
},
|
||||
animation::{self, command::fetch_animations_container, selection::AnimationSelection},
|
||||
asset::item::AssetItem,
|
||||
audio::AudioBusSelection,
|
||||
camera::{CameraController, PickingOptions},
|
||||
@@ -77,10 +82,6 @@ use crate::{
|
||||
},
|
||||
},
|
||||
highlight::HighlightRenderPass,
|
||||
inspector::{
|
||||
editors::handle::HandlePropertyEditorMessage,
|
||||
handlers::node::SceneNodePropertyChangedHandler,
|
||||
},
|
||||
interaction::navmesh::selection::NavmeshSelection,
|
||||
message::MessageSender,
|
||||
scene::{
|
||||
|
||||
+162
-45
@@ -18,7 +18,6 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::graph::BaseSceneGraph;
|
||||
use crate::fyrox::{
|
||||
core::{
|
||||
algebra::Vector2, make_pretty_type_name, parking_lot::Mutex, pool::Handle,
|
||||
@@ -26,14 +25,15 @@ use crate::fyrox::{
|
||||
visitor::prelude::*,
|
||||
},
|
||||
fxhash::FxHashSet,
|
||||
graph::BaseSceneGraph,
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
define_constructor, define_widget_deref,
|
||||
draw::DrawingContext,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
message::{MessageDirection, OsEvent, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
message::{KeyCode, MessageDirection, OsEvent, UiMessage},
|
||||
scroll_viewer::{ScrollViewerBuilder, ScrollViewerMessage},
|
||||
searchbar::{SearchBarBuilder, SearchBarMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
@@ -43,6 +43,8 @@ use crate::fyrox::{
|
||||
BuildContext, Control, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -52,10 +54,12 @@ use std::{
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum PropertySelectorMessage {
|
||||
Selection(Vec<PropertyDescriptorData>),
|
||||
ChooseFocus,
|
||||
}
|
||||
|
||||
impl PropertySelectorMessage {
|
||||
define_constructor!(PropertySelectorMessage:Selection => fn selection(Vec<PropertyDescriptorData>), layout: false);
|
||||
define_constructor!(PropertySelectorMessage:ChooseFocus => fn choose_focus(), layout: false);
|
||||
}
|
||||
|
||||
pub struct PropertyDescriptor {
|
||||
@@ -296,15 +300,61 @@ pub struct PropertySelector {
|
||||
widget: Widget,
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
selected_property_path: Vec<PropertyDescriptorData>,
|
||||
selected_property_paths: Vec<PropertyDescriptorData>,
|
||||
tree_root: Handle<UiNode>,
|
||||
search_bar: Handle<UiNode>,
|
||||
scroll_viewer: Handle<UiNode>,
|
||||
}
|
||||
|
||||
define_widget_deref!(PropertySelector);
|
||||
|
||||
uuid_provider!(PropertySelector = "8e58e123-48a1-4e18-9e90-fd35a1669bdc");
|
||||
|
||||
impl PropertySelector {
|
||||
fn find_selected_tree_items(&self, ui: &UserInterface) -> Vec<Handle<UiNode>> {
|
||||
let mut stack = vec![self.tree_root];
|
||||
let mut selected_trees = Vec::new();
|
||||
|
||||
while let Some(node_handle) = stack.pop() {
|
||||
let node = ui.node(node_handle);
|
||||
|
||||
if let Some(tree) = node.query_component::<Tree>() {
|
||||
if self.selected_property_paths.iter().any(|path| {
|
||||
path.path
|
||||
== tree
|
||||
.user_data_cloned::<PropertyDescriptorData>()
|
||||
.unwrap()
|
||||
.path
|
||||
}) {
|
||||
selected_trees.push(node_handle);
|
||||
}
|
||||
}
|
||||
|
||||
stack.extend_from_slice(node.children());
|
||||
}
|
||||
|
||||
selected_trees
|
||||
}
|
||||
|
||||
fn sync_selection(&self, ui: &UserInterface) {
|
||||
let selected_trees = self.find_selected_tree_items(ui);
|
||||
|
||||
if let Some(first) = selected_trees.first() {
|
||||
ui.send_message(ScrollViewerMessage::bring_into_view(
|
||||
self.scroll_viewer,
|
||||
MessageDirection::ToWidget,
|
||||
*first,
|
||||
))
|
||||
}
|
||||
|
||||
ui.send_message(TreeRootMessage::select(
|
||||
self.tree_root,
|
||||
MessageDirection::ToWidget,
|
||||
selected_trees,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
impl Control for PropertySelector {
|
||||
fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
|
||||
self.widget.handle_routed_message(ui, message);
|
||||
@@ -327,13 +377,25 @@ impl Control for PropertySelector {
|
||||
.collect(),
|
||||
));
|
||||
}
|
||||
} else if let Some(PropertySelectorMessage::Selection(selection)) = message.data() {
|
||||
} else if let Some(msg) = message.data::<PropertySelectorMessage>() {
|
||||
if message.destination() == self.handle
|
||||
&& message.direction() == MessageDirection::ToWidget
|
||||
&& &self.selected_property_path != selection
|
||||
{
|
||||
self.selected_property_path.clone_from(selection);
|
||||
ui.send_message(message.reverse());
|
||||
match msg {
|
||||
PropertySelectorMessage::Selection(selection) => {
|
||||
if &self.selected_property_paths != selection {
|
||||
self.selected_property_paths.clone_from(selection);
|
||||
ui.send_message(message.reverse());
|
||||
}
|
||||
}
|
||||
PropertySelectorMessage::ChooseFocus => {
|
||||
ui.send_message(WidgetMessage::focus(
|
||||
self.search_bar,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.sync_selection(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(SearchBarMessage::Text(filter_text)) = message.data() {
|
||||
if message.destination() == self.search_bar
|
||||
@@ -349,6 +411,7 @@ pub struct PropertySelectorBuilder {
|
||||
widget_builder: WidgetBuilder,
|
||||
property_descriptors: Vec<PropertyDescriptor>,
|
||||
allowed_types: Option<FxHashSet<TypeId>>,
|
||||
selected_property_paths: Vec<PropertyDescriptorData>,
|
||||
}
|
||||
|
||||
impl PropertySelectorBuilder {
|
||||
@@ -357,6 +420,7 @@ impl PropertySelectorBuilder {
|
||||
widget_builder,
|
||||
property_descriptors: Default::default(),
|
||||
allowed_types: Default::default(),
|
||||
selected_property_paths: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,9 +434,29 @@ impl PropertySelectorBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_selected_property_paths(mut self, paths: Vec<PropertyDescriptorData>) -> Self {
|
||||
self.selected_property_paths = paths;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
let tree_root;
|
||||
let search_bar;
|
||||
|
||||
let scroll_viewer =
|
||||
ScrollViewerBuilder::new(WidgetBuilder::new().with_margin(Thickness::uniform(1.0)))
|
||||
.with_content({
|
||||
tree_root = TreeRootBuilder::new(WidgetBuilder::new().with_tab_index(Some(1)))
|
||||
.with_items(make_views_for_property_descriptor_collection(
|
||||
ctx,
|
||||
&self.property_descriptors,
|
||||
self.allowed_types.as_ref(),
|
||||
))
|
||||
.build(ctx);
|
||||
tree_root
|
||||
})
|
||||
.build(ctx);
|
||||
|
||||
let content = GridBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_child({
|
||||
@@ -380,7 +464,8 @@ impl PropertySelectorBuilder {
|
||||
WidgetBuilder::new()
|
||||
.on_row(0)
|
||||
.on_column(0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_tab_index(Some(0)),
|
||||
)
|
||||
.build(ctx);
|
||||
search_bar
|
||||
@@ -388,25 +473,10 @@ impl PropertySelectorBuilder {
|
||||
.with_child(
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(fyrox::gui::BRUSH_DARK)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARK))
|
||||
.on_row(1)
|
||||
.on_column(0)
|
||||
.with_child(
|
||||
ScrollViewerBuilder::new(
|
||||
WidgetBuilder::new().with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_content({
|
||||
tree_root = TreeRootBuilder::new(WidgetBuilder::new())
|
||||
.with_items(make_views_for_property_descriptor_collection(
|
||||
ctx,
|
||||
&self.property_descriptors,
|
||||
self.allowed_types.as_ref(),
|
||||
))
|
||||
.build(ctx);
|
||||
tree_root
|
||||
})
|
||||
.build(ctx),
|
||||
),
|
||||
.with_child(scroll_viewer),
|
||||
)
|
||||
.build(ctx),
|
||||
),
|
||||
@@ -417,10 +487,11 @@ impl PropertySelectorBuilder {
|
||||
.build(ctx);
|
||||
|
||||
let selector = PropertySelector {
|
||||
widget: self.widget_builder.with_child(content).build(),
|
||||
selected_property_path: Default::default(),
|
||||
widget: self.widget_builder.with_child(content).build(ctx),
|
||||
selected_property_paths: self.selected_property_paths,
|
||||
tree_root,
|
||||
search_bar,
|
||||
scroll_viewer,
|
||||
};
|
||||
|
||||
ctx.add_node(UiNode::new(selector))
|
||||
@@ -453,6 +524,24 @@ impl DerefMut for PropertySelectorWindow {
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertySelectorWindow {
|
||||
pub fn confirm(&self, ui: &UserInterface) {
|
||||
ui.send_message(PropertySelectorMessage::selection(
|
||||
self.handle,
|
||||
MessageDirection::FromWidget,
|
||||
ui.node(self.selector)
|
||||
.query_component::<PropertySelector>()
|
||||
.unwrap()
|
||||
.selected_property_paths
|
||||
.clone(),
|
||||
));
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
uuid_provider!(PropertySelectorWindow = "725e4a10-eca6-4345-9833-d54dae2f20f2");
|
||||
|
||||
impl Control for PropertySelectorWindow {
|
||||
@@ -481,20 +570,7 @@ impl Control for PropertySelectorWindow {
|
||||
|
||||
if let Some(ButtonMessage::Click) = message.data() {
|
||||
if message.destination() == self.ok {
|
||||
ui.send_message(PropertySelectorMessage::selection(
|
||||
self.handle,
|
||||
MessageDirection::FromWidget,
|
||||
ui.node(self.selector)
|
||||
.query_component::<PropertySelector>()
|
||||
.unwrap()
|
||||
.selected_property_path
|
||||
.clone(),
|
||||
));
|
||||
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.confirm(ui);
|
||||
} else if message.destination() == self.cancel {
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
@@ -517,6 +593,22 @@ impl Control for PropertySelectorWindow {
|
||||
enabled,
|
||||
));
|
||||
}
|
||||
} else if let Some(WindowMessage::Open { .. })
|
||||
| Some(WindowMessage::OpenAt { .. })
|
||||
| Some(WindowMessage::OpenModal { .. })
|
||||
| Some(WindowMessage::OpenAndAlign { .. }) = message.data()
|
||||
{
|
||||
ui.send_message(PropertySelectorMessage::choose_focus(
|
||||
self.selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
} else if let Some(WidgetMessage::KeyDown(KeyCode::Enter | KeyCode::NumpadEnter)) =
|
||||
message.data()
|
||||
{
|
||||
if !message.handled() {
|
||||
self.confirm(ui);
|
||||
message.set_handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,6 +630,7 @@ pub struct PropertySelectorWindowBuilder {
|
||||
window_builder: WindowBuilder,
|
||||
property_descriptors: Vec<PropertyDescriptor>,
|
||||
allowed_types: Option<FxHashSet<TypeId>>,
|
||||
selected_property_paths: Vec<PropertyDescriptorData>,
|
||||
}
|
||||
|
||||
impl PropertySelectorWindowBuilder {
|
||||
@@ -546,6 +639,7 @@ impl PropertySelectorWindowBuilder {
|
||||
window_builder,
|
||||
property_descriptors: Default::default(),
|
||||
allowed_types: None,
|
||||
selected_property_paths: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,6 +653,11 @@ impl PropertySelectorWindowBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_selected_property_paths(mut self, paths: Vec<PropertyDescriptorData>) -> Self {
|
||||
self.selected_property_paths = paths;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
|
||||
let selector;
|
||||
let ok;
|
||||
@@ -572,6 +671,7 @@ impl PropertySelectorWindowBuilder {
|
||||
.on_column(0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_selected_property_paths(self.selected_property_paths)
|
||||
.with_allowed_types(self.allowed_types.clone())
|
||||
.with_property_descriptors(self.property_descriptors)
|
||||
.build(ctx);
|
||||
@@ -589,7 +689,8 @@ impl PropertySelectorWindowBuilder {
|
||||
WidgetBuilder::new()
|
||||
.with_enabled(false)
|
||||
.with_width(100.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_tab_index(Some(2)),
|
||||
)
|
||||
.with_text("OK")
|
||||
.build(ctx);
|
||||
@@ -599,7 +700,8 @@ impl PropertySelectorWindowBuilder {
|
||||
cancel = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(100.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_tab_index(Some(3)),
|
||||
)
|
||||
.with_text("Cancel")
|
||||
.build(ctx);
|
||||
@@ -611,7 +713,7 @@ impl PropertySelectorWindowBuilder {
|
||||
),
|
||||
)
|
||||
.add_row(Row::stretch())
|
||||
.add_row(Row::strict(22.0))
|
||||
.add_row(Row::strict(26.0))
|
||||
.add_column(Column::stretch())
|
||||
.build(ctx);
|
||||
|
||||
@@ -626,3 +728,18 @@ impl PropertySelectorWindowBuilder {
|
||||
ctx.add_node(UiNode::new(window))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::scene::property::{PropertySelectorBuilder, PropertySelectorWindowBuilder};
|
||||
use fyrox::gui::window::WindowBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| PropertySelectorBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
test_widget_deletion(|ctx| {
|
||||
PropertySelectorWindowBuilder::new(WindowBuilder::new(WidgetBuilder::new())).build(ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,32 +18,37 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::graph::BaseSceneGraph;
|
||||
use crate::fyrox::graph::{SceneGraph, SceneGraphNode};
|
||||
use crate::fyrox::{
|
||||
core::{
|
||||
algebra::Vector2, parking_lot::Mutex, pool::ErasedHandle, pool::Handle,
|
||||
reflect::prelude::*, type_traits::prelude::*, uuid_provider, visitor::prelude::*,
|
||||
},
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
define_constructor, define_widget_deref,
|
||||
draw::DrawingContext,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
message::{MessageDirection, OsEvent, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
scroll_viewer::ScrollViewerMessage,
|
||||
searchbar::{SearchBarBuilder, SearchBarMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
tree::{Tree, TreeBuilder, TreeRootBuilder, TreeRootMessage},
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
window::{Window, WindowBuilder, WindowMessage},
|
||||
BuildContext, Control, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::{
|
||||
algebra::Vector2, parking_lot::Mutex, pool::ErasedHandle, pool::Handle,
|
||||
reflect::prelude::*, type_traits::prelude::*, uuid_provider, visitor::prelude::*,
|
||||
},
|
||||
graph::{BaseSceneGraph, SceneGraph, SceneGraphNode},
|
||||
gui::{
|
||||
border::BorderBuilder,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
define_constructor, define_widget_deref,
|
||||
draw::DrawingContext,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
message::{MessageDirection, OsEvent, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
scroll_viewer::ScrollViewerMessage,
|
||||
searchbar::{SearchBarBuilder, SearchBarMessage},
|
||||
stack_panel::StackPanelBuilder,
|
||||
text::TextBuilder,
|
||||
tree::{Tree, TreeBuilder, TreeRootBuilder, TreeRootMessage},
|
||||
widget::{Widget, WidgetBuilder, WidgetMessage},
|
||||
window::{Window, WindowBuilder, WindowMessage},
|
||||
BuildContext, Control, HorizontalAlignment, Orientation, Thickness, UiNode,
|
||||
UserInterface,
|
||||
},
|
||||
},
|
||||
utils::make_node_name,
|
||||
};
|
||||
use crate::utils::make_node_name;
|
||||
use fyrox::gui::message::KeyCode;
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::mpsc::Sender,
|
||||
@@ -143,11 +148,13 @@ pub enum NodeSelectorMessage {
|
||||
#[allow(dead_code)] // Might be used in the future.
|
||||
Hierarchy(HierarchyNode),
|
||||
Selection(Vec<ErasedHandle>),
|
||||
ChooseFocus,
|
||||
}
|
||||
|
||||
impl NodeSelectorMessage {
|
||||
define_constructor!(NodeSelectorMessage:Hierarchy => fn hierarchy(HierarchyNode), layout: false);
|
||||
define_constructor!(NodeSelectorMessage:Selection => fn selection(Vec<ErasedHandle>), layout: false);
|
||||
define_constructor!(NodeSelectorMessage:ChooseFocus => fn choose_focus(), layout: false);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -219,6 +226,13 @@ impl Control for NodeSelector {
|
||||
ui.send_message(message.reverse());
|
||||
}
|
||||
}
|
||||
NodeSelectorMessage::ChooseFocus => {
|
||||
ui.send_message(WidgetMessage::focus(
|
||||
self.search_bar,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.sync_selection(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(SearchBarMessage::Text(filter_text)) = message.data() {
|
||||
@@ -329,7 +343,7 @@ impl NodeSelectorBuilder {
|
||||
.map(|h| vec![h.make_view(ctx)])
|
||||
.unwrap_or_default();
|
||||
|
||||
let tree_root = TreeRootBuilder::new(WidgetBuilder::new())
|
||||
let tree_root = TreeRootBuilder::new(WidgetBuilder::new().with_tab_index(Some(1)))
|
||||
.with_items(items)
|
||||
.build(ctx);
|
||||
let search_bar;
|
||||
@@ -337,13 +351,15 @@ impl NodeSelectorBuilder {
|
||||
let content = GridBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_child({
|
||||
search_bar = SearchBarBuilder::new(WidgetBuilder::new()).build(ctx);
|
||||
search_bar =
|
||||
SearchBarBuilder::new(WidgetBuilder::new().with_tab_index(Some(0)))
|
||||
.build(ctx);
|
||||
search_bar
|
||||
})
|
||||
.with_child(
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_background(fyrox::gui::BRUSH_DARK)
|
||||
.with_background(ctx.style.get_or_default(Style::BRUSH_DARK))
|
||||
.on_row(1)
|
||||
.on_column(0)
|
||||
.with_child({
|
||||
@@ -364,7 +380,7 @@ impl NodeSelectorBuilder {
|
||||
.build(ctx);
|
||||
|
||||
let selector = NodeSelector {
|
||||
widget: self.widget_builder.with_child(content).build(),
|
||||
widget: self.widget_builder.with_child(content).build(ctx),
|
||||
tree_root,
|
||||
search_bar,
|
||||
selected: Default::default(),
|
||||
@@ -398,6 +414,25 @@ impl DerefMut for NodeSelectorWindow {
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeSelectorWindow {
|
||||
fn confirm(&self, ui: &UserInterface) {
|
||||
ui.send_message(NodeSelectorMessage::selection(
|
||||
self.handle,
|
||||
MessageDirection::FromWidget,
|
||||
ui.node(self.selector)
|
||||
.query_component::<NodeSelector>()
|
||||
.unwrap()
|
||||
.selected
|
||||
.clone(),
|
||||
));
|
||||
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
uuid_provider!(NodeSelectorWindow = "5bb00f15-d6ec-4f0e-af7e-9472b0e290b4");
|
||||
|
||||
impl Control for NodeSelectorWindow {
|
||||
@@ -426,20 +461,7 @@ impl Control for NodeSelectorWindow {
|
||||
|
||||
if let Some(ButtonMessage::Click) = message.data() {
|
||||
if message.destination() == self.ok {
|
||||
ui.send_message(NodeSelectorMessage::selection(
|
||||
self.handle,
|
||||
MessageDirection::FromWidget,
|
||||
ui.node(self.selector)
|
||||
.query_component::<NodeSelector>()
|
||||
.unwrap()
|
||||
.selected
|
||||
.clone(),
|
||||
));
|
||||
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
self.confirm(ui);
|
||||
} else if message.destination() == self.cancel {
|
||||
ui.send_message(WindowMessage::close(
|
||||
self.handle,
|
||||
@@ -466,6 +488,22 @@ impl Control for NodeSelectorWindow {
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if let Some(WindowMessage::Open { .. })
|
||||
| Some(WindowMessage::OpenAt { .. })
|
||||
| Some(WindowMessage::OpenModal { .. })
|
||||
| Some(WindowMessage::OpenAndAlign { .. }) = message.data()
|
||||
{
|
||||
ui.send_message(NodeSelectorMessage::choose_focus(
|
||||
self.selector,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
} else if let Some(WidgetMessage::KeyDown(KeyCode::Enter | KeyCode::NumpadEnter)) =
|
||||
message.data()
|
||||
{
|
||||
if !message.handled() {
|
||||
self.confirm(ui);
|
||||
message.set_handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,7 +563,8 @@ impl NodeSelectorWindowBuilder {
|
||||
WidgetBuilder::new()
|
||||
.with_enabled(false)
|
||||
.with_width(100.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_tab_index(Some(2)),
|
||||
)
|
||||
.with_text("OK")
|
||||
.build(ctx);
|
||||
@@ -535,7 +574,8 @@ impl NodeSelectorWindowBuilder {
|
||||
cancel = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(100.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_tab_index(Some(3)),
|
||||
)
|
||||
.with_text("Cancel")
|
||||
.build(ctx);
|
||||
@@ -565,3 +605,18 @@ impl NodeSelectorWindowBuilder {
|
||||
ctx.add_node(UiNode::new(window))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::scene::selector::{NodeSelectorBuilder, NodeSelectorWindowBuilder};
|
||||
use fyrox::gui::window::WindowBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| NodeSelectorBuilder::new(WidgetBuilder::new()).build(ctx));
|
||||
test_widget_deletion(|ctx| {
|
||||
NodeSelectorWindowBuilder::new(WindowBuilder::new(WidgetBuilder::new())).build(ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,41 +18,41 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::fyrox::{
|
||||
core::{color::Color, pool::Handle},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
inspector::{
|
||||
editors::{
|
||||
enumeration::EnumPropertyEditorDefinition, PropertyEditorDefinitionContainer,
|
||||
},
|
||||
InspectorBuilder, InspectorContext, InspectorMessage, PropertyFilter,
|
||||
},
|
||||
message::UiMessage,
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
resource::texture::TextureResource,
|
||||
scene::{
|
||||
dim2,
|
||||
graph::{
|
||||
physics::{IntegrationParameters, PhysicsWorld},
|
||||
Graph, NodePool,
|
||||
},
|
||||
SceneRenderingOptions,
|
||||
},
|
||||
utils::lightmap::Lightmap,
|
||||
};
|
||||
use crate::plugins::inspector::editors::make_property_editors_container;
|
||||
use crate::{
|
||||
inspector::editors::make_property_editors_container, message::MessageSender, GameScene,
|
||||
Message, MessageDirection, MSG_SYNC_FLAG,
|
||||
command::make_command,
|
||||
fyrox::{
|
||||
core::{color::Color, pool::Handle, reflect::Reflect},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
inspector::{
|
||||
editors::{
|
||||
enumeration::EnumPropertyEditorDefinition, PropertyEditorDefinitionContainer,
|
||||
},
|
||||
InspectorBuilder, InspectorContext, InspectorMessage, PropertyFilter,
|
||||
},
|
||||
message::UiMessage,
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, UiNode, UserInterface,
|
||||
},
|
||||
resource::texture::TextureResource,
|
||||
scene::{
|
||||
dim2,
|
||||
graph::{
|
||||
physics::{IntegrationParameters, PhysicsWorld},
|
||||
Graph, NodePool,
|
||||
},
|
||||
SceneRenderingOptions,
|
||||
},
|
||||
utils::lightmap::Lightmap,
|
||||
},
|
||||
message::MessageSender,
|
||||
scene::commands::GameSceneContext,
|
||||
GameScene, Message, MessageDirection, MSG_SYNC_FLAG,
|
||||
};
|
||||
|
||||
use crate::command::make_command;
|
||||
use crate::fyrox::core::reflect::Reflect;
|
||||
use crate::scene::commands::GameSceneContext;
|
||||
use fyrox::{graph::SceneGraph, gui::window::Window};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct SceneSettingsWindow {
|
||||
@@ -104,7 +104,15 @@ impl SceneSettingsWindow {
|
||||
}
|
||||
|
||||
pub fn sync_to_model(&self, game_scene: &GameScene, engine: &mut Engine) {
|
||||
let ui = &mut engine.user_interfaces.first_mut();
|
||||
let ui = engine.user_interfaces.first_mut();
|
||||
if !ui
|
||||
.try_get_of_type::<Window>(self.window)
|
||||
.unwrap()
|
||||
.is_globally_visible()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let scene = &engine.scenes[game_scene.scene];
|
||||
|
||||
let context = InspectorContext::from_object(
|
||||
|
||||
@@ -48,7 +48,7 @@ use crate::{
|
||||
widget::{WidgetBuilder, WidgetMessage},
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
BuildContext, HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_BRIGHT_BLUE, BRUSH_DARKEST,
|
||||
VerticalAlignment,
|
||||
},
|
||||
renderer::framework::PolygonFillMode,
|
||||
resource::texture::TextureResource,
|
||||
@@ -68,6 +68,8 @@ use crate::{
|
||||
DropdownListBuilder, GameScene, Message, Mode, SaveSceneConfirmationDialogAction,
|
||||
SceneContainer, Settings,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
ops::Deref,
|
||||
sync::mpsc::{self, Receiver},
|
||||
@@ -111,7 +113,7 @@ impl GridSnappingMenu {
|
||||
ctx,
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!("../../resources/grid_snapping.png")),
|
||||
load_image!("../../resources/grid_snapping.png"),
|
||||
"Snapping Options",
|
||||
None,
|
||||
);
|
||||
@@ -215,7 +217,7 @@ impl GridSnappingMenu {
|
||||
ui.send_message(DecoratorMessage::selected_brush(
|
||||
*button.decorator,
|
||||
MessageDirection::ToWidget,
|
||||
BRUSH_BRIGHT_BLUE,
|
||||
ui.style.get_or_default(Style::BRUSH_BRIGHT_BLUE),
|
||||
));
|
||||
|
||||
ui.send_message(DecoratorMessage::select(
|
||||
@@ -420,9 +422,7 @@ impl SceneViewer {
|
||||
0, 200, 0,
|
||||
))),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/play.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../resources/play.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -445,9 +445,7 @@ impl SceneViewer {
|
||||
200, 0, 0,
|
||||
))),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../resources/stop.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../resources/stop.png"))
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
@@ -468,7 +466,7 @@ impl SceneViewer {
|
||||
let no_scene_reminder = TextBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_hit_test_visibility(false)
|
||||
.with_foreground(BRUSH_DARKEST),
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_DARKEST)),
|
||||
)
|
||||
.with_text("No scene loaded. Create a new scene (File -> New Scene) or load existing (File -> Load Scene)")
|
||||
.with_vertical_text_alignment(VerticalAlignment::Center)
|
||||
@@ -718,16 +716,6 @@ impl SceneViewer {
|
||||
} else if message.destination() == self.stop {
|
||||
self.sender.send(Message::SwitchToEditMode);
|
||||
}
|
||||
} else if let Some(WidgetMessage::MouseDown { button, .. }) =
|
||||
message.data::<WidgetMessage>()
|
||||
{
|
||||
for &mode_button in self.interaction_modes.values() {
|
||||
if ui.is_node_child_of(message.destination(), mode_button)
|
||||
&& *button == MouseButton::Right
|
||||
{
|
||||
self.sender.send(Message::OpenSettings);
|
||||
}
|
||||
}
|
||||
} else if let Some(DropdownListMessage::SelectionChanged(Some(index))) = message.data() {
|
||||
if message.direction == MessageDirection::FromWidget {
|
||||
if message.destination() == self.camera_projection {
|
||||
|
||||
+6
-237
@@ -18,52 +18,16 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::settings::build::{BuildCommand, BuildProfile, EnvironmentVariable};
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::{log::Log, pool::Handle, reflect::prelude::*},
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
inspector::{
|
||||
editors::{
|
||||
enumeration::EnumPropertyEditorDefinition,
|
||||
inspectable::InspectablePropertyEditorDefinition,
|
||||
key::HotKeyPropertyEditorDefinition, PropertyEditorDefinitionContainer,
|
||||
},
|
||||
InspectorBuilder, InspectorContext, InspectorMessage, PropertyAction,
|
||||
PropertyChanged,
|
||||
},
|
||||
message::{MessageDirection, UiMessage},
|
||||
scroll_viewer::ScrollViewerBuilder,
|
||||
stack_panel::StackPanelBuilder,
|
||||
widget::WidgetBuilder,
|
||||
window::{WindowBuilder, WindowMessage, WindowTitle},
|
||||
HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface,
|
||||
},
|
||||
renderer::{CsmSettings, QualitySettings, ShadowMapPrecision},
|
||||
},
|
||||
inspector::editors::make_property_editors_container,
|
||||
message::MessageSender,
|
||||
fyrox::core::{log::Log, reflect::prelude::*},
|
||||
settings::{
|
||||
build::BuildSettings,
|
||||
camera::CameraSettings,
|
||||
debugging::DebuggingSettings,
|
||||
general::{GeneralSettings, ScriptEditor},
|
||||
graphics::GraphicsSettings,
|
||||
keys::{KeyBindings, TerrainKeyBindings},
|
||||
model::ModelSettings,
|
||||
move_mode::MoveInteractionModeSettings,
|
||||
navmesh::NavmeshSettings,
|
||||
recent::RecentFiles,
|
||||
rotate_mode::RotateInteractionModeSettings,
|
||||
scene::SceneSettings,
|
||||
selection::SelectionSettings,
|
||||
windows::WindowsSettings,
|
||||
build::BuildSettings, camera::CameraSettings, debugging::DebuggingSettings,
|
||||
general::GeneralSettings, graphics::GraphicsSettings, keys::KeyBindings,
|
||||
model::ModelSettings, move_mode::MoveInteractionModeSettings, navmesh::NavmeshSettings,
|
||||
recent::RecentFiles, rotate_mode::RotateInteractionModeSettings, scene::SceneSettings,
|
||||
selection::SelectionSettings, windows::WindowsSettings,
|
||||
},
|
||||
Engine, MSG_SYNC_FLAG,
|
||||
};
|
||||
use fyrox::gui::inspector::editors::collection::VecCollectionPropertyEditorDefinition;
|
||||
use ron::ser::PrettyConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::mpsc::Sender;
|
||||
@@ -73,7 +37,6 @@ use std::{
|
||||
io::Write,
|
||||
ops::{Deref, DerefMut},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub mod build;
|
||||
@@ -91,13 +54,6 @@ pub mod scene;
|
||||
pub mod selection;
|
||||
pub mod windows;
|
||||
|
||||
pub struct SettingsWindow {
|
||||
pub window: Handle<UiNode>,
|
||||
ok: Handle<UiNode>,
|
||||
default: Handle<UiNode>,
|
||||
inspector: Handle<UiNode>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Clone, Default, Debug, Reflect)]
|
||||
pub struct SettingsData {
|
||||
pub selection: SelectionSettings,
|
||||
@@ -220,191 +176,4 @@ impl SettingsData {
|
||||
Log::info("Settings were successfully saved!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_property_editors_container(
|
||||
sender: MessageSender,
|
||||
) -> Arc<PropertyEditorDefinitionContainer> {
|
||||
let container = make_property_editors_container(sender);
|
||||
|
||||
container.insert(InspectablePropertyEditorDefinition::<GeneralSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<GraphicsSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<SelectionSettings>::new());
|
||||
container.insert(EnumPropertyEditorDefinition::<ShadowMapPrecision>::new());
|
||||
container.insert(EnumPropertyEditorDefinition::<ScriptEditor>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<DebuggingSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<CsmSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<QualitySettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<CameraSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<
|
||||
MoveInteractionModeSettings,
|
||||
>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<
|
||||
RotateInteractionModeSettings,
|
||||
>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<ModelSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<NavmeshSettings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<KeyBindings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<TerrainKeyBindings>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildSettings>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<EnvironmentVariable>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<EnvironmentVariable>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<BuildProfile>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildProfile>::new());
|
||||
container.insert(VecCollectionPropertyEditorDefinition::<BuildCommand>::new());
|
||||
container.insert(InspectablePropertyEditorDefinition::<BuildCommand>::new());
|
||||
container.insert(HotKeyPropertyEditorDefinition);
|
||||
|
||||
Arc::new(container)
|
||||
}
|
||||
|
||||
fn handle_property_changed(&mut self, property_changed: &PropertyChanged) {
|
||||
PropertyAction::from_field_kind(&property_changed.value).apply(
|
||||
&property_changed.path(),
|
||||
self,
|
||||
&mut Log::verify,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl SettingsWindow {
|
||||
pub fn new(engine: &mut Engine) -> Self {
|
||||
let ok;
|
||||
let default;
|
||||
|
||||
let ctx = &mut engine.user_interfaces.first_mut().build_ctx();
|
||||
|
||||
let inspector = InspectorBuilder::new(WidgetBuilder::new()).build(ctx);
|
||||
|
||||
let window = WindowBuilder::new(WidgetBuilder::new().with_width(500.0).with_height(600.0))
|
||||
.open(false)
|
||||
.with_title(WindowTitle::text("Settings"))
|
||||
.with_content(
|
||||
GridBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_child(
|
||||
ScrollViewerBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(2.0))
|
||||
.on_row(0),
|
||||
)
|
||||
.with_content(inspector)
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child(
|
||||
StackPanelBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.on_row(1)
|
||||
.with_horizontal_alignment(HorizontalAlignment::Right)
|
||||
.with_child({
|
||||
default = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(80.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_text("Default")
|
||||
.build(ctx);
|
||||
default
|
||||
})
|
||||
.with_child({
|
||||
ok = ButtonBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_width(80.0)
|
||||
.with_margin(Thickness::uniform(1.0)),
|
||||
)
|
||||
.with_text("OK")
|
||||
.build(ctx);
|
||||
ok
|
||||
}),
|
||||
)
|
||||
.with_orientation(Orientation::Horizontal)
|
||||
.build(ctx),
|
||||
),
|
||||
)
|
||||
.add_row(Row::stretch())
|
||||
.add_row(Row::strict(25.0))
|
||||
.add_column(Column::stretch())
|
||||
.build(ctx),
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
Self {
|
||||
window,
|
||||
ok,
|
||||
default,
|
||||
inspector,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&self, ui: &mut UserInterface, settings: &Settings, sender: &MessageSender) {
|
||||
ui.send_message(WindowMessage::open(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
|
||||
self.sync_to_model(ui, settings, sender);
|
||||
}
|
||||
|
||||
fn sync_to_model(&self, ui: &mut UserInterface, settings: &Settings, sender: &MessageSender) {
|
||||
let context = InspectorContext::from_object(
|
||||
&**settings,
|
||||
&mut ui.build_ctx(),
|
||||
SettingsData::make_property_editors_container(sender.clone()),
|
||||
None,
|
||||
MSG_SYNC_FLAG,
|
||||
0,
|
||||
true,
|
||||
Default::default(),
|
||||
150.0,
|
||||
);
|
||||
ui.send_message(InspectorMessage::context(
|
||||
self.inspector,
|
||||
MessageDirection::ToWidget,
|
||||
context,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn handle_message(
|
||||
&mut self,
|
||||
message: &UiMessage,
|
||||
engine: &mut Engine,
|
||||
settings: &mut Settings,
|
||||
sender: &MessageSender,
|
||||
) {
|
||||
if let Some(ButtonMessage::Click) = message.data::<ButtonMessage>() {
|
||||
if message.destination() == self.ok {
|
||||
engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
.send_message(WindowMessage::close(
|
||||
self.window,
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
} else if message.destination() == self.default {
|
||||
**settings = Default::default();
|
||||
|
||||
self.sync_to_model(engine.user_interfaces.first_mut(), settings, sender);
|
||||
}
|
||||
} else if let Some(InspectorMessage::PropertyChanged(property_changed)) = message.data() {
|
||||
if message.destination() == self.inspector {
|
||||
settings.handle_property_changed(property_changed);
|
||||
}
|
||||
}
|
||||
|
||||
let graphics_context = engine.graphics_context.as_initialized_mut();
|
||||
|
||||
if settings.graphics.quality != graphics_context.renderer.get_quality_settings() {
|
||||
if let Err(e) = graphics_context
|
||||
.renderer
|
||||
.set_quality_settings(&settings.graphics.quality)
|
||||
{
|
||||
Log::err(format!(
|
||||
"An error occurred at attempt to set new graphics settings: {e:?}"
|
||||
));
|
||||
} else {
|
||||
Log::info("New graphics quality settings were successfully set!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ use crate::{
|
||||
world::WorldViewerItemContextMenu,
|
||||
Engine, Message, MessageDirection,
|
||||
};
|
||||
use fyrox::gui::constructor::WidgetConstructorContainer;
|
||||
use fyrox::gui::menu::ContextMenuBuilder;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -77,14 +78,17 @@ fn resource_path_of_first_selected_node(
|
||||
}
|
||||
|
||||
impl WidgetContextMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
pub fn new(
|
||||
widget_constructors_container: &WidgetConstructorContainer,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let delete_selection;
|
||||
let copy_selection;
|
||||
let paste;
|
||||
let make_root;
|
||||
let open_asset;
|
||||
|
||||
let widgets_menu = UiMenu::new(UiMenu::default_entries(), "Create Child Widget", ctx);
|
||||
let widgets_menu = UiMenu::new(widget_constructors_container, "Create Child Widget", ctx);
|
||||
|
||||
let menu = ContextMenuBuilder::new(
|
||||
PopupBuilder::new(WidgetBuilder::new().with_visibility(false)).with_content(
|
||||
|
||||
@@ -53,12 +53,12 @@ use crate::fyrox::{
|
||||
resource::texture::{TextureKind, TextureResource, TextureResourceExtension},
|
||||
scene::SceneContainer,
|
||||
};
|
||||
use crate::plugins::absm::{command::fetch_machine, selection::SelectedEntity};
|
||||
use crate::plugins::animation::{self, command::fetch_animations_container};
|
||||
use crate::plugins::inspector::editors::handle::HandlePropertyEditorMessage;
|
||||
use crate::{
|
||||
absm::{command::fetch_machine, selection::SelectedEntity},
|
||||
animation::{self, command::fetch_animations_container},
|
||||
asset::item::AssetItem,
|
||||
command::{make_command, Command, CommandGroup, CommandStack},
|
||||
inspector::editors::handle::HandlePropertyEditorMessage,
|
||||
message::MessageSender,
|
||||
scene::{
|
||||
commands::ChangeSelectionCommand, controller::SceneController, selector::HierarchyNode,
|
||||
|
||||
@@ -123,41 +123,41 @@ impl<'a> WorldViewerDataProvider for UiSceneWorldViewerDataProvider<'a> {
|
||||
|
||||
// Containers
|
||||
if node.cast::<Canvas>().is_some() {
|
||||
load_image(include_bytes!("../../resources/canvas-icon.png"))
|
||||
load_image!("../../resources/canvas-icon.png")
|
||||
} else if node.cast::<Screen>().is_some() {
|
||||
load_image(include_bytes!("../../resources/screen-icon.png"))
|
||||
load_image!("../../resources/screen-icon.png")
|
||||
} else if node.cast::<Grid>().is_some() {
|
||||
load_image(include_bytes!("../../resources/grid-icon.png"))
|
||||
load_image!("../../resources/grid-icon.png")
|
||||
} else if node.cast::<StackPanel>().is_some() {
|
||||
load_image(include_bytes!("../../resources/stackPanel-icon.png"))
|
||||
load_image!("../../resources/stackPanel-icon.png")
|
||||
} else if node.cast::<Window>().is_some() {
|
||||
load_image(include_bytes!("../../resources/window-icon.png"))
|
||||
load_image!("../../resources/window-icon.png")
|
||||
} else if node.cast::<MessageBox>().is_some() {
|
||||
load_image(include_bytes!("../../resources/messageBox-icon.png"))
|
||||
load_image!("../../resources/messageBox-icon.png")
|
||||
} else if node.cast::<Menu>().is_some() {
|
||||
load_image(include_bytes!("../../resources/menu-icon.png"))
|
||||
load_image!("../../resources/menu-icon.png")
|
||||
} else if node.cast::<Popup>().is_some() {
|
||||
load_image(include_bytes!("../../resources/popup-icon.png"))
|
||||
load_image!("../../resources/popup-icon.png")
|
||||
}
|
||||
// Visual
|
||||
else if node.cast::<Text>().is_some() {
|
||||
load_image(include_bytes!("../../resources/text-icon.png"))
|
||||
load_image!("../../resources/text-icon.png")
|
||||
} else if node.cast::<Image>().is_some() {
|
||||
load_image(include_bytes!("../../resources/image-icon.png"))
|
||||
load_image!("../../resources/image-icon.png")
|
||||
} else if node.cast::<Border>().is_some() {
|
||||
load_image(include_bytes!("../../resources/border-icon.png"))
|
||||
load_image!("../../resources/border-icon.png")
|
||||
}
|
||||
// Controls
|
||||
else if node.cast::<Button>().is_some() {
|
||||
load_image(include_bytes!("../../resources/button-icon.png"))
|
||||
load_image!("../../resources/button-icon.png")
|
||||
} else if node.cast::<CheckBox>().is_some() {
|
||||
load_image(include_bytes!("../../resources/checkbox-icon.png"))
|
||||
load_image!("../../resources/checkbox-icon.png")
|
||||
} else if node.cast::<ListView>().is_some() {
|
||||
load_image(include_bytes!("../../resources/list-icon.png"))
|
||||
load_image!("../../resources/list-icon.png")
|
||||
} else if node.cast::<FileBrowser>().is_some() {
|
||||
load_image(include_bytes!("../../resources/fileBrowser-icon.png"))
|
||||
load_image!("../../resources/fileBrowser-icon.png")
|
||||
} else if node.cast::<Inspector>().is_some() {
|
||||
load_image(include_bytes!("../../resources/inspector-icon.png"))
|
||||
load_image!("../../resources/inspector-icon.png")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ use crate::fyrox::{
|
||||
use std::{fs::File, io::Read, path::Path};
|
||||
|
||||
pub mod doc;
|
||||
pub mod path_fixer;
|
||||
pub mod ragdoll;
|
||||
|
||||
/// True if `a` and `b` have the same length, and every element of `a` is equal to some element of `b`
|
||||
/// and every element of `b` is equal to some element of `a`.
|
||||
|
||||
@@ -42,6 +42,8 @@ use crate::fyrox::{
|
||||
},
|
||||
};
|
||||
use crate::{load_image, message::MessageSender, utils::make_node_name, Message};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use std::{
|
||||
fmt::{Debug, Formatter},
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -196,9 +198,7 @@ impl Control for SceneItem {
|
||||
.on_row(0)
|
||||
.on_column(2),
|
||||
)
|
||||
.with_opt_texture(load_image(include_bytes!(
|
||||
"../../../resources/warning.png"
|
||||
)))
|
||||
.with_opt_texture(load_image!("../../../resources/warning.png"))
|
||||
.build(&mut ui.build_ctx());
|
||||
|
||||
ui.send_message(WidgetMessage::link(
|
||||
@@ -325,7 +325,7 @@ impl SceneItemBuilder {
|
||||
WidgetBuilder::new()
|
||||
.with_foreground(
|
||||
self.text_brush
|
||||
.unwrap_or(Brush::Solid(fyrox::gui::COLOR_FOREGROUND)),
|
||||
.unwrap_or(ctx.style.get_or_default(Style::BRUSH_FOREGROUND)),
|
||||
)
|
||||
.with_margin(Thickness::left(1.0))
|
||||
.on_column(1)
|
||||
@@ -363,3 +363,18 @@ impl SceneItemBuilder {
|
||||
ctx.add_node(UiNode::new(item))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::world::graph::item::SceneItemBuilder;
|
||||
use fyrox::gui::tree::TreeBuilder;
|
||||
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_deletion() {
|
||||
test_widget_deletion(|ctx| {
|
||||
SceneItemBuilder::new(TreeBuilder::new(WidgetBuilder::new()))
|
||||
.build(ctx, Default::default())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ use crate::{
|
||||
world::WorldViewerItemContextMenu,
|
||||
Engine, Message, MessageDirection, PasteCommand,
|
||||
};
|
||||
use fyrox::engine::SerializationContext;
|
||||
use fyrox::gui::constructor::WidgetConstructorContainer;
|
||||
use fyrox::gui::menu::SortingPredicate;
|
||||
use std::{any::TypeId, path::PathBuf};
|
||||
|
||||
pub struct SceneNodeContextMenu {
|
||||
@@ -95,7 +98,11 @@ fn resource_path_of_first_selected_node(
|
||||
}
|
||||
|
||||
impl SceneNodeContextMenu {
|
||||
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||
pub fn new(
|
||||
serialization_context: &SerializationContext,
|
||||
widget_constructors_container: &WidgetConstructorContainer,
|
||||
ctx: &mut BuildContext,
|
||||
) -> Self {
|
||||
let delete_selection;
|
||||
let copy_selection;
|
||||
let save_as_prefab;
|
||||
@@ -103,12 +110,16 @@ impl SceneNodeContextMenu {
|
||||
let make_root;
|
||||
let open_asset;
|
||||
let reset_inheritable_properties;
|
||||
let create_parent;
|
||||
let create_child;
|
||||
let replace_with;
|
||||
|
||||
let (create_child_entity_menu, create_child_entity_menu_root_items) =
|
||||
CreateEntityMenu::new(ctx);
|
||||
let (create_parent_entity_menu, create_parent_entity_menu_root_items) =
|
||||
CreateEntityMenu::new(ctx);
|
||||
let (replace_with_menu, replace_with_menu_root_items) = CreateEntityMenu::new(ctx);
|
||||
let create_child_entity_menu =
|
||||
CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
|
||||
let create_parent_entity_menu =
|
||||
CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
|
||||
let replace_with_menu =
|
||||
CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
|
||||
|
||||
let menu = ContextMenuBuilder::new(
|
||||
PopupBuilder::new(WidgetBuilder::new().with_visibility(false)).with_content(
|
||||
@@ -132,34 +143,37 @@ impl SceneNodeContextMenu {
|
||||
save_as_prefab = create_menu_item("Save As Prefab...", vec![], ctx);
|
||||
save_as_prefab
|
||||
})
|
||||
.with_child(
|
||||
MenuItemBuilder::new(
|
||||
.with_child({
|
||||
create_parent = MenuItemBuilder::new(
|
||||
WidgetBuilder::new().with_min_size(Vector2::new(120.0, 22.0)),
|
||||
)
|
||||
.with_content(MenuItemContent::text("Create Parent"))
|
||||
.with_items(create_parent_entity_menu_root_items)
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child(
|
||||
MenuItemBuilder::new(
|
||||
.with_items(create_parent_entity_menu.root_items.clone())
|
||||
.build(ctx);
|
||||
create_parent
|
||||
})
|
||||
.with_child({
|
||||
create_child = MenuItemBuilder::new(
|
||||
WidgetBuilder::new().with_min_size(Vector2::new(120.0, 22.0)),
|
||||
)
|
||||
.with_content(MenuItemContent::text("Create Child"))
|
||||
.with_items(create_child_entity_menu_root_items)
|
||||
.build(ctx),
|
||||
)
|
||||
.with_items(create_child_entity_menu.root_items.clone())
|
||||
.build(ctx);
|
||||
create_child
|
||||
})
|
||||
.with_child({
|
||||
make_root = create_menu_item("Make Root", vec![], ctx);
|
||||
make_root
|
||||
})
|
||||
.with_child(
|
||||
MenuItemBuilder::new(
|
||||
.with_child({
|
||||
replace_with = MenuItemBuilder::new(
|
||||
WidgetBuilder::new().with_min_size(Vector2::new(120.0, 22.0)),
|
||||
)
|
||||
.with_content(MenuItemContent::text("Replace With"))
|
||||
.with_items(replace_with_menu_root_items)
|
||||
.build(ctx),
|
||||
)
|
||||
.with_items(replace_with_menu.root_items.clone())
|
||||
.build(ctx);
|
||||
replace_with
|
||||
})
|
||||
.with_child({
|
||||
open_asset = create_menu_item("Open Asset", vec![], ctx);
|
||||
open_asset
|
||||
@@ -176,8 +190,13 @@ impl SceneNodeContextMenu {
|
||||
.build(ctx);
|
||||
let menu = RcUiNodeHandle::new(menu, ctx.sender());
|
||||
|
||||
// TODO: Not sure if this is the right place for this dialog.
|
||||
let save_as_prefab_dialog = make_save_file_selector(ctx, PathBuf::from("unnamed.rgs"));
|
||||
for item in [create_child, create_parent, replace_with] {
|
||||
ctx.inner().send_message(MenuItemMessage::sort(
|
||||
item,
|
||||
MessageDirection::ToWidget,
|
||||
SortingPredicate::sort_by_text(),
|
||||
))
|
||||
}
|
||||
|
||||
Self {
|
||||
create_child_entity_menu,
|
||||
@@ -186,7 +205,7 @@ impl SceneNodeContextMenu {
|
||||
copy_selection,
|
||||
placement_target: Default::default(),
|
||||
save_as_prefab,
|
||||
save_as_prefab_dialog,
|
||||
save_as_prefab_dialog: Default::default(),
|
||||
replace_with_menu,
|
||||
paste,
|
||||
make_root,
|
||||
@@ -210,6 +229,7 @@ impl SceneNodeContextMenu {
|
||||
sender,
|
||||
controller,
|
||||
editor_selection,
|
||||
engine,
|
||||
) {
|
||||
if let Some(graph_selection) = editor_selection.as_graph() {
|
||||
if let Some(parent) = graph_selection.nodes().first() {
|
||||
@@ -221,6 +241,7 @@ impl SceneNodeContextMenu {
|
||||
sender,
|
||||
controller,
|
||||
editor_selection,
|
||||
engine,
|
||||
) {
|
||||
if let Some(graph_selection) = editor_selection.as_graph() {
|
||||
if let Some(first) = graph_selection.nodes().first() {
|
||||
@@ -262,10 +283,13 @@ impl SceneNodeContextMenu {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(replacement) =
|
||||
self.replace_with_menu
|
||||
.handle_ui_message(message, sender, controller, editor_selection)
|
||||
{
|
||||
} else if let Some(replacement) = self.replace_with_menu.handle_ui_message(
|
||||
message,
|
||||
sender,
|
||||
controller,
|
||||
editor_selection,
|
||||
engine,
|
||||
) {
|
||||
if let Some(graph_selection) = editor_selection.as_graph() {
|
||||
if let Some(first) = graph_selection.nodes().first() {
|
||||
sender.do_command(ReplaceNodeCommand {
|
||||
@@ -310,23 +334,22 @@ impl SceneNodeContextMenu {
|
||||
}
|
||||
}
|
||||
} else if message.destination() == self.save_as_prefab {
|
||||
engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
.send_message(WindowMessage::open_modal(
|
||||
self.save_as_prefab_dialog,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
engine
|
||||
.user_interfaces
|
||||
.first_mut()
|
||||
.send_message(FileSelectorMessage::root(
|
||||
self.save_as_prefab_dialog,
|
||||
MessageDirection::ToWidget,
|
||||
Some(std::env::current_dir().unwrap()),
|
||||
));
|
||||
let ui = engine.user_interfaces.first_mut();
|
||||
|
||||
self.save_as_prefab_dialog =
|
||||
make_save_file_selector(&mut ui.build_ctx(), PathBuf::from("unnamed.rgs"));
|
||||
|
||||
ui.send_message(WindowMessage::open_modal(
|
||||
self.save_as_prefab_dialog,
|
||||
MessageDirection::ToWidget,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
ui.send_message(FileSelectorMessage::root(
|
||||
self.save_as_prefab_dialog,
|
||||
MessageDirection::ToWidget,
|
||||
Some(std::env::current_dir().unwrap()),
|
||||
));
|
||||
} else if message.destination() == self.make_root {
|
||||
if let Some(graph_selection) = editor_selection.as_graph() {
|
||||
if let Some(first) = graph_selection.nodes.first() {
|
||||
|
||||
@@ -133,17 +133,17 @@ impl<'a> WorldViewerDataProvider for EditorSceneWrapper<'a> {
|
||||
fn icon_of(&self, node: ErasedHandle) -> Option<UntypedResource> {
|
||||
let node = self.scene.graph.try_get(node.into()).unwrap();
|
||||
if node.is_point_light() || node.is_directional_light() || node.is_spot_light() {
|
||||
load_image(include_bytes!("../../../resources/light.png"))
|
||||
load_image!("../../../resources/light.png")
|
||||
} else if node.is_joint() || node.is_joint2d() {
|
||||
load_image(include_bytes!("../../../resources/joint.png"))
|
||||
load_image!("../../../resources/joint.png")
|
||||
} else if node.is_rigid_body() || node.is_rigid_body2d() {
|
||||
load_image(include_bytes!("../../../resources/rigid_body.png"))
|
||||
load_image!("../../../resources/rigid_body.png")
|
||||
} else if node.is_collider() || node.is_collider2d() {
|
||||
load_image(include_bytes!("../../../resources/collider.png"))
|
||||
load_image!("../../../resources/collider.png")
|
||||
} else if node.is_sound() {
|
||||
load_image(include_bytes!("../../../resources/sound_source.png"))
|
||||
load_image!("../../../resources/sound_source.png")
|
||||
} else {
|
||||
load_image(include_bytes!("../../../resources/cube.png"))
|
||||
load_image!("../../../resources/cube.png")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-14
@@ -47,7 +47,7 @@ use crate::{
|
||||
window::{WindowBuilder, WindowTitle},
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
BuildContext, Orientation, RcUiNodeHandle, Thickness, UiNode, UserInterface,
|
||||
VerticalAlignment, BRUSH_BRIGHT_BLUE, BRUSH_PRIMARY,
|
||||
VerticalAlignment,
|
||||
},
|
||||
},
|
||||
gui::make_image_button_with_tooltip,
|
||||
@@ -58,6 +58,8 @@ use crate::{
|
||||
world::graph::item::{DropAnchor, SceneItem, SceneItemBuilder, SceneItemMessage},
|
||||
Mode, Settings,
|
||||
};
|
||||
use fyrox::gui::style::resource::StyleResourceExt;
|
||||
use fyrox::gui::style::Style;
|
||||
use rust_fuzzy_search::fuzzy_compare;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -156,7 +158,7 @@ fn make_graph_node_item(
|
||||
.with_text_brush(if is_instance {
|
||||
Brush::Solid(Color::opaque(160, 160, 200))
|
||||
} else {
|
||||
Brush::Solid(fyrox::gui::COLOR_FOREGROUND)
|
||||
ctx.style.get_or_default(Style::BRUSH_FOREGROUND)
|
||||
})
|
||||
.with_name(name.deref().to_owned())
|
||||
.with_entity_handle(handle)
|
||||
@@ -245,9 +247,7 @@ impl WorldViewer {
|
||||
ctx,
|
||||
size,
|
||||
size,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/collapse.png"
|
||||
)),
|
||||
load_image!("../../resources/collapse.png"),
|
||||
"Collapse Everything",
|
||||
Some(0),
|
||||
);
|
||||
@@ -258,9 +258,7 @@ impl WorldViewer {
|
||||
ctx,
|
||||
size,
|
||||
size,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/expand.png"
|
||||
)),
|
||||
load_image!("../../resources/expand.png"),
|
||||
"Expand Everything",
|
||||
Some(1),
|
||||
);
|
||||
@@ -271,9 +269,7 @@ impl WorldViewer {
|
||||
ctx,
|
||||
size,
|
||||
size,
|
||||
load_image(include_bytes!(
|
||||
"../../resources/locate.png"
|
||||
)),
|
||||
load_image!("../../resources/locate.png"),
|
||||
"Locate Selection",
|
||||
Some(2),
|
||||
);
|
||||
@@ -376,10 +372,11 @@ impl WorldViewer {
|
||||
let element = ButtonBuilder::new(WidgetBuilder::new().with_height(16.0))
|
||||
.with_back(
|
||||
DecoratorBuilder::new(BorderBuilder::new(
|
||||
WidgetBuilder::new().with_foreground(BRUSH_PRIMARY),
|
||||
WidgetBuilder::new()
|
||||
.with_foreground(ctx.style.get_or_default(Style::BRUSH_PRIMARY)),
|
||||
))
|
||||
.with_normal_brush(BRUSH_PRIMARY)
|
||||
.with_hover_brush(BRUSH_BRIGHT_BLUE)
|
||||
.with_normal_brush(ctx.style.get_or_default(Style::BRUSH_PRIMARY))
|
||||
.with_hover_brush(ctx.style.get_or_default(Style::BRUSH_BRIGHT_BLUE))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_content(
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::core::{
|
||||
visitor::prelude::*,
|
||||
ImmutableString,
|
||||
};
|
||||
use std::any::TypeId;
|
||||
use std::{
|
||||
any,
|
||||
any::Any,
|
||||
@@ -137,6 +138,60 @@ pub enum ValueType {
|
||||
UnitQuaternionF64,
|
||||
}
|
||||
|
||||
impl ValueType {
|
||||
/// Converts the value type into its respective type id.
|
||||
pub fn into_type_id(self) -> TypeId {
|
||||
match self {
|
||||
ValueType::Bool => TypeId::of::<bool>(),
|
||||
ValueType::F32 => TypeId::of::<f32>(),
|
||||
ValueType::F64 => TypeId::of::<f64>(),
|
||||
ValueType::U64 => TypeId::of::<u64>(),
|
||||
ValueType::I64 => TypeId::of::<i64>(),
|
||||
ValueType::U32 => TypeId::of::<u32>(),
|
||||
ValueType::I32 => TypeId::of::<i32>(),
|
||||
ValueType::U16 => TypeId::of::<u16>(),
|
||||
ValueType::I16 => TypeId::of::<i16>(),
|
||||
ValueType::U8 => TypeId::of::<u8>(),
|
||||
ValueType::I8 => TypeId::of::<i8>(),
|
||||
ValueType::Vector2Bool => TypeId::of::<Vector2<bool>>(),
|
||||
ValueType::Vector2F32 => TypeId::of::<Vector2<f32>>(),
|
||||
ValueType::Vector2F64 => TypeId::of::<Vector2<f64>>(),
|
||||
ValueType::Vector2U64 => TypeId::of::<Vector2<u64>>(),
|
||||
ValueType::Vector2I64 => TypeId::of::<Vector2<i64>>(),
|
||||
ValueType::Vector2U32 => TypeId::of::<Vector2<u32>>(),
|
||||
ValueType::Vector2I32 => TypeId::of::<Vector2<i32>>(),
|
||||
ValueType::Vector2U16 => TypeId::of::<Vector2<u16>>(),
|
||||
ValueType::Vector2I16 => TypeId::of::<Vector2<i16>>(),
|
||||
ValueType::Vector2U8 => TypeId::of::<Vector2<u8>>(),
|
||||
ValueType::Vector2I8 => TypeId::of::<Vector2<i8>>(),
|
||||
ValueType::Vector3Bool => TypeId::of::<Vector3<bool>>(),
|
||||
ValueType::Vector3F32 => TypeId::of::<Vector3<f32>>(),
|
||||
ValueType::Vector3F64 => TypeId::of::<Vector3<f64>>(),
|
||||
ValueType::Vector3U64 => TypeId::of::<Vector3<u64>>(),
|
||||
ValueType::Vector3I64 => TypeId::of::<Vector3<i64>>(),
|
||||
ValueType::Vector3U32 => TypeId::of::<Vector3<u32>>(),
|
||||
ValueType::Vector3I32 => TypeId::of::<Vector3<i32>>(),
|
||||
ValueType::Vector3U16 => TypeId::of::<Vector3<u16>>(),
|
||||
ValueType::Vector3I16 => TypeId::of::<Vector3<i16>>(),
|
||||
ValueType::Vector3U8 => TypeId::of::<Vector3<u8>>(),
|
||||
ValueType::Vector3I8 => TypeId::of::<Vector3<i8>>(),
|
||||
ValueType::Vector4Bool => TypeId::of::<Vector4<bool>>(),
|
||||
ValueType::Vector4F32 => TypeId::of::<Vector4<f32>>(),
|
||||
ValueType::Vector4F64 => TypeId::of::<Vector4<f64>>(),
|
||||
ValueType::Vector4U64 => TypeId::of::<Vector4<u64>>(),
|
||||
ValueType::Vector4I64 => TypeId::of::<Vector4<i64>>(),
|
||||
ValueType::Vector4U32 => TypeId::of::<Vector4<u32>>(),
|
||||
ValueType::Vector4I32 => TypeId::of::<Vector4<i32>>(),
|
||||
ValueType::Vector4U16 => TypeId::of::<Vector4<u16>>(),
|
||||
ValueType::Vector4I16 => TypeId::of::<Vector4<i16>>(),
|
||||
ValueType::Vector4U8 => TypeId::of::<Vector4<u8>>(),
|
||||
ValueType::Vector4I8 => TypeId::of::<Vector4<i8>>(),
|
||||
ValueType::UnitQuaternionF32 => TypeId::of::<UnitQuaternion<f32>>(),
|
||||
ValueType::UnitQuaternionF64 => TypeId::of::<UnitQuaternion<f64>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ValueType {
|
||||
fn default() -> Self {
|
||||
Self::F32
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user