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]]
|
||||
name = "bytemuck"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
||||
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
@ -665,6 +665,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
name = "element_bridge"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"flume",
|
||||
"makepad-widgets",
|
||||
"mp_elements",
|
||||
@ -1712,9 +1713,11 @@ name = "mp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"element_bridge",
|
||||
"futures",
|
||||
"glam",
|
||||
"image",
|
||||
"indexmap",
|
||||
"log",
|
||||
"makepad-widgets",
|
||||
@ -1764,6 +1767,7 @@ dependencies = [
|
||||
"quick_cache",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"thiserror 2.0.3",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
|
||||
@ -9,3 +9,4 @@ makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik",
|
||||
flume = "0.11.1"
|
||||
wgpu = "23.0.0"
|
||||
tokio = { version = "1.41.1", features = ["sync"] }
|
||||
bytemuck = "1.20.0"
|
||||
|
||||
@ -9,26 +9,18 @@ pub use mp_elements::app::Window;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextureBridge {
|
||||
dirty: bool,
|
||||
_buffer: Arc<tokio::sync::Mutex<Vec<u8>>>,
|
||||
window: Arc<RenderWindow>,
|
||||
_texture: Texture,
|
||||
}
|
||||
|
||||
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);
|
||||
Self {
|
||||
dirty: true,
|
||||
_buffer: Arc::new(tokio::sync::Mutex::new(vec![0u8; 256 * 256 * 4])),
|
||||
window: Arc::new(window),
|
||||
_texture: texture,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &Texture {
|
||||
&self._texture
|
||||
}
|
||||
|
||||
pub fn window(&self) -> &RenderWindow {
|
||||
&self.window
|
||||
}
|
||||
@ -41,7 +33,7 @@ impl TextureBridge {
|
||||
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 (sender, receiver) = flume::bounded(1);
|
||||
@ -52,18 +44,14 @@ impl TextureBridge {
|
||||
device.poll(wgpu::Maintain::wait()).panic_on_timeout();
|
||||
receiver.recv_async().await.unwrap().unwrap();
|
||||
|
||||
{
|
||||
let result = {
|
||||
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();
|
||||
}
|
||||
|
||||
pub fn update_texture(&self, cx: &mut Cx, buffer: Vec<u8>) {
|
||||
self._texture.put_back_vec_u8(cx, buffer, None);
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> Arc<tokio::sync::Mutex<Vec<u8>>> {
|
||||
self._buffer.clone()
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,3 +21,5 @@ futures = "0.3.31"
|
||||
async-trait = "0.1.83"
|
||||
thiserror = "2.0.3"
|
||||
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::menu::{handle_menu, spawn_background};
|
||||
use crate::widgets::area::TAreaWidgetRefExt;
|
||||
use crate::widgets::selector::{
|
||||
ItemKey, ItemValue, SelectorListWidgetRefExt, SelectorWidgetRefExt,
|
||||
};
|
||||
|
||||
use crate::windows_manager::WM;
|
||||
use crate::{render_task::RenderTasks, PLUGIN_MANAGER, RUNTIME};
|
||||
use crate::menu::handle_menu;
|
||||
use crate::selector::SelectorModalAction;
|
||||
use crate::task_register::{BridgeManager, ConfigManager, TaskConfig, TaskManager};
|
||||
use crate::widgets::area::{TAreaAction, TAreaWidgetRefExt};
|
||||
use crate::widgets::loading::{self, LoadingModalWidgetRefExt};
|
||||
use crate::windows_manager::{WindowId, WindowsManager};
|
||||
use crate::PLUGIN_MANAGER;
|
||||
use ::log::info;
|
||||
use element_bridge::TextureBridge;
|
||||
use makepad_widgets::makepad_micro_serde::*;
|
||||
use makepad_widgets::*;
|
||||
use mp_elements::app::DrawList as DW;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
live_design! {
|
||||
import makepad_widgets::base::*;
|
||||
import makepad_widgets::theme_desktop_dark::*;
|
||||
import crate::app_ui::MainView;
|
||||
import crate::widgets::selector::*;
|
||||
import crate::selector::SelectorBase;
|
||||
import crate::widgets::loading::*;
|
||||
|
||||
HELLO = "Hello, World!";
|
||||
|
||||
@ -62,7 +58,13 @@ live_design! {
|
||||
height: 470
|
||||
width:650
|
||||
show_bg: false
|
||||
selector = <Selector> {}
|
||||
selector = <SelectorBase> {}
|
||||
}
|
||||
}
|
||||
|
||||
loading_modal = <Modal> {
|
||||
content: {
|
||||
inner_loading = <LoadingModal> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,15 +146,12 @@ pub enum AppAction {
|
||||
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)]
|
||||
pub enum TaskAction {
|
||||
Register(usize, Arc<TextureBridge>, DW),
|
||||
Register {
|
||||
draw_list: DW,
|
||||
configs: Vec<Option<TaskConfig>>,
|
||||
},
|
||||
Unregister(),
|
||||
}
|
||||
|
||||
@ -162,20 +161,33 @@ pub enum FileAction {
|
||||
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)]
|
||||
pub struct App {
|
||||
#[live]
|
||||
ui: WidgetRef,
|
||||
#[rust]
|
||||
pub render_tasks: Arc<Mutex<RenderTasks>>,
|
||||
task_manager: TaskManager,
|
||||
#[rust]
|
||||
windows_manager: WM,
|
||||
windows_manager: WindowsManager,
|
||||
#[rust]
|
||||
tex_reciver: ToUIReceiver<Vec<u8>>,
|
||||
|
||||
bridge_manager: BridgeManager,
|
||||
#[rust]
|
||||
file_manager: FileManager,
|
||||
|
||||
#[rust]
|
||||
config_manager: ConfigManager,
|
||||
#[rust]
|
||||
app_state: AppState,
|
||||
#[rust]
|
||||
timer: Timer,
|
||||
}
|
||||
@ -188,56 +200,45 @@ impl LiveRegister for App {
|
||||
crate::widgets::renderer::live_design(_cx);
|
||||
crate::widgets::background_text::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 {
|
||||
// Start UP
|
||||
fn handle_startup(&mut self, cx: &mut Cx) {
|
||||
info!("Starting up......");
|
||||
let ui = self.ui.clone();
|
||||
|
||||
// New Area init
|
||||
let area = ui.tarea(id!(quad));
|
||||
area.set_windows(self.windows_manager.clone());
|
||||
// Listening to the render tasks
|
||||
let render_tasks = self.render_tasks.clone();
|
||||
RUNTIME.spawn(async move {
|
||||
let render_task = render_tasks.lock().await;
|
||||
render_task.render().await;
|
||||
});
|
||||
let id = self.windows_manager.add_window(area.clone());
|
||||
area.set_id(id.clone());
|
||||
|
||||
let items = vec![(
|
||||
ItemKey {
|
||||
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(),
|
||||
},
|
||||
],
|
||||
)];
|
||||
// Default Focus
|
||||
self.app_state.window_state.current_focus = Some(id.clone());
|
||||
|
||||
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) {
|
||||
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) {
|
||||
let ui = self.ui.clone();
|
||||
|
||||
if ui.button(id!(start)).clicked(actions) {
|
||||
cx.action(AppAction::OpenFile);
|
||||
}
|
||||
@ -274,17 +275,37 @@ impl MatchEvent for App {
|
||||
}
|
||||
|
||||
AppAction::Task(task) => match task {
|
||||
TaskAction::Register(bridge_id, bridge, draw_list) => {
|
||||
info!(
|
||||
"Register Task for {:?}, draw_list: {:?}",
|
||||
bridge_id, draw_list
|
||||
);
|
||||
let bridge = bridge.render_window();
|
||||
let sender = self.tex_reciver.sender();
|
||||
RUNTIME.block_on(async {
|
||||
let mut render_tasks = self.render_tasks.lock().await;
|
||||
render_tasks.register_task(sender, bridge_id, bridge, draw_list);
|
||||
});
|
||||
TaskAction::Register { draw_list, configs } => {
|
||||
info!("Register Task for draw_list");
|
||||
let current_window = &self.app_state.window_state.current_focus;
|
||||
if let Some(window) = current_window.as_ref() {
|
||||
let bridge = self
|
||||
.bridge_manager
|
||||
.get_bridge(window)
|
||||
.expect("Bridge not found");
|
||||
|
||||
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() => {
|
||||
@ -296,6 +317,13 @@ impl MatchEvent for App {
|
||||
FileAction::OpenFile(file) => {
|
||||
info!("Open File: {:?}", 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) => {
|
||||
@ -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 {
|
||||
fn handle_event(&mut self, cx: &mut Cx, event: &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(|_| {
|
||||
let notifacion: PopupNotificationRef = self.ui.popup_notification(id!(notification));
|
||||
notifacion.close(cx);
|
||||
@ -330,6 +389,4 @@ impl AppMain for App {
|
||||
}
|
||||
}
|
||||
|
||||
impl 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 makepad_draw::shader::std::*;
|
||||
import crate::widgets::selector_modal::*;
|
||||
import crate::widgets::background_text::BackgroundLabel;
|
||||
import crate::widgets::selector::*;
|
||||
import crate::sidepanel::*;
|
||||
|
||||
HELLO = "Hello, World!";
|
||||
|
||||
@ -63,14 +63,7 @@ live_design! {
|
||||
y: 0.5
|
||||
},
|
||||
|
||||
<View> {
|
||||
width: 600
|
||||
height: 500
|
||||
align: {
|
||||
x: 0.5,
|
||||
y: 0.5
|
||||
}
|
||||
}
|
||||
quad = <Area> {}
|
||||
|
||||
}
|
||||
|
||||
@ -83,108 +76,10 @@ live_design! {
|
||||
Controller = <RectView> {
|
||||
draw_bg: { color: (THEME_COLOR_U_1) }
|
||||
height: Fill, width: Fill
|
||||
padding: 10.,
|
||||
// padding: 10.,
|
||||
flow: Down,
|
||||
spacing: 15.,
|
||||
|
||||
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"}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
<SidePanel> {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
use crate::{
|
||||
app::AppAction,
|
||||
errors::AppErr,
|
||||
widgets::selector::{ItemKey, ItemValue, SelectorWidgetRefExt},
|
||||
selector::SelectorBaseWidgetRefExt,
|
||||
widgets::selector::{ItemKey, ItemValue},
|
||||
GIAPP, RUNTIME,
|
||||
};
|
||||
use ::log::info;
|
||||
use makepad_widgets::*;
|
||||
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 crate::DATAPOOL;
|
||||
@ -45,17 +44,16 @@ impl FileManager {
|
||||
}
|
||||
|
||||
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 loading_modal = ui.modal(id!(loading_modal));
|
||||
while let Ok(mut data) = self.receiver.try_recv() {
|
||||
if data.len() == 1 {
|
||||
let (path, data) = data.pop().unwrap();
|
||||
if let Ok(data) = data {
|
||||
info!("Data: {:?}", data);
|
||||
cx.action(AppAction::Notification {
|
||||
message: format!("hello,World, {:?}", data),
|
||||
duration: 3.0,
|
||||
});
|
||||
|
||||
let mut items = vec![];
|
||||
|
||||
@ -64,6 +62,7 @@ impl FileManager {
|
||||
let supported_elements = pipelines.supported_elements(&data);
|
||||
|
||||
let key_name = ItemKey {
|
||||
data_idx: *idx,
|
||||
path: "".to_string(),
|
||||
category: data.description.clone(),
|
||||
description: data.description.clone(),
|
||||
@ -71,9 +70,14 @@ impl FileManager {
|
||||
|
||||
let item_values = supported_elements
|
||||
.iter()
|
||||
.map(|v| ItemValue {
|
||||
.map(|v| {
|
||||
(
|
||||
ItemValue {
|
||||
name: v.name().to_string(),
|
||||
icon: "".to_string(),
|
||||
},
|
||||
v.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -85,12 +89,13 @@ impl FileManager {
|
||||
.map(|v| v.to_string_lossy())
|
||||
.unwrap_or_default();
|
||||
|
||||
selector.set_items(cx, items);
|
||||
selector.set_base_name(&base_name);
|
||||
selector.set_items(cx, data, &base_name, items);
|
||||
selector_modal.open(cx);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
loading_modal.close(cx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,9 @@ pub mod app_ui;
|
||||
pub mod errors;
|
||||
pub mod file;
|
||||
pub mod menu;
|
||||
pub mod render_task;
|
||||
pub mod selector;
|
||||
pub mod sidepanel;
|
||||
pub mod task_register;
|
||||
pub mod widgets;
|
||||
|
||||
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) {
|
||||
match event {
|
||||
Event::Draw(_) => {
|
||||
// Render Task
|
||||
let tasks = app.render_tasks.clone();
|
||||
RUNTIME.spawn(async move {
|
||||
let tasks = tasks.lock().await;
|
||||
tasks.render().await;
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// pub fn spawn_background(app: &mut App, event: &Event) {
|
||||
// match event {
|
||||
// Event::Draw(_) => {
|
||||
// // Render Task
|
||||
// let tasks = app.render_tasks.clone();
|
||||
// RUNTIME.spawn(async move {
|
||||
// let tasks = tasks.lock().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::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::windows_manager::WindowId;
|
||||
use crate::windows_manager::WM;
|
||||
use crate::GIAPP;
|
||||
use ::log::info;
|
||||
use element_bridge::{TextureBridge, Window};
|
||||
use element_bridge::TextureBridge;
|
||||
use makepad_widgets::makepad_derive_widget::*;
|
||||
use makepad_widgets::makepad_draw::*;
|
||||
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::projection::Projection;
|
||||
|
||||
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)]
|
||||
pub struct TArea {
|
||||
#[redraw]
|
||||
#[deref]
|
||||
#[live]
|
||||
draw: DrawQuad,
|
||||
#[walk]
|
||||
walk: Walk,
|
||||
#[layout]
|
||||
layout: Layout,
|
||||
view: View,
|
||||
#[live]
|
||||
id: String,
|
||||
#[live]
|
||||
@ -36,9 +65,16 @@ pub struct TArea {
|
||||
width_scale: f64,
|
||||
|
||||
#[rust]
|
||||
bridge: Option<Arc<Mutex<TextureBridge>>>,
|
||||
window_id: Option<WindowId>,
|
||||
|
||||
#[rust]
|
||||
windows: WM,
|
||||
texture: Option<Texture>,
|
||||
}
|
||||
|
||||
#[derive(Clone, DefaultNone, Debug)]
|
||||
pub enum TAreaAction {
|
||||
GetFocus(WindowId),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -81,25 +117,6 @@ impl TAreaState {
|
||||
pub fn resize(&mut self, width: f32, height: f32) {
|
||||
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 {}
|
||||
@ -110,68 +127,73 @@ pub enum MyWidgetAction {
|
||||
}
|
||||
|
||||
impl Widget for TArea {
|
||||
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {}
|
||||
|
||||
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||
let rect = cx.peek_walk_turtle(walk);
|
||||
let current_size = rect.size;
|
||||
|
||||
let current_texture = self.get_texture();
|
||||
// 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,
|
||||
},
|
||||
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||
match event.hits(cx, self.view.area()) {
|
||||
Hit::FingerDown(_) => {
|
||||
cx.widget_action(
|
||||
self.widget_uid(),
|
||||
&scope.path,
|
||||
TAreaAction::GetFocus(self.window_id.clone().unwrap()),
|
||||
);
|
||||
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 {
|
||||
fn get_texture(&self) -> Option<Texture> {
|
||||
self.bridge
|
||||
.as_ref()
|
||||
.map(|bridge| bridge.lock().unwrap().texture().clone())
|
||||
fn set_id(&mut self, id: WindowId) {
|
||||
self.window_id = Some(id);
|
||||
}
|
||||
|
||||
fn set_windows(&mut self, windows: WM) {
|
||||
info!("Setting windows for area: {}", self.id);
|
||||
self.windows = windows;
|
||||
fn set_texture(&mut self, cx: &mut Cx, texture: Texture) {
|
||||
self.texture = Some(texture);
|
||||
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 {
|
||||
pub fn set_windows(&self, windows: WM) {
|
||||
if let Some(mut area) = self.borrow_mut() {
|
||||
area.set_windows(windows);
|
||||
pub fn set_id(&self, id: WindowId) {
|
||||
if let Some(mut s) = self.borrow_mut() {
|
||||
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 background_text;
|
||||
pub mod element_panels;
|
||||
pub mod loading;
|
||||
pub mod renderer;
|
||||
pub mod selector;
|
||||
|
||||
@ -76,25 +76,6 @@ impl RenderState {
|
||||
pub fn resize(&mut self, width: f32, height: f32) {
|
||||
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 {}
|
||||
|
||||
@ -2,6 +2,8 @@ use std::collections::HashMap;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use makepad_widgets::*;
|
||||
use mp_core::Data;
|
||||
use mp_elements::elements::{Element, Elements};
|
||||
|
||||
live_design! {
|
||||
import makepad_widgets::base::*;
|
||||
@ -276,12 +278,16 @@ pub enum SelectorAction {
|
||||
None,
|
||||
SelectItem(ItemKey, ItemValue, usize, usize),
|
||||
|
||||
Selected(ItemKey, usize),
|
||||
Unselected(ItemKey, usize),
|
||||
Selected {
|
||||
element: Vec<Elements>,
|
||||
key: ItemKey,
|
||||
item: ItemValue,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ItemKey {
|
||||
pub data_idx: usize,
|
||||
pub path: String,
|
||||
pub category: String,
|
||||
pub description: String,
|
||||
@ -545,7 +551,7 @@ pub struct Selector {
|
||||
view: View,
|
||||
|
||||
#[rust]
|
||||
class: Vec<(ItemKey, Vec<ItemValue>)>,
|
||||
class: Vec<(ItemKey, Vec<(ItemValue, Elements)>)>,
|
||||
|
||||
#[rust]
|
||||
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) {
|
||||
let list = self.view.widget(id!(list)).as_portal_list();
|
||||
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() {
|
||||
SelectorAction::SelectItem(key, item, list_id, item_id) => {
|
||||
let raw_selected = &self.selected;
|
||||
@ -570,13 +578,25 @@ impl Widget for Selector {
|
||||
list.get_item(list_id).map(|v| {
|
||||
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 {
|
||||
@ -586,6 +606,10 @@ impl Widget for Selector {
|
||||
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;
|
||||
// TitleBar and List
|
||||
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 = 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);
|
||||
}
|
||||
|
||||
@ -626,19 +650,23 @@ impl Widget for 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;
|
||||
|
||||
let list = self.view.widget(id!(list)).as_portal_list();
|
||||
|
||||
list.clear_query_cache();
|
||||
self.view.redraw(cx);
|
||||
}
|
||||
|
||||
fn set_base_name(&mut self, name: &str) {
|
||||
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 {
|
||||
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() {
|
||||
item.set_items(cx, items);
|
||||
}
|
||||
|
||||
@ -1,103 +1,97 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
};
|
||||
use makepad_widgets::{Cx, PointUsize, RectUsize, SizeUsize, Texture, ToUIReceiver, ToUISender};
|
||||
|
||||
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 {
|
||||
id: u64,
|
||||
name: String,
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct WindowsManager {
|
||||
inner: HashMap<WindowId, Arc<Mutex<TextureBridge>>>,
|
||||
|
||||
all_bridges: Vec<(usize, Arc<Mutex<TextureBridge>>)>,
|
||||
|
||||
all_revelant_buffers: Arc<Mutex<HashMap<usize, Arc<tokio::sync::Mutex<Vec<u8>>>>>>,
|
||||
inner: HashMap<WindowId, TAreaRef>,
|
||||
recv: ToUIReceiver<(TaskId, Vec<f32>)>,
|
||||
}
|
||||
|
||||
impl WindowsManager {
|
||||
pub fn new() -> Self {
|
||||
let recv = ToUIReceiver::default();
|
||||
Self {
|
||||
inner: HashMap::new(),
|
||||
all_bridges: Vec::new(),
|
||||
all_revelant_buffers: Arc::new(Mutex::new(HashMap::new())),
|
||||
recv,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edit_window<F>(&mut self, id: WindowId, f: F) -> (usize, Arc<Mutex<TextureBridge>>)
|
||||
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));
|
||||
pub fn add_window(&mut self, window: TAreaRef) -> WindowId {
|
||||
// New window
|
||||
self.inner
|
||||
.entry(id)
|
||||
.and_modify(|e| *e = bridge.clone())
|
||||
.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)
|
||||
let id = WindowId::primary();
|
||||
self.inner.entry(id.clone()).or_insert(window);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn get_bridge(&self, id: usize) -> Option<Arc<Mutex<TextureBridge>>> {
|
||||
self.all_bridges.get(id).map(|(_, bridge)| bridge.clone())
|
||||
pub fn get_window(&self, id: &WindowId) -> Option<&TAreaRef> {
|
||||
self.inner.get(id)
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> AllBuffers {
|
||||
self.all_revelant_buffers.clone()
|
||||
pub fn sender(&self) -> ToUISender<(TaskId, Vec<f32>)> {
|
||||
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 {
|
||||
pub fn new<S: Into<String>>(name: S) -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
id: WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
|
||||
name: name.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct WM(Arc<std::sync::Mutex<WindowsManager>>);
|
||||
|
||||
impl WM {
|
||||
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()
|
||||
pub fn primary() -> Self {
|
||||
Self {
|
||||
id: WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
|
||||
name: "Primary".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ pub enum PipelineError {
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConfigError {
|
||||
#[error("")]
|
||||
#[error("because: {0}")]
|
||||
IOError(#[from] std::io::Error),
|
||||
#[error("")]
|
||||
TomlError(#[from] toml::de::Error),
|
||||
|
||||
@ -14,6 +14,7 @@ image = "0.25.5"
|
||||
rust-embed = "8.5.0"
|
||||
flume = "0.11.1"
|
||||
log = "0.4.22"
|
||||
thiserror = "2.0.3"
|
||||
|
||||
[build-dependencies]
|
||||
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::elementvec::ElementVec;
|
||||
use encase;
|
||||
@ -63,8 +66,8 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_pool(&mut self) -> &mut DataBufferPool {
|
||||
&mut self.buffer_pool
|
||||
pub fn buffer_pool(&self) -> &DataBufferPool {
|
||||
&self.buffer_pool
|
||||
}
|
||||
|
||||
// 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, &[]);
|
||||
}
|
||||
|
||||
// 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.
|
||||
attach.bind(&mut render_pass);
|
||||
|
||||
@ -170,6 +179,7 @@ pub struct RenderWindow {
|
||||
texture_view: wgpu::TextureView,
|
||||
output: Output,
|
||||
window: Window,
|
||||
scissors: Mutex<[u32; 2]>,
|
||||
}
|
||||
|
||||
impl RenderWindow {
|
||||
@ -187,7 +197,8 @@ impl RenderWindow {
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
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,
|
||||
view_formats: &[],
|
||||
});
|
||||
@ -196,6 +207,7 @@ impl RenderWindow {
|
||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let output = Output::new(device);
|
||||
let scissors = Mutex::new([window.width, window.height]);
|
||||
|
||||
Self {
|
||||
_texture: texture,
|
||||
@ -203,6 +215,7 @@ impl RenderWindow {
|
||||
texture_view,
|
||||
output,
|
||||
window,
|
||||
scissors,
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,6 +224,10 @@ impl RenderWindow {
|
||||
}
|
||||
|
||||
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(
|
||||
wgpu::ImageCopyTexture {
|
||||
texture: &self._texture,
|
||||
@ -222,13 +239,13 @@ impl RenderWindow {
|
||||
buffer: &self.output.output_buffer,
|
||||
layout: wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256 * 4),
|
||||
rows_per_image: Some(256),
|
||||
bytes_per_row: Some((width * 16 + 255) / 256 * 256),
|
||||
rows_per_image: Some(height),
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: self.window.width,
|
||||
height: self.window.height,
|
||||
width: width,
|
||||
height: height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
@ -387,9 +404,9 @@ pub struct Output {
|
||||
|
||||
impl Output {
|
||||
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 {
|
||||
size: output_buffer_size,
|
||||
usage: wgpu::BufferUsages::COPY_DST
|
||||
@ -403,7 +420,7 @@ impl Output {
|
||||
Self { output_buffer }
|
||||
}
|
||||
|
||||
pub async fn get_data(&self, ctx: &Ctx) {
|
||||
async fn get_data(&self, ctx: &Ctx) {
|
||||
let device = &ctx.device;
|
||||
// 需要对映射变量设置范围,以便我们能够解除缓冲区的映射
|
||||
let buffer_slice = self.output_buffer.slice(..);
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
pub mod ppi;
|
||||
use crate::{
|
||||
app::{BufferKey, Ctx, DataBufferPool},
|
||||
errors::ElementError,
|
||||
App,
|
||||
};
|
||||
use mp_core::config;
|
||||
use mp_core::{
|
||||
config,
|
||||
errors::{ConfigError, DataError},
|
||||
Data, Setting,
|
||||
};
|
||||
pub use ppi::PPI;
|
||||
use std::any::Any;
|
||||
use wgpu::util::DeviceExt;
|
||||
@ -78,6 +83,45 @@ macro_rules! elements {
|
||||
$(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> {
|
||||
@ -116,7 +160,7 @@ pub trait Element {
|
||||
type Vertex;
|
||||
type Uniform;
|
||||
type Data;
|
||||
type Config;
|
||||
type Config: Default + ElementConfig<Element = Self>;
|
||||
|
||||
const NAME: &'static str;
|
||||
const DESC: &'static str;
|
||||
@ -143,6 +187,28 @@ pub trait Element {
|
||||
buffer_pool: &DataBufferPool,
|
||||
config: &Self::Config,
|
||||
) -> 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)]
|
||||
|
||||
@ -8,10 +8,10 @@ use crate::{
|
||||
};
|
||||
use bytemuck;
|
||||
use glam::{Vec3, Vec4};
|
||||
use mp_core::{data::CoordType, RadarGridData};
|
||||
use mp_core::{data::CoordType, errors::ConfigError, RadarGridData};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use super::{Element, ElementAttach};
|
||||
use super::{Element, ElementAttach, ElementConfig};
|
||||
|
||||
const EMAXNUM: u64 = 50;
|
||||
const AMAXNUM: u64 = 360;
|
||||
@ -24,15 +24,51 @@ pub struct PPI {
|
||||
colormap: Option<ColorMap>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PPIConfig {
|
||||
pub colormap: Vec<[f32; 4]>,
|
||||
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)]
|
||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct PPIUniform {
|
||||
origin: Vec4,
|
||||
common_cfg: [f32; 4],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -145,7 +181,8 @@ impl Element for PPI {
|
||||
compilation_options: Default::default(),
|
||||
entry_point: Some("fragment"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
// format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
format: wgpu::TextureFormat::Rgba32Float,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
@ -219,6 +256,7 @@ impl Element for PPI {
|
||||
label: Some("PPI Uniform Buffer"),
|
||||
contents: bytemuck::cast_slice(&[PPIUniform {
|
||||
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,
|
||||
});
|
||||
@ -286,6 +324,19 @@ impl Element for PPI {
|
||||
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 {
|
||||
|
||||
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 elements;
|
||||
pub mod elementvec;
|
||||
pub mod errors;
|
||||
pub mod renderer;
|
||||
pub mod tools;
|
||||
mod utils;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user