init
This commit is contained in:
parent
87e49cae9c
commit
08358ef968
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -311,9 +311,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.19.0"
|
version = "1.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
@ -665,6 +665,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
|||||||
name = "element_bridge"
|
name = "element_bridge"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"flume",
|
"flume",
|
||||||
"makepad-widgets",
|
"makepad-widgets",
|
||||||
"mp_elements",
|
"mp_elements",
|
||||||
@ -1712,9 +1713,11 @@ name = "mp"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"bytemuck",
|
||||||
"element_bridge",
|
"element_bridge",
|
||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
|
"image",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log",
|
"log",
|
||||||
"makepad-widgets",
|
"makepad-widgets",
|
||||||
@ -1764,6 +1767,7 @@ dependencies = [
|
|||||||
"quick_cache",
|
"quick_cache",
|
||||||
"regex",
|
"regex",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
|
"thiserror 2.0.3",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -9,3 +9,4 @@ makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik",
|
|||||||
flume = "0.11.1"
|
flume = "0.11.1"
|
||||||
wgpu = "23.0.0"
|
wgpu = "23.0.0"
|
||||||
tokio = { version = "1.41.1", features = ["sync"] }
|
tokio = { version = "1.41.1", features = ["sync"] }
|
||||||
|
bytemuck = "1.20.0"
|
||||||
|
|||||||
@ -9,26 +9,18 @@ pub use mp_elements::app::Window;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TextureBridge {
|
pub struct TextureBridge {
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
_buffer: Arc<tokio::sync::Mutex<Vec<u8>>>,
|
|
||||||
window: Arc<RenderWindow>,
|
window: Arc<RenderWindow>,
|
||||||
_texture: Texture,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureBridge {
|
impl TextureBridge {
|
||||||
pub fn new(texture: Texture, app: &App, window: Window) -> Self {
|
pub fn new(app: &App, window: Window) -> Self {
|
||||||
let window = app.create_window(window);
|
let window = app.create_window(window);
|
||||||
Self {
|
Self {
|
||||||
dirty: true,
|
dirty: true,
|
||||||
_buffer: Arc::new(tokio::sync::Mutex::new(vec![0u8; 256 * 256 * 4])),
|
|
||||||
window: Arc::new(window),
|
window: Arc::new(window),
|
||||||
_texture: texture,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture(&self) -> &Texture {
|
|
||||||
&self._texture
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn window(&self) -> &RenderWindow {
|
pub fn window(&self) -> &RenderWindow {
|
||||||
&self.window
|
&self.window
|
||||||
}
|
}
|
||||||
@ -41,7 +33,7 @@ impl TextureBridge {
|
|||||||
app.draw(&self.window, draw_list).await;
|
app.draw(&self.window, draw_list).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_data(buffer: &mut Vec<u8>, ctx: &Ctx, render_window: &RenderWindow) {
|
pub async fn load_data(ctx: &Ctx, render_window: &RenderWindow) -> Vec<f32> {
|
||||||
let output = &render_window.output().output_buffer;
|
let output = &render_window.output().output_buffer;
|
||||||
|
|
||||||
let (sender, receiver) = flume::bounded(1);
|
let (sender, receiver) = flume::bounded(1);
|
||||||
@ -52,18 +44,14 @@ impl TextureBridge {
|
|||||||
device.poll(wgpu::Maintain::wait()).panic_on_timeout();
|
device.poll(wgpu::Maintain::wait()).panic_on_timeout();
|
||||||
receiver.recv_async().await.unwrap().unwrap();
|
receiver.recv_async().await.unwrap().unwrap();
|
||||||
|
|
||||||
{
|
let result = {
|
||||||
let view = slice.get_mapped_range();
|
let view = slice.get_mapped_range();
|
||||||
buffer.copy_from_slice(&view[..]);
|
|
||||||
}
|
let new_vec: Vec<f32> = bytemuck::cast_slice(&view[..]).to_vec();
|
||||||
|
new_vec
|
||||||
|
};
|
||||||
output.unmap();
|
output.unmap();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_texture(&self, cx: &mut Cx, buffer: Vec<u8>) {
|
result
|
||||||
self._texture.put_back_vec_u8(cx, buffer, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer(&self) -> Arc<tokio::sync::Mutex<Vec<u8>>> {
|
|
||||||
self._buffer.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,3 +21,5 @@ futures = "0.3.31"
|
|||||||
async-trait = "0.1.83"
|
async-trait = "0.1.83"
|
||||||
thiserror = "2.0.3"
|
thiserror = "2.0.3"
|
||||||
indexmap = "2.6.0"
|
indexmap = "2.6.0"
|
||||||
|
image = "0.25.5"
|
||||||
|
bytemuck = "1.20.0"
|
||||||
|
|||||||
203
mp/src/app.rs
203
mp/src/app.rs
@ -1,26 +1,22 @@
|
|||||||
use crate::file::*;
|
use crate::file::*;
|
||||||
use crate::menu::{handle_menu, spawn_background};
|
use crate::menu::handle_menu;
|
||||||
use crate::widgets::area::TAreaWidgetRefExt;
|
use crate::selector::SelectorModalAction;
|
||||||
use crate::widgets::selector::{
|
use crate::task_register::{BridgeManager, ConfigManager, TaskConfig, TaskManager};
|
||||||
ItemKey, ItemValue, SelectorListWidgetRefExt, SelectorWidgetRefExt,
|
use crate::widgets::area::{TAreaAction, TAreaWidgetRefExt};
|
||||||
};
|
use crate::widgets::loading::{self, LoadingModalWidgetRefExt};
|
||||||
|
use crate::windows_manager::{WindowId, WindowsManager};
|
||||||
use crate::windows_manager::WM;
|
use crate::PLUGIN_MANAGER;
|
||||||
use crate::{render_task::RenderTasks, PLUGIN_MANAGER, RUNTIME};
|
|
||||||
use ::log::info;
|
use ::log::info;
|
||||||
use element_bridge::TextureBridge;
|
|
||||||
use makepad_widgets::makepad_micro_serde::*;
|
|
||||||
use makepad_widgets::*;
|
use makepad_widgets::*;
|
||||||
use mp_elements::app::DrawList as DW;
|
use mp_elements::app::DrawList as DW;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
live_design! {
|
live_design! {
|
||||||
import makepad_widgets::base::*;
|
import makepad_widgets::base::*;
|
||||||
import makepad_widgets::theme_desktop_dark::*;
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
import crate::app_ui::MainView;
|
import crate::app_ui::MainView;
|
||||||
import crate::widgets::selector::*;
|
import crate::selector::SelectorBase;
|
||||||
|
import crate::widgets::loading::*;
|
||||||
|
|
||||||
HELLO = "Hello, World!";
|
HELLO = "Hello, World!";
|
||||||
|
|
||||||
@ -62,7 +58,13 @@ live_design! {
|
|||||||
height: 470
|
height: 470
|
||||||
width:650
|
width:650
|
||||||
show_bg: false
|
show_bg: false
|
||||||
selector = <Selector> {}
|
selector = <SelectorBase> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loading_modal = <Modal> {
|
||||||
|
content: {
|
||||||
|
inner_loading = <LoadingModal> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,15 +146,12 @@ pub enum AppAction {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppAction {
|
|
||||||
pub fn register_task(id: usize, bridge: Arc<TextureBridge>, draw_list: DW) -> AppAction {
|
|
||||||
AppAction::Task(TaskAction::Register(id, bridge, draw_list))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TaskAction {
|
pub enum TaskAction {
|
||||||
Register(usize, Arc<TextureBridge>, DW),
|
Register {
|
||||||
|
draw_list: DW,
|
||||||
|
configs: Vec<Option<TaskConfig>>,
|
||||||
|
},
|
||||||
Unregister(),
|
Unregister(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,20 +161,33 @@ pub enum FileAction {
|
|||||||
OpenFolder(PathBuf),
|
OpenFolder(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WindowState {
|
||||||
|
pub all_windows_num: usize,
|
||||||
|
pub current_focus: Option<WindowId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct AppState {
|
||||||
|
pub window_state: WindowState,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Live, LiveHook)]
|
#[derive(Live, LiveHook)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
#[live]
|
#[live]
|
||||||
ui: WidgetRef,
|
ui: WidgetRef,
|
||||||
#[rust]
|
#[rust]
|
||||||
pub render_tasks: Arc<Mutex<RenderTasks>>,
|
task_manager: TaskManager,
|
||||||
#[rust]
|
#[rust]
|
||||||
windows_manager: WM,
|
windows_manager: WindowsManager,
|
||||||
#[rust]
|
#[rust]
|
||||||
tex_reciver: ToUIReceiver<Vec<u8>>,
|
bridge_manager: BridgeManager,
|
||||||
|
|
||||||
#[rust]
|
#[rust]
|
||||||
file_manager: FileManager,
|
file_manager: FileManager,
|
||||||
|
#[rust]
|
||||||
|
config_manager: ConfigManager,
|
||||||
|
#[rust]
|
||||||
|
app_state: AppState,
|
||||||
#[rust]
|
#[rust]
|
||||||
timer: Timer,
|
timer: Timer,
|
||||||
}
|
}
|
||||||
@ -188,56 +200,45 @@ impl LiveRegister for App {
|
|||||||
crate::widgets::renderer::live_design(_cx);
|
crate::widgets::renderer::live_design(_cx);
|
||||||
crate::widgets::background_text::live_design(_cx);
|
crate::widgets::background_text::live_design(_cx);
|
||||||
crate::widgets::selector::live_design(_cx);
|
crate::widgets::selector::live_design(_cx);
|
||||||
|
crate::widgets::loading::live_design(_cx);
|
||||||
|
crate::selector::live_design(_cx);
|
||||||
|
crate::widgets::element_panels::live_design(_cx);
|
||||||
|
crate::sidepanel::live_design(_cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SerRon, DeRon)]
|
|
||||||
struct AppStateRon {
|
|
||||||
slide: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MatchEvent for App {
|
impl MatchEvent for App {
|
||||||
// Start UP
|
// Start UP
|
||||||
fn handle_startup(&mut self, cx: &mut Cx) {
|
fn handle_startup(&mut self, cx: &mut Cx) {
|
||||||
info!("Starting up......");
|
info!("Starting up......");
|
||||||
let ui = self.ui.clone();
|
let ui = self.ui.clone();
|
||||||
|
|
||||||
|
// New Area init
|
||||||
let area = ui.tarea(id!(quad));
|
let area = ui.tarea(id!(quad));
|
||||||
area.set_windows(self.windows_manager.clone());
|
let id = self.windows_manager.add_window(area.clone());
|
||||||
// Listening to the render tasks
|
area.set_id(id.clone());
|
||||||
let render_tasks = self.render_tasks.clone();
|
|
||||||
RUNTIME.spawn(async move {
|
|
||||||
let render_task = render_tasks.lock().await;
|
|
||||||
render_task.render().await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let items = vec![(
|
// Default Focus
|
||||||
ItemKey {
|
self.app_state.window_state.current_focus = Some(id.clone());
|
||||||
path: "path".to_string(),
|
|
||||||
category: "category".to_string(),
|
|
||||||
description: "description_1".to_string(),
|
|
||||||
},
|
|
||||||
vec![
|
|
||||||
ItemValue {
|
|
||||||
name: "Item 1".to_string(),
|
|
||||||
icon: "icon_radar.svg".to_string(),
|
|
||||||
},
|
|
||||||
ItemValue {
|
|
||||||
name: "Item 2".to_string(),
|
|
||||||
icon: "icon_threed.svg".to_string(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)];
|
|
||||||
|
|
||||||
ui.selector(id!(selector)).set_items(cx, items);
|
// Default Bridge for Primary Renderer
|
||||||
|
self.bridge_manager.new_bridge(id);
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
self.task_manager.set_sender(self.windows_manager.sender());
|
||||||
|
|
||||||
|
info!("Rendering pipelines......");
|
||||||
|
self.task_manager.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_signal(&mut self, cx: &mut Cx) {
|
fn handle_signal(&mut self, cx: &mut Cx) {
|
||||||
self.file_manager.try_deal_file(&self.ui, cx);
|
self.file_manager.try_deal_file(&self.ui, cx);
|
||||||
|
self.windows_manager
|
||||||
|
.try_deal_render_result(cx, &self.bridge_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
||||||
let ui = self.ui.clone();
|
let ui = self.ui.clone();
|
||||||
|
|
||||||
if ui.button(id!(start)).clicked(actions) {
|
if ui.button(id!(start)).clicked(actions) {
|
||||||
cx.action(AppAction::OpenFile);
|
cx.action(AppAction::OpenFile);
|
||||||
}
|
}
|
||||||
@ -274,17 +275,37 @@ impl MatchEvent for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppAction::Task(task) => match task {
|
AppAction::Task(task) => match task {
|
||||||
TaskAction::Register(bridge_id, bridge, draw_list) => {
|
TaskAction::Register { draw_list, configs } => {
|
||||||
info!(
|
info!("Register Task for draw_list");
|
||||||
"Register Task for {:?}, draw_list: {:?}",
|
let current_window = &self.app_state.window_state.current_focus;
|
||||||
bridge_id, draw_list
|
if let Some(window) = current_window.as_ref() {
|
||||||
);
|
let bridge = self
|
||||||
let bridge = bridge.render_window();
|
.bridge_manager
|
||||||
let sender = self.tex_reciver.sender();
|
.get_bridge(window)
|
||||||
RUNTIME.block_on(async {
|
.expect("Bridge not found");
|
||||||
let mut render_tasks = self.render_tasks.lock().await;
|
|
||||||
render_tasks.register_task(sender, bridge_id, bridge, draw_list);
|
let render_window = bridge.render_window();
|
||||||
});
|
|
||||||
|
if let Ok(id) = self.task_manager.register_task_for_drawlist(
|
||||||
|
draw_list,
|
||||||
|
render_window,
|
||||||
|
configs.clone(),
|
||||||
|
) {
|
||||||
|
info!("Task Registered");
|
||||||
|
// Add Task Config to Config Manager
|
||||||
|
self.config_manager.register_config(id, configs);
|
||||||
|
|
||||||
|
// Create Net for the Task
|
||||||
|
self.bridge_manager.create_net(id, window.clone());
|
||||||
|
|
||||||
|
// Redraw the window
|
||||||
|
self.task_manager.redraw();
|
||||||
|
} else {
|
||||||
|
error!("Task Register Failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("No window found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction::Unregister() => {
|
TaskAction::Unregister() => {
|
||||||
@ -296,6 +317,13 @@ impl MatchEvent for App {
|
|||||||
FileAction::OpenFile(file) => {
|
FileAction::OpenFile(file) => {
|
||||||
info!("Open File: {:?}", file);
|
info!("Open File: {:?}", file);
|
||||||
self.file_manager.load_data(&file);
|
self.file_manager.load_data(&file);
|
||||||
|
|
||||||
|
let loading_modal = ui.modal(id!(loading_modal));
|
||||||
|
let inner_loading = loading_modal.loading_modal(id!(inner_loading));
|
||||||
|
|
||||||
|
inner_loading
|
||||||
|
.set_state(_cx, loading::LoadingModalState::BackwardsPaginateUntilEvent);
|
||||||
|
loading_modal.open(_cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAction::OpenFolder(folder) => {
|
FileAction::OpenFolder(folder) => {
|
||||||
@ -313,16 +341,47 @@ impl MatchEvent for App {
|
|||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match e.as_widget_action().cast() {
|
||||||
|
SelectorModalAction::Close => {
|
||||||
|
let selector_modal = ui.modal(id!(selector_modal));
|
||||||
|
selector_modal.close(_cx);
|
||||||
|
}
|
||||||
|
SelectorModalAction::RegisterTask {
|
||||||
|
elements,
|
||||||
|
data,
|
||||||
|
config,
|
||||||
|
} => {
|
||||||
|
if let Ok(draw_list) = self.task_manager.get_draw_list(&data, elements, &config) {
|
||||||
|
_cx.action(AppAction::Task(TaskAction::Register {
|
||||||
|
draw_list,
|
||||||
|
configs: config,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
error!("Draw List not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match e.as_widget_action().cast() {
|
||||||
|
TAreaAction::GetFocus(id) => {
|
||||||
|
info!("Get Focus: {:?}", id);
|
||||||
|
self.app_state.window_state.current_focus = Some(id);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppMain for App {
|
impl AppMain for App {
|
||||||
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
|
||||||
self.match_event(cx, event);
|
self.match_event(cx, event);
|
||||||
self.ui.handle_event(cx, event, &mut Scope::empty());
|
|
||||||
spawn_background(self, event);
|
|
||||||
handle_menu(cx, event);
|
|
||||||
|
|
||||||
|
let scope = &mut Scope::with_data(&mut self.app_state);
|
||||||
|
self.ui.handle_event(cx, event, scope);
|
||||||
|
|
||||||
|
handle_menu(cx, event);
|
||||||
self.timer.is_event(event).map(|_| {
|
self.timer.is_event(event).map(|_| {
|
||||||
let notifacion: PopupNotificationRef = self.ui.popup_notification(id!(notification));
|
let notifacion: PopupNotificationRef = self.ui.popup_notification(id!(notification));
|
||||||
notifacion.close(cx);
|
notifacion.close(cx);
|
||||||
@ -330,6 +389,4 @@ impl AppMain for App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {}
|
|
||||||
|
|
||||||
app_main!(App);
|
app_main!(App);
|
||||||
|
|||||||
113
mp/src/app_ui.rs
113
mp/src/app_ui.rs
@ -6,9 +6,9 @@ live_design! {
|
|||||||
import crate::widgets::renderer::IRenderer;
|
import crate::widgets::renderer::IRenderer;
|
||||||
|
|
||||||
import makepad_draw::shader::std::*;
|
import makepad_draw::shader::std::*;
|
||||||
import crate::widgets::selector_modal::*;
|
|
||||||
import crate::widgets::background_text::BackgroundLabel;
|
import crate::widgets::background_text::BackgroundLabel;
|
||||||
import crate::widgets::selector::*;
|
import crate::widgets::selector::*;
|
||||||
|
import crate::sidepanel::*;
|
||||||
|
|
||||||
HELLO = "Hello, World!";
|
HELLO = "Hello, World!";
|
||||||
|
|
||||||
@ -63,14 +63,7 @@ live_design! {
|
|||||||
y: 0.5
|
y: 0.5
|
||||||
},
|
},
|
||||||
|
|
||||||
<View> {
|
quad = <Area> {}
|
||||||
width: 600
|
|
||||||
height: 500
|
|
||||||
align: {
|
|
||||||
x: 0.5,
|
|
||||||
y: 0.5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,108 +76,10 @@ live_design! {
|
|||||||
Controller = <RectView> {
|
Controller = <RectView> {
|
||||||
draw_bg: { color: (THEME_COLOR_U_1) }
|
draw_bg: { color: (THEME_COLOR_U_1) }
|
||||||
height: Fill, width: Fill
|
height: Fill, width: Fill
|
||||||
padding: 10.,
|
// padding: 10.,
|
||||||
flow: Down,
|
flow: Down,
|
||||||
spacing: 15.,
|
spacing: 15.,
|
||||||
|
<SidePanel> {}
|
||||||
scroll_bars: <ScrollBars> {show_scroll_x: false, show_scroll_y: true}
|
|
||||||
|
|
||||||
<H4>{ text: "Controller"}
|
|
||||||
|
|
||||||
start = <Button> {
|
|
||||||
text: "Start"
|
|
||||||
width: Fill
|
|
||||||
}
|
|
||||||
|
|
||||||
<Group> {
|
|
||||||
<Slider> {
|
|
||||||
width: Fill,
|
|
||||||
height: 30,
|
|
||||||
draw_slider:{
|
|
||||||
slider_type: Horizontal
|
|
||||||
},
|
|
||||||
}
|
|
||||||
<Slider> {
|
|
||||||
width: Fill,
|
|
||||||
height: 30,
|
|
||||||
draw_slider:{
|
|
||||||
slider_type: Horizontal
|
|
||||||
},
|
|
||||||
}
|
|
||||||
<Slider> {
|
|
||||||
width: Fill,
|
|
||||||
height: 30,
|
|
||||||
draw_slider:{
|
|
||||||
slider_type: Horizontal
|
|
||||||
},
|
|
||||||
}
|
|
||||||
open_modal = <Button> {
|
|
||||||
text: "Click me"
|
|
||||||
width: Fill
|
|
||||||
}
|
|
||||||
<CheckBox> {text: "Check me"}
|
|
||||||
<DropDown>{
|
|
||||||
height: 24,
|
|
||||||
width: Fill,
|
|
||||||
labels: ["ValueOne", "ValueTwo","Thrice","FourthValue","OptionE","Hexagons"],
|
|
||||||
values: [ ValueOne,ValueTwo,Thrice,FourthValue,OptionE,Hexagons]
|
|
||||||
}
|
|
||||||
<Slider> {
|
|
||||||
width: Fill,
|
|
||||||
height: 30,
|
|
||||||
draw_slider:{
|
|
||||||
slider_type: Horizontal
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
<H4>{ text: "Input"}
|
|
||||||
|
|
||||||
|
|
||||||
<View>{
|
|
||||||
flow: Right
|
|
||||||
width: Fill
|
|
||||||
height: Fit
|
|
||||||
|
|
||||||
<BackgroundLabel>{
|
|
||||||
text: "Holy Shit",
|
|
||||||
}
|
|
||||||
|
|
||||||
<BackgroundLabel>{
|
|
||||||
text: "Holy Shit",
|
|
||||||
}
|
|
||||||
|
|
||||||
<BackgroundLabel>{
|
|
||||||
text: "Holy Shit",
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
<Group> {
|
|
||||||
|
|
||||||
<ButtonGroup> {
|
|
||||||
spacing: 10.,
|
|
||||||
<Button> {text: "One"}
|
|
||||||
<Button> {text: "Two"}
|
|
||||||
<Button> {text: "Three"}
|
|
||||||
}
|
|
||||||
<TextInput> {
|
|
||||||
width: Fill,
|
|
||||||
height: Fit,
|
|
||||||
text: "Text Input"
|
|
||||||
}
|
|
||||||
<TextFlowBase> {
|
|
||||||
width: Fill,
|
|
||||||
height: Fit,
|
|
||||||
<Text> {text: "Text Flow"}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::AppAction,
|
selector::SelectorBaseWidgetRefExt,
|
||||||
errors::AppErr,
|
widgets::selector::{ItemKey, ItemValue},
|
||||||
widgets::selector::{ItemKey, ItemValue, SelectorWidgetRefExt},
|
|
||||||
GIAPP, RUNTIME,
|
GIAPP, RUNTIME,
|
||||||
};
|
};
|
||||||
use ::log::info;
|
use ::log::info;
|
||||||
use makepad_widgets::*;
|
use makepad_widgets::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use makepad_widgets::{id, Cx, ToUIReceiver, ToUISender, WidgetRef};
|
use makepad_widgets::{id, Cx, ToUIReceiver, WidgetRef};
|
||||||
use mp_core::{datapool::Value, errors::DataError, Data};
|
use mp_core::{datapool::Value, errors::DataError, Data};
|
||||||
|
|
||||||
use crate::DATAPOOL;
|
use crate::DATAPOOL;
|
||||||
@ -45,17 +44,16 @@ impl FileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_deal_file(&mut self, ui: &WidgetRef, cx: &mut Cx) {
|
pub fn try_deal_file(&mut self, ui: &WidgetRef, cx: &mut Cx) {
|
||||||
let selector = ui.selector(id!(selector));
|
// let selector = ui.selector(id!(selector));
|
||||||
|
let selector = ui.selector_base(id!(selector));
|
||||||
let selector_modal = ui.modal(id!(selector_modal));
|
let selector_modal = ui.modal(id!(selector_modal));
|
||||||
|
|
||||||
|
let loading_modal = ui.modal(id!(loading_modal));
|
||||||
while let Ok(mut data) = self.receiver.try_recv() {
|
while let Ok(mut data) = self.receiver.try_recv() {
|
||||||
if data.len() == 1 {
|
if data.len() == 1 {
|
||||||
let (path, data) = data.pop().unwrap();
|
let (path, data) = data.pop().unwrap();
|
||||||
if let Ok(data) = data {
|
if let Ok(data) = data {
|
||||||
info!("Data: {:?}", data);
|
info!("Data: {:?}", data);
|
||||||
cx.action(AppAction::Notification {
|
|
||||||
message: format!("hello,World, {:?}", data),
|
|
||||||
duration: 3.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
|
|
||||||
@ -64,6 +62,7 @@ impl FileManager {
|
|||||||
let supported_elements = pipelines.supported_elements(&data);
|
let supported_elements = pipelines.supported_elements(&data);
|
||||||
|
|
||||||
let key_name = ItemKey {
|
let key_name = ItemKey {
|
||||||
|
data_idx: *idx,
|
||||||
path: "".to_string(),
|
path: "".to_string(),
|
||||||
category: data.description.clone(),
|
category: data.description.clone(),
|
||||||
description: data.description.clone(),
|
description: data.description.clone(),
|
||||||
@ -71,9 +70,14 @@ impl FileManager {
|
|||||||
|
|
||||||
let item_values = supported_elements
|
let item_values = supported_elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| ItemValue {
|
.map(|v| {
|
||||||
|
(
|
||||||
|
ItemValue {
|
||||||
name: v.name().to_string(),
|
name: v.name().to_string(),
|
||||||
icon: "".to_string(),
|
icon: "".to_string(),
|
||||||
|
},
|
||||||
|
v.clone(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@ -85,12 +89,13 @@ impl FileManager {
|
|||||||
.map(|v| v.to_string_lossy())
|
.map(|v| v.to_string_lossy())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
selector.set_items(cx, items);
|
selector.set_items(cx, data, &base_name, items);
|
||||||
selector.set_base_name(&base_name);
|
|
||||||
selector_modal.open(cx);
|
selector_modal.open(cx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loading_modal.close(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,9 @@ pub mod app_ui;
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
pub mod render_task;
|
pub mod selector;
|
||||||
|
pub mod sidepanel;
|
||||||
|
pub mod task_register;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
use mp_core::{config::Setting, datapool::DataPool, plugin_system::PluginManager};
|
use mp_core::{config::Setting, datapool::DataPool, plugin_system::PluginManager};
|
||||||
|
|||||||
@ -16,16 +16,16 @@ pub fn handle_menu(cx: &mut Cx, event: &Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_background(app: &mut App, event: &Event) {
|
// pub fn spawn_background(app: &mut App, event: &Event) {
|
||||||
match event {
|
// match event {
|
||||||
Event::Draw(_) => {
|
// Event::Draw(_) => {
|
||||||
// Render Task
|
// // Render Task
|
||||||
let tasks = app.render_tasks.clone();
|
// let tasks = app.render_tasks.clone();
|
||||||
RUNTIME.spawn(async move {
|
// RUNTIME.spawn(async move {
|
||||||
let tasks = tasks.lock().await;
|
// let tasks = tasks.lock().await;
|
||||||
tasks.render().await;
|
// tasks.render().await;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
_ => {}
|
// _ => {}
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -1,93 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
widgets::renderer,
|
|
||||||
windows_manager::{AllBuffers, WindowsManager},
|
|
||||||
GIAPP, RUNTIME,
|
|
||||||
};
|
|
||||||
use element_bridge::TextureBridge;
|
|
||||||
use futures::future::BoxFuture;
|
|
||||||
use log::info;
|
|
||||||
use makepad_widgets::{Cx, Texture, ToUISender};
|
|
||||||
use mp_elements::{
|
|
||||||
app::{DrawList, RenderWindow},
|
|
||||||
App,
|
|
||||||
};
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct RenderTasks {
|
|
||||||
pub(crate) tasks: Vec<RenderTask>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderTasks {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { tasks: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_task(&mut self, task: RenderTask) {
|
|
||||||
self.tasks.push(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_task(
|
|
||||||
&mut self,
|
|
||||||
sender: ToUISender<Vec<u8>>,
|
|
||||||
bridge_id: usize,
|
|
||||||
bridge: Arc<RenderWindow>,
|
|
||||||
draw_list: DrawList,
|
|
||||||
) {
|
|
||||||
let task = RenderTask::new(bridge_id, sender, bridge, draw_list);
|
|
||||||
self.push_task(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.tasks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn render(&self) {
|
|
||||||
// Draw all tasks
|
|
||||||
let futures: Vec<_> = self
|
|
||||||
.tasks
|
|
||||||
.iter()
|
|
||||||
.map(|task| async {
|
|
||||||
info!("Drawing task");
|
|
||||||
task.draw().await;
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
futures::future::join_all(futures).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RenderTask {
|
|
||||||
bridge_id: usize,
|
|
||||||
sender: ToUISender<Vec<u8>>,
|
|
||||||
buffer: Arc<Mutex<Vec<u8>>>,
|
|
||||||
render_window: Arc<RenderWindow>,
|
|
||||||
draw_list: DrawList,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderTask {
|
|
||||||
pub fn new(
|
|
||||||
bridge_id: usize,
|
|
||||||
sender: ToUISender<Vec<u8>>,
|
|
||||||
bridge_render_window: Arc<RenderWindow>,
|
|
||||||
draw_list: DrawList,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
bridge_id,
|
|
||||||
sender,
|
|
||||||
buffer: Arc::new(Mutex::new(vec![0u8; 256 * 256 * 4])),
|
|
||||||
render_window: bridge_render_window,
|
|
||||||
draw_list,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn draw(&self) {
|
|
||||||
GIAPP
|
|
||||||
.draw(&self.render_window, self.draw_list.clone())
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let ctx = GIAPP.ctx();
|
|
||||||
let mut bf = Vec::with_capacity(256 * 256 * 4);
|
|
||||||
TextureBridge::load_data(&mut bf, ctx, &self.render_window).await;
|
|
||||||
self.sender.send(bf).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
146
mp/src/selector.rs
Normal file
146
mp/src/selector.rs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
task_register::TaskConfig,
|
||||||
|
widgets::selector::{ItemKey, ItemValue, SelectorAction, SelectorWidgetRefExt},
|
||||||
|
CONFIG,
|
||||||
|
};
|
||||||
|
use ::log::info;
|
||||||
|
use makepad_widgets::*;
|
||||||
|
use mp_core::{Data, DataValue};
|
||||||
|
use mp_elements::elements::Elements;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
import crate::widgets::selector::Selector;
|
||||||
|
import makepad_widgets::base::*;
|
||||||
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
|
|
||||||
|
SelectorBase = {{SelectorBase}} {
|
||||||
|
<View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
show_bg: false
|
||||||
|
selector = <Selector> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct SelectorBase {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
data: Option<DataValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, DefaultNone)]
|
||||||
|
pub enum SelectorModalAction {
|
||||||
|
RegisterTask {
|
||||||
|
elements: Vec<Elements>,
|
||||||
|
data: Arc<Data>,
|
||||||
|
config: Vec<Option<TaskConfig>>,
|
||||||
|
},
|
||||||
|
Close,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for SelectorBase {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let modal_dismissed = actions
|
||||||
|
.iter()
|
||||||
|
.find(|a| matches!(a.downcast_ref(), Some(ModalAction::Dismissed)))
|
||||||
|
.is_some();
|
||||||
|
for action in actions {
|
||||||
|
match action.as_widget_action().cast() {
|
||||||
|
SelectorAction::Selected { element, key, item } => {
|
||||||
|
info!("Selected: {:?} {:?}", key, item);
|
||||||
|
log!("Registering Task ... ... ");
|
||||||
|
|
||||||
|
let data_idx = key.data_idx;
|
||||||
|
// Register the task
|
||||||
|
let data = self.data.as_ref().unwrap().get(data_idx).unwrap().clone();
|
||||||
|
|
||||||
|
let mut configs = Vec::new();
|
||||||
|
for ele in element.iter() {
|
||||||
|
match ele.init_config(&data, &CONFIG) {
|
||||||
|
Ok(config) => configs.push(Some(config)),
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Failed to init config for element: {:?}, cause of: {:?}",
|
||||||
|
ele, e
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.widget_action(
|
||||||
|
self.widget_uid(),
|
||||||
|
&scope.path,
|
||||||
|
SelectorModalAction::RegisterTask {
|
||||||
|
elements: element,
|
||||||
|
data: data,
|
||||||
|
config: configs,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Close the modal
|
||||||
|
if !modal_dismissed {
|
||||||
|
cx.widget_action(
|
||||||
|
self.widget_uid(),
|
||||||
|
&scope.path,
|
||||||
|
SelectorModalAction::Close,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for SelectorBase {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectorBase {
|
||||||
|
pub fn set_items(&mut self, cx: &mut Cx, items: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>) {
|
||||||
|
let selector = self.view.widget(id!(selector)).as_selector();
|
||||||
|
selector.set_items(cx, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_data(&mut self, data: DataValue) {
|
||||||
|
self.data = Some(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_base_name(&mut self, name: &str) {
|
||||||
|
let selector = self.view.widget(id!(selector)).as_selector();
|
||||||
|
|
||||||
|
selector.set_base_name(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectorBaseRef {
|
||||||
|
pub fn set_items(
|
||||||
|
&self,
|
||||||
|
cx: &mut Cx,
|
||||||
|
data: DataValue,
|
||||||
|
base_name: &str,
|
||||||
|
items: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>,
|
||||||
|
) {
|
||||||
|
if let Some(mut s) = self.borrow_mut() {
|
||||||
|
s.set_data(data);
|
||||||
|
s.set_items(cx, items);
|
||||||
|
s.set_base_name(base_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
mp/src/sidepanel.rs
Normal file
131
mp/src/sidepanel.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
import makepad_widgets::base::*;
|
||||||
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
|
import crate::widgets::element_panels::*;
|
||||||
|
|
||||||
|
SidePanel = {{SidePanel}}{
|
||||||
|
<View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
scroll_bars: <ScrollBars> {show_scroll_x: false, show_scroll_y: true}
|
||||||
|
|
||||||
|
flow: Down
|
||||||
|
|
||||||
|
start = <Button> {
|
||||||
|
text: "Start"
|
||||||
|
width: Fill
|
||||||
|
height: 30
|
||||||
|
margin: {top: 30, bottom: 30}
|
||||||
|
}
|
||||||
|
|
||||||
|
panel_dock = <Dock> {
|
||||||
|
|
||||||
|
width: Fill
|
||||||
|
height: Fill
|
||||||
|
|
||||||
|
root = Splitter {
|
||||||
|
axis: Vertical,
|
||||||
|
align: FromA(250.0),
|
||||||
|
a: common_tab,
|
||||||
|
b: element_tabs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
common_tab = Tab {
|
||||||
|
name: "Common"
|
||||||
|
kind: common
|
||||||
|
}
|
||||||
|
|
||||||
|
common = <View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
draw_bg: {
|
||||||
|
color: #f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element_tabs = Tabs {
|
||||||
|
tabs: [new_tab]
|
||||||
|
}
|
||||||
|
|
||||||
|
ppi_tab = Tab {
|
||||||
|
name: "PPI"
|
||||||
|
kind: ppi
|
||||||
|
}
|
||||||
|
|
||||||
|
new_tab = Tab {
|
||||||
|
name: "New"
|
||||||
|
kind: new
|
||||||
|
}
|
||||||
|
|
||||||
|
ppi = <PPIPanel> {}
|
||||||
|
|
||||||
|
new_element = <View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
draw_bg: {
|
||||||
|
color: #f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new = <View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
|
||||||
|
align: {x:0.5, y:0.5}
|
||||||
|
|
||||||
|
new_tab_button = <Button> {
|
||||||
|
text: "New"
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct SidePanel {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for SidePanel {
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
|
||||||
|
let dock = self.dock(id!(panel_dock));
|
||||||
|
self.match_event(cx, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchEvent for SidePanel {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
||||||
|
let new_tab_button = self.button(id!(new_tab_button));
|
||||||
|
let dock = self.dock(id!(panel_dock));
|
||||||
|
|
||||||
|
if new_tab_button.clicked(actions) {
|
||||||
|
let (tab_bar, pos) = dock.find_tab_bar_of_tab(live_id!(new_tab)).unwrap();
|
||||||
|
|
||||||
|
let result = dock.create_and_select_tab(
|
||||||
|
cx,
|
||||||
|
tab_bar,
|
||||||
|
live_id!(ppi),
|
||||||
|
live_id!(new_element),
|
||||||
|
"PPI".into(),
|
||||||
|
live_id!(CloseableTab),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
dock.close_tab(cx, live_id!(new_tab));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
246
mp/src/task_register.rs
Normal file
246
mp/src/task_register.rs
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
use futures::future::BoxFuture;
|
||||||
|
use log::info;
|
||||||
|
use makepad_widgets::ToUISender;
|
||||||
|
use std::{
|
||||||
|
any::Any,
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
use crate::{errors::AppErr, windows_manager::WindowId, GIAPP, RUNTIME};
|
||||||
|
use element_bridge::{TextureBridge, Window};
|
||||||
|
use mp_core::Data;
|
||||||
|
use mp_elements::{
|
||||||
|
app::{Ctx, DataBufferPool, DrawList, RenderWindow},
|
||||||
|
elements::Elements,
|
||||||
|
};
|
||||||
|
use std::{hash::Hash, sync::atomic::AtomicU64};
|
||||||
|
|
||||||
|
static TASK_ID: AtomicU64 = AtomicU64::new(0);
|
||||||
|
pub type TaskConfig = Arc<Mutex<dyn Any + Send + 'static>>;
|
||||||
|
type TaskList = Vec<BoxFuture<'static, ()>>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TaskManager {
|
||||||
|
req: Option<Sender<TaskList>>,
|
||||||
|
render_tasks: Vec<Arc<RenderTask>>,
|
||||||
|
sender: Option<ToUISender<(TaskId, Vec<f32>)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
req: None,
|
||||||
|
render_tasks: Vec::new(),
|
||||||
|
sender: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported_elements(&self, data: &Data) -> Vec<Elements> {
|
||||||
|
GIAPP.pipelines().supported_elements(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ctx(&self) -> &Ctx {
|
||||||
|
GIAPP.ctx()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buffer_pool(&self) -> &DataBufferPool {
|
||||||
|
GIAPP.buffer_pool()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sender(&mut self, sender: ToUISender<(TaskId, Vec<f32>)>) {
|
||||||
|
self.sender = Some(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_draw_list(
|
||||||
|
&self,
|
||||||
|
data: &Data,
|
||||||
|
element: Vec<Elements>,
|
||||||
|
configs: &Vec<Option<TaskConfig>>,
|
||||||
|
) -> Result<DrawList, AppErr> {
|
||||||
|
let ctx = self.ctx();
|
||||||
|
let buffer_pool = self.buffer_pool();
|
||||||
|
|
||||||
|
let mut draw_list = DrawList::new();
|
||||||
|
|
||||||
|
for (element, config) in element.into_iter().zip(configs.iter()) {
|
||||||
|
let attachment = if let Some(config) = config {
|
||||||
|
let config = config.lock().unwrap();
|
||||||
|
let config = &*config;
|
||||||
|
element.load_data(ctx, data, buffer_pool, Some(config))?
|
||||||
|
} else {
|
||||||
|
element.load_data(ctx, data, buffer_pool, None)?
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_list.push(element, Arc::new(attachment));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(draw_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redraw(&self) {
|
||||||
|
let sender = self.req.clone().unwrap();
|
||||||
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
|
for t in self.render_tasks.iter() {
|
||||||
|
let sender = self.sender.clone().unwrap();
|
||||||
|
let t = t.clone();
|
||||||
|
tasks.push(Box::pin(async move {
|
||||||
|
let buffer = t.buffer.clone();
|
||||||
|
let buffer = t.draw().await;
|
||||||
|
sender.send((t.id.clone(), buffer)).unwrap();
|
||||||
|
}) as BoxFuture<'static, ()>);
|
||||||
|
}
|
||||||
|
RUNTIME.spawn(async move {
|
||||||
|
sender.send(tasks).await.unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_task(&mut self, task: RenderTask) {
|
||||||
|
self.render_tasks.push(Arc::new(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_task(
|
||||||
|
&mut self,
|
||||||
|
render_window: Arc<RenderWindow>,
|
||||||
|
draw_list: DrawList,
|
||||||
|
config: Vec<Option<TaskConfig>>,
|
||||||
|
) -> TaskId {
|
||||||
|
let configs = {
|
||||||
|
let mut configs = HashMap::new();
|
||||||
|
for (idx, conf) in config.into_iter().enumerate() {
|
||||||
|
if let Some(p) = conf {
|
||||||
|
configs.insert(idx, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configs
|
||||||
|
};
|
||||||
|
let task = RenderTask::new(draw_list, render_window, configs);
|
||||||
|
let task_id = task.id.clone();
|
||||||
|
self.push_task(task);
|
||||||
|
|
||||||
|
task_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_task_for_drawlist(
|
||||||
|
&mut self,
|
||||||
|
draw_list: DrawList,
|
||||||
|
render_window: Arc<RenderWindow>,
|
||||||
|
config: Vec<Option<TaskConfig>>,
|
||||||
|
) -> Result<TaskId, AppErr> {
|
||||||
|
let id = self.register_task(render_window, draw_list, config);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
|
||||||
|
self.req = Some(tx);
|
||||||
|
|
||||||
|
RUNTIME.spawn(async move {
|
||||||
|
while let Some(tasks) = rx.recv().await {
|
||||||
|
futures::future::join_all(tasks).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct BridgeManager {
|
||||||
|
inner: HashMap<WindowId, TextureBridge>,
|
||||||
|
net: HashMap<TaskId, Vec<WindowId>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BridgeManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: HashMap::new(),
|
||||||
|
net: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bridge(&self, id: &WindowId) -> Option<&TextureBridge> {
|
||||||
|
self.inner.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bridge_mut(&mut self, id: &WindowId) -> Option<&mut TextureBridge> {
|
||||||
|
self.inner.get_mut(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_bridge(&mut self, id: WindowId) {
|
||||||
|
let bridge = TextureBridge::new(
|
||||||
|
&GIAPP,
|
||||||
|
// Default window size, MAX size
|
||||||
|
Window {
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.inner.insert(id, bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_net(&mut self, task_id: TaskId, window_id: WindowId) {
|
||||||
|
self.net
|
||||||
|
.entry(task_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(window_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_net(&self, task_id: &TaskId) -> Option<&Vec<WindowId>> {
|
||||||
|
self.net.get(task_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TaskId(u64);
|
||||||
|
impl TaskId {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(TASK_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RenderTask {
|
||||||
|
pub id: TaskId,
|
||||||
|
buffer: Arc<Mutex<Vec<u8>>>,
|
||||||
|
render_window: Arc<RenderWindow>,
|
||||||
|
configs: HashMap<usize, TaskConfig>,
|
||||||
|
draw_list: DrawList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderTask {
|
||||||
|
pub fn new(
|
||||||
|
draw_list: DrawList,
|
||||||
|
render_window: Arc<RenderWindow>,
|
||||||
|
config: HashMap<usize, Arc<Mutex<dyn Any + Send + 'static>>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id: TaskId::new(),
|
||||||
|
buffer: Arc::new(Mutex::new(vec![0u8; 1920 * 1080 * 4])),
|
||||||
|
configs: config,
|
||||||
|
render_window,
|
||||||
|
draw_list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn draw(&self) -> Vec<f32> {
|
||||||
|
GIAPP
|
||||||
|
.draw(&self.render_window, self.draw_list.clone())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let ctx = GIAPP.ctx();
|
||||||
|
// let buffer = self.buffer.clone();
|
||||||
|
let data = TextureBridge::load_data(ctx, &self.render_window).await;
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ConfigManager {
|
||||||
|
configs: HashMap<TaskId, Vec<Option<TaskConfig>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigManager {
|
||||||
|
pub fn register_config(&mut self, task_id: TaskId, config: Vec<Option<TaskConfig>>) {
|
||||||
|
self.configs.insert(task_id, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,31 +1,60 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use crate::windows_manager::WindowId;
|
use crate::windows_manager::WindowId;
|
||||||
use crate::windows_manager::WM;
|
use element_bridge::TextureBridge;
|
||||||
use crate::GIAPP;
|
|
||||||
use ::log::info;
|
|
||||||
use element_bridge::{TextureBridge, Window};
|
|
||||||
use makepad_widgets::makepad_derive_widget::*;
|
use makepad_widgets::makepad_derive_widget::*;
|
||||||
use makepad_widgets::makepad_draw::*;
|
use makepad_widgets::makepad_draw::*;
|
||||||
use makepad_widgets::widget::*;
|
use makepad_widgets::widget::*;
|
||||||
|
use makepad_widgets::Image;
|
||||||
|
use makepad_widgets::ImageWidgetRefExt;
|
||||||
|
use makepad_widgets::View;
|
||||||
use mp_elements::renderer::camera::Camera;
|
use mp_elements::renderer::camera::Camera;
|
||||||
use mp_elements::renderer::projection::Projection;
|
use mp_elements::renderer::projection::Projection;
|
||||||
|
|
||||||
live_design! {
|
live_design! {
|
||||||
Area = {{TArea}} {}
|
Area = {{TArea}} {
|
||||||
|
|
||||||
|
import makepad_draw::shader::std::*;
|
||||||
|
import makepad_widgets::base::*;
|
||||||
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
|
||||||
|
video_frame = <Image> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
fit: Biggest
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
uniform image_size: vec2
|
||||||
|
|
||||||
|
fn get_pixel(self, pos:vec2) -> vec4 {
|
||||||
|
let pix = self.pos * self.image_size;
|
||||||
|
let data = sample2d(self.image, pix).xyzw;
|
||||||
|
return vec4(data.x, data.y, data.z, 1,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
// return self.get_pixel(self.pos);
|
||||||
|
return vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Live, Widget)]
|
#[derive(Live, Widget)]
|
||||||
pub struct TArea {
|
pub struct TArea {
|
||||||
#[redraw]
|
#[deref]
|
||||||
#[live]
|
#[live]
|
||||||
draw: DrawQuad,
|
view: View,
|
||||||
#[walk]
|
|
||||||
walk: Walk,
|
|
||||||
#[layout]
|
|
||||||
layout: Layout,
|
|
||||||
#[live]
|
#[live]
|
||||||
id: String,
|
id: String,
|
||||||
#[live]
|
#[live]
|
||||||
@ -36,9 +65,16 @@ pub struct TArea {
|
|||||||
width_scale: f64,
|
width_scale: f64,
|
||||||
|
|
||||||
#[rust]
|
#[rust]
|
||||||
bridge: Option<Arc<Mutex<TextureBridge>>>,
|
window_id: Option<WindowId>,
|
||||||
|
|
||||||
#[rust]
|
#[rust]
|
||||||
windows: WM,
|
texture: Option<Texture>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, DefaultNone, Debug)]
|
||||||
|
pub enum TAreaAction {
|
||||||
|
GetFocus(WindowId),
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -81,25 +117,6 @@ impl TAreaState {
|
|||||||
pub fn resize(&mut self, width: f32, height: f32) {
|
pub fn resize(&mut self, width: f32, height: f32) {
|
||||||
self.projection.resize(width as u32, height as u32);
|
self.projection.resize(width as u32, height as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_bridge(&mut self, bridge: TextureBridge) {
|
|
||||||
self.bridge = Some(bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_bridge(&mut self, cx: &mut Cx, window: Window) {
|
|
||||||
let texture = Texture::new_with_format(
|
|
||||||
cx,
|
|
||||||
TextureFormat::VecRGBAf32 {
|
|
||||||
width: window.width as usize,
|
|
||||||
height: window.height as usize,
|
|
||||||
data: None,
|
|
||||||
updated: TextureUpdated::Full,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let bridge = TextureBridge::new(texture, &GIAPP, window);
|
|
||||||
self.bridge = Some(bridge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiveHook for TArea {}
|
impl LiveHook for TArea {}
|
||||||
@ -110,68 +127,73 @@ pub enum MyWidgetAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for TArea {
|
impl Widget for TArea {
|
||||||
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {}
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
match event.hits(cx, self.view.area()) {
|
||||||
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
|
Hit::FingerDown(_) => {
|
||||||
let rect = cx.peek_walk_turtle(walk);
|
cx.widget_action(
|
||||||
let current_size = rect.size;
|
self.widget_uid(),
|
||||||
|
&scope.path,
|
||||||
let current_texture = self.get_texture();
|
TAreaAction::GetFocus(self.window_id.clone().unwrap()),
|
||||||
// If the texture is not created or the size is different, recreate the texture
|
|
||||||
if current_texture.is_none()
|
|
||||||
|| current_texture
|
|
||||||
.unwrap()
|
|
||||||
.get_format(cx)
|
|
||||||
.vec_width_height()
|
|
||||||
.map(|(w, h)| (w as f64, h as f64))
|
|
||||||
!= Some((current_size.x, current_size.y))
|
|
||||||
{
|
|
||||||
let window_id = WindowId::new(&self.id);
|
|
||||||
let (width, height) = (current_size.x, current_size.y);
|
|
||||||
let dpi = cx.current_dpi_factor();
|
|
||||||
let window = Window {
|
|
||||||
height: height as u32,
|
|
||||||
width: width as u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Creating texture for window: {:?}", window_id);
|
|
||||||
let texture = Texture::new_with_format(
|
|
||||||
cx,
|
|
||||||
TextureFormat::VecRGBAf32 {
|
|
||||||
width: window.width as usize,
|
|
||||||
height: window.height as usize,
|
|
||||||
data: None,
|
|
||||||
updated: TextureUpdated::Full,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
let bridge = TextureBridge::new(texture, &GIAPP, window);
|
|
||||||
let mut windows = self.windows.wm();
|
|
||||||
let (_, bridge) = windows.add_window(window_id, bridge);
|
|
||||||
self.bridge = Some(bridge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw.draw_walk(cx, walk);
|
_ => {}
|
||||||
DrawStep::done()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TArea {
|
impl TArea {
|
||||||
fn get_texture(&self) -> Option<Texture> {
|
fn set_id(&mut self, id: WindowId) {
|
||||||
self.bridge
|
self.window_id = Some(id);
|
||||||
.as_ref()
|
|
||||||
.map(|bridge| bridge.lock().unwrap().texture().clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_windows(&mut self, windows: WM) {
|
fn set_texture(&mut self, cx: &mut Cx, texture: Texture) {
|
||||||
info!("Setting windows for area: {}", self.id);
|
self.texture = Some(texture);
|
||||||
self.windows = windows;
|
self.view
|
||||||
|
.widget(id!(video_frame))
|
||||||
|
.as_image()
|
||||||
|
.set_texture(cx, self.texture.clone());
|
||||||
|
self.view.widget(id!(video_frame)).as_image().set_uniform(
|
||||||
|
cx,
|
||||||
|
id!(image_size),
|
||||||
|
&[1920.0, 1080.0],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_texutre(&self) -> Option<Texture> {
|
||||||
|
self.texture.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TAreaRef {
|
impl TAreaRef {
|
||||||
pub fn set_windows(&self, windows: WM) {
|
pub fn set_id(&self, id: WindowId) {
|
||||||
if let Some(mut area) = self.borrow_mut() {
|
if let Some(mut s) = self.borrow_mut() {
|
||||||
area.set_windows(windows);
|
s.set_id(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_texture(&self, cx: &mut Cx, texture: Texture) {
|
||||||
|
if let Some(mut s) = self.borrow_mut() {
|
||||||
|
s.set_texture(cx, texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_texture(&self, cx: &mut Cx) {
|
||||||
|
if let Some(mut s) = self.borrow_mut() {
|
||||||
|
let texture = Texture::new(cx);
|
||||||
|
s.set_texture(cx, texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_texture(&self) -> Option<Texture> {
|
||||||
|
if let Some(s) = self.borrow() {
|
||||||
|
s.get_texutre()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
103
mp/src/widgets/element_panels.rs
Normal file
103
mp/src/widgets/element_panels.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use makepad_widgets::*;
|
||||||
|
use mp_elements::elements::ppi::PPIConfig;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
import makepad_widgets::base::*;
|
||||||
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
|
|
||||||
|
Group = <RoundedView> {
|
||||||
|
flow: Down
|
||||||
|
spacing: 10.
|
||||||
|
padding: 15.
|
||||||
|
height: Fit
|
||||||
|
width: Fill
|
||||||
|
draw_bg: {
|
||||||
|
instance border_width: 1.0
|
||||||
|
instance border_color: (THEME_COLOR_U_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PPIPanel = {{PPIPanel}}{
|
||||||
|
<View> {
|
||||||
|
height: Fill
|
||||||
|
width: Fill
|
||||||
|
flow: Down
|
||||||
|
padding: {left:10, right: 10}
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
<H4> {
|
||||||
|
text: "PPI Control"
|
||||||
|
}
|
||||||
|
|
||||||
|
<Group> {
|
||||||
|
|
||||||
|
<Button> {
|
||||||
|
width: Fill
|
||||||
|
text: "Add"
|
||||||
|
}
|
||||||
|
|
||||||
|
layer = <Slider> {
|
||||||
|
width: Fill
|
||||||
|
min: 0
|
||||||
|
max:1
|
||||||
|
step:0.01
|
||||||
|
text: "Scale"
|
||||||
|
}
|
||||||
|
|
||||||
|
<Slider> {
|
||||||
|
width: Fill
|
||||||
|
min: 0
|
||||||
|
max: 50
|
||||||
|
step: 1
|
||||||
|
text: "Size"
|
||||||
|
}
|
||||||
|
|
||||||
|
threed_switch = <CheckBox> {
|
||||||
|
text: "3d"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct PPIPanel {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
config: Arc<Mutex<PPIConfig>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for PPIPanel {
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
self.match_event(cx, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchEvent for PPIPanel {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
||||||
|
let threed = self.check_box(id!(threed_switch));
|
||||||
|
let mut config = self.config.lock().unwrap();
|
||||||
|
config.three_d = threed.selected(cx);
|
||||||
|
|
||||||
|
let layer = self.slider(id!(layer));
|
||||||
|
// config.layer = layer.value();
|
||||||
|
|
||||||
|
if layer.value() != Some(config.layer as f64) {
|
||||||
|
config.layer = layer.value().unwrap() as f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
264
mp/src/widgets/loading.rs
Normal file
264
mp/src/widgets/loading.rs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
import makepad_widgets::base::*;
|
||||||
|
import makepad_widgets::theme_desktop_dark::*;
|
||||||
|
import makepad_draw::shader::std::*;
|
||||||
|
|
||||||
|
LoadingModal = {{LoadingModal}} {
|
||||||
|
width: Fit
|
||||||
|
height: Fit
|
||||||
|
|
||||||
|
<RoundedView> {
|
||||||
|
flow: Down
|
||||||
|
width: 600
|
||||||
|
height: Fit
|
||||||
|
padding: {top: 25, right: 30 bottom: 30 left: 45}
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
show_bg: true
|
||||||
|
draw_bg: {
|
||||||
|
color: #fff
|
||||||
|
radius: 3.0
|
||||||
|
}
|
||||||
|
|
||||||
|
title_view = <View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
padding: {top: 0, bottom: 40}
|
||||||
|
align: {x: 0.5, y: 0.0}
|
||||||
|
|
||||||
|
title = <Label> {
|
||||||
|
text: "Loading content..."
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 13},
|
||||||
|
color: #000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body = <View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down,
|
||||||
|
spacing: 40,
|
||||||
|
|
||||||
|
status = <Label> {
|
||||||
|
width: Fill
|
||||||
|
draw_text: {
|
||||||
|
text_style: <REGULAR_TEXT>{
|
||||||
|
font_size: 11.5,
|
||||||
|
height_factor: 1.3
|
||||||
|
},
|
||||||
|
color: #000
|
||||||
|
wrap: Word
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
width: Fill, height: Fit
|
||||||
|
flow: Right,
|
||||||
|
align: {x: 1.0, y: 0.5}
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
// cancel_button = <RobrixIconButton> {
|
||||||
|
// padding: {left: 15, right: 15}
|
||||||
|
// // draw_icon: {
|
||||||
|
// // svg_file: (ICON_BLOCK_USER)
|
||||||
|
// // color: (COLOR_DANGER_RED),
|
||||||
|
// // }
|
||||||
|
// icon_walk: {width: 0, height: 0 }
|
||||||
|
|
||||||
|
// draw_bg: {
|
||||||
|
// border_color: (COLOR_DANGER_RED),
|
||||||
|
// color: #fff0f0 // light red
|
||||||
|
// }
|
||||||
|
// text: "Cancel"
|
||||||
|
// draw_text:{
|
||||||
|
// color: (COLOR_DANGER_RED),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct LoadingModal {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
#[rust]
|
||||||
|
state: LoadingModalState,
|
||||||
|
}
|
||||||
|
impl Drop for LoadingModal {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let LoadingModalState::BackwardsPaginateUntilEvent {
|
||||||
|
// target_event_id,
|
||||||
|
// request_sender,
|
||||||
|
..
|
||||||
|
} = &self.state
|
||||||
|
{
|
||||||
|
warning!(
|
||||||
|
"Dropping LoadingModal with target_event_id ",
|
||||||
|
// target_event_id
|
||||||
|
);
|
||||||
|
// request_sender.send_if_modified(|requests| {
|
||||||
|
// let initial_len = requests.len();
|
||||||
|
// requests.retain(|r| &r.target_event_id != target_event_id);
|
||||||
|
// // if we actually cancelled this request, notify the receivers
|
||||||
|
// // such that they can stop looking for the target event.
|
||||||
|
// requests.len() != initial_len
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An action sent from this LoadingModal widget to its parent widget,
|
||||||
|
/// which is currently required in order for the parent to close this modal.
|
||||||
|
#[derive(Clone, Debug, DefaultNone)]
|
||||||
|
pub enum LoadingModalAction {
|
||||||
|
Close,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The state of a LoadingModal: the possible tasks that it may be performing.
|
||||||
|
#[derive(Clone, DefaultNone)]
|
||||||
|
pub enum LoadingModalState {
|
||||||
|
/// The room is being backwards paginated until the target event is reached.
|
||||||
|
BackwardsPaginateUntilEvent,
|
||||||
|
/// The loading modal is displaying an error message until the user closes it.
|
||||||
|
Error(String),
|
||||||
|
/// The LoadingModal is not doing anything and can be hidden.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for LoadingModal {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for LoadingModal {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let widget_uid = self.widget_uid();
|
||||||
|
// let cancel_button = self.button(id!(cancel_button));
|
||||||
|
|
||||||
|
let modal_dismissed = actions
|
||||||
|
.iter()
|
||||||
|
.find(|a| matches!(a.downcast_ref(), Some(ModalAction::Dismissed)))
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
if modal_dismissed {
|
||||||
|
log!(
|
||||||
|
"LoadingModal: close requested: {}",
|
||||||
|
if modal_dismissed {
|
||||||
|
"by modal dismiss"
|
||||||
|
} else {
|
||||||
|
"by cancel button"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if let LoadingModalState::BackwardsPaginateUntilEvent {
|
||||||
|
// target_event_id,
|
||||||
|
// request_sender,
|
||||||
|
..
|
||||||
|
} = &self.state
|
||||||
|
{
|
||||||
|
// let _did_send = request_sender.send_if_modified(|requests| {
|
||||||
|
// let initial_len = requests.len();
|
||||||
|
// requests.retain(|r| &r.target_event_id != target_event_id);
|
||||||
|
// // if we actually cancelled this request, notify the receivers
|
||||||
|
// // such that they can stop looking for the target event.
|
||||||
|
// requests.len() != initial_len
|
||||||
|
// });
|
||||||
|
// log!(
|
||||||
|
// "LoadingModal: {} cancel request for target_event_id: {target_event_id}",
|
||||||
|
// if _did_send { "Sent" } else { "Did not send" },
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
self.set_state(cx, LoadingModalState::None);
|
||||||
|
|
||||||
|
// If the modal was dismissed by clicking outside of it, we MUST NOT emit
|
||||||
|
// a `LoadingModalAction::Close` action, as that would cause
|
||||||
|
// an infinite action feedback loop.
|
||||||
|
if !modal_dismissed {
|
||||||
|
cx.widget_action(widget_uid, &scope.path, LoadingModalAction::Close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadingModal {
|
||||||
|
pub fn set_state(&mut self, cx: &mut Cx, state: LoadingModalState) {
|
||||||
|
// let cancel_button = self.button(id!(cancel_button));
|
||||||
|
match &state {
|
||||||
|
LoadingModalState::BackwardsPaginateUntilEvent {
|
||||||
|
// target_event_id,
|
||||||
|
// events_paginated,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
self.set_title(cx, "Searching older messages...");
|
||||||
|
self.set_status(
|
||||||
|
cx,
|
||||||
|
&format!(
|
||||||
|
"Looking for event \n\n\
|
||||||
|
",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// cancel_button.set_text_and_redraw(cx, "Cancel");
|
||||||
|
}
|
||||||
|
LoadingModalState::Error(error_message) => {
|
||||||
|
self.set_title(cx, "Error loading content");
|
||||||
|
self.set_status(cx, error_message);
|
||||||
|
// cancel_button.set_text_and_redraw(cx, "Okay");
|
||||||
|
}
|
||||||
|
LoadingModalState::None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state = state;
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&mut self, cx: &mut Cx, status: &str) {
|
||||||
|
self.label(id!(status)).set_text_and_redraw(cx, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_title(&mut self, cx: &mut Cx, title: &str) {
|
||||||
|
self.label(id!(title)).set_text_and_redraw(cx, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadingModalRef {
|
||||||
|
pub fn take_state(&self) -> LoadingModalState {
|
||||||
|
self.borrow_mut()
|
||||||
|
.map(|mut inner| std::mem::take(&mut inner.state))
|
||||||
|
.unwrap_or(LoadingModalState::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&self, cx: &mut Cx, state: LoadingModalState) {
|
||||||
|
let Some(mut inner) = self.borrow_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
inner.set_state(cx, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&self, cx: &mut Cx, status: &str) {
|
||||||
|
let Some(mut inner) = self.borrow_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
inner.set_status(cx, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_title(&self, cx: &mut Cx, title: &str) {
|
||||||
|
let Some(mut inner) = self.borrow_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
inner.set_title(cx, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
pub mod area;
|
pub mod area;
|
||||||
pub mod background_text;
|
pub mod background_text;
|
||||||
|
pub mod element_panels;
|
||||||
|
pub mod loading;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod selector;
|
pub mod selector;
|
||||||
|
|||||||
@ -76,25 +76,6 @@ impl RenderState {
|
|||||||
pub fn resize(&mut self, width: f32, height: f32) {
|
pub fn resize(&mut self, width: f32, height: f32) {
|
||||||
self.projection.resize(width as u32, height as u32);
|
self.projection.resize(width as u32, height as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_bridge(&mut self, bridge: TextureBridge) {
|
|
||||||
self.bridge = Some(bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_bridge(&mut self, cx: &mut Cx, window: Window) {
|
|
||||||
let texture = Texture::new_with_format(
|
|
||||||
cx,
|
|
||||||
TextureFormat::VecRGBAf32 {
|
|
||||||
width: window.width as usize,
|
|
||||||
height: window.height as usize,
|
|
||||||
data: None,
|
|
||||||
updated: TextureUpdated::Full,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let bridge = TextureBridge::new(texture, &GIAPP, window);
|
|
||||||
self.bridge = Some(bridge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiveHook for Renderer {}
|
impl LiveHook for Renderer {}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use makepad_widgets::*;
|
use makepad_widgets::*;
|
||||||
|
use mp_core::Data;
|
||||||
|
use mp_elements::elements::{Element, Elements};
|
||||||
|
|
||||||
live_design! {
|
live_design! {
|
||||||
import makepad_widgets::base::*;
|
import makepad_widgets::base::*;
|
||||||
@ -276,12 +278,16 @@ pub enum SelectorAction {
|
|||||||
None,
|
None,
|
||||||
SelectItem(ItemKey, ItemValue, usize, usize),
|
SelectItem(ItemKey, ItemValue, usize, usize),
|
||||||
|
|
||||||
Selected(ItemKey, usize),
|
Selected {
|
||||||
Unselected(ItemKey, usize),
|
element: Vec<Elements>,
|
||||||
|
key: ItemKey,
|
||||||
|
item: ItemValue,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ItemKey {
|
pub struct ItemKey {
|
||||||
|
pub data_idx: usize,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub category: String,
|
pub category: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
@ -545,7 +551,7 @@ pub struct Selector {
|
|||||||
view: View,
|
view: View,
|
||||||
|
|
||||||
#[rust]
|
#[rust]
|
||||||
class: Vec<(ItemKey, Vec<ItemValue>)>,
|
class: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>,
|
||||||
|
|
||||||
#[rust]
|
#[rust]
|
||||||
selected: Option<(ItemKey, ItemValue, usize, usize)>,
|
selected: Option<(ItemKey, ItemValue, usize, usize)>,
|
||||||
@ -555,7 +561,9 @@ impl Widget for Selector {
|
|||||||
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
let list = self.view.widget(id!(list)).as_portal_list();
|
let list = self.view.widget(id!(list)).as_portal_list();
|
||||||
let ok_button = self.view.widget(id!(ok_button)).as_button();
|
let ok_button = self.view.widget(id!(ok_button)).as_button();
|
||||||
for action in cx.capture_actions(|cx| self.view.handle_event(cx, event, scope)) {
|
|
||||||
|
let actions = cx.capture_actions(|cx| self.view.handle_event(cx, event, scope));
|
||||||
|
for action in actions.iter() {
|
||||||
match action.as_widget_action().cast() {
|
match action.as_widget_action().cast() {
|
||||||
SelectorAction::SelectItem(key, item, list_id, item_id) => {
|
SelectorAction::SelectItem(key, item, list_id, item_id) => {
|
||||||
let raw_selected = &self.selected;
|
let raw_selected = &self.selected;
|
||||||
@ -570,13 +578,25 @@ impl Widget for Selector {
|
|||||||
list.get_item(list_id).map(|v| {
|
list.get_item(list_id).map(|v| {
|
||||||
v.1.as_selector_list().set_selected(cx, item_id, true);
|
v.1.as_selector_list().set_selected(cx, item_id, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
ok_button.set_enabled(self.selected.is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ok_button.clicked(&actions) {
|
||||||
|
let selected = self.selected.clone().unwrap();
|
||||||
|
let elements = self.class[selected.2 / 2].1[selected.3].1.clone();
|
||||||
|
cx.widget_action(
|
||||||
|
self.widget_uid(),
|
||||||
|
&scope.path,
|
||||||
|
SelectorAction::Selected {
|
||||||
|
element: vec![elements],
|
||||||
|
key: selected.0,
|
||||||
|
item: selected.1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
@ -586,6 +606,10 @@ impl Widget for Selector {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ok_button = self.view.widget(id!(ok_button)).as_button();
|
||||||
|
|
||||||
|
ok_button.set_enabled(self.selected.is_some());
|
||||||
|
|
||||||
let count = self.class.len() * 2;
|
let count = self.class.len() * 2;
|
||||||
// TitleBar and List
|
// TitleBar and List
|
||||||
list.set_item_range(cx, 0, count);
|
list.set_item_range(cx, 0, count);
|
||||||
@ -609,7 +633,7 @@ impl Widget for Selector {
|
|||||||
let list_item = list.item(cx, item_id, live_id!(list_item));
|
let list_item = list.item(cx, item_id, live_id!(list_item));
|
||||||
let list = list_item.as_selector_list();
|
let list = list_item.as_selector_list();
|
||||||
|
|
||||||
for item in prepared.1.iter() {
|
for (item, _) in prepared.1.iter() {
|
||||||
list.insert_if_not_exists(cx, item_id, item);
|
list.insert_if_not_exists(cx, item_id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,19 +650,23 @@ impl Widget for Selector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Selector {
|
impl Selector {
|
||||||
fn set_items(&mut self, cx: &mut Cx, items: Vec<(ItemKey, Vec<ItemValue>)>) {
|
fn set_items(&mut self, cx: &mut Cx, items: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>) {
|
||||||
self.class = items;
|
self.class = items;
|
||||||
|
|
||||||
|
let list = self.view.widget(id!(list)).as_portal_list();
|
||||||
|
|
||||||
|
list.clear_query_cache();
|
||||||
self.view.redraw(cx);
|
self.view.redraw(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_base_name(&mut self, name: &str) {
|
fn set_base_name(&mut self, name: &str) {
|
||||||
let title_bar = self.view.widget(id!(file_base_name)).as_label();
|
let title_bar = self.view.widget(id!(file_base_name)).as_label();
|
||||||
title_bar.set_text(name);
|
title_bar.set_text(format!("File: {}", name).as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorRef {
|
impl SelectorRef {
|
||||||
pub fn set_items(&self, cx: &mut Cx, items: Vec<(ItemKey, Vec<ItemValue>)>) {
|
pub fn set_items(&self, cx: &mut Cx, items: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>) {
|
||||||
if let Some(mut item) = self.borrow_mut() {
|
if let Some(mut item) = self.borrow_mut() {
|
||||||
item.set_items(cx, items);
|
item.set_items(cx, items);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,103 +1,97 @@
|
|||||||
use std::{
|
use makepad_widgets::{Cx, PointUsize, RectUsize, SizeUsize, Texture, ToUIReceiver, ToUISender};
|
||||||
collections::HashMap,
|
|
||||||
sync::{Arc, Mutex, MutexGuard},
|
|
||||||
};
|
|
||||||
|
|
||||||
use element_bridge::TextureBridge;
|
use crate::task_register::{BridgeManager, TaskId};
|
||||||
|
use crate::widgets::area::TAreaRef;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
pub type AllBuffers = Arc<Mutex<HashMap<usize, Arc<tokio::sync::Mutex<Vec<u8>>>>>>;
|
static WINDOW_ID: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq, Debug)]
|
#[derive(Eq, Hash, PartialEq, Debug, Clone)]
|
||||||
pub struct WindowId {
|
pub struct WindowId {
|
||||||
id: u64,
|
id: u64,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct WindowsManager {
|
pub struct WindowsManager {
|
||||||
inner: HashMap<WindowId, Arc<Mutex<TextureBridge>>>,
|
inner: HashMap<WindowId, TAreaRef>,
|
||||||
|
recv: ToUIReceiver<(TaskId, Vec<f32>)>,
|
||||||
all_bridges: Vec<(usize, Arc<Mutex<TextureBridge>>)>,
|
|
||||||
|
|
||||||
all_revelant_buffers: Arc<Mutex<HashMap<usize, Arc<tokio::sync::Mutex<Vec<u8>>>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsManager {
|
impl WindowsManager {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let recv = ToUIReceiver::default();
|
||||||
Self {
|
Self {
|
||||||
inner: HashMap::new(),
|
inner: HashMap::new(),
|
||||||
all_bridges: Vec::new(),
|
recv,
|
||||||
all_revelant_buffers: Arc::new(Mutex::new(HashMap::new())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_window<F>(&mut self, id: WindowId, f: F) -> (usize, Arc<Mutex<TextureBridge>>)
|
pub fn add_window(&mut self, window: TAreaRef) -> WindowId {
|
||||||
where
|
|
||||||
F: FnOnce(&mut TextureBridge),
|
|
||||||
{
|
|
||||||
let bridge = self.inner.get(&id).unwrap();
|
|
||||||
let mut _bridge = bridge.lock().unwrap();
|
|
||||||
f(&mut _bridge);
|
|
||||||
(0, bridge.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_window(
|
|
||||||
&mut self,
|
|
||||||
id: WindowId,
|
|
||||||
bridge: TextureBridge,
|
|
||||||
) -> (usize, Arc<Mutex<TextureBridge>>) {
|
|
||||||
let bridge = Arc::new(Mutex::new(bridge));
|
|
||||||
// New window
|
// New window
|
||||||
self.inner
|
let id = WindowId::primary();
|
||||||
.entry(id)
|
self.inner.entry(id.clone()).or_insert(window);
|
||||||
.and_modify(|e| *e = bridge.clone())
|
id
|
||||||
.or_insert(bridge.clone());
|
|
||||||
|
|
||||||
let new_id = self.all_bridges.len();
|
|
||||||
self.all_bridges.push((new_id, bridge.clone()));
|
|
||||||
|
|
||||||
let buffer = {
|
|
||||||
let bridge = bridge.lock().unwrap();
|
|
||||||
bridge.buffer()
|
|
||||||
};
|
|
||||||
self.all_revelant_buffers
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.insert(new_id, buffer);
|
|
||||||
|
|
||||||
(new_id, bridge)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bridge(&self, id: usize) -> Option<Arc<Mutex<TextureBridge>>> {
|
pub fn get_window(&self, id: &WindowId) -> Option<&TAreaRef> {
|
||||||
self.all_bridges.get(id).map(|(_, bridge)| bridge.clone())
|
self.inner.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer(&self) -> AllBuffers {
|
pub fn sender(&self) -> ToUISender<(TaskId, Vec<f32>)> {
|
||||||
self.all_revelant_buffers.clone()
|
self.recv.sender()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_deal_render_result(&mut self, cx: &mut Cx, bridge_manager: &BridgeManager) {
|
||||||
|
while let Ok((id, data)) = self.recv.try_recv() {
|
||||||
|
let windows = bridge_manager.get_net(&id).unwrap();
|
||||||
|
|
||||||
|
for window in windows {
|
||||||
|
let window = self.get_window(window).unwrap();
|
||||||
|
let texture = window.get_texture();
|
||||||
|
|
||||||
|
if texture.is_none() {
|
||||||
|
let texture = Texture::new_with_format(
|
||||||
|
cx,
|
||||||
|
makepad_widgets::TextureFormat::VecRGBAf32 {
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
data: None,
|
||||||
|
updated: makepad_widgets::TextureUpdated::Full,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
window.set_texture(cx, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
let texture = window.get_texture().unwrap();
|
||||||
|
|
||||||
|
texture.put_back_vec_f32(
|
||||||
|
cx,
|
||||||
|
data.clone(),
|
||||||
|
Some(RectUsize::new(
|
||||||
|
PointUsize::new(0, 0),
|
||||||
|
SizeUsize::new(1920, 1080),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.redraw(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowId {
|
impl WindowId {
|
||||||
pub fn new<S: Into<String>>(name: S) -> Self {
|
pub fn new<S: Into<String>>(name: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: 0,
|
id: WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
pub fn primary() -> Self {
|
||||||
pub struct WM(Arc<std::sync::Mutex<WindowsManager>>);
|
Self {
|
||||||
|
id: WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
|
||||||
impl WM {
|
name: "Primary".into(),
|
||||||
pub fn new() -> Self {
|
}
|
||||||
Self(Arc::new(std::sync::Mutex::new(WindowsManager::new())))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn windows_manager(&self) -> Arc<std::sync::Mutex<WindowsManager>> {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wm(&self) -> MutexGuard<'_, WindowsManager> {
|
|
||||||
self.0.lock().unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub enum PipelineError {
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
#[error("")]
|
#[error("because: {0}")]
|
||||||
IOError(#[from] std::io::Error),
|
IOError(#[from] std::io::Error),
|
||||||
#[error("")]
|
#[error("")]
|
||||||
TomlError(#[from] toml::de::Error),
|
TomlError(#[from] toml::de::Error),
|
||||||
|
|||||||
@ -14,6 +14,7 @@ image = "0.25.5"
|
|||||||
rust-embed = "8.5.0"
|
rust-embed = "8.5.0"
|
||||||
flume = "0.11.1"
|
flume = "0.11.1"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
|
thiserror = "2.0.3"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
|||||||
263
mp_elements/config.toml
Normal file
263
mp_elements/config.toml
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
[common]
|
||||||
|
background = "Terrain"
|
||||||
|
path = "resources/alts.png"
|
||||||
|
plugins = "loaders"
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "DBZ"
|
||||||
|
levels = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75]
|
||||||
|
colors = [
|
||||||
|
"#aaaaaa",
|
||||||
|
"#0022ff",
|
||||||
|
"#01a0f6",
|
||||||
|
"#00ecec",
|
||||||
|
"#00d800",
|
||||||
|
"#019000",
|
||||||
|
"#ffff00",
|
||||||
|
"#e7c000",
|
||||||
|
"#ff9000",
|
||||||
|
"#ff0000",
|
||||||
|
"#d60000",
|
||||||
|
"#c00000",
|
||||||
|
"#ff00f0",
|
||||||
|
"#9600b4",
|
||||||
|
"#ad90f0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "VEL"
|
||||||
|
levels = [
|
||||||
|
-90,
|
||||||
|
-45,
|
||||||
|
-35,
|
||||||
|
-27,
|
||||||
|
-20,
|
||||||
|
-15,
|
||||||
|
-10,
|
||||||
|
-5,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
10,
|
||||||
|
15,
|
||||||
|
20,
|
||||||
|
27,
|
||||||
|
1000,
|
||||||
|
]
|
||||||
|
colors = [
|
||||||
|
"#9fffff",
|
||||||
|
"#00e0ff",
|
||||||
|
"#0080ff",
|
||||||
|
"#320096",
|
||||||
|
"#00fb90",
|
||||||
|
"#00bb90",
|
||||||
|
"#008f00",
|
||||||
|
"#cdc09f",
|
||||||
|
"#000000",
|
||||||
|
"#f88700",
|
||||||
|
"#ffcf00",
|
||||||
|
"#ffff00",
|
||||||
|
"#ae0000",
|
||||||
|
"#d07000",
|
||||||
|
"#dd0000",
|
||||||
|
"#ff0000",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "SW"
|
||||||
|
colors = [
|
||||||
|
"#E0E0E0",
|
||||||
|
"#7CE0E0",
|
||||||
|
"#00E0E0",
|
||||||
|
"#00B0B0",
|
||||||
|
"#00FEFE",
|
||||||
|
"#00C400",
|
||||||
|
"#008000",
|
||||||
|
"#FEFE00",
|
||||||
|
"#FED200",
|
||||||
|
"#FE7C00",
|
||||||
|
"#FEB0B0",
|
||||||
|
"#FE5858",
|
||||||
|
"#FE0000",
|
||||||
|
"#FEFEFE",
|
||||||
|
]
|
||||||
|
levels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "CC"
|
||||||
|
colors = [
|
||||||
|
"#003CFF",
|
||||||
|
"#00EFEF",
|
||||||
|
"#00BABF",
|
||||||
|
"#00837D",
|
||||||
|
"#008938",
|
||||||
|
"#00B729",
|
||||||
|
"#00DA0D",
|
||||||
|
"#00FF00",
|
||||||
|
"#FFFF3B",
|
||||||
|
"#FFF000",
|
||||||
|
"#FFC600",
|
||||||
|
"#FFA500",
|
||||||
|
"#FF7200",
|
||||||
|
"#FF1F00",
|
||||||
|
"#C10000",
|
||||||
|
"#D400AA",
|
||||||
|
]
|
||||||
|
levels = [
|
||||||
|
0,
|
||||||
|
0.1,
|
||||||
|
0.3,
|
||||||
|
0.5,
|
||||||
|
0.6,
|
||||||
|
0.7,
|
||||||
|
0.8,
|
||||||
|
0.85,
|
||||||
|
0.9,
|
||||||
|
0.92,
|
||||||
|
0.94,
|
||||||
|
0.95,
|
||||||
|
0.96,
|
||||||
|
0.97,
|
||||||
|
0.98,
|
||||||
|
0.99,
|
||||||
|
]
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "KDP"
|
||||||
|
colors = [
|
||||||
|
"#00FFFF",
|
||||||
|
"#00EFEF",
|
||||||
|
"#00A8AC",
|
||||||
|
"#B4B4B4",
|
||||||
|
"#B4B4B4",
|
||||||
|
"#00C027",
|
||||||
|
"#00E80A",
|
||||||
|
"#24FF24",
|
||||||
|
"#FFFF1E",
|
||||||
|
"#FFE600",
|
||||||
|
"#FFBC00",
|
||||||
|
"#FF9800",
|
||||||
|
"#FF5E00",
|
||||||
|
"#F20F00",
|
||||||
|
"#BB003A",
|
||||||
|
"#DD009C",
|
||||||
|
"#FF00FF",
|
||||||
|
]
|
||||||
|
levels = [
|
||||||
|
-0.8,
|
||||||
|
-0.4,
|
||||||
|
-0.2,
|
||||||
|
-0.1,
|
||||||
|
0.1,
|
||||||
|
0.15,
|
||||||
|
0.22,
|
||||||
|
0.33,
|
||||||
|
0.5,
|
||||||
|
0.75,
|
||||||
|
1.1,
|
||||||
|
1.7,
|
||||||
|
2.4,
|
||||||
|
3.1,
|
||||||
|
7,
|
||||||
|
20,
|
||||||
|
]
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "ZDR"
|
||||||
|
colors = [
|
||||||
|
"#464646",
|
||||||
|
"#505050",
|
||||||
|
"#5A5A5A",
|
||||||
|
"#646464",
|
||||||
|
"#6E6E6E",
|
||||||
|
"#787878",
|
||||||
|
"#828282",
|
||||||
|
"#8C8C8C",
|
||||||
|
"#969696",
|
||||||
|
"#AFAFAF",
|
||||||
|
"#C8C8C8",
|
||||||
|
"#DCF0DC",
|
||||||
|
"#00C027",
|
||||||
|
"#00E80A",
|
||||||
|
"#24FF24",
|
||||||
|
"#FFFF1E",
|
||||||
|
"#FFF20F",
|
||||||
|
"#FFE600",
|
||||||
|
"#FFBC00",
|
||||||
|
"#FF9800",
|
||||||
|
"#FF5E00",
|
||||||
|
"#FFFF00",
|
||||||
|
"#F20F00",
|
||||||
|
"#BB003A",
|
||||||
|
"#DD009C",
|
||||||
|
"#FF00FF",
|
||||||
|
]
|
||||||
|
levels = [
|
||||||
|
-5,
|
||||||
|
-4.5,
|
||||||
|
-4,
|
||||||
|
-3.5,
|
||||||
|
-3,
|
||||||
|
-2.5,
|
||||||
|
-2,
|
||||||
|
-1.5,
|
||||||
|
-1,
|
||||||
|
-0.5,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
1,
|
||||||
|
1.5,
|
||||||
|
2,
|
||||||
|
2.5,
|
||||||
|
3,
|
||||||
|
3.5,
|
||||||
|
4,
|
||||||
|
4.5,
|
||||||
|
5,
|
||||||
|
5.5,
|
||||||
|
6,
|
||||||
|
6.5,
|
||||||
|
7,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[cmap]]
|
||||||
|
type = "VIL"
|
||||||
|
levels = [
|
||||||
|
0.1,
|
||||||
|
1,
|
||||||
|
2.5,
|
||||||
|
5,
|
||||||
|
7.5,
|
||||||
|
10,
|
||||||
|
10.25,
|
||||||
|
15,
|
||||||
|
20,
|
||||||
|
25,
|
||||||
|
30,
|
||||||
|
35,
|
||||||
|
40,
|
||||||
|
45,
|
||||||
|
50,
|
||||||
|
55,
|
||||||
|
104,
|
||||||
|
]
|
||||||
|
colors = [
|
||||||
|
'#484892',
|
||||||
|
'#01a0f6',
|
||||||
|
'#00ecec',
|
||||||
|
'#01ff00',
|
||||||
|
'#00c800',
|
||||||
|
'#019000',
|
||||||
|
'#ffff00',
|
||||||
|
'#e7c000',
|
||||||
|
'#ff9000',
|
||||||
|
'#ff0000',
|
||||||
|
'#d60000',
|
||||||
|
'#c00000',
|
||||||
|
'#ff00f0',
|
||||||
|
'#ad90f0',
|
||||||
|
'#780084',
|
||||||
|
'#d8af97',
|
||||||
|
]
|
||||||
@ -1,3 +1,6 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use crate::elements::{Element, ElementAttach, Elements};
|
use crate::elements::{Element, ElementAttach, Elements};
|
||||||
use crate::elementvec::ElementVec;
|
use crate::elementvec::ElementVec;
|
||||||
use encase;
|
use encase;
|
||||||
@ -63,8 +66,8 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_pool(&mut self) -> &mut DataBufferPool {
|
pub fn buffer_pool(&self) -> &DataBufferPool {
|
||||||
&mut self.buffer_pool
|
&self.buffer_pool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new context struct. This struct contains references to the device, queue, bind group layout, and bind group.
|
// Create a new context struct. This struct contains references to the device, queue, bind group layout, and bind group.
|
||||||
@ -127,6 +130,12 @@ impl App {
|
|||||||
render_pass.set_bind_group(*index, bind_group, &[]);
|
render_pass.set_bind_group(*index, bind_group, &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the scissors for the render pass.
|
||||||
|
{
|
||||||
|
let scissors = window.scissors.lock().unwrap();
|
||||||
|
render_pass.set_scissor_rect(0, 0, scissors[0], scissors[1]);
|
||||||
|
}
|
||||||
|
|
||||||
// Set the bind group for the render pass.
|
// Set the bind group for the render pass.
|
||||||
attach.bind(&mut render_pass);
|
attach.bind(&mut render_pass);
|
||||||
|
|
||||||
@ -170,6 +179,7 @@ pub struct RenderWindow {
|
|||||||
texture_view: wgpu::TextureView,
|
texture_view: wgpu::TextureView,
|
||||||
output: Output,
|
output: Output,
|
||||||
window: Window,
|
window: Window,
|
||||||
|
scissors: Mutex<[u32; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderWindow {
|
impl RenderWindow {
|
||||||
@ -187,7 +197,8 @@ impl RenderWindow {
|
|||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
// format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
format: wgpu::TextureFormat::Rgba32Float,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||||
view_formats: &[],
|
view_formats: &[],
|
||||||
});
|
});
|
||||||
@ -196,6 +207,7 @@ impl RenderWindow {
|
|||||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
let output = Output::new(device);
|
let output = Output::new(device);
|
||||||
|
let scissors = Mutex::new([window.width, window.height]);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_texture: texture,
|
_texture: texture,
|
||||||
@ -203,6 +215,7 @@ impl RenderWindow {
|
|||||||
texture_view,
|
texture_view,
|
||||||
output,
|
output,
|
||||||
window,
|
window,
|
||||||
|
scissors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +224,10 @@ impl RenderWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&self, encoder: &mut wgpu::CommandEncoder) {
|
pub fn finish(&self, encoder: &mut wgpu::CommandEncoder) {
|
||||||
|
let (width, height) = {
|
||||||
|
let l = self.scissors.lock().unwrap();
|
||||||
|
(l[0], l[1])
|
||||||
|
};
|
||||||
encoder.copy_texture_to_buffer(
|
encoder.copy_texture_to_buffer(
|
||||||
wgpu::ImageCopyTexture {
|
wgpu::ImageCopyTexture {
|
||||||
texture: &self._texture,
|
texture: &self._texture,
|
||||||
@ -222,13 +239,13 @@ impl RenderWindow {
|
|||||||
buffer: &self.output.output_buffer,
|
buffer: &self.output.output_buffer,
|
||||||
layout: wgpu::ImageDataLayout {
|
layout: wgpu::ImageDataLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row: Some(256 * 4),
|
bytes_per_row: Some((width * 16 + 255) / 256 * 256),
|
||||||
rows_per_image: Some(256),
|
rows_per_image: Some(height),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wgpu::Extent3d {
|
wgpu::Extent3d {
|
||||||
width: self.window.width,
|
width: width,
|
||||||
height: self.window.height,
|
height: height,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -387,9 +404,9 @@ pub struct Output {
|
|||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
let u32_size = std::mem::size_of::<u32>() as u32;
|
let f32_size = std::mem::size_of::<f32>() as u32;
|
||||||
|
|
||||||
let output_buffer_size = (u32_size * 256 * 256) as wgpu::BufferAddress;
|
let output_buffer_size = (f32_size * 4 * 1920 * 1080) as wgpu::BufferAddress;
|
||||||
let output_buffer_desc = wgpu::BufferDescriptor {
|
let output_buffer_desc = wgpu::BufferDescriptor {
|
||||||
size: output_buffer_size,
|
size: output_buffer_size,
|
||||||
usage: wgpu::BufferUsages::COPY_DST
|
usage: wgpu::BufferUsages::COPY_DST
|
||||||
@ -403,7 +420,7 @@ impl Output {
|
|||||||
Self { output_buffer }
|
Self { output_buffer }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_data(&self, ctx: &Ctx) {
|
async fn get_data(&self, ctx: &Ctx) {
|
||||||
let device = &ctx.device;
|
let device = &ctx.device;
|
||||||
// 需要对映射变量设置范围,以便我们能够解除缓冲区的映射
|
// 需要对映射变量设置范围,以便我们能够解除缓冲区的映射
|
||||||
let buffer_slice = self.output_buffer.slice(..);
|
let buffer_slice = self.output_buffer.slice(..);
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
pub mod ppi;
|
pub mod ppi;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{BufferKey, Ctx, DataBufferPool},
|
app::{BufferKey, Ctx, DataBufferPool},
|
||||||
|
errors::ElementError,
|
||||||
App,
|
App,
|
||||||
};
|
};
|
||||||
use mp_core::config;
|
use mp_core::{
|
||||||
|
config,
|
||||||
|
errors::{ConfigError, DataError},
|
||||||
|
Data, Setting,
|
||||||
|
};
|
||||||
pub use ppi::PPI;
|
pub use ppi::PPI;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
@ -78,6 +83,45 @@ macro_rules! elements {
|
|||||||
$(Elements::$element_name(_) => <$element>::DESC,)+
|
$(Elements::$element_name(_) => <$element>::DESC,)+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_data(&self,ctx:&Ctx,data: &Data, buffer_pool: &DataBufferPool, config: Option<&dyn Any>) -> Result<ElementAttach, DataError> {
|
||||||
|
Ok(match self {
|
||||||
|
$(Elements::$element_name(element) => {
|
||||||
|
|
||||||
|
if let Some(cfg) = config {
|
||||||
|
if let Some(cfg) = cfg.downcast_ref::<<$element as Element>::Config>(){
|
||||||
|
element.load_data(ctx, data.try_into()?, buffer_pool, cfg)
|
||||||
|
} else {
|
||||||
|
panic!("Invalid config type")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element.load_data(ctx, data.try_into()?, buffer_pool, &<$element as Element>::Config::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
},)+
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_uniform(&self, ctx: &Ctx, attach: &ElementAttach, config: &dyn Any) {
|
||||||
|
match self {
|
||||||
|
$(Elements::$element_name(element) => {
|
||||||
|
if let Some(cfg) = config.downcast_ref::<<$element as Element>::Config>(){
|
||||||
|
element.update_uniform(ctx, attach, cfg )
|
||||||
|
} else {
|
||||||
|
panic!("Invalid config type")
|
||||||
|
}
|
||||||
|
})+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_config(&self, data: &Data, setting: &Setting) -> Result<Arc<Mutex<dyn Any + Send + 'static>>, ElementError> {
|
||||||
|
Ok(match self {
|
||||||
|
$(Elements::$element_name(element) => {
|
||||||
|
let cfg = element.init_config(data.try_into()?, setting)?;
|
||||||
|
Arc::new(Mutex::new(cfg)) as Arc<Mutex<dyn Any + Send + 'static>>
|
||||||
|
})+
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElementsRef<'a> {
|
impl<'a> ElementsRef<'a> {
|
||||||
@ -116,7 +160,7 @@ pub trait Element {
|
|||||||
type Vertex;
|
type Vertex;
|
||||||
type Uniform;
|
type Uniform;
|
||||||
type Data;
|
type Data;
|
||||||
type Config;
|
type Config: Default + ElementConfig<Element = Self>;
|
||||||
|
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
const DESC: &'static str;
|
const DESC: &'static str;
|
||||||
@ -143,6 +187,28 @@ pub trait Element {
|
|||||||
buffer_pool: &DataBufferPool,
|
buffer_pool: &DataBufferPool,
|
||||||
config: &Self::Config,
|
config: &Self::Config,
|
||||||
) -> ElementAttach;
|
) -> ElementAttach;
|
||||||
|
|
||||||
|
fn update_uniform(&self, ctx: &Ctx, attach: &ElementAttach, config: &Self::Config);
|
||||||
|
|
||||||
|
fn init_config(
|
||||||
|
&self,
|
||||||
|
data: &Self::Data,
|
||||||
|
setting: &Setting,
|
||||||
|
) -> Result<Self::Config, ConfigError> {
|
||||||
|
let mut default_config = Self::Config::default();
|
||||||
|
default_config.init(data, setting)?;
|
||||||
|
Ok(default_config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ElementConfig {
|
||||||
|
type Element: Element;
|
||||||
|
|
||||||
|
fn init(
|
||||||
|
&mut self,
|
||||||
|
data: &<Self::Element as Element>::Data,
|
||||||
|
setting: &Setting,
|
||||||
|
) -> Result<(), ConfigError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@ -8,10 +8,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
use glam::{Vec3, Vec4};
|
use glam::{Vec3, Vec4};
|
||||||
use mp_core::{data::CoordType, RadarGridData};
|
use mp_core::{data::CoordType, errors::ConfigError, RadarGridData};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
use super::{Element, ElementAttach};
|
use super::{Element, ElementAttach, ElementConfig};
|
||||||
|
|
||||||
const EMAXNUM: u64 = 50;
|
const EMAXNUM: u64 = 50;
|
||||||
const AMAXNUM: u64 = 360;
|
const AMAXNUM: u64 = 360;
|
||||||
@ -24,15 +24,51 @@ pub struct PPI {
|
|||||||
colormap: Option<ColorMap>,
|
colormap: Option<ColorMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct PPIConfig {
|
pub struct PPIConfig {
|
||||||
pub colormap: Vec<[f32; 4]>,
|
pub colormap: Vec<[f32; 4]>,
|
||||||
pub color_range: [f32; 2],
|
pub color_range: [f32; 2],
|
||||||
|
pub layer: f32,
|
||||||
|
pub three_d: bool,
|
||||||
|
pub scale: f32,
|
||||||
|
pub size: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementConfig for PPIConfig {
|
||||||
|
type Element = PPI;
|
||||||
|
|
||||||
|
fn init(
|
||||||
|
&mut self,
|
||||||
|
data: &<Self::Element as Element>::Data,
|
||||||
|
setting: &mp_core::Setting,
|
||||||
|
) -> Result<(), ConfigError> {
|
||||||
|
let data_type = &data.data_type();
|
||||||
|
let cb = setting.find(data_type);
|
||||||
|
|
||||||
|
if let Some(cb) = cb {
|
||||||
|
let colormaps = cb.color()?;
|
||||||
|
self.colormap = colormaps
|
||||||
|
.iter()
|
||||||
|
.map(|c| {
|
||||||
|
[
|
||||||
|
c[0] as f32 / 255.0,
|
||||||
|
c[1] as f32 / 255.0,
|
||||||
|
c[2] as f32 / 255.0,
|
||||||
|
c[3] as f32 / 255.0,
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
pub struct PPIUniform {
|
pub struct PPIUniform {
|
||||||
origin: Vec4,
|
origin: Vec4,
|
||||||
|
common_cfg: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -145,7 +181,8 @@ impl Element for PPI {
|
|||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
entry_point: Some("fragment"),
|
entry_point: Some("fragment"),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
// format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
format: wgpu::TextureFormat::Rgba32Float,
|
||||||
blend: None,
|
blend: None,
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
})],
|
})],
|
||||||
@ -219,6 +256,7 @@ impl Element for PPI {
|
|||||||
label: Some("PPI Uniform Buffer"),
|
label: Some("PPI Uniform Buffer"),
|
||||||
contents: bytemuck::cast_slice(&[PPIUniform {
|
contents: bytemuck::cast_slice(&[PPIUniform {
|
||||||
origin: Vec4::new(0.0, 0.0, 0.0, 0.0),
|
origin: Vec4::new(0.0, 0.0, 0.0, 0.0),
|
||||||
|
common_cfg: [0.0, 0.0, 0.0, 0.0],
|
||||||
}]),
|
}]),
|
||||||
usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::UNIFORM,
|
usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::UNIFORM,
|
||||||
});
|
});
|
||||||
@ -286,6 +324,19 @@ impl Element for PPI {
|
|||||||
data_buffer_key: Some(key),
|
data_buffer_key: Some(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_uniform(&self, ctx: &Ctx, attach: &ElementAttach, config: &Self::Config) {
|
||||||
|
let uniform_buffer = attach.uniform_buffer.as_ref().unwrap();
|
||||||
|
|
||||||
|
let uniform = PPIUniform {
|
||||||
|
origin: Vec4::new(0.0, 0.0, 0.0, 0.0),
|
||||||
|
common_cfg: [0.0, 0.0, 0.0, 0.0],
|
||||||
|
};
|
||||||
|
|
||||||
|
let queue = &ctx.queue;
|
||||||
|
|
||||||
|
queue.write_buffer(uniform_buffer, 0, bytemuck::cast_slice(&[uniform]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PPI {
|
impl PPI {
|
||||||
|
|||||||
10
mp_elements/src/errors.rs
Normal file
10
mp_elements/src/errors.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use mp_core::errors::{ConfigError, DataError};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ElementError {
|
||||||
|
#[error("Init Failed, {0}")]
|
||||||
|
ConfigFailed(#[from] ConfigError),
|
||||||
|
#[error("Data Failed, {0}")]
|
||||||
|
DataFailed(#[from] DataError),
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod elementvec;
|
pub mod elementvec;
|
||||||
|
pub mod errors;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod tools;
|
pub mod tools;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user