progress
This commit is contained in:
+119
-144
@@ -1,20 +1,22 @@
|
||||
use std::{fs, path::PathBuf, sync::LazyLock};
|
||||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
use egui::{RichText, ScrollArea};
|
||||
use egui::ScrollArea;
|
||||
|
||||
mod error;
|
||||
mod editors;
|
||||
mod explorer;
|
||||
mod main_editor;
|
||||
mod note;
|
||||
mod object;
|
||||
mod scene;
|
||||
mod template;
|
||||
use egui_file::DialogType;
|
||||
use object::ObjectInstance;
|
||||
use template::{FieldType, Template};
|
||||
|
||||
use crate::{explorer::Explorer, main_editor::MainEditor, note::Note};
|
||||
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");
|
||||
@@ -23,7 +25,6 @@ static PROJECT_FOLDER: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
|
||||
fn main() {
|
||||
let app = Interface::new();
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 600.0]),
|
||||
..Default::default()
|
||||
@@ -33,111 +34,74 @@ fn main() {
|
||||
}
|
||||
|
||||
pub struct Interface {
|
||||
dialog: Option<egui_file::FileDialog>,
|
||||
// dialog: Option<egui_file::FileDialog>,
|
||||
right_panel_content: RightPanelContent,
|
||||
editor: main_editor::MainEditor,
|
||||
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 {
|
||||
dialog: None,
|
||||
right_panel_content: RightPanelContent::None,
|
||||
editor: main_editor::MainEditor::new(),
|
||||
editor: content_editor::MainEditor::new(),
|
||||
scene: scene::EditorScene::new(),
|
||||
explorer: Explorer::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Interface {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// /home/zxq5/Pictures/logos and pfps/YT profile picture background.png
|
||||
|
||||
impl eframe::App for Interface {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui_extras::install_image_loaders(ctx);
|
||||
|
||||
{
|
||||
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);
|
||||
ctx.set_visuals(visuals);
|
||||
}
|
||||
|
||||
if let Some(dialog) = &mut self.dialog {
|
||||
if dialog.show(ctx).selected() {
|
||||
if let Some(path) = dialog.path() {
|
||||
if dialog.dialog_type() == DialogType::OpenFile {
|
||||
// Handle file dialog for loading templates/instances
|
||||
if let Ok(object) =
|
||||
ObjectInstance::load(path.file_stem().unwrap().to_str().unwrap())
|
||||
{
|
||||
// Instance
|
||||
self.right_panel_content = RightPanelContent::instance(Some(object));
|
||||
self.dialog = None;
|
||||
} else if let Ok(template) =
|
||||
Template::load(path.file_stem().unwrap().to_str().unwrap())
|
||||
{
|
||||
// Template
|
||||
self.right_panel_content = RightPanelContent::template(Some(template));
|
||||
self.dialog = None;
|
||||
}
|
||||
} else if dialog.dialog_type() == DialogType::SaveFile {
|
||||
// Handle file dialog for saving templates/instances
|
||||
if let RightPanelContent::Template { template, .. } =
|
||||
&mut self.right_panel_content
|
||||
{
|
||||
// set the save location and save
|
||||
if template.save().is_err() {
|
||||
eprintln!("Failed to save template");
|
||||
} else {
|
||||
self.dialog = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_top_panel(&self, ctx: &egui::Context) {
|
||||
// Top bar with actions
|
||||
egui::TopBottomPanel::top("top").show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
// Open Markdown Editor button
|
||||
if ui.button("📝 Open Editor").clicked() {
|
||||
self.editor.show_editor = true;
|
||||
}
|
||||
|
||||
// title widget
|
||||
ui.heading("WorldCoder");
|
||||
ui.separator();
|
||||
|
||||
// create new template
|
||||
if ui.button("New Template").clicked() {
|
||||
self.right_panel_content = RightPanelContent::Template {
|
||||
template: Box::new(Template::default()),
|
||||
new_field_name: String::new(),
|
||||
new_field_type: FieldType::SingleLine,
|
||||
new_field_required: false,
|
||||
new_field_description: String::new(),
|
||||
};
|
||||
}
|
||||
|
||||
// load instance or template from file
|
||||
if ui.button("Load Template/Instance").clicked() {
|
||||
self.dialog = Some(egui_file::FileDialog::open_file(Some(
|
||||
PROJECT_FOLDER.clone(),
|
||||
)));
|
||||
self.dialog.as_mut().unwrap().open();
|
||||
}
|
||||
// version
|
||||
ui.label(VERSION)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn render_left_panel(&mut self, ctx: &egui::Context) {
|
||||
// Left panel - File browser
|
||||
egui::SidePanel::left("file_browser")
|
||||
.resizable(true)
|
||||
@@ -147,7 +111,7 @@ impl eframe::App for Interface {
|
||||
ui.separator();
|
||||
|
||||
let mut to_load: Option<RightPanelContent> = None;
|
||||
let mut load_doc: Option<MainEditor> = 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);
|
||||
@@ -163,21 +127,28 @@ impl eframe::App for Interface {
|
||||
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 } => {
|
||||
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);
|
||||
object.ui(
|
||||
ui,
|
||||
&template,
|
||||
&mut right_panel,
|
||||
&mut self.explorer.objects(),
|
||||
);
|
||||
});
|
||||
|
||||
if let Some(right_panel) = right_panel {
|
||||
@@ -186,22 +157,15 @@ impl eframe::App for Interface {
|
||||
}
|
||||
|
||||
// an editable template
|
||||
RightPanelContent::Template {
|
||||
template,
|
||||
new_field_name,
|
||||
new_field_type,
|
||||
new_field_required,
|
||||
new_field_description,
|
||||
} => template.ui(
|
||||
ui,
|
||||
&mut new_instance,
|
||||
new_field_name,
|
||||
new_field_type,
|
||||
new_field_required,
|
||||
new_field_description,
|
||||
),
|
||||
RightPanelContent::Template(template) => {
|
||||
template.ui(ui, &mut new_instance);
|
||||
}
|
||||
|
||||
RightPanelContent::Note { note } => note.ui(ui),
|
||||
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| {
|
||||
@@ -217,44 +181,55 @@ impl eframe::App for Interface {
|
||||
self.right_panel_content = new;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn render_main_content(&mut self, ctx: &egui::Context) {
|
||||
self.editor.ui(ctx);
|
||||
self.scene.ui(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RightPanelContent {
|
||||
Template {
|
||||
template: Box<Template>,
|
||||
// fields to edit
|
||||
new_field_name: String,
|
||||
new_field_type: FieldType,
|
||||
new_field_required: bool,
|
||||
new_field_description: String,
|
||||
},
|
||||
Object {
|
||||
object: Box<ObjectInstance>,
|
||||
},
|
||||
Note {
|
||||
note: Box<Note>,
|
||||
},
|
||||
None,
|
||||
}
|
||||
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;
|
||||
|
||||
impl RightPanelContent {
|
||||
fn template(template: Option<Template>) -> Self {
|
||||
Self::Template {
|
||||
template: Box::new(template.unwrap_or_default()),
|
||||
new_field_name: String::new(),
|
||||
new_field_type: FieldType::SingleLine,
|
||||
new_field_required: false,
|
||||
new_field_description: String::new(),
|
||||
}
|
||||
}
|
||||
ctx.set_visuals(visuals);
|
||||
|
||||
fn instance(instance: Option<ObjectInstance>) -> Self {
|
||||
Self::Object {
|
||||
object: Box::new(instance.unwrap_or_default()),
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user