mirror of
https://github.com/ratatui-org/ratatui
synced 2024-09-20 14:42:06 +00:00
revert to single Block struct; add set_border_type method and BorderType enum
This commit is contained in:
parent
f1bc00b67f
commit
a72389b28c
2 changed files with 68 additions and 364 deletions
|
@ -54,4 +54,5 @@ pub mod double {
|
|||
pub const VERTICAL_RIGHT: &str = "╠";
|
||||
pub const HORIZONTAL_DOWN: &str = "╦";
|
||||
pub const HORIZONTAL_UP: &str = "╩";
|
||||
pub const CROSS: &str = "╬";
|
||||
}
|
||||
|
|
|
@ -29,8 +29,11 @@ pub struct Block<'a> {
|
|||
title_style: Style,
|
||||
/// Visible borders
|
||||
borders: Borders,
|
||||
/// Border style
|
||||
/// Border style (meaning colors)
|
||||
border_style: Style,
|
||||
/// Border type (meaning one of single lines w/sharp corners, single lines w/rounded corners,
|
||||
/// or double lines w/sharp corners)
|
||||
border_type: BorderType,
|
||||
/// Widget style
|
||||
style: Style,
|
||||
}
|
||||
|
@ -42,11 +45,19 @@ impl<'a> Default for Block<'a> {
|
|||
title_style: Default::default(),
|
||||
borders: Borders::NONE,
|
||||
border_style: Default::default(),
|
||||
border_type: BorderType::Plain,
|
||||
style: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum BorderType {
|
||||
Plain,
|
||||
Rounded,
|
||||
Double,
|
||||
}
|
||||
|
||||
impl<'a> Block<'a> {
|
||||
pub fn title(mut self, title: &'a str) -> Block<'a> {
|
||||
self.title = Some(title);
|
||||
|
@ -73,12 +84,9 @@ impl<'a> Block<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn rounded(self) -> RoundedBlock<'a> {
|
||||
RoundedBlock::from(self)
|
||||
}
|
||||
|
||||
pub fn double_border(self) -> DoubleBlock<'a> {
|
||||
DoubleBlock::from(self)
|
||||
pub fn set_border_type(mut self, border_type: BorderType) -> Block<'a> {
|
||||
self.border_type = border_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Compute the inner area of a block based on its border visibility rules.
|
||||
|
@ -117,14 +125,24 @@ impl<'a> Widget for Block<'a> {
|
|||
if self.borders.intersects(Borders::LEFT) {
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(area.left(), y)
|
||||
.set_symbol(line::VERTICAL)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::VERTICAL,
|
||||
_ => line::VERTICAL,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::TOP) {
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, area.top())
|
||||
.set_symbol(line::HORIZONTAL)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::HORIZONTAL,
|
||||
_ => line::HORIZONTAL,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +150,12 @@ impl<'a> Widget for Block<'a> {
|
|||
let x = area.right() - 1;
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(line::VERTICAL)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::VERTICAL,
|
||||
_ => line::VERTICAL,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +163,12 @@ impl<'a> Widget for Block<'a> {
|
|||
let y = area.bottom() - 1;
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(line::HORIZONTAL)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::HORIZONTAL,
|
||||
_ => line::HORIZONTAL,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
|
@ -148,371 +176,46 @@ impl<'a> Widget for Block<'a> {
|
|||
// Corners
|
||||
if self.borders.contains(Borders::LEFT | Borders::TOP) {
|
||||
buf.get_mut(area.left(), area.top())
|
||||
.set_symbol(line::TOP_LEFT)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::TOP_LEFT,
|
||||
BorderType::Rounded => rounded::TOP_LEFT,
|
||||
_ => line::TOP_LEFT,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::TOP) {
|
||||
buf.get_mut(area.right() - 1, area.top())
|
||||
.set_symbol(line::TOP_RIGHT)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::TOP_RIGHT,
|
||||
BorderType::Rounded => rounded::TOP_RIGHT,
|
||||
_ => line::TOP_RIGHT,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.left(), area.bottom() - 1)
|
||||
.set_symbol(line::BOTTOM_LEFT)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::BOTTOM_LEFT,
|
||||
BorderType::Rounded => rounded::BOTTOM_LEFT,
|
||||
_ => line::BOTTOM_LEFT,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.right() - 1, area.bottom() - 1)
|
||||
.set_symbol(line::BOTTOM_RIGHT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
|
||||
if area.width > 2 {
|
||||
if let Some(title) = self.title {
|
||||
let lx = if self.borders.intersects(Borders::LEFT) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let rx = if self.borders.intersects(Borders::RIGHT) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let width = area.width - lx - rx;
|
||||
buf.set_stringn(
|
||||
area.left() + lx,
|
||||
area.top(),
|
||||
title,
|
||||
width as usize,
|
||||
self.title_style,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RoundedBlock<'a> {
|
||||
/// Optional title place on the upper left of the block
|
||||
title: Option<&'a str>,
|
||||
/// Title style
|
||||
title_style: Style,
|
||||
/// Visible borders
|
||||
borders: Borders,
|
||||
/// Border style
|
||||
border_style: Style,
|
||||
/// Widget style
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl<'a> From<Block<'a>> for RoundedBlock<'a> {
|
||||
fn from(block: Block<'a>) -> RoundedBlock<'a> {
|
||||
RoundedBlock {
|
||||
title: block.title,
|
||||
title_style: block.title_style,
|
||||
borders: block.borders,
|
||||
border_style: block.border_style,
|
||||
style: block.style,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for RoundedBlock<'a> {
|
||||
fn default() -> RoundedBlock<'a> {
|
||||
RoundedBlock {
|
||||
title: None,
|
||||
title_style: Default::default(),
|
||||
borders: Borders::NONE,
|
||||
border_style: Default::default(),
|
||||
style: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RoundedBlock<'a> {
|
||||
pub fn title(mut self, title: &'a str) -> RoundedBlock<'a> {
|
||||
self.title = Some(title);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn title_style(mut self, style: Style) -> RoundedBlock<'a> {
|
||||
self.title_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn border_style(mut self, style: Style) -> RoundedBlock<'a> {
|
||||
self.border_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn style(mut self, style: Style) -> RoundedBlock<'a> {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn borders(mut self, flag: Borders) -> RoundedBlock<'a> {
|
||||
self.borders = flag;
|
||||
self
|
||||
}
|
||||
|
||||
/// Compute the inner area of a block based on its border visibility rules.
|
||||
pub fn inner(&self, area: Rect) -> Rect {
|
||||
if area.width < 2 || area.height < 2 {
|
||||
return Rect::default();
|
||||
}
|
||||
let mut inner = area;
|
||||
if self.borders.intersects(Borders::LEFT) {
|
||||
inner.x += 1;
|
||||
inner.width -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::TOP) || self.title.is_some() {
|
||||
inner.y += 1;
|
||||
inner.height -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::RIGHT) {
|
||||
inner.width -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::BOTTOM) {
|
||||
inner.height -= 1;
|
||||
}
|
||||
inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for RoundedBlock<'a> {
|
||||
fn draw(&mut self, area: Rect, buf: &mut Buffer) {
|
||||
if area.width < 2 || area.height < 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.background(area, buf, self.style.bg);
|
||||
|
||||
// Sides
|
||||
if self.borders.intersects(Borders::LEFT) {
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(area.left(), y)
|
||||
.set_symbol(line::VERTICAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::TOP) {
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, area.top())
|
||||
.set_symbol(line::HORIZONTAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::RIGHT) {
|
||||
let x = area.right() - 1;
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(line::VERTICAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::BOTTOM) {
|
||||
let y = area.bottom() - 1;
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(line::HORIZONTAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
|
||||
// Corners
|
||||
if self.borders.contains(Borders::LEFT | Borders::TOP) {
|
||||
buf.get_mut(area.left(), area.top())
|
||||
.set_symbol(rounded::TOP_LEFT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::TOP) {
|
||||
buf.get_mut(area.right() - 1, area.top())
|
||||
.set_symbol(rounded::TOP_RIGHT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.left(), area.bottom() - 1)
|
||||
.set_symbol(rounded::BOTTOM_LEFT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.right() - 1, area.bottom() - 1)
|
||||
.set_symbol(rounded::BOTTOM_RIGHT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
|
||||
if area.width > 2 {
|
||||
if let Some(title) = self.title {
|
||||
let lx = if self.borders.intersects(Borders::LEFT) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let rx = if self.borders.intersects(Borders::RIGHT) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let width = area.width - lx - rx;
|
||||
buf.set_stringn(
|
||||
area.left() + lx,
|
||||
area.top(),
|
||||
title,
|
||||
width as usize,
|
||||
self.title_style,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DoubleBlock<'a> {
|
||||
/// Optional title place on the upper left of the block
|
||||
title: Option<&'a str>,
|
||||
/// Title style
|
||||
title_style: Style,
|
||||
/// Visible borders
|
||||
borders: Borders,
|
||||
/// Border style
|
||||
border_style: Style,
|
||||
/// Widget style
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl<'a> From<Block<'a>> for DoubleBlock<'a> {
|
||||
fn from(block: Block<'a>) -> DoubleBlock<'a> {
|
||||
DoubleBlock {
|
||||
title: block.title,
|
||||
title_style: block.title_style,
|
||||
borders: block.borders,
|
||||
border_style: block.border_style,
|
||||
style: block.style,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> Default for DoubleBlock<'a> {
|
||||
fn default() -> DoubleBlock<'a> {
|
||||
DoubleBlock {
|
||||
title: None,
|
||||
title_style: Default::default(),
|
||||
borders: Borders::NONE,
|
||||
border_style: Default::default(),
|
||||
style: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleBlock<'a> {
|
||||
pub fn title(mut self, title: &'a str) -> DoubleBlock<'a> {
|
||||
self.title = Some(title);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn title_style(mut self, style: Style) -> DoubleBlock<'a> {
|
||||
self.title_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn border_style(mut self, style: Style) -> DoubleBlock<'a> {
|
||||
self.border_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn style(mut self, style: Style) -> DoubleBlock<'a> {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn borders(mut self, flag: Borders) -> DoubleBlock<'a> {
|
||||
self.borders = flag;
|
||||
self
|
||||
}
|
||||
|
||||
/// Compute the inner area of a block based on its border visibility rules.
|
||||
pub fn inner(&self, area: Rect) -> Rect {
|
||||
if area.width < 2 || area.height < 2 {
|
||||
return Rect::default();
|
||||
}
|
||||
let mut inner = area;
|
||||
if self.borders.intersects(Borders::LEFT) {
|
||||
inner.x += 1;
|
||||
inner.width -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::TOP) || self.title.is_some() {
|
||||
inner.y += 1;
|
||||
inner.height -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::RIGHT) {
|
||||
inner.width -= 1;
|
||||
}
|
||||
if self.borders.intersects(Borders::BOTTOM) {
|
||||
inner.height -= 1;
|
||||
}
|
||||
inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for DoubleBlock<'a> {
|
||||
fn draw(&mut self, area: Rect, buf: &mut Buffer) {
|
||||
if area.width < 2 || area.height < 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.background(area, buf, self.style.bg);
|
||||
|
||||
// Sides
|
||||
if self.borders.intersects(Borders::LEFT) {
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(area.left(), y)
|
||||
.set_symbol(double::VERTICAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::TOP) {
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, area.top())
|
||||
.set_symbol(double::HORIZONTAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::RIGHT) {
|
||||
let x = area.right() - 1;
|
||||
for y in area.top()..area.bottom() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(double::VERTICAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
if self.borders.intersects(Borders::BOTTOM) {
|
||||
let y = area.bottom() - 1;
|
||||
for x in area.left()..area.right() {
|
||||
buf.get_mut(x, y)
|
||||
.set_symbol(double::HORIZONTAL)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
}
|
||||
|
||||
// Corners
|
||||
if self.borders.contains(Borders::LEFT | Borders::TOP) {
|
||||
buf.get_mut(area.left(), area.top())
|
||||
.set_symbol(double::TOP_LEFT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::TOP) {
|
||||
buf.get_mut(area.right() - 1, area.top())
|
||||
.set_symbol(double::TOP_RIGHT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.left(), area.bottom() - 1)
|
||||
.set_symbol(double::BOTTOM_LEFT)
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {
|
||||
buf.get_mut(area.right() - 1, area.bottom() - 1)
|
||||
.set_symbol(double::BOTTOM_RIGHT)
|
||||
.set_symbol({
|
||||
match self.border_type {
|
||||
BorderType::Double => double::BOTTOM_RIGHT,
|
||||
BorderType::Rounded => rounded::BOTTOM_RIGHT,
|
||||
_ => line::BOTTOM_RIGHT,
|
||||
}
|
||||
})
|
||||
.set_style(self.border_style);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue