Skip to content

Commit

Permalink
Refactor Block View/Widget to Border View/Widget (#14)
Browse files Browse the repository at this point in the history
Closes #4

As described in the issue, it's likely more flexible and cleaner
to let the user have more control via smaller widgets
This cleans up the somewhat convoluted codebase of the Block widget
(Such as `BorderStyles`). And adds more control over rendering the border.
By having more `Borders` (such as `TOP_CORNERS` or `TOP_LEFT_CORNER` etc.).
Combining different borders can just be done by using multiple `.border()`
invocations.
  • Loading branch information
Philipp-M authored Feb 9, 2024
1 parent d089a2b commit 7a6e183
Show file tree
Hide file tree
Showing 17 changed files with 634 additions and 741 deletions.
13 changes: 7 additions & 6 deletions examples/async_event_handler_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub fn words_stream(input: &str) -> impl Stream<Item = String> + Send {
fn main() -> Result<()> {
App::new(String::new(), |app_state| {
v_stack((
block("Click me for some non-sense")
.with_borders(BorderKind::Rounded)
"Click me for some non-sense"
.border(BorderKind::Rounded)
.on_hover_fg(Color::Blue)
.on_pressed_fg(Color::Red)
.on_click(stream(
Expand Down Expand Up @@ -60,8 +60,8 @@ fn main() -> Result<()> {
StreamMessage::Finished => (),
},
)),
block("Click me for some non-sense, but only once")
.with_borders(BorderKind::Rounded)
"Click me for some non-sense, but only once"
.border(BorderKind::Rounded)
.on_hover_fg(Color::Blue)
.on_pressed_fg(Color::Green)
.on_click(defer(
Expand All @@ -80,8 +80,9 @@ fn main() -> Result<()> {
*app_state += &message;
},
)),
block(app_state.clone()) //.wrapped()
.with_borders(())
app_state
.clone() //.wrapped()
.border(())
.fg(if app_state.is_empty() {
Color::White
} else {
Expand Down
46 changes: 21 additions & 25 deletions examples/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,33 @@ use trui::*;

fn main() -> Result<()> {
let view = Arc::new(
block(weighted_h_stack((
weighted_h_stack((
"text inside block"
.fill_max_height(0.5)
.border(BorderKind::Straight)
.fill_max_width(1.0)
.margin((Position::VERTICAL, 1))
.weight(1.5),
v_stack((
// block(("With".fg(Color::Yellow), " background").wrapped()).bg(Color::LightYellow),
block("text inside block".fill_max_height(0.5))
.with_borders(BorderKind::Straight)
.fill_max_width(1.0)
.margin((Position::VERTICAL, 1)),
))
.weight(1.5),
v_stack((
block("Styled title".bg(Color::Red).fg(Color::White)).bg(Color::LightCyan),
block(
v_stack((
"With styled borders and doubled borders",
block("Block inside block")
.with_borders(BorderKind::Straight)
.fill_max_size(0.7)
.margin(2),
))
.margin((Position::TOP, 1))
.margin((Position::HORIZONTAL, 2))
.fill_max_height(1.0),
)
.with_borders((
"Styled title".bg(Color::Red).fg(Color::White),
v_stack((
"With styled borders and doubled borders",
"Block inside block"
.border(BorderKind::Straight)
.fill_max_size(0.7)
.margin(2),
))
.margin((Position::TOP, 1))
.margin((Position::HORIZONTAL, 2))
.fill_max_height(1.0)
.border((
Borders::VERTICAL,
Style::default().fg(Color::Cyan),
BorderKind::DoubleStraight,
)),
)),
)))
.with_borders(BorderKind::Rounded)
))
.border(BorderKind::Rounded)
.margin(1),
);
App::new((), move |()| view.clone()).run()
Expand Down
4 changes: 2 additions & 2 deletions examples/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ pub fn button<T>(
content: impl View<T>,
click_cb: impl EventHandler<T> + Send,
) -> impl View<T> + Styleable {
block(content)
.with_borders(BorderKind::ThickStraight)
content
.border(BorderKind::ThickStraight)
.on_hover_style(Style::default().fg(Color::Green).bg(Color::LightYellow))
.on_pressed_fg(Color::Blue)
.on_click(click_cb)
Expand Down
16 changes: 8 additions & 8 deletions examples/local_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ fn button_with_state<T>(view: impl View<T>) -> impl View<T> {
view.with_state(
|| 123,
|view, n| {
block(v_stack((view, n.to_string())))
.with_borders(BorderKind::ThickStraight)
v_stack((view, n.to_string()))
.border(BorderKind::ThickStraight)
.on_click(|(_, l): &mut (Handle<T>, i32)| *l += 1)
},
)
Expand All @@ -26,8 +26,8 @@ fn button_with_state_accessor<T>(
view: impl View<T>,
access_local_state: impl Fn(&mut T) -> &mut i32 + Send + Sync,
) -> impl View<T> {
block(v_stack((view, access_local_state(state).to_string())))
.with_borders(BorderKind::Straight)
v_stack((view, access_local_state(state).to_string()))
.border(BorderKind::Straight)
.on_click(move |state: &mut T| *access_local_state(state) += 1)
}

Expand All @@ -38,8 +38,8 @@ fn button_use_state<T, V: View<(Handle<T>, i32)>>(
use_state(
|| 123,
move |n| {
block(v_stack((view(), n.to_string())))
.with_borders(BorderKind::DoubleStraight)
v_stack((view(), n.to_string()))
.border(BorderKind::DoubleStraight)
.on_click(|(_, n): &mut (Handle<T>, i32)| *n += 1)
},
)
Expand All @@ -54,8 +54,8 @@ fn main() -> Result<()> {
|state| {
let count = state.count;
v_stack((
block(format!("Increment the global state: {}", state.count))
.with_borders(BorderKind::Rounded)
format!("Increment the global state: {}", state.count)
.border(BorderKind::Rounded)
.on_click(|state: &mut AppState| state.count += 1),
button_with_state(format!("With local state, app_state: {}", state.count)),
button_with_state_accessor(
Expand Down
31 changes: 13 additions & 18 deletions examples/rainbow_blocks.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::Result;
use ratatui::style::Color;
use trui::{
block, memoize, v_stack, AnyView, App, BorderKind, Borders, EventHandler, IntoBoxedView,
Styleable, View, ViewExt,
memoize, v_stack, AnyView, App, BorderKind, Borders, EventHandler, IntoBoxedView, Styleable,
View, ViewExt,
};

// TODO this basic logic (hover, styling etc.) should probably be its own widget (state)...
Expand All @@ -13,8 +13,9 @@ pub fn button<T>(
hover_cb: impl EventHandler<T>,
hover_lost_cb: impl EventHandler<T>,
) -> impl View<T> + Styleable {
block(label.into())
.with_borders(Borders::ALL)
label
.into()
.border(Borders::ALL)
.fg(block_color)
.on_click(click_cb)
.on_hover(hover_cb)
Expand Down Expand Up @@ -45,10 +46,7 @@ pub fn rainbow_blocks<T: 'static>(
let mut view = content.boxed();
for i in 0..count {
let color = rainbow((i as f32 / (count - 1) as f32 + 0.001).max(0.0).min(1.0));
view = block(view)
.with_borders(BorderKind::Rounded)
.fg(color)
.boxed();
view = view.border(BorderKind::Rounded).fg(color).boxed();
}
view
}
Expand Down Expand Up @@ -94,7 +92,10 @@ fn main() -> Result<()> {
memoize(
(state.current_button_color2, state.count),
|(button_color, count)| {
tracing::debug!("This will be printed on every change of state.current_button_color2 or state.count");
tracing::debug!(
"This will be printed on every change\
of state.current_button_color2 or state.count"
);
let count = *count;
let v: Box<dyn AnyView<_>> = if count <= 10 {
Box::new(format!(
Expand All @@ -104,22 +105,16 @@ fn main() -> Result<()> {
} else if count > 10 && count < 42 {
Box::new(format!("Count is bigger than 10 ({})", count).fg(Color::Gray))
} else if count == 42 {
Box::new(
block("You have found the sense of life!".fg(Color::Green))
.fg(Color::Red),
)
Box::new("You have found the sense of life!".fg(Color::Green))
} else {
let color = Color::Rgb(
255usize.saturating_sub(count * 2) as u8,
255usize.saturating_sub(count * 2) as u8,
255usize.saturating_sub(count * 2) as u8,
);
Box::new(
block("Everything's downhill from here on...".fg(color)).fg(color),
)
Box::new("Everything's downhill from here on...".fg(color))
};
block(v)
.with_borders(BorderKind::DoubleStraight)
v.border(BorderKind::DoubleStraight)
.fg(*button_color)
.on_click(|state: &mut AppState| {
state.current_button_color2 = Color::Red;
Expand Down
2 changes: 1 addition & 1 deletion src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ impl Widget for DebugWidget {
/// dumped to stdout.
///
/// ```sh
/// DEBUG_SNAPSHOT=1 cargo test --lib -- --nocapture --test simple_block_test
/// DEBUG_SNAPSHOT=1 cargo test --lib -- --nocapture --test simple_border_test
/// ```
///
/// !!! The normal test output frequently interferes which results in scrambled output, especially
Expand Down
17 changes: 14 additions & 3 deletions src/view.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod block;
mod border;
mod common;
mod core;
mod defer;
Expand All @@ -17,7 +17,7 @@ pub use xilem_core::{Id, IdPath, VecSplice};

// TODO do this via a prelude instead (and possibly not wildcard export)
pub use self::core::*;
pub use block::*;
pub use border::*;
pub use common::*;
pub use defer::*;
pub use events::*;
Expand All @@ -28,7 +28,7 @@ pub use text::*;
pub use use_state::*;
pub use weighted_linear_layout::*;

// TODO this could maybe also be added directly to `View` (possibly copying the macro expanded version of it
// TODO this could maybe also be added directly to `View` (possibly copying the macro expanded version of it)
/// A trait that makes it possible to use core views such as [`Adapt`] in the continuation/builder style.
pub trait ViewExt<T, A>: View<T, A> + Sized {
fn adapt<ParentT, ParentA, F>(self, f: F) -> Adapt<ParentT, ParentA, T, A, Self, F>
Expand Down Expand Up @@ -57,6 +57,17 @@ pub trait ViewExt<T, A>: View<T, A> + Sized {
}
}

fn border<S: Into<BorderStyle>>(self, style: S) -> Border<Self, T, A> {
let style = style.into();
Border {
content: self,
borders: style.borders,
kind: style.kind,
style: style.style,
phantom: PhantomData,
}
}

fn fill_max_size<S: Into<FillMaxSizeStyle>>(self, style: S) -> FillMaxSize<Self, T, A> {
let style = style.into();
FillMaxSize {
Expand Down
Loading

0 comments on commit 7a6e183

Please sign in to comment.