Make Widget::size like toss::AsyncWidget::size
This commit is contained in:
parent
059ff94aef
commit
ff9a16d8a3
21 changed files with 244 additions and 110 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -68,6 +68,17 @@ version = "1.0.70"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.68"
|
||||
|
|
@ -240,6 +251,7 @@ name = "cove"
|
|||
version = "0.6.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"clap",
|
||||
"cookie",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.70"
|
||||
async-recursion = "1.0.4"
|
||||
async-trait = "0.1.68"
|
||||
clap = { version = "4.2.1", features = ["derive", "deprecated"] }
|
||||
cookie = "0.17.0"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::{fmt, io};
|
|||
use async_trait::async_trait;
|
||||
use parking_lot::FairMutex;
|
||||
use time::OffsetDateTime;
|
||||
use toss::{Frame, Size, Styled, Terminal};
|
||||
use toss::{Frame, Size, Styled, Terminal, WidthDb};
|
||||
|
||||
use crate::store::{Msg, MsgStore};
|
||||
|
||||
|
|
@ -139,14 +139,19 @@ pub enum Chat<M: Msg, S: MsgStore<M>> {
|
|||
#[async_trait]
|
||||
impl<M, S> Widget for Chat<M, S>
|
||||
where
|
||||
M: Msg + ChatMsg,
|
||||
M: Msg + ChatMsg + Send + Sync,
|
||||
M::Id: Send + Sync,
|
||||
S: MsgStore<M> + Send + Sync,
|
||||
S::Error: fmt::Display,
|
||||
{
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
match self {
|
||||
Self::Tree(tree) => tree.size(frame, max_width, max_height),
|
||||
Self::Tree(tree) => tree.size(widthdb, max_width, max_height).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@ pub struct Block<I> {
|
|||
}
|
||||
|
||||
impl<I> Block<I> {
|
||||
pub fn new<W: Into<BoxedWidget>>(frame: &mut Frame, id: I, widget: W) -> Self {
|
||||
pub async fn new<W: Into<BoxedWidget>>(frame: &mut Frame, id: I, widget: W) -> Self {
|
||||
// Interestingly, rust-analyzer fails to deduce the type of `widget`
|
||||
// here but rustc knows it's a `BoxedWidget`.
|
||||
let widget = widget.into();
|
||||
let size = widget.size(frame, Some(frame.size().width), None);
|
||||
let max_width = frame.size().width;
|
||||
let size = widget.size(frame.widthdb(), Some(max_width), None).await;
|
||||
let height = size.height.into();
|
||||
Self {
|
||||
id,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::sync::Arc;
|
|||
use async_trait::async_trait;
|
||||
use parking_lot::FairMutex;
|
||||
use tokio::sync::Mutex;
|
||||
use toss::{Frame, Pos, Size, Terminal};
|
||||
use toss::{Frame, Pos, Size, Terminal, WidthDb};
|
||||
|
||||
use crate::macros::logging_unwrap;
|
||||
use crate::store::{Msg, MsgStore};
|
||||
|
|
@ -427,12 +427,17 @@ pub struct TreeView<M: Msg, S: MsgStore<M>> {
|
|||
#[async_trait]
|
||||
impl<M, S> Widget for TreeView<M, S>
|
||||
where
|
||||
M: Msg + ChatMsg,
|
||||
M: Msg + ChatMsg + Send + Sync,
|
||||
M::Id: Send + Sync,
|
||||
S: MsgStore<M> + Send + Sync,
|
||||
S::Error: fmt::Display,
|
||||
{
|
||||
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
_widthdb: &mut WidthDb,
|
||||
_max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
Size::ZERO
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use async_recursion::async_recursion;
|
||||
use toss::Frame;
|
||||
|
||||
use crate::store::{Msg, MsgStore, Path, Tree};
|
||||
|
|
@ -21,7 +22,12 @@ struct Context {
|
|||
focused: bool,
|
||||
}
|
||||
|
||||
impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||
impl<M, S> InnerTreeViewState<M, S>
|
||||
where
|
||||
M: Msg + ChatMsg + Send + Sync,
|
||||
M::Id: Send + Sync,
|
||||
S: MsgStore<M> + Send + Sync,
|
||||
{
|
||||
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Result<Path<M::Id>, S::Error> {
|
||||
Ok(match cursor {
|
||||
Cursor::Msg(id) => self.store.path(id).await?,
|
||||
|
|
@ -69,7 +75,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
.is_some()
|
||||
}
|
||||
|
||||
fn editor_block(
|
||||
async fn editor_block(
|
||||
&self,
|
||||
context: &Context,
|
||||
frame: &mut Frame,
|
||||
|
|
@ -78,20 +84,23 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
let (widget, cursor_row) =
|
||||
widgets::editor::<M>(frame.widthdb(), indent, &context.nick, &self.editor);
|
||||
let cursor_row = cursor_row as i32;
|
||||
Block::new(frame, BlockId::Cursor, widget).focus(cursor_row..cursor_row + 1)
|
||||
Block::new(frame, BlockId::Cursor, widget)
|
||||
.await
|
||||
.focus(cursor_row..cursor_row + 1)
|
||||
}
|
||||
|
||||
fn pseudo_block(
|
||||
async fn pseudo_block(
|
||||
&self,
|
||||
context: &Context,
|
||||
frame: &mut Frame,
|
||||
indent: usize,
|
||||
) -> Block<BlockId<M::Id>> {
|
||||
let widget = widgets::pseudo::<M>(indent, &context.nick, &self.editor);
|
||||
Block::new(frame, BlockId::Cursor, widget)
|
||||
Block::new(frame, BlockId::Cursor, widget).await
|
||||
}
|
||||
|
||||
fn layout_subtree(
|
||||
#[async_recursion]
|
||||
async fn layout_subtree(
|
||||
&self,
|
||||
context: &Context,
|
||||
frame: &mut Frame,
|
||||
|
|
@ -102,7 +111,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
) {
|
||||
// Ghost cursor in front, for positioning according to last cursor line
|
||||
if self.last_cursor.refers_to(id) {
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new());
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new()).await;
|
||||
blocks.blocks_mut().push_back(block);
|
||||
}
|
||||
|
||||
|
|
@ -121,43 +130,40 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
} else {
|
||||
widgets::msg_placeholder(highlighted, indent, folded_info)
|
||||
};
|
||||
let block = Block::new(frame, BlockId::Msg(id.clone()), widget);
|
||||
let block = Block::new(frame, BlockId::Msg(id.clone()), widget).await;
|
||||
blocks.blocks_mut().push_back(block);
|
||||
|
||||
// Children, recursively
|
||||
if !folded {
|
||||
if let Some(children) = tree.children(id) {
|
||||
for child in children {
|
||||
self.layout_subtree(context, frame, tree, indent + 1, child, blocks);
|
||||
self.layout_subtree(context, frame, tree, indent + 1, child, blocks)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trailing ghost cursor, for positioning according to last cursor line
|
||||
if self.last_cursor.refers_to_last_child_of(id) {
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new());
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new()).await;
|
||||
blocks.blocks_mut().push_back(block);
|
||||
}
|
||||
|
||||
// Trailing editor or pseudomessage
|
||||
if self.cursor.refers_to_last_child_of(id) {
|
||||
match self.cursor {
|
||||
Cursor::Editor { .. } => {
|
||||
blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.editor_block(context, frame, indent + 1))
|
||||
}
|
||||
Cursor::Pseudo { .. } => {
|
||||
blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.pseudo_block(context, frame, indent + 1))
|
||||
}
|
||||
Cursor::Editor { .. } => blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.editor_block(context, frame, indent + 1).await),
|
||||
Cursor::Pseudo { .. } => blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.pseudo_block(context, frame, indent + 1).await),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_tree(
|
||||
async fn layout_tree(
|
||||
&self,
|
||||
context: &Context,
|
||||
frame: &mut Frame,
|
||||
|
|
@ -165,32 +171,33 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
) -> TreeBlocks<M::Id> {
|
||||
let root = Root::Tree(tree.root().clone());
|
||||
let mut blocks = TreeBlocks::new(root.clone(), root);
|
||||
self.layout_subtree(context, frame, &tree, 0, tree.root(), &mut blocks);
|
||||
self.layout_subtree(context, frame, &tree, 0, tree.root(), &mut blocks)
|
||||
.await;
|
||||
blocks
|
||||
}
|
||||
|
||||
fn layout_bottom(&self, context: &Context, frame: &mut Frame) -> TreeBlocks<M::Id> {
|
||||
async fn layout_bottom(&self, context: &Context, frame: &mut Frame) -> TreeBlocks<M::Id> {
|
||||
let mut blocks = TreeBlocks::new(Root::Bottom, Root::Bottom);
|
||||
|
||||
// Ghost cursor, for positioning according to last cursor line
|
||||
if let Cursor::Editor { parent: None, .. } | Cursor::Pseudo { parent: None, .. } =
|
||||
self.last_cursor
|
||||
{
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new());
|
||||
let block = Block::new(frame, BlockId::LastCursor, Empty::new()).await;
|
||||
blocks.blocks_mut().push_back(block);
|
||||
}
|
||||
|
||||
match self.cursor {
|
||||
Cursor::Bottom => {
|
||||
let block = Block::new(frame, BlockId::Cursor, Empty::new());
|
||||
let block = Block::new(frame, BlockId::Cursor, Empty::new()).await;
|
||||
blocks.blocks_mut().push_back(block);
|
||||
}
|
||||
Cursor::Editor { parent: None, .. } => blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.editor_block(context, frame, 0)),
|
||||
.push_back(self.editor_block(context, frame, 0).await),
|
||||
Cursor::Pseudo { parent: None, .. } => blocks
|
||||
.blocks_mut()
|
||||
.push_back(self.pseudo_block(context, frame, 0)),
|
||||
.push_back(self.pseudo_block(context, frame, 0).await),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +223,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
None => break,
|
||||
};
|
||||
let prev_tree = self.store.tree(&prev_root_id).await?;
|
||||
blocks.prepend(self.layout_tree(context, frame, prev_tree));
|
||||
blocks.prepend(self.layout_tree(context, frame, prev_tree).await);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -238,9 +245,9 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
};
|
||||
if let Some(next_root_id) = next_root_id {
|
||||
let next_tree = self.store.tree(&next_root_id).await?;
|
||||
blocks.append(self.layout_tree(context, frame, next_tree));
|
||||
blocks.append(self.layout_tree(context, frame, next_tree).await);
|
||||
} else {
|
||||
blocks.append(self.layout_bottom(context, frame));
|
||||
blocks.append(self.layout_bottom(context, frame).await);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +288,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
) -> Result<TreeBlocks<M::Id>, S::Error> {
|
||||
Ok(match &self.last_cursor {
|
||||
Cursor::Bottom => {
|
||||
let mut blocks = self.layout_bottom(context, frame);
|
||||
let mut blocks = self.layout_bottom(context, frame).await;
|
||||
|
||||
let bottom_line = frame.size().height as i32 - 1;
|
||||
blocks.blocks_mut().set_bottom_line(bottom_line);
|
||||
|
|
@ -289,7 +296,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
blocks
|
||||
}
|
||||
Cursor::Editor { parent: None, .. } | Cursor::Pseudo { parent: None, .. } => {
|
||||
let mut blocks = self.layout_bottom(context, frame);
|
||||
let mut blocks = self.layout_bottom(context, frame).await;
|
||||
|
||||
blocks
|
||||
.blocks_mut()
|
||||
|
|
@ -306,7 +313,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
} => {
|
||||
let root = last_cursor_path.first();
|
||||
let tree = self.store.tree(root).await?;
|
||||
let mut blocks = self.layout_tree(context, frame, tree);
|
||||
let mut blocks = self.layout_tree(context, frame, tree).await;
|
||||
|
||||
blocks
|
||||
.blocks_mut()
|
||||
|
|
@ -330,7 +337,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
Cursor::Bottom
|
||||
| Cursor::Editor { parent: None, .. }
|
||||
| Cursor::Pseudo { parent: None, .. } => {
|
||||
let mut blocks = self.layout_bottom(context, frame);
|
||||
let mut blocks = self.layout_bottom(context, frame).await;
|
||||
|
||||
blocks.blocks_mut().set_bottom_line(bottom_line);
|
||||
|
||||
|
|
@ -345,7 +352,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
} => {
|
||||
let root = cursor_path.first();
|
||||
let tree = self.store.tree(root).await?;
|
||||
let mut blocks = self.layout_tree(context, frame, tree);
|
||||
let mut blocks = self.layout_tree(context, frame, tree).await;
|
||||
|
||||
let cursor_above_last = cursor_path < last_cursor_path;
|
||||
let cursor_line = if cursor_above_last { 0 } else { bottom_line };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size, Style};
|
||||
use toss::{Frame, Pos, Size, Style, WidthDb};
|
||||
|
||||
use crate::ui::widgets::Widget;
|
||||
|
||||
|
|
@ -19,7 +19,12 @@ impl Indent {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Indent {
|
||||
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
_widthdb: &mut WidthDb,
|
||||
_max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
Size::new((INDENT_WIDTH * self.level) as u16, 0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,20 +19,25 @@ pub mod rules;
|
|||
pub mod text;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use toss::{Frame, Size};
|
||||
use toss::{Frame, Size, WidthDb};
|
||||
|
||||
// TODO Add Error type and return Result-s (at least in Widget::render)
|
||||
|
||||
#[async_trait]
|
||||
pub trait Widget {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size;
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size;
|
||||
|
||||
async fn render(self: Box<Self>, frame: &mut Frame);
|
||||
}
|
||||
|
||||
pub type BoxedWidget = Box<dyn Widget + Send>;
|
||||
pub type BoxedWidget = Box<dyn Widget + Send + Sync>;
|
||||
|
||||
impl<W: 'static + Widget + Send> From<W> for BoxedWidget {
|
||||
impl<W: 'static + Widget + Send + Sync> From<W> for BoxedWidget {
|
||||
fn from(widget: W) -> Self {
|
||||
Box::new(widget)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size, Style};
|
||||
use toss::{Frame, Pos, Size, Style, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -24,8 +24,13 @@ impl Background {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Background {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
self.inner.size(frame, max_width, max_height)
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
self.inner.size(widthdb, max_width, max_height).await
|
||||
}
|
||||
|
||||
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size, Style};
|
||||
use toss::{Frame, Pos, Size, Style, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -24,10 +24,15 @@ impl Border {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Border {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let max_width = max_width.map(|w| w.saturating_sub(2));
|
||||
let max_height = max_height.map(|h| h.saturating_sub(2));
|
||||
let size = self.inner.size(frame, max_width, max_height);
|
||||
let size = self.inner.size(widthdb, max_width, max_height).await;
|
||||
size + Size::new(2, 2)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -28,8 +28,13 @@ impl Cursor {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Cursor {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
self.inner.size(frame, max_width, max_height)
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
self.inner.size(widthdb, max_width, max_height).await
|
||||
}
|
||||
|
||||
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||
|
|
|
|||
|
|
@ -493,9 +493,14 @@ impl Editor {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Editor {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
if let Some(placeholder) = &self.hidden {
|
||||
let mut size = placeholder.size(frame, max_width, max_height);
|
||||
let mut size = placeholder.size(widthdb, max_width, max_height).await;
|
||||
|
||||
// Cursor needs to fit regardless of focus
|
||||
size.width = size.width.max(1);
|
||||
|
|
@ -504,8 +509,6 @@ impl Widget for Editor {
|
|||
return size;
|
||||
}
|
||||
|
||||
let widthdb = frame.widthdb();
|
||||
|
||||
let max_width = max_width.map(|w| w as usize).unwrap_or(usize::MAX).max(1);
|
||||
let max_text_width = max_width - 1;
|
||||
let indices = wrap(widthdb, self.text.text(), max_text_width);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Size};
|
||||
use toss::{Frame, Size, WidthDb};
|
||||
|
||||
use super::Widget;
|
||||
|
||||
|
|
@ -31,7 +31,12 @@ impl Empty {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Empty {
|
||||
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
_widthdb: &mut WidthDb,
|
||||
_max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
self.size
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -31,14 +31,22 @@ impl Float {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Float {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
self.inner.size(frame, max_width, max_height)
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
self.inner.size(widthdb, max_width, max_height).await
|
||||
}
|
||||
|
||||
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||
let size = frame.size();
|
||||
|
||||
let mut inner_size = self.inner.size(frame, Some(size.width), Some(size.height));
|
||||
let mut inner_size = self
|
||||
.inner
|
||||
.size(frame.widthdb(), Some(size.width), Some(size.height))
|
||||
.await;
|
||||
inner_size.width = inner_size.width.min(size.width);
|
||||
inner_size.height = inner_size.height.min(size.height);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -54,9 +54,9 @@ impl SizedSegment {
|
|||
}
|
||||
}
|
||||
|
||||
fn sizes_horiz(
|
||||
async fn sizes_horiz(
|
||||
segments: &[Segment],
|
||||
frame: &mut Frame,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Vec<SizedSegment> {
|
||||
|
|
@ -74,7 +74,8 @@ fn sizes_horiz(
|
|||
.map(|w| w.saturating_sub(total_width));
|
||||
s.size = segments[s.idx]
|
||||
.widget
|
||||
.size(frame, available_width, max_height);
|
||||
.size(widthdb, available_width, max_height)
|
||||
.await;
|
||||
if let Some(available_width) = available_width {
|
||||
s.size.width = s.size.width.min(available_width);
|
||||
}
|
||||
|
|
@ -84,9 +85,9 @@ fn sizes_horiz(
|
|||
sized
|
||||
}
|
||||
|
||||
fn sizes_vert(
|
||||
async fn sizes_vert(
|
||||
segments: &[Segment],
|
||||
frame: &mut Frame,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Vec<SizedSegment> {
|
||||
|
|
@ -104,7 +105,8 @@ fn sizes_vert(
|
|||
.map(|w| w.saturating_sub(total_height));
|
||||
s.size = segments[s.idx]
|
||||
.widget
|
||||
.size(frame, max_width, available_height);
|
||||
.size(widthdb, max_width, available_height)
|
||||
.await;
|
||||
if let Some(available_height) = available_height {
|
||||
s.size.height = s.size.height.min(available_height);
|
||||
}
|
||||
|
|
@ -177,8 +179,13 @@ impl HJoin {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for HJoin {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
let sizes = sizes_horiz(&self.segments, frame, max_width, max_height);
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let sizes = sizes_horiz(&self.segments, widthdb, max_width, max_height).await;
|
||||
let width = sizes.iter().map(|s| s.size.width).sum::<u16>();
|
||||
let height = sizes.iter().map(|s| s.size.height).max().unwrap_or(0);
|
||||
Size::new(width, height)
|
||||
|
|
@ -187,7 +194,13 @@ impl Widget for HJoin {
|
|||
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||
let size = frame.size();
|
||||
|
||||
let mut sizes = sizes_horiz(&self.segments, frame, Some(size.width), Some(size.height));
|
||||
let mut sizes = sizes_horiz(
|
||||
&self.segments,
|
||||
frame.widthdb(),
|
||||
Some(size.width),
|
||||
Some(size.height),
|
||||
)
|
||||
.await;
|
||||
expand_horiz(&mut sizes, size.width);
|
||||
|
||||
sizes.sort_by_key(|s| s.idx);
|
||||
|
|
@ -215,8 +228,13 @@ impl VJoin {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for VJoin {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
let sizes = sizes_vert(&self.segments, frame, max_width, max_height);
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let sizes = sizes_vert(&self.segments, widthdb, max_width, max_height).await;
|
||||
let width = sizes.iter().map(|s| s.size.width).max().unwrap_or(0);
|
||||
let height = sizes.iter().map(|s| s.size.height).sum::<u16>();
|
||||
Size::new(width, height)
|
||||
|
|
@ -225,7 +243,13 @@ impl Widget for VJoin {
|
|||
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||
let size = frame.size();
|
||||
|
||||
let mut sizes = sizes_vert(&self.segments, frame, Some(size.width), Some(size.height));
|
||||
let mut sizes = sizes_vert(
|
||||
&self.segments,
|
||||
frame.widthdb(),
|
||||
Some(size.width),
|
||||
Some(size.height),
|
||||
)
|
||||
.await;
|
||||
expand_vert(&mut sizes, size.height);
|
||||
|
||||
sizes.sort_by_key(|s| s.idx);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Size};
|
||||
use toss::{Frame, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -15,10 +15,15 @@ impl Layer {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Layer {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let mut max_size = Size::ZERO;
|
||||
for layer in &self.layers {
|
||||
let size = layer.size(frame, max_width, max_height);
|
||||
let size = layer.size(widthdb, max_width, max_height).await;
|
||||
max_size.width = max_size.width.max(size.width);
|
||||
max_size.height = max_size.height.max(size.height);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use parking_lot::Mutex;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -266,14 +266,19 @@ impl<Id> Row<Id> {
|
|||
}
|
||||
}
|
||||
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
match self {
|
||||
Self::Unselectable { normal } => normal.size(frame, max_width, max_height),
|
||||
Self::Unselectable { normal } => normal.size(widthdb, max_width, max_height).await,
|
||||
Self::Selectable {
|
||||
normal, selected, ..
|
||||
} => {
|
||||
let normal_size = normal.size(frame, max_width, max_height);
|
||||
let selected_size = selected.size(frame, max_width, max_height);
|
||||
let normal_size = normal.size(widthdb, max_width, max_height).await;
|
||||
let selected_size = selected.size(widthdb, max_width, max_height).await;
|
||||
Size::new(
|
||||
normal_size.width.max(selected_size.width),
|
||||
normal_size.height.max(selected_size.height),
|
||||
|
|
@ -327,14 +332,18 @@ impl<Id> List<Id> {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Id: Clone + Eq + Send> Widget for List<Id> {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
let width = self
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| r.size(frame, max_width, Some(1)).width)
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
impl<Id: Clone + Eq + Send + Sync> Widget for List<Id> {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let mut width = 0;
|
||||
for row in &self.rows {
|
||||
let size = row.size(widthdb, max_width, Some(1)).await;
|
||||
width = width.max(size.width);
|
||||
}
|
||||
let height = self.rows.len();
|
||||
Size::new(width, height as u16)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -66,14 +66,19 @@ impl Padding {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Padding {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let horizontal = self.left + self.right;
|
||||
let vertical = self.top + self.bottom;
|
||||
|
||||
let max_width = max_width.map(|w| w.saturating_sub(horizontal));
|
||||
let max_height = max_height.map(|h| h.saturating_sub(vertical));
|
||||
|
||||
let size = self.inner.size(frame, max_width, max_height);
|
||||
let size = self.inner.size(widthdb, max_width, max_height).await;
|
||||
|
||||
size + Size::new(horizontal, vertical)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Size};
|
||||
use toss::{Frame, Size, WidthDb};
|
||||
|
||||
use super::{BoxedWidget, Widget};
|
||||
|
||||
|
|
@ -45,7 +45,12 @@ impl Resize {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Resize {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let max_width = match (max_width, self.max_width) {
|
||||
(None, None) => None,
|
||||
(Some(w), None) => Some(w),
|
||||
|
|
@ -60,7 +65,7 @@ impl Widget for Resize {
|
|||
(Some(h), Some(sh)) => Some(h.min(sh)),
|
||||
};
|
||||
|
||||
let size = self.inner.size(frame, max_width, max_height);
|
||||
let size = self.inner.size(widthdb, max_width, max_height).await;
|
||||
|
||||
let width = match self.min_width {
|
||||
Some(min_width) => size.width.max(min_width),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use toss::{Frame, Pos, Size};
|
||||
use toss::{Frame, Pos, Size, WidthDb};
|
||||
|
||||
use super::Widget;
|
||||
|
||||
|
|
@ -7,7 +7,12 @@ pub struct HRule;
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for HRule {
|
||||
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
_widthdb: &mut WidthDb,
|
||||
_max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
Size::new(0, 1)
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +28,12 @@ pub struct VRule;
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for VRule {
|
||||
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
async fn size(
|
||||
&self,
|
||||
_widthdb: &mut WidthDb,
|
||||
_max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
Size::new(1, 0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,13 @@ impl Text {
|
|||
|
||||
#[async_trait]
|
||||
impl Widget for Text {
|
||||
fn size(&self, frame: &mut Frame, max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||
let lines = self.wrapped(frame.widthdb(), max_width);
|
||||
let widthdb = frame.widthdb();
|
||||
async fn size(
|
||||
&self,
|
||||
widthdb: &mut WidthDb,
|
||||
max_width: Option<u16>,
|
||||
_max_height: Option<u16>,
|
||||
) -> Size {
|
||||
let lines = self.wrapped(widthdb, max_width);
|
||||
let min_width = lines
|
||||
.iter()
|
||||
.map(|l| widthdb.width(l.text().trim_end()))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue