mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
@@ -52,7 +52,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
message::MessageSender,
|
message::MessageSender,
|
||||||
Message,
|
utils, Message,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
@@ -382,7 +382,7 @@ impl AssetItemContextMenu {
|
|||||||
return true;
|
return true;
|
||||||
} else if message.destination() == self.show_in_explorer {
|
} else if message.destination() == self.show_in_explorer {
|
||||||
if let Ok(canonical_path) = item.path.canonicalize() {
|
if let Ok(canonical_path) = item.path.canonicalize() {
|
||||||
asset::show_in_explorer(canonical_path)
|
utils::show_in_explorer(canonical_path)
|
||||||
}
|
}
|
||||||
} else if message.destination() == self.open {
|
} else if message.destination() == self.open {
|
||||||
item.open();
|
item.open();
|
||||||
|
|||||||
@@ -85,34 +85,6 @@ pub mod preview;
|
|||||||
mod selection;
|
mod selection;
|
||||||
pub mod selector;
|
pub mod selector;
|
||||||
|
|
||||||
fn show_in_explorer<P: AsRef<Path>>(path: P) {
|
|
||||||
// opener crate is bugged on Windows, so using explorer's command directly.
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn execute_command(command: &mut Command) {
|
|
||||||
match command.spawn() {
|
|
||||||
Ok(mut process) => Log::verify(process.wait()),
|
|
||||||
Err(err) => Log::err(format!(
|
|
||||||
"Failed to show asset item in explorer. Reason: {err:?}"
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
execute_command(Command::new("explorer").arg("/select,").arg(path.as_ref()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
{
|
|
||||||
if let Err(err) = opener::reveal(path) {
|
|
||||||
Log::err(format!(
|
|
||||||
"Failed to show asset item in explorer. Reason: {err:?}"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_in_explorer<P: AsRef<Path>>(path: P) {
|
fn open_in_explorer<P: AsRef<Path>>(path: P) {
|
||||||
if let Ok(path) = path.as_ref().canonicalize() {
|
if let Ok(path) = path.as_ref().canonicalize() {
|
||||||
Log::verify(open::that(path))
|
Log::verify(open::that(path))
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// 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,
|
||||||
|
uuid::{uuid, Uuid},
|
||||||
|
},
|
||||||
|
gui::{
|
||||||
|
menu::{ContextMenuBuilder, MenuItem, MenuItemMessage},
|
||||||
|
message::UiMessage,
|
||||||
|
popup::PopupBuilder,
|
||||||
|
stack_panel::StackPanelBuilder,
|
||||||
|
widget::WidgetBuilder,
|
||||||
|
BuildContext, RcUiNodeHandle,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
menu::create_menu_item,
|
||||||
|
};
|
||||||
|
use fyrox::graph::SceneGraph;
|
||||||
|
use fyrox::gui::popup::{Placement, PopupMessage};
|
||||||
|
use fyrox::gui::{UiNode, UserInterface};
|
||||||
|
|
||||||
|
pub struct SceneItemMenu {
|
||||||
|
pub menu: RcUiNodeHandle,
|
||||||
|
close: Handle<MenuItem>,
|
||||||
|
show_in_explorer: Handle<MenuItem>,
|
||||||
|
placement_target: Handle<UiNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SceneItemAction {
|
||||||
|
None,
|
||||||
|
Close(Uuid),
|
||||||
|
ShowInExplorer(Uuid),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SceneItemMenu {
|
||||||
|
pub const CLOSE: Uuid = uuid!("e4c7f0eb-c9a7-4cf2-af4b-78c028be9c58");
|
||||||
|
pub const SHOW_IN_EXPLORER: Uuid = uuid!("97a43a80-7860-4fce-b0fa-26ae6677d132");
|
||||||
|
|
||||||
|
pub fn new(ctx: &mut BuildContext) -> Self {
|
||||||
|
let close = create_menu_item("Close", Self::CLOSE, vec![], ctx);
|
||||||
|
let show_in_explorer =
|
||||||
|
create_menu_item("Show In Explorer", Self::SHOW_IN_EXPLORER, vec![], ctx);
|
||||||
|
let content = StackPanelBuilder::new(
|
||||||
|
WidgetBuilder::new()
|
||||||
|
.with_child(close)
|
||||||
|
.with_child(show_in_explorer),
|
||||||
|
)
|
||||||
|
.build(ctx);
|
||||||
|
let menu = ContextMenuBuilder::new(
|
||||||
|
PopupBuilder::new(WidgetBuilder::new().with_visibility(false)).with_content(content),
|
||||||
|
)
|
||||||
|
.build(ctx);
|
||||||
|
let menu = RcUiNodeHandle::new(menu, ctx.sender());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
menu,
|
||||||
|
close,
|
||||||
|
show_in_explorer,
|
||||||
|
placement_target: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_ui_message(
|
||||||
|
&mut self,
|
||||||
|
ui: &UserInterface,
|
||||||
|
message: &UiMessage,
|
||||||
|
) -> SceneItemAction {
|
||||||
|
if let Some(MenuItemMessage::Click) = message.data() {
|
||||||
|
if let Some(placement_target_id) = self.placement_target_id(ui) {
|
||||||
|
if message.destination == self.close {
|
||||||
|
return SceneItemAction::Close(placement_target_id);
|
||||||
|
} else if message.destination == self.show_in_explorer {
|
||||||
|
return SceneItemAction::ShowInExplorer(placement_target_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(PopupMessage::Placement(Placement::Cursor(target))) =
|
||||||
|
message.data_from(self.menu.handle())
|
||||||
|
{
|
||||||
|
self.placement_target = *target;
|
||||||
|
}
|
||||||
|
SceneItemAction::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn placement_target_id(&self, ui: &UserInterface) -> Option<Uuid> {
|
||||||
|
ui.try_get(self.placement_target).ok().map(|n| n.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
use crate::scene_viewer::menu::{SceneItemAction, SceneItemMenu};
|
||||||
use crate::{
|
use crate::{
|
||||||
fyrox::{
|
fyrox::{
|
||||||
core::{color::Color, math::Rect, pool::Handle, uuid::Uuid},
|
core::{color::Color, math::Rect, pool::Handle, uuid::Uuid},
|
||||||
@@ -60,6 +61,7 @@ use crate::{
|
|||||||
scene::container::EditorSceneEntry,
|
scene::container::EditorSceneEntry,
|
||||||
scene_viewer::gizmo::{SceneGizmo, SceneGizmoAction},
|
scene_viewer::gizmo::{SceneGizmo, SceneGizmoAction},
|
||||||
settings::SettingsMessage,
|
settings::SettingsMessage,
|
||||||
|
utils,
|
||||||
utils::enable_widget,
|
utils::enable_widget,
|
||||||
DropdownListBuilder, GameScene, Message, Mode, SaveSceneConfirmationDialogAction,
|
DropdownListBuilder, GameScene, Message, Mode, SaveSceneConfirmationDialogAction,
|
||||||
SceneContainer, Settings,
|
SceneContainer, Settings,
|
||||||
@@ -82,6 +84,7 @@ use strum::{IntoEnumIterator, VariantNames};
|
|||||||
use strum_macros::{AsRefStr, EnumIter, EnumString, VariantNames};
|
use strum_macros::{AsRefStr, EnumIter, EnumString, VariantNames};
|
||||||
|
|
||||||
mod gizmo;
|
mod gizmo;
|
||||||
|
mod menu;
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, EnumIter, AsRefStr, EnumString, VariantNames)]
|
#[derive(Default, Clone, Debug, EnumIter, AsRefStr, EnumString, VariantNames)]
|
||||||
pub enum GraphicsDebugSwitches {
|
pub enum GraphicsDebugSwitches {
|
||||||
@@ -284,6 +287,7 @@ pub struct SceneViewer {
|
|||||||
scene_gizmo_image: Handle<Image>,
|
scene_gizmo_image: Handle<Image>,
|
||||||
debug_switches: Handle<DropdownList>,
|
debug_switches: Handle<DropdownList>,
|
||||||
grid_snap_menu: GridSnappingMenu,
|
grid_snap_menu: GridSnappingMenu,
|
||||||
|
scene_item_menu: SceneItemMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneViewer {
|
impl SceneViewer {
|
||||||
@@ -558,6 +562,9 @@ impl SceneViewer {
|
|||||||
.with_title(WindowTitle::text("Scene Preview"))
|
.with_title(WindowTitle::text("Scene Preview"))
|
||||||
.with_tab_label("Scene")
|
.with_tab_label("Scene")
|
||||||
.build(ctx);
|
.build(ctx);
|
||||||
|
|
||||||
|
let scene_item_menu = SceneItemMenu::new(ctx);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sender,
|
sender,
|
||||||
window,
|
window,
|
||||||
@@ -577,6 +584,7 @@ impl SceneViewer {
|
|||||||
debug_switches,
|
debug_switches,
|
||||||
grid_snap_menu,
|
grid_snap_menu,
|
||||||
build,
|
build,
|
||||||
|
scene_item_menu,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -671,6 +679,19 @@ impl SceneViewer {
|
|||||||
self.sync_interaction_modes(new_scene, ui)
|
self.sync_interaction_modes(new_scene, ui)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn close_scene(&self, scenes: &mut SceneContainer, uuid: &Uuid) {
|
||||||
|
if let Some(entry) = scenes.entry_by_scene_id(*uuid) {
|
||||||
|
if entry.need_save() {
|
||||||
|
self.sender.send(Message::OpenSaveSceneConfirmationDialog {
|
||||||
|
id: entry.id,
|
||||||
|
action: SaveSceneConfirmationDialogAction::CloseScene(entry.id),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.sender.send(Message::CloseScene(entry.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_ui_message(
|
pub fn handle_ui_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: &mut UiMessage,
|
message: &mut UiMessage,
|
||||||
@@ -683,6 +704,20 @@ impl SceneViewer {
|
|||||||
|
|
||||||
let ui = engine.user_interfaces.first_mut();
|
let ui = engine.user_interfaces.first_mut();
|
||||||
|
|
||||||
|
match self.scene_item_menu.handle_ui_message(ui, message) {
|
||||||
|
SceneItemAction::None => {}
|
||||||
|
SceneItemAction::Close(scene_id) => self.close_scene(scenes, &scene_id),
|
||||||
|
SceneItemAction::ShowInExplorer(scene_id) => {
|
||||||
|
if let Some(entry) = scenes.entry_by_scene_id(scene_id) {
|
||||||
|
if let Some(entry_path) = entry.path.as_ref() {
|
||||||
|
if let Ok(canonical_path) = entry_path.canonicalize() {
|
||||||
|
utils::show_in_explorer(canonical_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ButtonMessage::Click) = message.data::<ButtonMessage>() {
|
if let Some(ButtonMessage::Click) = message.data::<ButtonMessage>() {
|
||||||
for (mode_id, mode_button) in self.interaction_modes.iter() {
|
for (mode_id, mode_button) in self.interaction_modes.iter() {
|
||||||
if message.destination() == *mode_button {
|
if message.destination() == *mode_button {
|
||||||
@@ -744,18 +779,7 @@ impl SceneViewer {
|
|||||||
&& message.direction() == MessageDirection::FromWidget
|
&& message.direction() == MessageDirection::FromWidget
|
||||||
{
|
{
|
||||||
match msg {
|
match msg {
|
||||||
TabControlMessage::CloseTab(uuid) => {
|
TabControlMessage::CloseTab(uuid) => self.close_scene(scenes, uuid),
|
||||||
if let Some(entry) = scenes.entry_by_scene_id(*uuid) {
|
|
||||||
if entry.need_save() {
|
|
||||||
self.sender.send(Message::OpenSaveSceneConfirmationDialog {
|
|
||||||
id: entry.id,
|
|
||||||
action: SaveSceneConfirmationDialogAction::CloseScene(entry.id),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.sender.send(Message::CloseScene(entry.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TabControlMessage::ActiveTab(Some(uuid)) => {
|
TabControlMessage::ActiveTab(Some(uuid)) => {
|
||||||
if let Some(entry) = scenes.entry_by_scene_id(*uuid) {
|
if let Some(entry) = scenes.entry_by_scene_id(*uuid) {
|
||||||
self.sender.send(Message::SetCurrentScene(entry.id));
|
self.sender.send(Message::SetCurrentScene(entry.id));
|
||||||
@@ -920,7 +944,7 @@ impl SceneViewer {
|
|||||||
content: Default::default(),
|
content: Default::default(),
|
||||||
can_be_closed: true,
|
can_be_closed: true,
|
||||||
user_data: None,
|
user_data: None,
|
||||||
context_menu: None,
|
context_menu: Some(self.scene_item_menu.menu.clone()),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
load_image,
|
load_image,
|
||||||
};
|
};
|
||||||
|
use fyrox::core::log::Log;
|
||||||
use fyrox::core::pool::ObjectOrVariant;
|
use fyrox::core::pool::ObjectOrVariant;
|
||||||
use fyrox::gui::button::Button;
|
use fyrox::gui::button::Button;
|
||||||
use fyrox::gui::file_browser::{FileSelector, FileSelectorMode, FileType};
|
use fyrox::gui::file_browser::{FileSelector, FileSelectorMode, FileType};
|
||||||
@@ -176,6 +177,34 @@ pub fn is_native_scene(path: &Path) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_in_explorer<P: AsRef<Path>>(path: P) {
|
||||||
|
// opener crate is bugged on Windows, so using explorer's command directly.
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn execute_command(command: &mut Command) {
|
||||||
|
match command.spawn() {
|
||||||
|
Ok(mut process) => Log::verify(process.wait()),
|
||||||
|
Err(err) => Log::err(format!(
|
||||||
|
"Failed to show asset item in explorer. Reason: {err:?}"
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_command(Command::new("explorer").arg("/select,").arg(path.as_ref()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
if let Err(err) = opener::reveal(path) {
|
||||||
|
Log::err(format!(
|
||||||
|
"Failed to show asset item in explorer. Reason: {err:?}"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -523,6 +523,7 @@ impl Header {
|
|||||||
WidgetBuilder::new()
|
WidgetBuilder::new()
|
||||||
.on_row(0)
|
.on_row(0)
|
||||||
.on_column(0)
|
.on_column(0)
|
||||||
|
.with_id(tab_definition.uuid)
|
||||||
.with_opt_context_menu(tab_definition.context_menu.clone()),
|
.with_opt_context_menu(tab_definition.context_menu.clone()),
|
||||||
)
|
)
|
||||||
.with_back({
|
.with_back({
|
||||||
|
|||||||
Reference in New Issue
Block a user