236 lines
7.1 KiB
Rust
236 lines
7.1 KiB
Rust
use std::{path::PathBuf, sync::LazyLock};
|
|
|
|
use egui::ScrollArea;
|
|
|
|
mod editors;
|
|
mod explorer;
|
|
mod scene;
|
|
|
|
mod util;
|
|
|
|
use crate::{
|
|
editors::{
|
|
asset_editor::Asset, content_editor, note_editor, object_editor::ObjectInstance, tags::Tag,
|
|
template_editor::Template,
|
|
},
|
|
explorer::Explorer,
|
|
};
|
|
|
|
static VERSION: &str = "0.1.0";
|
|
static PROJECT_FOLDER: LazyLock<PathBuf> = LazyLock::new(|| {
|
|
let mut path = std::env::current_dir().unwrap();
|
|
path.push("project");
|
|
path
|
|
});
|
|
|
|
fn main() {
|
|
let app = Interface::new();
|
|
let options = eframe::NativeOptions {
|
|
viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 600.0]),
|
|
..Default::default()
|
|
};
|
|
|
|
let _ = eframe::run_native("Code Editor", options, Box::new(|_cc| Ok(Box::new(app))));
|
|
}
|
|
|
|
pub struct Interface {
|
|
// dialog: Option<egui_file::FileDialog>,
|
|
right_panel_content: RightPanelContent,
|
|
editor: content_editor::MainEditor,
|
|
scene: scene::EditorScene,
|
|
explorer: Explorer,
|
|
}
|
|
|
|
impl eframe::App for Interface {
|
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
|
egui_extras::install_image_loaders(ctx);
|
|
|
|
self.configure_appearance(ctx);
|
|
self.render_top_panel(ctx);
|
|
self.render_left_panel(ctx);
|
|
self.render_right_panel(ctx);
|
|
self.render_main_content(ctx);
|
|
}
|
|
}
|
|
|
|
pub enum RightPanelContent {
|
|
Template(Box<Template>),
|
|
Object(Box<ObjectInstance>),
|
|
Note(Box<note_editor::Note>),
|
|
Tag(Tag),
|
|
Asset(Box<Asset>),
|
|
None,
|
|
}
|
|
|
|
impl RightPanelContent {
|
|
fn template(template: Option<Template>) -> Self {
|
|
Self::Template(Box::new(template.unwrap_or_default()))
|
|
}
|
|
|
|
fn object(instance: Option<ObjectInstance>) -> Self {
|
|
Self::Object(Box::new(instance.unwrap_or_default()))
|
|
}
|
|
|
|
fn note(note: Option<note_editor::Note>) -> Self {
|
|
Self::Note(Box::new(note.unwrap_or_default()))
|
|
}
|
|
}
|
|
|
|
impl Interface {
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self {
|
|
right_panel_content: RightPanelContent::None,
|
|
editor: content_editor::MainEditor::new(),
|
|
scene: scene::EditorScene::new(),
|
|
explorer: Explorer::new(),
|
|
}
|
|
}
|
|
|
|
fn render_top_panel(&self, ctx: &egui::Context) {
|
|
// Top bar with actions
|
|
egui::TopBottomPanel::top("top").show(ctx, |ui| {
|
|
ui.horizontal(|ui| {
|
|
// title widget
|
|
ui.heading("WorldCoder");
|
|
ui.separator();
|
|
|
|
// version
|
|
ui.label(VERSION)
|
|
});
|
|
});
|
|
}
|
|
|
|
fn render_left_panel(&mut self, ctx: &egui::Context) {
|
|
// Left panel - File browser
|
|
egui::SidePanel::left("file_browser")
|
|
.resizable(true)
|
|
.default_width(250.0)
|
|
.show(ctx, |ui| {
|
|
ui.heading("Project Files");
|
|
ui.separator();
|
|
|
|
let mut to_load: Option<RightPanelContent> = None;
|
|
let mut load_doc: Option<content_editor::MainEditor> = None;
|
|
|
|
ScrollArea::vertical().show(ui, |ui| {
|
|
self.explorer.ui(&mut to_load, &mut load_doc, ui);
|
|
});
|
|
|
|
if let Some(to_load) = to_load {
|
|
self.right_panel_content = to_load;
|
|
}
|
|
|
|
if let Some(load_doc) = load_doc {
|
|
self.editor = load_doc;
|
|
self.editor.show_editor = true;
|
|
self.editor.show_preview = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
fn render_right_panel(&mut self, ctx: &egui::Context) {
|
|
// Main content area
|
|
egui::SidePanel::right("templates").show(ctx, |ui| {
|
|
let mut new_instance: Option<RightPanelContent> = None;
|
|
|
|
match &mut self.right_panel_content {
|
|
// an instance of a template
|
|
RightPanelContent::Object(object) => {
|
|
// load template from path
|
|
|
|
let mut right_panel = None;
|
|
|
|
let template = Template::load(&object.template_id).unwrap();
|
|
ScrollArea::vertical().show(ui, |ui| {
|
|
object.ui(
|
|
ui,
|
|
&template,
|
|
&mut right_panel,
|
|
&mut self.explorer.objects(),
|
|
);
|
|
});
|
|
|
|
if let Some(right_panel) = right_panel {
|
|
self.right_panel_content = right_panel;
|
|
}
|
|
}
|
|
|
|
// an editable template
|
|
RightPanelContent::Template(template) => {
|
|
template.ui(ui, &mut new_instance);
|
|
}
|
|
|
|
RightPanelContent::Note(note) => note.ui(ui),
|
|
|
|
RightPanelContent::Tag(tag) => tag.ui(ui),
|
|
|
|
RightPanelContent::Asset(asset) => asset.ui(ui),
|
|
|
|
RightPanelContent::None => {
|
|
ui.centered_and_justified(|ui| {
|
|
ui.label("No template loaded to edit.");
|
|
if ui.button("Back").clicked() {
|
|
self.right_panel_content = RightPanelContent::None;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
if let Some(new) = new_instance {
|
|
self.right_panel_content = new;
|
|
}
|
|
});
|
|
}
|
|
|
|
fn render_main_content(&mut self, ctx: &egui::Context) {
|
|
self.editor.ui(ctx);
|
|
self.scene.ui(ctx);
|
|
}
|
|
|
|
fn configure_appearance(&self, ctx: &egui::Context) {
|
|
let mut visuals = egui::Visuals::dark();
|
|
visuals.window_fill = egui::Color32::from_rgb(20, 20, 20);
|
|
visuals.panel_fill = egui::Color32::from_rgb(20, 20, 20);
|
|
visuals.widgets.inactive.fg_stroke =
|
|
egui::Stroke::from((2.0, egui::Color32::from_rgb(255, 255, 255)));
|
|
visuals.widgets.inactive.bg_stroke =
|
|
egui::Stroke::from((2.0, egui::Color32::from_rgb(60, 60, 60)));
|
|
visuals.widgets.inactive.corner_radius = egui::CornerRadius::from(4);
|
|
visuals.widgets.inactive.bg_fill = egui::Color32::from_rgb(20, 20, 20);
|
|
visuals.widgets.inactive.weak_bg_fill = egui::Color32::from_rgb(20, 20, 20);
|
|
visuals.widgets.inactive.expansion = 2.0;
|
|
|
|
ctx.set_visuals(visuals);
|
|
|
|
let mut fonts = egui::FontDefinitions::default();
|
|
|
|
fonts.font_data.insert(
|
|
"JetBrains Mono Nerd Font".to_string(),
|
|
std::sync::Arc::new(egui::FontData::from_static(include_bytes!(
|
|
"/usr/local/share/fonts/j/JetBrainsMonoNerdFont_Regular.ttf",
|
|
))),
|
|
);
|
|
|
|
fonts
|
|
.families
|
|
.entry(egui::FontFamily::Proportional)
|
|
.or_default()
|
|
.insert(0, "JetBrains Mono Nerd Font".to_string());
|
|
|
|
fonts
|
|
.families
|
|
.entry(egui::FontFamily::Monospace)
|
|
.or_default()
|
|
.insert(0, "JetBrains Mono Nerd Font".to_string());
|
|
|
|
ctx.set_fonts(fonts);
|
|
}
|
|
}
|
|
|
|
impl Default for Interface {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|