Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions editor/src/plugins/inspector/editors/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ use crate::{
};
use fyrox::gui::brush::Brush;
use fyrox::gui::message::MessageData;
use std::{
any::TypeId,
sync::mpsc::Sender,
};
use std::{any::TypeId, sync::mpsc::Sender};

#[derive(Debug, PartialEq, Clone)]
pub enum SurfaceDataPropertyEditorMessage {
Expand Down
36 changes: 30 additions & 6 deletions editor/src/scene_viewer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ use strum::{IntoEnumIterator, VariantNames};
use strum_macros::{AsRefStr, EnumIter, EnumString, VariantNames};

mod gizmo;
mod scene_tab_context_menu;

pub use scene_tab_context_menu::SceneTabContextMenu;

#[derive(Default, Clone, Debug, EnumIter, AsRefStr, EnumString, VariantNames)]
pub enum GraphicsDebugSwitches {
Expand Down Expand Up @@ -280,6 +283,7 @@ pub struct SceneViewer {
scene_gizmo_image: Handle<UiNode>,
debug_switches: Handle<UiNode>,
grid_snap_menu: GridSnappingMenu,
scene_tab_context_menu: SceneTabContextMenu,
}

impl SceneViewer {
Expand All @@ -306,6 +310,7 @@ impl SceneViewer {
.build(ctx);

let grid_snap_menu = GridSnappingMenu::new(ctx, settings);
let scene_tab_context_menu = SceneTabContextMenu::new(ctx);

let debug_switches;
let contextual_actions = StackPanelBuilder::new(
Expand Down Expand Up @@ -573,6 +578,7 @@ impl SceneViewer {
scene_gizmo_image,
debug_switches,
grid_snap_menu,
scene_tab_context_menu,
build,
}
}
Expand Down Expand Up @@ -685,6 +691,17 @@ impl SceneViewer {
) {
self.grid_snap_menu.handle_ui_message(message, settings);

// Handle scene tab context menu
let scene_ids: Vec<_> = scenes.iter().map(|e| e.id).collect();
let scene_paths: Vec<_> = scenes.iter().map(|e| e.path.as_deref()).collect();
self.scene_tab_context_menu.handle_ui_message(
message,
&self.sender,
&scene_ids,
&scene_paths,
engine.user_interfaces.first(),
);

let ui = engine.user_interfaces.first_mut();

if let Some(ButtonMessage::Click) = message.data::<ButtonMessage>() {
Expand Down Expand Up @@ -918,12 +935,19 @@ impl SceneViewer {
// Add any missing tabs.
for entry in scenes.iter() {
if tabs.iter().all(|tab| tab.uuid != entry.id) {
let header = TextBuilder::new(WidgetBuilder::new().with_margin(Thickness {
left: 4.0,
top: 2.0,
right: 4.0,
bottom: 2.0,
}))
let header = TextBuilder::new(
WidgetBuilder::new()
.with_margin(Thickness {
left: 4.0,
top: 2.0,
right: 4.0,
bottom: 2.0,
})
.with_context_menu(self.scene_tab_context_menu.menu.clone())
.with_user_data(std::sync::Arc::new(fyrox::core::parking_lot::Mutex::new(
entry.id,
))),
)
.with_text(entry.name())
.build(&mut engine.user_interfaces.first_mut().build_ctx());

Expand Down
205 changes: 205 additions & 0 deletions editor/src/scene_viewer/scene_tab_context_menu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// 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.

//! Context menu for scene tabs in the scene viewer.

use crate::{
fyrox::{
core::{pool::Handle, uuid::Uuid},
graph::BaseSceneGraph,
gui::{
menu::{ContextMenuBuilder, MenuItemBuilder, MenuItemContent, MenuItemMessage},
message::UiMessage,
popup::{Placement, PopupBuilder, PopupMessage},
stack_panel::StackPanelBuilder,
widget::WidgetBuilder,
BuildContext, RcUiNodeHandle, UiNode, UserInterface,
},
},
message::MessageSender,
Message,
};
use std::path::Path;

/// Context menu for scene tab headers.
pub struct SceneTabContextMenu {
/// The context menu popup handle.
pub menu: RcUiNodeHandle,
/// "Show in Explorer" menu item.
pub show_in_explorer: Handle<UiNode>,
/// "Close" menu item.
pub close: Handle<UiNode>,
/// "Close All Tabs" menu item.
pub close_all: Handle<UiNode>,
/// The UUID of the scene that was right-clicked.
pub target_scene_id: Option<Uuid>,
}

impl SceneTabContextMenu {
/// Creates a new scene tab context menu.
pub fn new(ctx: &mut BuildContext) -> Self {
fn item(text: &str, ctx: &mut BuildContext) -> Handle<UiNode> {
MenuItemBuilder::new(WidgetBuilder::new())
.with_content(MenuItemContent::text(text))
.build(ctx)
}

let show_in_explorer = item("Show In Explorer", ctx);
let close = item("Close", ctx);
let close_all = item("Close All Tabs", ctx);

let menu = ContextMenuBuilder::new(
PopupBuilder::new(WidgetBuilder::new())
.with_content(
StackPanelBuilder::new(
WidgetBuilder::new()
.with_child(show_in_explorer)
.with_child(close)
.with_child(close_all),
)
.build(ctx),
)
.with_restrict_picking(false),
)
.build(ctx);
let menu = RcUiNodeHandle::new(menu, ctx.sender());

Self {
menu,
show_in_explorer,
close,
close_all,
target_scene_id: None,
}
}

/// Handles UI messages for the context menu.
pub fn handle_ui_message(
&mut self,
message: &UiMessage,
sender: &MessageSender,
scene_ids: &[Uuid],
scene_paths: &[Option<&Path>],
ui: &UserInterface,
) {
if let Some(PopupMessage::Placement(Placement::Cursor(target))) = message.data() {
if message.destination() == self.menu.handle() {
// Get the scene ID from the user data of the target widget
if let Some(uuid) = ui.node(*target).user_data_cloned::<Uuid>() {
self.target_scene_id = Some(uuid);

// Enable/disable "Show in Explorer" based on whether the scene has a path
let has_path = scene_ids
.iter()
.zip(scene_paths.iter())
.find(|(id, _)| **id == uuid)
.map(|(_, path)| path.is_some())
.unwrap_or(false);

ui.send(
self.show_in_explorer,
fyrox::gui::widget::WidgetMessage::Enabled(has_path),
);
}
}
} else if let Some(MenuItemMessage::Click) = message.data() {
if let Some(target_id) = self.target_scene_id {
if message.destination() == self.show_in_explorer {
// Find the path for this scene
if let Some(path) = scene_ids
.iter()
.zip(scene_paths.iter())
.find(|(id, _)| **id == target_id)
.and_then(|(_, path)| *path)
{
if let Ok(canonical_path) = path.canonicalize() {
show_in_explorer(canonical_path);
}
}
} else if message.destination() == self.close {
sender.send(Message::CloseScene(target_id));
} else if message.destination() == self.close_all {
// Close all scenes
for &id in scene_ids {
sender.send(Message::CloseScene(id));
}
}
}
}
}
}

/// Opens the file explorer and highlights the specified path.
fn show_in_explorer<P: AsRef<Path>>(path: P) {
#[cfg(target_os = "windows")]
{
use std::process::Command;

fn execute_command(command: &mut Command) {
match command.spawn() {
Ok(mut process) => {
let _ = process.wait();
}
Err(err) => {
fyrox::core::log::Log::err(format!(
"Failed to show in explorer. Reason: {err:?}"
));
}
}
}

let path = path.as_ref();
if path.is_dir() {
execute_command(Command::new("explorer").arg(path));
} else if let Some(parent) = path.parent() {
execute_command(
Command::new("explorer")
.arg("/select,")
.arg(path.as_os_str()),
);
}
}

#[cfg(target_os = "macos")]
{
let path = path.as_ref();
if path.is_dir() {
let _ = std::process::Command::new("open").arg(path).spawn();
} else {
let _ = std::process::Command::new("open")
.args(["-R", &path.to_string_lossy()])
.spawn();
}
}

#[cfg(target_os = "linux")]
{
// Try to use xdg-open for the parent directory
let path = path.as_ref();
let target = if path.is_dir() {
path.to_path_buf()
} else {
path.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| path.to_path_buf())
};
let _ = std::process::Command::new("xdg-open").arg(target).spawn();
}
}
5 changes: 1 addition & 4 deletions fyrox-ui/src/color/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ use fyrox_core::uuid_provider;
use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
use fyrox_graph::BaseSceneGraph;
use fyrox_material::MaterialResource;
use std::{
ops::Deref,
sync::mpsc::Sender,
};
use std::{ops::Deref, sync::mpsc::Sender};

pub mod gradient;

Expand Down
5 changes: 1 addition & 4 deletions fyrox-ui/src/inspector/editors/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ use crate::{
use crate::message::{DeliveryMode, MessageData};
use fyrox_graph::BaseSceneGraph;
use std::sync::Arc;
use std::{
any::TypeId,
fmt::Debug,
};
use std::{any::TypeId, fmt::Debug};

#[derive(Clone, Debug, PartialEq, Visit, Reflect, Default)]
pub struct Item {
Expand Down
8 changes: 1 addition & 7 deletions project-manager/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,17 @@ fn main() {

let mut previous = Instant::now();

#[allow(unused_assignments)]
let mut time_step = 1.0 / 60.0;

event_loop
.run(move |event, active_event_loop| {
if project_manager.mode.is_build() {
// Keep updating with reduced rate to keep printing to the build log, but do not
// eat as much time as in normal update mode.
time_step = 1.0 / 10.0;

active_event_loop.set_control_flow(ControlFlow::wait_duration(
Duration::from_secs_f32(time_step),
Duration::from_secs_f32(1.0 / 10.0),
));
} else {
// Wait for an event.
active_event_loop.set_control_flow(ControlFlow::Wait);
time_step = 1.0 / 60.0;
}

match event {
Expand Down