172 lines
6.4 KiB
Rust
172 lines
6.4 KiB
Rust
//! Top editor toolbar (below menu bar): spawn/file left, transport center.
|
|
|
|
use bevy::prelude::*;
|
|
use bevy_egui::egui;
|
|
use egui_phosphor_icons::icons;
|
|
|
|
use crate::history::spawn_with_history;
|
|
use crate::scene_io::{SceneIo, SceneIoRequest};
|
|
use crate::state::{EditorMode, PlayPaused, PlayPossession};
|
|
use crate::ui::UiState;
|
|
use crate::viewport::brush_tool::start_draw_brush_tool;
|
|
use crate::viewport::{editor_spawn_ground_position, snap_translation, ViewportSettings};
|
|
use shared::PrimitiveShape;
|
|
|
|
use super::helpers::{
|
|
light_snapshot, primitive_snapshot, toggle_play_mode, toggle_play_paused, toggle_possession,
|
|
};
|
|
use super::widgets::{icon_button, panel_toolbar_row, toolbar_separator, transport_button_large};
|
|
|
|
/// Toolbar strip height (menu bar is separate).
|
|
const TOOLBAR_HEIGHT: f32 = 56.0;
|
|
const TRANSPORT_WIDTH: f32 = 152.0;
|
|
const TRANSPORT_SLOT_STEP: f32 = 54.0;
|
|
|
|
pub fn editor_toolbar_panel(world: &mut World, root_ui: &mut egui::Ui) {
|
|
egui::Panel::top("editor_toolbar")
|
|
.exact_size(TOOLBAR_HEIGHT)
|
|
.show_inside(root_ui, |ui| {
|
|
toolbar_ui(world, ui);
|
|
});
|
|
}
|
|
|
|
pub fn toolbar_ui(world: &mut World, ui: &mut egui::Ui) {
|
|
let (toolbar_rect, _) = ui.allocate_exact_size(
|
|
egui::vec2(ui.available_width(), TOOLBAR_HEIGHT - 4.0),
|
|
egui::Sense::hover(),
|
|
);
|
|
|
|
let center_y = toolbar_rect.center().y;
|
|
let left_rect = egui::Rect::from_min_max(
|
|
egui::pos2(toolbar_rect.left() + 8.0, center_y - 18.0),
|
|
egui::pos2(toolbar_rect.right(), center_y + 18.0),
|
|
);
|
|
let transport_rect = egui::Rect::from_center_size(
|
|
egui::pos2(toolbar_rect.center().x, center_y),
|
|
egui::vec2(TRANSPORT_WIDTH, 44.0),
|
|
);
|
|
|
|
let mut left_ui = ui.new_child(
|
|
egui::UiBuilder::new()
|
|
.id_salt("toolbar_left")
|
|
.max_rect(left_rect)
|
|
.layout(egui::Layout::left_to_right(egui::Align::Center)),
|
|
);
|
|
left_ui.spacing_mut().item_spacing.x = 6.0;
|
|
left_toolbar(world, &mut left_ui);
|
|
|
|
let mut transport_ui = ui.new_child(
|
|
egui::UiBuilder::new()
|
|
.id_salt("toolbar_transport")
|
|
.max_rect(transport_rect)
|
|
.layout(egui::Layout::left_to_right(egui::Align::Center)),
|
|
);
|
|
transport_ui.spacing_mut().item_spacing.x = 10.0;
|
|
transport_controls(world, &mut transport_ui);
|
|
}
|
|
|
|
fn left_toolbar(world: &mut World, ui: &mut egui::Ui) {
|
|
panel_toolbar_row(ui, |ui| {
|
|
if icon_button(ui, icons::CUBE, "Spawn cube").clicked() {
|
|
spawn_primitive_at_camera(world, PrimitiveShape::Box, "Cube");
|
|
}
|
|
if icon_button(ui, icons::MOUNTAINS, "Spawn ramp").clicked() {
|
|
spawn_primitive_at_camera(world, PrimitiveShape::Ramp, "Ramp");
|
|
}
|
|
if icon_button(ui, icons::SPHERE, "Spawn sphere").clicked() {
|
|
spawn_primitive_at_camera(world, PrimitiveShape::Sphere, "Sphere");
|
|
}
|
|
if icon_button(ui, icons::LIGHTBULB, "Spawn point light").clicked() {
|
|
let pos = camera_ground_spawn(world);
|
|
spawn_with_history(world, light_snapshot("Point Light", pos));
|
|
}
|
|
if icon_button(ui, icons::PENCIL_SIMPLE_LINE, "Draw brush (B)").clicked() {
|
|
start_draw_brush_tool(world);
|
|
}
|
|
|
|
toolbar_separator(ui);
|
|
|
|
if icon_button(ui, icons::FILE, "New scene").clicked() {
|
|
world.resource_mut::<SceneIo>().request = Some(SceneIoRequest::New);
|
|
}
|
|
if icon_button(ui, icons::FOLDER_OPEN, "Open scene").clicked() {
|
|
world.resource_mut::<SceneIo>().request = Some(SceneIoRequest::Open);
|
|
}
|
|
if icon_button(ui, icons::FLOPPY_DISK, "Save scene").clicked() {
|
|
world.resource_mut::<SceneIo>().request = Some(SceneIoRequest::Save);
|
|
}
|
|
if icon_button(ui, icons::COPY, "Save scene as").clicked() {
|
|
world.resource_mut::<SceneIo>().request = Some(SceneIoRequest::SaveAs);
|
|
}
|
|
});
|
|
}
|
|
|
|
fn transport_controls(world: &mut World, ui: &mut egui::Ui) {
|
|
let mode = *world.resource::<State<EditorMode>>().get();
|
|
match mode {
|
|
EditorMode::Editing => {
|
|
ui.add_space(TRANSPORT_SLOT_STEP);
|
|
let play_clicked = ui
|
|
.push_id("transport_center", |ui| {
|
|
transport_button_large(ui, icons::PLAY, "Play (F5)", true).clicked()
|
|
})
|
|
.inner;
|
|
if play_clicked {
|
|
toggle_play_mode(world);
|
|
}
|
|
}
|
|
EditorMode::Playing => {
|
|
let paused = world.resource::<PlayPaused>().0;
|
|
let pause_icon = if paused { icons::PLAY } else { icons::PAUSE };
|
|
let pause_tip = if paused {
|
|
"Resume simulation (F6)"
|
|
} else {
|
|
"Pause simulation (F6)"
|
|
};
|
|
let pause_clicked = ui
|
|
.push_id("transport_left", |ui| {
|
|
transport_button_large(ui, pause_icon, pause_tip, false).clicked()
|
|
})
|
|
.inner;
|
|
if pause_clicked {
|
|
toggle_play_paused(world);
|
|
}
|
|
let stop_clicked = ui
|
|
.push_id("transport_center", |ui| {
|
|
transport_button_large(ui, icons::STOP, "Stop and return to Edit (F5)", false)
|
|
.clicked()
|
|
})
|
|
.inner;
|
|
if stop_clicked {
|
|
toggle_play_mode(world);
|
|
}
|
|
|
|
let possession = *world.resource::<PlayPossession>();
|
|
let (eject_icon, eject_tip) = match possession {
|
|
PlayPossession::Possessed => (icons::SIGN_OUT, "Eject from player (F8)"),
|
|
PlayPossession::Ejected => (icons::USER, "Possess player (F8)"),
|
|
};
|
|
let possession_clicked = ui
|
|
.push_id("transport_right", |ui| {
|
|
transport_button_large(ui, eject_icon, eject_tip, false).clicked()
|
|
})
|
|
.inner;
|
|
if possession_clicked {
|
|
toggle_possession(world);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn camera_ground_spawn(world: &mut World) -> Vec3 {
|
|
let rect = world.resource::<UiState>().viewport_rect;
|
|
let settings = world.resource::<ViewportSettings>().clone();
|
|
let pos = editor_spawn_ground_position(world, rect);
|
|
snap_translation(pos, &settings)
|
|
}
|
|
|
|
fn spawn_primitive_at_camera(world: &mut World, shape: PrimitiveShape, name: &str) {
|
|
let pos = camera_ground_spawn(world);
|
|
spawn_with_history(world, primitive_snapshot(name, shape, pos));
|
|
}
|