voxel-zone/app/src/systems/ui/ui_spawner.rs

143 lines
4.1 KiB
Rust

use bevy_egui::{EguiContext, EguiContexts};
use common::space::{
level_tile::LevelTile, three_dimensional::hash_map_container::VoxelHashMapLayer,
two_dimensional::depth_tiles::DepthTileContainer,
};
use egui::Ui;
use std::{collections::VecDeque, fmt::Display, future::Future};
use bevy::prelude::*;
use super::{super::generic_command_queue::CommandQueue};
pub fn ui_spawner(
mut spawner_commands: ResMut<CommandQueue<UiSpawnerCommand>>,
mut state: ResMut<UiSpawnerState>,
mut egui_context: EguiContexts,
) {
for command in spawner_commands.get_commands() {
match command {
UiSpawnerCommand::CreateElement(e) => {
state.elements.push(e)
},
}
}
// remove elements that aren't open
state.elements.retain(|e| e.is_open());
for element in &mut state.elements {
element.display(egui_context.ctx_mut());
}
}
pub enum UiSpawnerCommand {
CreateElement(Box<dyn SpawnedUiElement + Send + Sync>)
}
pub struct EditorPopup {
pub title: String,
pub data: String,
pub open: bool,
}
pub trait SpawnedUiElement {
fn display(&mut self, egui_context: &egui::Context);
fn is_open(&self) -> bool;
}
pub struct MessageBox<T> {
title: String,
body: String,
buttons: Vec<T>,
onclick_sender: async_channel::Sender<T>,
open: bool,
dismiss_on_click: bool,
}
impl<T> SpawnedUiElement for MessageBox<T> where T: Display + Clone {
fn display(&mut self, egui_context: &egui::Context) {
let mut should_close = false;
egui::Window::new(&self.title)
.open(&mut self.open)
.show(egui_context, |ui| {
ui.label(&self.body);
ui.horizontal(|ui| {
for button in self.buttons.iter() {
if ui.button(button.to_string()).clicked() {
self.onclick_sender.try_send(button.clone());
if self.dismiss_on_click {
self.onclick_sender.close();
should_close = true;
}
}
}
});
});
if should_close {
self.open = false;
}
}
fn is_open(&self) -> bool {
self.open
}
}
impl SpawnedUiElement for EditorPopup {
fn display(&mut self, egui_context: &egui::Context) {
// let mut layouter = |ui: &egui::Ui, string: &str, wrap_width: f32| {
// let mut layout_job =
// syntax_highlighting::highlight(ui.ctx(), &CodeTheme::dark(), string, "toml");
// layout_job.wrap.max_width = wrap_width;
// ui.fonts().layout_job(layout_job)
// };
// new: but not hooked up
// let mut theme = egui_extras::syntax_highlighting::CodeTheme::from_memory(ui.ctx());
egui::Window::new(&self.title)
.open(&mut self.open)
.show(egui_context, |ui|{
egui::ScrollArea::vertical().show(ui, |ui|{
ui.add(egui::TextEdit::multiline(&mut self.data)
.font(egui::TextStyle::Monospace)
.code_editor()
.desired_rows(20)
.lock_focus(true)
.desired_width(400.0)
// .layouter(&mut layouter)
)
});
});
}
fn is_open(&self) -> bool {
self.open
}
}
pub fn build_message_box_command<TButton> (title: String, body: String, buttons: Vec<TButton>, dismiss_on_click: bool) -> (UiSpawnerCommand, async_channel::Receiver<TButton>)
where TButton: Display + Send + Sync + Clone + 'static {
let (onclick_sender, onclick_recv) = async_channel::bounded(1);
let mb = MessageBox{
title,
body,
buttons: buttons,
onclick_sender,
open: true,
dismiss_on_click
};
(build_command(mb), onclick_recv)
}
pub fn build_command<T> (element: T) -> UiSpawnerCommand
where T: SpawnedUiElement + Send + Sync + 'static {
UiSpawnerCommand::CreateElement(Box::new(element))
}
#[derive(Default, Resource)]
pub struct UiSpawnerState {
elements: Vec<Box<dyn SpawnedUiElement + Send + Sync>>
}