wallet: call method insert_line through scene graph

This commit is contained in:
darkfi
2024-08-02 16:25:25 +02:00
parent 9ffe5ffa36
commit 1796ba2f2c
8 changed files with 224 additions and 104 deletions

View File

@@ -0,0 +1,11 @@
from gui import *
node_id = api.lookup_node_id("/window/view/chatty")
arg_data = bytearray()
serial.write_u32(arg_data, 110)
serial.encode_str(arg_data, "nick")
serial.encode_str(arg_data, "hello1234")
api.call_method(node_id, "insert_line", arg_data)

View File

@@ -152,6 +152,7 @@ class ErrorCode:
PY_EVAL_ERR = 30
SEXPR_EMPTY = 31
SEXPR_GLOBAL_NOT_FOUND = 32
CHANNEL_CLOSED = 36
@staticmethod
def to_str(errc):
@@ -218,6 +219,8 @@ class ErrorCode:
return "sexpr_empty"
case ErrorCode.SEXPR_GLOBAL_NOT_FOUND:
return "sexpr_global_not_found"
case ErrorCode.CHANNEL_CLOSED:
return "channel_closed"
def vertex(x, y, r, g, b, a, u, v):
buf = bytearray()
@@ -319,6 +322,8 @@ class Api:
raise exc.SExprEmpty
case 32:
raise exc.SExprGlobalNotFound
case 36:
raise exc.ChannelClosed
return cursor
def hello(self):
@@ -475,7 +480,7 @@ class Api:
serial.encode_str(req, node_path)
try:
cur = self._make_request(Command.LOOKUP_NODE_ID, req)
except exc.RequestNodeNotFound:
except exc.NodeNotFound:
return None
return serial.read_u32(cur)

View File

