Add Widget and BoxedWidget
This commit is contained in:
parent
d6b9aea273
commit
ba68e34d0d
4 changed files with 112 additions and 1 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -2,9 +2,18 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "showbits-common"
|
name = "showbits-common"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "showbits-thermal-printer"
|
name = "showbits-thermal-printer"
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,8 @@ name = "showbits-common"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.80"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub use crate::{buffer::Buffer, rect::Rect, vec2::Vec2, view::View};
|
pub use crate::{buffer::*, rect::*, vec2::*, view::*, widget::*};
|
||||||
|
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod vec2;
|
mod vec2;
|
||||||
mod view;
|
mod view;
|
||||||
|
mod widget;
|
||||||
|
|
|
||||||
98
showbits-common/src/widget.rs
Normal file
98
showbits-common/src/widget.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
use crate::{Rect, Vec2, View};
|
||||||
|
|
||||||
|
pub trait Widget<C> {
|
||||||
|
/// Size that the widget wants to be, given the width and height
|
||||||
|
/// constraints.
|
||||||
|
fn size(&self, max_width: Option<i32>, max_height: Option<i32>) -> Vec2;
|
||||||
|
|
||||||
|
/// Recalculate the size of all inner widgets given the widget's own size.
|
||||||
|
///
|
||||||
|
/// # Implement if...
|
||||||
|
///
|
||||||
|
/// - There are inner widgets
|
||||||
|
fn resize(&mut self, _area: Rect) {}
|
||||||
|
|
||||||
|
/// Perform any updates (e.g. fetching map tiles) that require the widget's
|
||||||
|
/// size and may fail.
|
||||||
|
///
|
||||||
|
/// # Implement if...
|
||||||
|
///
|
||||||
|
/// - There are inner widgets
|
||||||
|
/// - This widget needs to perform updates
|
||||||
|
fn update(&mut self, _area: Rect) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(self, view: &mut View<'_, C>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper trait around [`Widget`] that turns `Box<Self>` into a `Self` to get
|
||||||
|
/// around the "size cannot be statically determined" error with the naïve
|
||||||
|
/// approach of `Box<Widget>`.
|
||||||
|
trait WidgetWrapper<C> {
|
||||||
|
fn size(&self, max_width: Option<i32>, max_height: Option<i32>) -> Vec2;
|
||||||
|
fn resize(&mut self, _area: Rect);
|
||||||
|
fn update(&mut self, _area: Rect) -> anyhow::Result<()>;
|
||||||
|
fn draw(self: Box<Self>, view: &mut View<'_, C>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, W: Widget<C>> WidgetWrapper<C> for W {
|
||||||
|
// These implementations explicitly use `Widget::*` to call the widget
|
||||||
|
// methods even though they have priority over the `WidgetWrapper::*`
|
||||||
|
// methods for some reason. Just a bit of rustc magic, I guess.
|
||||||
|
|
||||||
|
fn size(&self, max_width: Option<i32>, max_height: Option<i32>) -> Vec2 {
|
||||||
|
Widget::size(self, max_width, max_height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, area: Rect) {
|
||||||
|
Widget::resize(self, area);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, area: Rect) -> anyhow::Result<()> {
|
||||||
|
Widget::update(self, area)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(self: Box<Self>, view: &mut View<'_, C>) {
|
||||||
|
Widget::draw(*self, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BoxedWidget<C> {
|
||||||
|
area: Rect,
|
||||||
|
widget: Box<dyn WidgetWrapper<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> BoxedWidget<C> {
|
||||||
|
pub fn new<W>(widget: W) -> Self
|
||||||
|
where
|
||||||
|
W: Widget<C> + 'static,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
area: Rect::ZERO,
|
||||||
|
widget: Box::new(widget),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn area(&self) -> Rect {
|
||||||
|
self.area
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> Widget<C> for BoxedWidget<C> {
|
||||||
|
fn size(&self, max_width: Option<i32>, max_height: Option<i32>) -> Vec2 {
|
||||||
|
self.widget.size(max_width, max_height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, area: Rect) {
|
||||||
|
self.widget.resize(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, area: Rect) -> anyhow::Result<()> {
|
||||||
|
self.widget.update(area)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(self, view: &mut View<'_, C>) {
|
||||||
|
self.widget.draw(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue