// mod action; mod blocks; // mod cursor; mod layout; // mod render; mod util; use std::sync::Arc; use async_trait::async_trait; use tokio::sync::Mutex; use toss::frame::{Frame, Size}; use crate::store::{Msg, MsgStore}; use crate::ui::widgets::Widget; use self::blocks::Blocks; /////////// // State // /////////// /// Position of a cursor that is displayed as the last child of its parent /// message, or last thread if it has no parent. #[derive(Debug, Clone, Copy)] struct LastChild { coming_from: Option, after: Option, } #[derive(Debug, Clone, Copy)] enum Cursor { /// No cursor visible because it is at the bottom of the chat history. /// /// See also [`Anchor::Bottom`]. Bottom, /// The cursor points to a message. Msg(I), /// The cursor has turned into an editor because we're composing a new /// message. Compose(LastChild), /// A placeholder message is being displayed for a message that was just /// sent by the user. /// /// Will be replaced by a [`Cursor::Msg`] as soon as the server replies to /// the send command with the sent message. Placeholder(LastChild), } struct InnerTreeViewState> { store: S, last_blocks: Blocks, last_cursor: Cursor, cursor: Cursor, /// Set to true if the chat should be scrolled such that the cursor is fully /// visible (if possible). If set to false, then the cursor itself is moved /// to a different message such that it remains visible. make_cursor_visible: bool, editor: (), // TODO } impl> InnerTreeViewState { fn new(store: S) -> Self { Self { store, last_blocks: Blocks::new(), last_cursor: Cursor::Bottom, cursor: Cursor::Bottom, make_cursor_visible: false, editor: (), } } } pub struct TreeViewState>(Arc>>); impl> TreeViewState { pub fn new(store: S) -> Self { Self(Arc::new(Mutex::new(InnerTreeViewState::new(store)))) } pub fn widget(&self) -> TreeView { TreeView(self.0.clone()) } } //////////// // Widget // //////////// pub struct TreeView>(Arc>>); #[async_trait] impl Widget for TreeView where M: Msg, M::Id: Send + Sync, S: MsgStore + Send + Sync, { fn size(&self, _frame: &mut Frame, _max_width: Option, _max_height: Option) -> Size { Size::ZERO } async fn render(self: Box, frame: &mut Frame) { let mut guard = self.0.lock().await; guard.relayout(frame).await; // Draw layout to screen todo!() } }