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,
|
||||
utils, Message,
|
||||
};
|
||||
use std::{
|
||||
fs::File,
|
||||
@@ -382,7 +382,7 @@ impl AssetItemContextMenu {
|
||||
return true;
|
||||
} else if message.destination() == self.show_in_explorer {
|
||||
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 {
|
||||
item.open();
|
||||
|
||||
@@ -85,34 +85,6 @@ pub mod preview;
|
||||
mod selection;
|
||||
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) {
|
||||
if let Ok(path) = path.as_ref().canonicalize() {
|
||||
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
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::scene_viewer::menu::{SceneItemAction, SceneItemMenu};
|
||||
use crate::{
|
||||
fyrox::{
|
||||
core::{color::Color, math::Rect, pool::Handle, uuid::Uuid},
|
||||
@@ -60,6 +61,7 @@ use crate::{
|
||||
scene::container::EditorSceneEntry,
|
||||
scene_viewer::gizmo::{SceneGizmo, SceneGizmoAction},
|
||||
settings::SettingsMessage,
|
||||
utils,
|
||||
utils::enable_widget,
|
||||
DropdownListBuilder, GameScene, Message, Mode, SaveSceneConfirmationDialogAction,
|
||||
SceneContainer, Settings,
|
||||
@@ -82,6 +84,7 @@ use strum::{IntoEnumIterator, VariantNames};
|
||||
use strum_macros::{AsRefStr, EnumIter, EnumString, VariantNames};
|
||||
|
||||
mod gizmo;
|
||||
mod menu;
|
||||
|
||||
#[derive(Default, Clone, Debug, EnumIter, AsRefStr, EnumString, VariantNames)]
|
||||
pub enum GraphicsDebugSwitches {
|
||||
@@ -284,6 +287,7 @@ pub struct SceneViewer {
|
||||
scene_gizmo_image: Handle<Image>,
|
||||
debug_switches: Handle<DropdownList>,
|
||||
grid_snap_menu: GridSnappingMenu,
|
||||
scene_item_menu: SceneItemMenu,
|
||||
}
|
||||
|
||||
impl SceneViewer {
|
||||
@@ -558,6 +562,9 @@ impl SceneViewer {
|
||||
.with_title(WindowTitle::text("Scene Preview"))
|
||||
.with_tab_label("Scene")
|
||||
.build(ctx);
|
||||
|
||||
let scene_item_menu = SceneItemMenu::new(ctx);
|
||||
|
||||
Self {
|
||||
sender,
|
||||
window,
|
||||
@@ -577,6 +584,7 @@ impl SceneViewer {
|
||||
debug_switches,
|
||||
grid_snap_menu,
|
||||
build,
|
||||
scene_item_menu,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -671,6 +679,19 @@ impl SceneViewer {
|
||||
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(
|
||||
&mut self,
|
||||
message: &mut UiMessage,
|
||||
@@ -683,6 +704,20 @@ impl SceneViewer {
|
||||
|
||||
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>() {
|
||||
for (mode_id, mode_button) in self.interaction_modes.iter() {
|
||||
if message.destination() == *mode_button {
|
||||
@@ -744,18 +779,7 @@ impl SceneViewer {
|
||||
&& message.direction() == MessageDirection::FromWidget
|
||||
{
|
||||
match msg {
|
||||
TabControlMessage::CloseTab(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::CloseTab(uuid) => self.close_scene(scenes, uuid),
|
||||
TabControlMessage::ActiveTab(Some(uuid)) => {
|
||||
if let Some(entry) = scenes.entry_by_scene_id(*uuid) {
|
||||
self.sender.send(Message::SetCurrentScene(entry.id));
|
||||
@@ -920,7 +944,7 @@ impl SceneViewer {
|
||||
content: Default::default(),
|
||||
can_be_closed: true,
|
||||
user_data: None,
|
||||
context_menu: None,
|
||||
context_menu: Some(self.scene_item_menu.menu.clone()),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use crate::{
|
||||
},
|
||||
load_image,
|
||||
};
|
||||
use fyrox::core::log::Log;
|
||||
use fyrox::core::pool::ObjectOrVariant;
|
||||
use fyrox::gui::button::Button;
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user