on_message() and egui message editor
This commit is contained in:
parent
ecbff9975b
commit
81bd65cf29
|
@ -1,5 +1,6 @@
|
|||
use canary::{CursorEventKind, ScriptInstance};
|
||||
use eframe::egui;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() {
|
||||
|
@ -10,7 +11,6 @@ fn main() {
|
|||
.to_owned();
|
||||
|
||||
let native_options = eframe::NativeOptions {
|
||||
multisampling: 8,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -24,9 +24,12 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
type Script = Arc<RwLock<canary::WasmtimeScript<canary::ScriptAbiImpl>>>;
|
||||
|
||||
struct App {
|
||||
script: canary::WasmtimeScript<canary::ScriptAbiImpl>,
|
||||
panels: Vec<canary::PanelId>,
|
||||
script: Script,
|
||||
panels: Vec<Panel>,
|
||||
next_idx: usize,
|
||||
last_update: Instant,
|
||||
bind_message_buf: String,
|
||||
}
|
||||
|
@ -39,8 +42,9 @@ impl App {
|
|||
let script = runtime.load_module(abi, &module).unwrap();
|
||||
|
||||
Self {
|
||||
script,
|
||||
script: Arc::new(RwLock::new(script)),
|
||||
panels: vec![],
|
||||
next_idx: 0,
|
||||
last_update: Instant::now(),
|
||||
bind_message_buf: String::new(),
|
||||
}
|
||||
|
@ -51,13 +55,26 @@ impl eframe::App for App {
|
|||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
ctx.request_repaint();
|
||||
|
||||
let mut script = self.script.write().unwrap();
|
||||
|
||||
egui::SidePanel::left("left_panel").show(ctx, |ui| {
|
||||
let text_edit = egui::TextEdit::multiline(&mut self.bind_message_buf).code_editor();
|
||||
ui.add(text_edit);
|
||||
|
||||
if ui.button("Bind Panel").clicked() {
|
||||
let msg = self.bind_message_buf.as_bytes().to_vec();
|
||||
let panel = self.script.bind_panel(msg);
|
||||
let id = script.bind_panel(msg);
|
||||
let index = self.next_idx;
|
||||
self.next_idx += 1;
|
||||
|
||||
let panel = Panel {
|
||||
script: self.script.to_owned(),
|
||||
id,
|
||||
index,
|
||||
msg_buf: String::new(),
|
||||
show_msg: false,
|
||||
};
|
||||
|
||||
self.panels.push(panel);
|
||||
}
|
||||
});
|
||||
|
@ -65,76 +82,107 @@ impl eframe::App for App {
|
|||
let dt = self.last_update.elapsed().as_secs_f32();
|
||||
self.last_update = Instant::now();
|
||||
|
||||
for (idx, panel) in self.panels.iter().enumerate() {
|
||||
self.script.update(*panel, dt);
|
||||
|
||||
let window_id = egui::Id::new(format!("panel_{}", idx));
|
||||
egui::Window::new("Panel").id(window_id).show(ctx, |ui| {
|
||||
let size = egui::vec2(800.0, 800.0);
|
||||
let sense = egui::Sense {
|
||||
click: true,
|
||||
drag: true,
|
||||
focusable: true,
|
||||
};
|
||||
|
||||
let (rect, response) = ui.allocate_at_least(size, sense);
|
||||
|
||||
if let Some(hover_pos) = response.hover_pos() {
|
||||
let local = (hover_pos - rect.left_top()) / rect.size();
|
||||
let norm = local * 2.0 - egui::vec2(1.0, 1.0);
|
||||
let x = norm.x;
|
||||
let y = -norm.y;
|
||||
let pos = canary::Vec2 { x, y };
|
||||
|
||||
let kind = if response.drag_started() {
|
||||
CursorEventKind::Select
|
||||
} else if response.drag_released() {
|
||||
CursorEventKind::Deselect
|
||||
} else if response.dragged() {
|
||||
CursorEventKind::Drag
|
||||
} else {
|
||||
CursorEventKind::Hover
|
||||
};
|
||||
|
||||
self.script.on_cursor_event(*panel, kind, pos);
|
||||
}
|
||||
|
||||
let texture = egui::TextureId::Managed(0);
|
||||
let uv = egui::pos2(0.0, 0.0);
|
||||
let mut mesh = egui::Mesh::with_texture(texture);
|
||||
|
||||
self.script.draw(*panel, |commands| {
|
||||
for command in commands.iter() {
|
||||
let voff = mesh.vertices.len() as u32;
|
||||
|
||||
match command {
|
||||
canary::DrawCommand::Mesh { vertices, indices } => {
|
||||
for v in vertices.iter() {
|
||||
use egui::epaint::Vertex;
|
||||
let pos = egui::pos2(v.position.x, -v.position.y);
|
||||
let pos = pos.to_vec2() / 2.0 + egui::vec2(0.5, 0.5);
|
||||
let pos = rect.left_top() + pos * rect.size();
|
||||
let (r, g, b, a) = v.color.to_rgba_unmultiplied();
|
||||
let color = egui::Color32::from_rgba_unmultiplied(r, g, b, a);
|
||||
let v = Vertex { pos, uv, color };
|
||||
mesh.vertices.push(v);
|
||||
}
|
||||
|
||||
for i in indices.iter() {
|
||||
mesh.indices.push(i + voff);
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let painter = ui.painter_at(rect);
|
||||
let shape = egui::Shape::mesh(mesh);
|
||||
painter.add(shape);
|
||||
|
||||
response
|
||||
});
|
||||
for panel in self.panels.iter_mut() {
|
||||
script.update(panel.id, dt);
|
||||
panel.show(&mut *script, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Panel {
|
||||
pub script: Script,
|
||||
pub id: canary::PanelId,
|
||||
pub index: usize,
|
||||
pub msg_buf: String,
|
||||
pub show_msg: bool,
|
||||
}
|
||||
|
||||
impl Panel {
|
||||
pub fn show(&mut self, script: &mut impl canary::ScriptInstance, ctx: &egui::Context) {
|
||||
let window_id = egui::Id::new(format!("panel_{}", self.index));
|
||||
egui::Window::new("Panel").id(window_id).show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
ui.checkbox(&mut self.show_msg, "Show Message Editor");
|
||||
});
|
||||
|
||||
let size = egui::vec2(800.0, 800.0);
|
||||
let sense = egui::Sense {
|
||||
click: true,
|
||||
drag: true,
|
||||
focusable: true,
|
||||
};
|
||||
|
||||
let (rect, response) = ui.allocate_at_least(size, sense);
|
||||
|
||||
if let Some(hover_pos) = response.hover_pos() {
|
||||
let local = (hover_pos - rect.left_top()) / rect.size();
|
||||
let norm = local * 2.0 - egui::vec2(1.0, 1.0);
|
||||
let x = norm.x;
|
||||
let y = -norm.y;
|
||||
let pos = canary::Vec2 { x, y };
|
||||
|
||||
let kind = if response.drag_started() {
|
||||
CursorEventKind::Select
|
||||
} else if response.drag_released() {
|
||||
CursorEventKind::Deselect
|
||||
} else if response.dragged() {
|
||||
CursorEventKind::Drag
|
||||
} else {
|
||||
CursorEventKind::Hover
|
||||
};
|
||||
|
||||
script.on_cursor_event(self.id, kind, pos);
|
||||
}
|
||||
|
||||
let texture = egui::TextureId::Managed(0);
|
||||
let uv = egui::pos2(0.0, 0.0);
|
||||
let mut mesh = egui::Mesh::with_texture(texture);
|
||||
|
||||
script.draw(self.id, |commands| {
|
||||
for command in commands.iter() {
|
||||
let voff = mesh.vertices.len() as u32;
|
||||
|
||||
match command {
|
||||
canary::DrawCommand::Mesh { vertices, indices } => {
|
||||
for v in vertices.iter() {
|
||||
use egui::epaint::Vertex;
|
||||
let pos = egui::pos2(v.position.x, -v.position.y);
|
||||
let pos = pos.to_vec2() / 2.0 + egui::vec2(0.5, 0.5);
|
||||
let pos = rect.left_top() + pos * rect.size();
|
||||
let (r, g, b, a) = v.color.to_rgba_unmultiplied();
|
||||
let color = egui::Color32::from_rgba_unmultiplied(r, g, b, a);
|
||||
let v = Vertex { pos, uv, color };
|
||||
mesh.vertices.push(v);
|
||||
}
|
||||
|
||||
for i in indices.iter() {
|
||||
mesh.indices.push(i + voff);
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let painter = ui.painter_at(rect);
|
||||
let shape = egui::Shape::mesh(mesh);
|
||||
painter.add(shape);
|
||||
|
||||
response
|
||||
});
|
||||
|
||||
let msg_edit_id = egui::Id::new(format!("msg_edit_{}", self.index));
|
||||
egui::Window::new("Message Editor")
|
||||
.open(&mut self.show_msg)
|
||||
.id(msg_edit_id)
|
||||
.show(ctx, |ui| {
|
||||
let text_edit = egui::TextEdit::multiline(&mut self.msg_buf).code_editor();
|
||||
ui.add(text_edit);
|
||||
|
||||
if ui.button("Send Message").clicked() {
|
||||
let msg = self.msg_buf.as_bytes().to_vec();
|
||||
script.on_message(self.id, msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -36,6 +36,7 @@ pub trait ScriptInstance {
|
|||
fn update(&mut self, panel: PanelId, dt: f32);
|
||||
fn draw(&mut self, panel: PanelId, f: impl FnOnce(&[DrawCommand]));
|
||||
fn on_cursor_event(&mut self, panel: PanelId, kind: CursorEventKind, at: Vec2);
|
||||
fn on_message(&mut self, panel: PanelId, msg: Vec<u8>);
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
|
@ -77,6 +78,7 @@ impl WasmtimeRuntime {
|
|||
let update = instance.get_typed_func(&mut store, "update")?;
|
||||
let draw = instance.get_typed_func(&mut store, "draw")?;
|
||||
let on_cursor_event = instance.get_typed_func(&mut store, "on_cursor_event")?;
|
||||
let on_message = instance.get_typed_func(&mut store, "on_message")?;
|
||||
|
||||
Ok(WasmtimeScript {
|
||||
store,
|
||||
|
@ -85,6 +87,7 @@ impl WasmtimeRuntime {
|
|||
update,
|
||||
draw,
|
||||
on_cursor_event,
|
||||
on_message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +99,7 @@ pub struct WasmtimeScript<T> {
|
|||
update: wasmtime::TypedFunc<(u32, f32), ()>,
|
||||
draw: wasmtime::TypedFunc<u32, ()>,
|
||||
on_cursor_event: wasmtime::TypedFunc<(u32, u32, f32, f32), ()>,
|
||||
on_message: wasmtime::TypedFunc<(u32, u32), ()>,
|
||||
}
|
||||
|
||||
impl<T: ScriptAbi> WasmtimeScript<T> {
|
||||
|
@ -245,6 +249,7 @@ impl<T: ScriptAbi> ScriptInstance for WasmtimeScript<T> {
|
|||
let args = (id as u32, msg);
|
||||
let data = self.bind_panel.call(&mut self.store, args).unwrap();
|
||||
*self.panel_datas.get_mut(id).unwrap() = data;
|
||||
self.store.data().message_free(msg);
|
||||
PanelId(id)
|
||||
}
|
||||
|
||||
|
@ -266,6 +271,13 @@ impl<T: ScriptAbi> ScriptInstance for WasmtimeScript<T> {
|
|||
.call(&mut self.store, (data, kind as u32, at.x, at.y))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn on_message(&mut self, panel: PanelId, msg: Vec<u8>) {
|
||||
let data = self.get_panel_data(panel);
|
||||
let msg = self.store.data().message_new(msg);
|
||||
self.on_message.call(&mut self.store, (data, msg)).unwrap();
|
||||
self.store.data().message_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// The standard [ScriptAbi] implementation to use.
|
||||
|
|
Loading…
Reference in New Issue