From 9df7c5c0e6d03579fa90735adf316d7e563340d7 Mon Sep 17 00:00:00 2001 From: Max Audron Date: Mon, 29 Nov 2021 14:27:27 +0100 Subject: statetracker: add bufferview widget and do some reorganization --- examples/statetracker/Cargo.toml | 2 + examples/statetracker/src/aliasmanager.rs | 91 ---------------- examples/statetracker/src/command.rs | 14 +-- examples/statetracker/src/formatter.rs | 3 +- examples/statetracker/src/main.rs | 123 +++++++++++++++------- examples/statetracker/src/server.rs | 46 +++----- examples/statetracker/src/widgets/aliasmanager.rs | 91 ++++++++++++++++ examples/statetracker/src/widgets/bufferview.rs | 96 +++++++++++++++++ examples/statetracker/src/widgets/mod.rs | 5 + 9 files changed, 302 insertions(+), 169 deletions(-) delete mode 100644 examples/statetracker/src/aliasmanager.rs create mode 100644 examples/statetracker/src/widgets/aliasmanager.rs create mode 100644 examples/statetracker/src/widgets/bufferview.rs create mode 100644 examples/statetracker/src/widgets/mod.rs (limited to 'examples/statetracker') diff --git a/examples/statetracker/Cargo.toml b/examples/statetracker/Cargo.toml index 3ac9668..8290032 100644 --- a/examples/statetracker/Cargo.toml +++ b/examples/statetracker/Cargo.toml @@ -19,6 +19,8 @@ either = "1" time = "0.2" log = "*" +crossbeam-channel = "0.5" + tokio = { version = "1", features = ["full", "rt-multi-thread"]} tokio-util = { version = "0.6", features = ["codec"] } tokio-rustls = { version = "0.22" } diff --git a/examples/statetracker/src/aliasmanager.rs b/examples/statetracker/src/aliasmanager.rs deleted file mode 100644 index afa8c91..0000000 --- a/examples/statetracker/src/aliasmanager.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::sync::Arc; - -use druid::widget::{Align, Label}; -use druid::{lens, Lens, Point, WidgetPod}; -use druid::{widget::Flex, Widget}; - -use libquassel::message::objects::AliasManager; - -pub struct AliasManagerWidget { - inner: WidgetPod, Box>>>, -} - -impl AliasManagerWidget { - pub fn new() -> Self { - let widget = WidgetPod::new(Flex::column()).boxed(); - - AliasManagerWidget { inner: widget } - } -} - -impl Widget> for AliasManagerWidget { - fn event( - &mut self, - ctx: &mut druid::EventCtx, - event: &druid::Event, - data: &mut Arc, - env: &druid::Env, - ) { - self.inner.event(ctx, event, data, env) - } - - fn lifecycle( - &mut self, - ctx: &mut druid::LifeCycleCtx, - event: &druid::LifeCycle, - data: &Arc, - env: &druid::Env, - ) { - self.inner.lifecycle(ctx, event, data, env) - } - - fn update( - &mut self, - ctx: &mut druid::UpdateCtx, - _old_data: &Arc, - data: &Arc, - _env: &druid::Env, - ) { - let aliases = lens!(AliasManager, aliases); - - let mut names: Flex> = Flex::column(); - let mut sign: Flex> = Flex::column(); - let mut expansions: Flex> = Flex::column(); - - // TODO optimise this whole thing - aliases.with(data, |aliases| { - for alias in aliases { - names.add_child(Align::right(Label::new(alias.name.clone()))); - sign.add_child(Label::new("=>")); - expansions.add_child(Align::left(Label::new(alias.expansion.clone()))); - } - }); - - let widget: Flex> = Flex::row() - .with_flex_child(names, 1.0) - .with_flex_child(sign, 1.0) - .with_flex_child(expansions, 1.0); - - self.inner = WidgetPod::new(widget).boxed(); - - ctx.children_changed(); - ctx.request_layout(); - ctx.request_paint(); - } - - fn layout( - &mut self, - ctx: &mut druid::LayoutCtx, - bc: &druid::BoxConstraints, - data: &Arc, - env: &druid::Env, - ) -> druid::Size { - let size = self.inner.layout(ctx, bc, data, env); - self.inner.set_origin(ctx, data, env, Point::ZERO); - return size; - } - - fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &Arc, env: &druid::Env) { - self.inner.paint(ctx, data, env) - } -} diff --git a/examples/statetracker/src/command.rs b/examples/statetracker/src/command.rs index 09b49d7..b10aa90 100644 --- a/examples/statetracker/src/command.rs +++ b/examples/statetracker/src/command.rs @@ -1,19 +1,13 @@ use druid::{Selector, SingleUse}; -use libquassel::{ - message::{ - objects::{Alias, AliasManager}, - SyncMessage, - }, - primitive::VariantMap, -}; +use libquassel::message::{objects::Alias, InitData, SyncMessage}; use crate::server::Direction; pub const CONNECT: Selector = Selector::new("connect"); pub const ADD_MESSAGE: Selector> = Selector::new("add_message"); -pub const ALIASMANAGER_INIT: Selector> = Selector::new("aliasmanager_init"); -pub const ALIASMANAGER_UPDATE: Selector> = - Selector::new("aliasmanager_update"); pub const ALIASMANAGER_ADD_ALIAS: Selector> = Selector::new("aliasmanager_add_alias"); + +pub const SYNCMESSAGE: Selector> = Selector::new("syncmessage"); +pub const INITDATA: Selector> = Selector::new("initdata"); diff --git a/examples/statetracker/src/formatter.rs b/examples/statetracker/src/formatter.rs index 4ceb68f..dc81887 100644 --- a/examples/statetracker/src/formatter.rs +++ b/examples/statetracker/src/formatter.rs @@ -40,7 +40,8 @@ pub enum U16ValidationError { impl std::fmt::Display for U16ValidationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", std::any::type_name_of_val(self)) + // TODO set correct display based on actual value + write!(f, "U16ValidationError::WrongNumberOfCharacters") } } diff --git a/examples/statetracker/src/main.rs b/examples/statetracker/src/main.rs index 65ee4ce..a56d054 100644 --- a/examples/statetracker/src/main.rs +++ b/examples/statetracker/src/main.rs @@ -1,19 +1,16 @@ -#![feature(type_name_of_val)] +use std::{collections::HashMap, sync::Arc}; -use std::{ops::Deref, sync::Arc}; - -use aliasmanager::AliasManagerWidget; use druid::{ - lens, widget::{Align, Either, Flex, Label, List, Split}, AppDelegate, Command, }; use druid::{AppLauncher, Data, Env, Lens, LocalizedString, Widget, WidgetExt, WindowDesc}; +use widgets::{AliasManagerWidget, BufferViewWidget}; -use libquassel::message::{NetworkMap, StatefulSyncableServer}; -use libquassel::{ - message::{objects::AliasManager, StatefulSyncableClient}, - session::Session, +use libquassel::message::{objects::AliasManager, StatefulSyncableClient, SyncProxy}; +use libquassel::message::{ + objects::{self, BufferViewManager}, + StatefulSyncableServer, }; use tracing::debug; @@ -25,18 +22,19 @@ const SPACING: f64 = 10.0; const VERTICAL_WIDGET_SPACING: f64 = 20.0; const WINDOW_TITLE: LocalizedString = LocalizedString::new("StateTracker"); +mod widgets; + mod command; mod connect; mod formatter; mod server; -mod aliasmanager; - #[derive(Clone, Data, Lens)] struct StateTracker { server: server::Server, messages: Arc>, alias_manager: Arc, + buffer_view_manager: Arc, connected: bool, #[data(ignore)] syncer: Syncer, @@ -44,14 +42,22 @@ struct StateTracker { impl StateTracker { fn new() -> StateTracker { + let (sync_channel, rpc_channel) = SyncProxy::init(1024); + StateTracker { server: server::Server::default(), messages: Arc::new(Vec::new()), alias_manager: Arc::new(AliasManager { aliases: Vec::new(), }), + buffer_view_manager: Arc::new(BufferViewManager { + buffer_view_configs: HashMap::new(), + }), connected: false, - syncer: Syncer {}, + syncer: Syncer { + sync_channel, + rpc_channel, + }, } } @@ -61,7 +67,10 @@ impl StateTracker { Split::columns( Flex::column() .with_child(Label::new("AliasManager")) - .with_child(AliasManagerWidget::new().lens(StateTracker::alias_manager)), + .with_child(AliasManagerWidget::new().lens(StateTracker::alias_manager)) + .with_spacer(SPACING) + .with_child(Label::new("BufferViewManager")) + .with_child(BufferViewWidget::new().lens(StateTracker::buffer_view_manager)), List::new(|| { Label::new(|item: &Message, _env: &_| format!("{:#?}", item)).padding(10.0) }) @@ -83,6 +92,12 @@ impl StateTracker { } } +impl Default for StateTracker { + fn default() -> Self { + Self::new() + } +} + struct StateTrackerDelegate; impl AppDelegate for StateTrackerDelegate { fn command( @@ -107,22 +122,66 @@ impl AppDelegate for StateTrackerDelegate { let mut alias_manager = Arc::make_mut(&mut data.alias_manager).clone(); alias_manager.add_alias(alias.take().unwrap()); data.alias_manager = Arc::new(alias_manager); - } else if let Some(alias_manager) = cmd.get(command::ALIASMANAGER_INIT) { - data.alias_manager = Arc::new(alias_manager.take().unwrap()); - } else if let Some(msg) = cmd.get(command::ALIASMANAGER_UPDATE) { + } else if let Some(initdata) = cmd.get(command::INITDATA) { + let (_, initdata) = initdata.take().unwrap(); + match initdata.init_data { + objects::Types::AliasManager(alias_manager) => { + data.alias_manager = Arc::new(alias_manager) + } + objects::Types::BufferViewManager(buffer_view_manager) => { + data.buffer_view_manager = Arc::new(buffer_view_manager) + } + objects::Types::BufferViewConfig(config) => { + let id: i32 = initdata.object_name.parse().unwrap(); + + let mut buffer_view_manager = + Arc::make_mut(&mut data.buffer_view_manager).clone(); + + buffer_view_manager.buffer_view_configs.insert(id, config); + + data.buffer_view_manager = Arc::new(buffer_view_manager) + } + _ => (), + } + } else if let Some(msg) = cmd.get(command::SYNCMESSAGE) { let (direction, msg) = msg.take().unwrap(); debug!("direction: {:#?}, msg: {:#?}", direction, msg); - let mut alias_manager = Arc::make_mut(&mut data.alias_manager).clone(); + match msg.class_name.as_str() { + "AliasManager" => { + let mut alias_manager = Arc::make_mut(&mut data.alias_manager).clone(); - if direction == Direction::ServerToClient { - StatefulSyncableClient::sync(&mut alias_manager, &data, msg); - } else { - StatefulSyncableServer::sync(&mut alias_manager, &data, msg); - } + if direction == Direction::ServerToClient { + StatefulSyncableClient::sync(&mut alias_manager, msg); + } else { + StatefulSyncableServer::sync(&mut alias_manager, msg); + } - data.alias_manager = Arc::new(alias_manager); + data.alias_manager = Arc::new(alias_manager); + } + "BufferViewConfig" => { + let mut buffer_view_manager = + Arc::make_mut(&mut data.buffer_view_manager).clone(); + + let id: i32 = msg.object_name.parse().unwrap(); + + let buffer_view_config = buffer_view_manager + .buffer_view_configs + .get_mut(&id) + .unwrap(); + + if direction == Direction::ServerToClient { + StatefulSyncableClient::sync(buffer_view_config, msg); + } else { + StatefulSyncableServer::sync(buffer_view_config, msg); + } + + data.buffer_view_manager = Arc::new(buffer_view_manager); + } + + _ => (), + } } druid::Handled::No @@ -137,21 +196,9 @@ impl AppDelegate for StateTrackerDelegate { // TODO make this somehow deref or smth #[derive(Clone)] -pub struct Syncer; -impl libquassel::message::SyncProxy for StateTracker { - fn sync( - &self, - class_name: &str, - object_name: Option<&str>, - function: &str, - params: libquassel::primitive::VariantList, - ) { - todo!() - } - - fn rpc(&self, function: &str, params: libquassel::primitive::VariantList) { - todo!() - } +pub struct Syncer { + sync_channel: crossbeam_channel::Receiver, + rpc_channel: crossbeam_channel::Receiver, } fn main() { diff --git a/examples/statetracker/src/server.rs b/examples/statetracker/src/server.rs index 63b36f7..f95a5fe 100644 --- a/examples/statetracker/src/server.rs +++ b/examples/statetracker/src/server.rs @@ -1,7 +1,5 @@ use anyhow::{bail, Error}; -use std::convert::TryFrom; - use druid::{ widget::{ Align, Button, Checkbox, Container, Controller, ControllerHost, Flex, Label, TextBox, @@ -12,8 +10,7 @@ use druid::{ use libquassel::{ deserialize::Deserialize, frame::QuasselCodec, - message::{self, objects, ConnAck, HandshakeMessage, Init}, - primitive::VariantMap, + message::{self, ConnAck, HandshakeMessage, Init}, }; use futures::{ @@ -26,7 +23,7 @@ use tokio::{ }; use tokio_util::codec::Framed; -use tracing::{debug, info, trace}; +use tracing::{debug, trace}; use crate::{command, formatter}; @@ -147,7 +144,7 @@ impl Server { async fn handle_login_message( buf: &[u8], state: &mut ClientState, - direction: Direction, + _direction: Direction, _ctx: ExtEventSink, ) -> Result { use libquassel::HandshakeDeserialize; @@ -183,31 +180,22 @@ impl Server { #[allow(unused_variables)] match res { - message::Message::SyncMessage(msg) => match msg.class_name.as_str() { - "AliasManager" => match msg.slot_name.as_str() { - "update" => ctx - .submit_command( - command::ALIASMANAGER_UPDATE, - SingleUse::new((direction, msg)), - Target::Global, - ) - .unwrap(), - _ => (), - }, - _ => (), - }, + message::Message::SyncMessage(msg) => ctx + .submit_command( + command::SYNCMESSAGE, + SingleUse::new((direction, msg)), + Target::Global, + ) + .unwrap(), message::Message::RpcCall(msg) => (), message::Message::InitRequest(msg) => (), - message::Message::InitData(msg) => match msg.init_data { - objects::Types::AliasManager(alias_manager) => ctx - .submit_command( - command::ALIASMANAGER_INIT, - SingleUse::new(alias_manager), - Target::Global, - ) - .unwrap(), - _ => (), - }, + message::Message::InitData(msg) => ctx + .submit_command( + command::INITDATA, + SingleUse::new((direction, msg)), + Target::Global, + ) + .unwrap(), message::Message::HeartBeat(msg) => (), message::Message::HeartBeatReply(msg) => (), } diff --git a/examples/statetracker/src/widgets/aliasmanager.rs b/examples/statetracker/src/widgets/aliasmanager.rs new file mode 100644 index 0000000..afa8c91 --- /dev/null +++ b/examples/statetracker/src/widgets/aliasmanager.rs @@ -0,0 +1,91 @@ +use std::sync::Arc; + +use druid::widget::{Align, Label}; +use druid::{lens, Lens, Point, WidgetPod}; +use druid::{widget::Flex, Widget}; + +use libquassel::message::objects::AliasManager; + +pub struct AliasManagerWidget { + inner: WidgetPod, Box>>>, +} + +impl AliasManagerWidget { + pub fn new() -> Self { + let widget = WidgetPod::new(Flex::column()).boxed(); + + AliasManagerWidget { inner: widget } + } +} + +impl Widget> for AliasManagerWidget { + fn event( + &mut self, + ctx: &mut druid::EventCtx, + event: &druid::Event, + data: &mut Arc, + env: &druid::Env, + ) { + self.inner.event(ctx, event, data, env) + } + + fn lifecycle( + &mut self, + ctx: &mut druid::LifeCycleCtx, + event: &druid::LifeCycle, + data: &Arc, + env: &druid::Env, + ) { + self.inner.lifecycle(ctx, event, data, env) + } + + fn update( + &mut self, + ctx: &mut druid::UpdateCtx, + _old_data: &Arc, + data: &Arc, + _env: &druid::Env, + ) { + let aliases = lens!(AliasManager, aliases); + + let mut names: Flex> = Flex::column(); + let mut sign: Flex> = Flex::column(); + let mut expansions: Flex> = Flex::column(); + + // TODO optimise this whole thing + aliases.with(data, |aliases| { + for alias in aliases { + names.add_child(Align::right(Label::new(alias.name.clone()))); + sign.add_child(Label::new("=>")); + expansions.add_child(Align::left(Label::new(alias.expansion.clone()))); + } + }); + + let widget: Flex> = Flex::row() + .with_flex_child(names, 1.0) + .with_flex_child(sign, 1.0) + .with_flex_child(expansions, 1.0); + + self.inner = WidgetPod::new(widget).boxed(); + + ctx.children_changed(); + ctx.request_layout(); + ctx.request_paint(); + } + + fn layout( + &mut self, + ctx: &mut druid::LayoutCtx, + bc: &druid::BoxConstraints, + data: &Arc, + env: &druid::Env, + ) -> druid::Size { + let size = self.inner.layout(ctx, bc, data, env); + self.inner.set_origin(ctx, data, env, Point::ZERO); + return size; + } + + fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &Arc, env: &druid::Env) { + self.inner.paint(ctx, data, env) + } +} diff --git a/examples/statetracker/src/widgets/bufferview.rs b/examples/statetracker/src/widgets/bufferview.rs new file mode 100644 index 0000000..c96f8d5 --- /dev/null +++ b/examples/statetracker/src/widgets/bufferview.rs @@ -0,0 +1,96 @@ +use std::sync::Arc; + +use druid::widget::{Align, Label}; +use druid::{lens, Lens, Point, WidgetPod}; +use druid::{widget::Flex, Widget}; + +use libquassel::message::objects::BufferViewManager; + +pub struct BufferViewWidget { + inner: WidgetPod, Box>>>, +} + +impl BufferViewWidget { + pub fn new() -> Self { + let widget = WidgetPod::new(Flex::column()).boxed(); + + BufferViewWidget { inner: widget } + } +} + +impl Widget> for BufferViewWidget { + fn event( + &mut self, + ctx: &mut druid::EventCtx, + event: &druid::Event, + data: &mut Arc, + env: &druid::Env, + ) { + self.inner.event(ctx, event, data, env) + } + + fn lifecycle( + &mut self, + ctx: &mut druid::LifeCycleCtx, + event: &druid::LifeCycle, + data: &Arc, + env: &druid::Env, + ) { + self.inner.lifecycle(ctx, event, data, env) + } + + fn update( + &mut self, + ctx: &mut druid::UpdateCtx, + _old_data: &Arc, + data: &Arc, + _env: &druid::Env, + ) { + let buffer_view_configs = lens!(BufferViewManager, buffer_view_configs); + + let mut names: Flex> = Flex::column(); + let mut buffers: Flex> = Flex::column(); + // let mut expansions: Flex> = Flex::column(); + + // TODO optimise this whole thing + buffer_view_configs.with(data, |configs| { + for (_id, config) in configs { + names.add_child(Label::new(config.buffer_view_name.clone())); + buffers.add_child(Label::new(format!("{:?}", config.buffers))); + // expansions.add_child(Align::left(Label::new(alias.expansion.clone()))); + } + }); + + let widget: Flex> = Flex::row() + .with_flex_child(names, 1.0) + .with_flex_child(buffers, 1.0); + // .with_flex_child(expansions, 1.0); + + self.inner = WidgetPod::new(widget).boxed(); + + ctx.children_changed(); + ctx.request_layout(); + ctx.request_paint(); + } + + fn layout( + &mut self, + ctx: &mut druid::LayoutCtx, + bc: &druid::BoxConstraints, + data: &Arc, + env: &druid::Env, + ) -> druid::Size { + let size = self.inner.layout(ctx, bc, data, env); + self.inner.set_origin(ctx, data, env, Point::ZERO); + return size; + } + + fn paint( + &mut self, + ctx: &mut druid::PaintCtx, + data: &Arc, + env: &druid::Env, + ) { + self.inner.paint(ctx, data, env) + } +} diff --git a/examples/statetracker/src/widgets/mod.rs b/examples/statetracker/src/widgets/mod.rs new file mode 100644 index 0000000..c837e5d --- /dev/null +++ b/examples/statetracker/src/widgets/mod.rs @@ -0,0 +1,5 @@ +mod aliasmanager; +mod bufferview; + +pub use aliasmanager::*; +pub use bufferview::*; -- cgit v1.2.3