@@ -22,10 +22,11 @@ use futures::{stream::FuturesUnordered, StreamExt};
use std::{sync::Arc, thread};
use crate::{
error::Error,
expr::Op,
gfx2::{GraphicsEventPublisherPtr, RenderApiPtr, Vertex},
prop::{Property, PropertySubType, PropertyType},
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType},
scene::{MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType},
text2::TextShaperPtr,
ui::{chatview, Button, ChatView, EditBox, Image, Mesh, RenderLayer, Stoppable, Text, Window},
};
@@ -635,7 +636,7 @@ impl App {
sg.link(node_id, layer_node_id).unwrap();
// ChatView
let node_id = create_chatview(&mut sg, "chatty");
let (node_id, recvr) = create_chatview(&mut sg, "chatty");
let node = sg.get_node(node_id).unwrap();
let prop = node.get_property("rect").unwrap();
prop.set_f32(0, 0.).unwrap();
@@ -708,6 +709,7 @@ impl App {
self.event_pub.clone(),
self.text_shaper.clone(),
chat_tree,
recvr,
)
.await;
let mut sg = self.sg.lock().await;
@@ -916,7 +918,10 @@ fn create_editbox(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
node.id
}
fn create_chatview(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
fn create_chatview(
sg: &mut SceneGraph,
name: &str,
) -> (SceneNodeId, async_channel::Receiver<Vec<u8>>) {
debug!(target: "app", "create_chatview({name})");
let node = sg.add_node(name, SceneNodeType::ChatView);
@@ -959,5 +964,25 @@ fn create_chatview(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
node.add_property(prop).unwrap();
node.id
let (sender, recvr) = async_channel::unbounded::<Vec<u8>>();
let method = move |data: Vec<u8>, response_fn: MethodResponseFn| {
if sender.try_send(data).is_err() {
response_fn(Err(Error::ChannelClosed));
} else {
response_fn(Ok(vec![]));
}
};
node.add_method(
"insert_line",
vec![
("timestamp", "Timestamp", PropertyType::Uint32),
("nick", "Nickname", PropertyType::Str),
("text", "Text", PropertyType::Str),
],
vec![],
Box::new(method),
)
.unwrap();
(node.id, recvr)
}

View File

@@ -125,4 +125,7 @@ pub enum Error {
#[error("Empty atlas")]
AtlasIsEmpty = 35,
#[error("Channel closed")]
ChannelClosed = 36,
}

View File

@@ -526,7 +526,7 @@ impl ZeroMQAdapter {
let node = scene_graph.get_node_mut(node_id).ok_or(Error::NodeNotFound)?;
let method_name2 = method_name.clone();
let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(0);
let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(1);
let response_fn = Box::new(move |result| {
debug!(target: "req", "processing callmethod for {}:'{}'", node_id, method_name2);
tx.send(result).unwrap();

View File

@@ -66,27 +66,18 @@ impl Button {
let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
let ev_sub = event_pub.subscribe_mouse_btn_down();
let me2 = me.clone();
let mouse_btn_down_task = ex.spawn(async move {
loop {
Self::process_mouse_btn_down(&me2, &ev_sub).await;
}
});
let mouse_btn_down_task =
ex.spawn(async move { while Self::process_mouse_btn_down(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_mouse_btn_up();
let me2 = me.clone();
let mouse_btn_up_task = ex.spawn(async move {
loop {
Self::process_mouse_btn_up(&me2, &ev_sub).await;
}
});
let mouse_btn_up_task =
ex.spawn(async move { while Self::process_mouse_btn_up(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_touch();
let me2 = me.clone();
let touch_task = ex.spawn(async move {
loop {
Self::process_touch(&me2, &ev_sub).await;
}
});
let touch_task =
ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
let tasks = vec![mouse_btn_down_task, mouse_btn_up_task, touch_task];
@@ -99,10 +90,10 @@ impl Button {
async fn process_mouse_btn_down(
me: &Weak<Self>,
ev_sub: &Subscription<(MouseButton, f32, f32)>,
) {
) -> bool {
let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::button", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -111,16 +102,20 @@ impl Button {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_mouse_btn_down(btn, mouse_x, mouse_y);
true
}
async fn process_mouse_btn_up(me: &Weak<Self>, ev_sub: &Subscription<(MouseButton, f32, f32)>) {
async fn process_mouse_btn_up(
me: &Weak<Self>,
ev_sub: &Subscription<(MouseButton, f32, f32)>,
) -> bool {
let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::button", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -129,16 +124,20 @@ impl Button {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_mouse_btn_up(btn, mouse_x, mouse_y).await;
true
}
async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
async fn process_touch(
me: &Weak<Self>,
ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
) -> bool {
let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
debug!(target: "ui::button", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -147,10 +146,11 @@ impl Button {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_touch(phase, id, touch_x, touch_y).await;
true
}
fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_x: f32, mouse_y: f32) {

View File

@@ -22,6 +22,7 @@ use rand::{rngs::OsRng, Rng};
use std::{
collections::BTreeMap,
hash::{DefaultHasher, Hash, Hasher},
io::Cursor,
sync::{Arc, Mutex as SyncMutex, Weak},
};
@@ -244,6 +245,7 @@ impl ChatView {
event_pub: GraphicsEventPublisherPtr,
text_shaper: TextShaperPtr,
tree: sled::Tree,
recvr: async_channel::Receiver<Vec<u8>>,
) -> Pimpl {
debug!(target: "ui::chatview", "ChatView::new()");
let scene_graph = sg.lock().await;
@@ -265,27 +267,24 @@ impl ChatView {
let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
let ev_sub = event_pub.subscribe_mouse_wheel();
let me2 = me.clone();
let mouse_wheel_task = ex.spawn(async move {
loop {
Self::process_mouse_wheel(&me2, &ev_sub).await;
}
});
let mouse_wheel_task =
ex.spawn(async move { while Self::process_mouse_wheel(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_mouse_move();
let me2 = me.clone();
let mouse_move_task = ex.spawn(async move {
loop {
Self::process_mouse_move(&me2, &ev_sub).await;
}
});
let mouse_move_task =
ex.spawn(async move { while Self::process_mouse_move(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_touch();
let me2 = me.clone();
let touch_task = ex.spawn(async move {
loop {
Self::process_touch(&me2, &ev_sub).await;
}
});
let touch_task =
ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
let me2 = me.clone();
let insert_line_method_task =
ex.spawn(
async move { while Self::process_insert_line_method(&me2, &recvr).await {} },
);
let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
@@ -296,7 +295,8 @@ impl ChatView {
}
on_modify.when_change(rect.clone(), redraw);
let mut tasks = vec![mouse_wheel_task, mouse_move_task, touch_task];
let mut tasks =
vec![mouse_wheel_task, mouse_move_task, touch_task, insert_line_method_task];
tasks.append(&mut on_modify.tasks);
Self {
@@ -334,10 +334,10 @@ impl ChatView {
Pimpl::ChatView(self_)
}
async fn process_mouse_wheel(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
async fn process_mouse_wheel(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
let Ok((wheel_x, wheel_y)) = ev_sub.receive().await else {
debug!(target: "ui::chatview", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -346,12 +346,13 @@ impl ChatView {
};
self_.handle_mouse_wheel(wheel_x, wheel_y).await;
true
}
async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
let Ok((mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::chatview", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -360,12 +361,16 @@ impl ChatView {
};
self_.handle_mouse_move(mouse_x, mouse_y).await;
true
}
async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
async fn process_touch(
me: &Weak<Self>,
ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
) -> bool {
let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
debug!(target: "ui::chatview", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -374,6 +379,38 @@ impl ChatView {
};
self_.handle_touch(phase, id, touch_x, touch_y).await;
true
}
async fn process_insert_line_method(
me: &Weak<Self>,
recvr: &async_channel::Receiver<Vec<u8>>,
) -> bool {
let Ok(data) = recvr.recv().await else {
debug!(target: "ui::chatview", "Event relayer closed");
return false
};
fn decode_data(data: &[u8]) -> std::io::Result<(u32, String, String)> {
let mut cur = Cursor::new(&data);
let timestamp = u32::decode(&mut cur)?;
let nick = String::decode(&mut cur)?;
let text = String::decode(&mut cur)?;
Ok((timestamp, nick, text))
}
let Ok((timestamp, nick, text)) = decode_data(&data) else {
error!(target: "ui::chatview", "insert_line() method invalid arg data");
return true
};
let Some(self_) = me.upgrade() else {
// Should not happen
panic!("self destroyed before touch_task was stopped!");
};
self_.handle_insert_line(timestamp, nick, text).await;
true
}
async fn handle_mouse_wheel(&self, wheel_x: f32, wheel_y: f32) {
@@ -435,6 +472,48 @@ impl ChatView {
}
}
async fn handle_insert_line(&self, timest: u32, nick: String, text: String) {
debug!(target: "ui::chatview", "handle_insert_line({timest}, {nick}, {text})");
/*
let chatmsg = ChatMsg { nick, text };
let timestr = timest.to_string();
// left pad with zeros
let mut timestr = format!("{:0>4}", timestr);
timestr.insert(2, ':');
let text = format!("{} {} {}", timestr, chatmsg.nick, chatmsg.text);
let glyphs = self.text_shaper.shape(text, self.font_size.get()).await;
// Now add message to page
let mut pages = self.pages2.lock().unwrap();
let mut idx = None;
for (i, page) in pages.iter_mut().enumerate() {
let first_timest = page.msgs.first().unwrap().timest;
let last_timest = page.msgs.last().unwrap().timest;
if first_timest <= timest && timest <= last_timest {
idx = Some(i);
}
}
if idx.is_none() {
idx = Some(pages.len() - 1);
}
let idx = idx.unwrap();
let mut msgs = pages[idx].msgs.clone();
msgs.push(Message { timest, chatmsg, glyphs });
msgs.sort_unstable_by_key(|msg| msg.timest);
let new_page = Page2::new(msgs, &self.render_api).await;
let _ = std::mem::replace(&mut pages[idx], new_page);
drop(pages);
*/
}
/// Descent = line height - baseline
fn descent(&self) -> f32 {
self.line_height.get() - self.baseline.get()

View File

@@ -204,19 +204,13 @@ impl EditBox {
// Start a task monitoring for key down events
let ev_sub = event_pub.subscribe_char();
let me2 = me.clone();
let char_task = ex.spawn(async move {
loop {
Self::process_char(&me2, &ev_sub).await;
}
});
let char_task =
ex.spawn(async move { while Self::process_char(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_key_down();
let me2 = me.clone();
let key_down_task = ex.spawn(async move {
loop {
Self::process_key_down(&me2, &ev_sub).await;
}
});
let key_down_task =
ex.spawn(async move { while Self::process_key_down(&me2, &ev_sub).await {} });
/*
let ev_sub = event_pub.subscribe_key_up();
@@ -242,35 +236,23 @@ impl EditBox {
let ev_sub = event_pub.subscribe_mouse_btn_down();
let me2 = me.clone();
let mouse_btn_down_task = ex.spawn(async move {
loop {
Self::process_mouse_btn_down(&me2, &ev_sub).await;
}
});
let mouse_btn_down_task =
ex.spawn(async move { while Self::process_mouse_btn_down(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_mouse_btn_up();
let me2 = me.clone();
let mouse_btn_up_task = ex.spawn(async move {
loop {
Self::process_mouse_btn_up(&me2, &ev_sub).await;
}
});
let mouse_btn_up_task =
ex.spawn(async move { while Self::process_mouse_btn_up(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_mouse_move();
let me2 = me.clone();
let mouse_move_task = ex.spawn(async move {
loop {
Self::process_mouse_move(&me2, &ev_sub).await;
}
});
let mouse_move_task =
ex.spawn(async move { while Self::process_mouse_move(&me2, &ev_sub).await {} });
let ev_sub = event_pub.subscribe_touch();
let me2 = me.clone();
let touch_task = ex.spawn(async move {
loop {
Self::process_touch(&me2, &ev_sub).await;
}
});
let touch_task =
ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
on_modify.when_change(is_focused.prop(), Self::change_focus);
@@ -479,15 +461,15 @@ impl EditBox {
}
}
async fn process_char(me: &Weak<Self>, ev_sub: &Subscription<(char, KeyMods, bool)>) {
async fn process_char(me: &Weak<Self>, ev_sub: &Subscription<(char, KeyMods, bool)>) -> bool {
let Ok((key, mods, repeat)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
// First filter for only single digit keys
if DISALLOWED_CHARS.contains(&key) {
return
return true
}
let Some(self_) = me.upgrade() else {
@@ -496,15 +478,15 @@ impl EditBox {
};
if !self_.is_focused.get() {
return
return true
}
if mods.ctrl || mods.alt {
if repeat {
return
return true
}
self_.handle_shortcut(key, &mods).await;
return
return true
}
let actions = {
@@ -515,18 +497,22 @@ impl EditBox {
for _ in 0..actions {
self_.insert_char(key).await;
}
true
}
async fn process_key_down(me: &Weak<Self>, ev_sub: &Subscription<(KeyCode, KeyMods, bool)>) {
async fn process_key_down(
me: &Weak<Self>,
ev_sub: &Subscription<(KeyCode, KeyMods, bool)>,
) -> bool {
let Ok((key, mods, repeat)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
// First filter for only single digit keys
// Avoid processing events handled by insert_char()
if !ALLOWED_KEYCODES.contains(&key) {
return
return true
}
let Some(self_) = me.upgrade() else {
@@ -535,7 +521,7 @@ impl EditBox {
};
if !self_.is_focused.get() {
return
return true
}
let actions = {
@@ -549,15 +535,16 @@ impl EditBox {
for _ in 0..actions {
self_.handle_key(&key, &mods).await;
}
true
}
async fn process_mouse_btn_down(
me: &Weak<Self>,
ev_sub: &Subscription<(MouseButton, f32, f32)>,
) {
) -> bool {
let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -566,16 +553,20 @@ impl EditBox {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_mouse_btn_down(btn, mouse_x, mouse_y).await;
true
}
async fn process_mouse_btn_up(me: &Weak<Self>, ev_sub: &Subscription<(MouseButton, f32, f32)>) {
async fn process_mouse_btn_up(
me: &Weak<Self>,
ev_sub: &Subscription<(MouseButton, f32, f32)>,
) -> bool {
let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -584,16 +575,17 @@ impl EditBox {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_mouse_btn_up(btn, mouse_x, mouse_y);
true
}
async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
let Ok((mouse_x, mouse_y)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -602,16 +594,20 @@ impl EditBox {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_mouse_move(mouse_x, mouse_y).await;
true
}
async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
async fn process_touch(
me: &Weak<Self>,
ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
) -> bool {
let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
debug!(target: "ui::editbox", "Event relayer closed");
return
return false
};
let Some(self_) = me.upgrade() else {
@@ -620,10 +616,11 @@ impl EditBox {
};
if !self_.is_active.get() {
return
return true
}
self_.handle_touch(phase, id, touch_x, touch_y).await;
true
}
async fn change_focus(self: Arc<Self>) {