use crate::{
fyrox::{
core::{
algebra::Vector2,
pool::Handle,
uuid::{uuid, Uuid},
TypeUuidProvider,
},
gui::BuildContext,
scene::node::Node,
},
interaction::{make_interaction_mode_button, InteractionMode},
message::MessageSender,
scene::{commands::ChangeSelectionCommand, controller::SceneController, GameScene, Selection},
settings::Settings,
world::selection::GraphSelection,
Engine,
};
use fyrox::gui::border::Border;
use fyrox::gui::button::Button;
use fyrox::gui::image::Image;
use fyrox::gui::widget::WidgetMessage;
pub struct SelectInteractionMode {
preview: Handle<Image>,
selection_frame: Handle<Border>,
message_sender: MessageSender,
stack: Vec<Handle<Node>>,
click_pos: Vector2<f32>,
}
impl SelectInteractionMode {
pub fn new(
preview: Handle<Image>,
selection_frame: Handle<Border>,
message_sender: MessageSender,
) -> Self {
Self {
preview,
selection_frame,
message_sender,
stack: Vec::new(),
click_pos: Vector2::default(),
}
}
}
impl TypeUuidProvider for SelectInteractionMode {
fn type_uuid() -> Uuid {
uuid!("bab9ce8c-d679-4c49-beb9-f5a8482e0678")
}
}
impl InteractionMode for SelectInteractionMode {
fn on_left_mouse_button_down(
&mut self,
_editor_selection: &Selection,
_controller: &mut dyn SceneController,
engine: &mut Engine,
mouse_pos: Vector2<f32>,
_frame_size: Vector2<f32>,
_settings: &Settings,
) {
self.click_pos = mouse_pos;
engine.user_interfaces.first().send_many(
self.selection_frame,
[
WidgetMessage::Visibility(true),
WidgetMessage::DesiredPosition(mouse_pos),
WidgetMessage::Width(0.0),
WidgetMessage::Height(0.0),
],
);
}
fn on_left_mouse_button_up(
&mut self,
editor_selection: &Selection,
controller: &mut dyn SceneController,
engine: &mut Engine,
_mouse_pos: Vector2<f32>,
frame_size: Vector2<f32>,
_settings: &Settings,
) {
let Some(game_scene) = controller.downcast_mut::<GameScene>() else {
return;
};
let scene = &engine.scenes[game_scene.scene];
let camera = &scene.graph[game_scene.camera_controller.camera];
let preview_screen_bounds =
engine.user_interfaces.first_mut()[self.preview].screen_bounds();
let frame_screen_bounds =
engine.user_interfaces.first_mut()[self.selection_frame].screen_bounds();
let frame_relative_bounds = frame_screen_bounds.translate(-preview_screen_bounds.position);
self.stack.clear();
self.stack.push(scene.graph.get_root());
let mut graph_selection = GraphSelection::default();
while let Some(handle) = self.stack.pop() {
let node = &scene.graph[handle];
if handle == game_scene.editor_objects_root {
continue;
}
if handle == scene.graph.get_root() {
self.stack.extend_from_slice(node.children());
continue;
}
let node_screen_bounds = node.world_bounding_box().project(
&camera.view_projection_matrix(),
&camera.viewport_pixels(frame_size),
);
if frame_relative_bounds.intersects(node_screen_bounds) {
graph_selection.insert_or_exclude(handle);
}
self.stack.extend_from_slice(node.children());
}
let new_selection = Selection::new(graph_selection);
if &new_selection != editor_selection {
self.message_sender
.do_command(ChangeSelectionCommand::new(new_selection));
}
engine
.user_interfaces
.first()
.send(self.selection_frame, WidgetMessage::Visibility(false));
}
fn on_mouse_move(
&mut self,
_mouse_offset: Vector2<f32>,
mouse_position: Vector2<f32>,
_editor_selection: &Selection,
_controller: &mut dyn SceneController,
engine: &mut Engine,
_frame_size: Vector2<f32>,
_settings: &Settings,
) {
let ui = &mut engine.user_interfaces.first_mut();
let width = mouse_position.x - self.click_pos.x;
let height = mouse_position.y - self.click_pos.y;
let position = Vector2::new(
if width < 0.0 {
mouse_position.x
} else {
self.click_pos.x
},
if height < 0.0 {
mouse_position.y
} else {
self.click_pos.y
},
);
ui.send_many(
self.selection_frame,
[
WidgetMessage::DesiredPosition(position),
WidgetMessage::Width(width.abs()),
WidgetMessage::Height(height.abs()),
],
);
}
fn update(
&mut self,
_editor_selection: &Selection,
_controller: &mut dyn SceneController,
_engine: &mut Engine,
_settings: &Settings,
) {
}
fn make_button(&mut self, ctx: &mut BuildContext, selected: bool) -> Handle<Button> {
let select_mode_tooltip = "Select Object(s) - Shortcut: [1]\n\nSelection interaction mode \
allows you to select an object by a single left mouse button click or multiple objects using either \
frame selection (click and drag) or by holding Ctrl+Click";
make_interaction_mode_button(
ctx,
include_bytes!("../../resources/select.png"),
select_mode_tooltip,
selected,
)
}
fn uuid(&self) -> Uuid {
Self::type_uuid()
}
}