Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

Commit

Permalink
feat!: remove title from Popup::new (#31)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The `Popup::new` method no longer accepts a title
parameter. Instead, the title can be set using the `title` method on the
`Popup` instance.

```diff
- let popup = Popup::new("tui-popup demo", "Press any key to exit")
+ let popup = Popup::new("Press any key to exit")
+     .title("tui-popup demo")
      .style(Style::new().white().on_blue());
```
  • Loading branch information
joshka authored Jul 7, 2024
1 parent 290ac42 commit 1c79c1c
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 99 deletions.
5 changes: 3 additions & 2 deletions examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ fn main() -> Result<()> {
fn render(frame: &mut Frame) {
let area = frame.size();
let background = background(area);
let popup =
Popup::new("tui-popup demo", "Press any key to exit").style(Style::new().white().on_blue());
let popup = Popup::new("Press any key to exit")
.title("tui-popup demo")
.style(Style::new().white().on_blue());
frame.render_widget(background, area);
frame.render_widget(&popup, area);
}
Expand Down
5 changes: 3 additions & 2 deletions examples/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ impl App {
let background = background(area);

let paragraph = paragraph(self.scroll);
let popup =
Popup::new("scroll: ↑/↓ quit: Esc", paragraph).style(Style::new().white().on_blue());
let popup = Popup::new(paragraph)
.title("scroll: ↑/↓ quit: Esc")
.style(Style::new().white().on_blue());

frame.render_widget(background, area);
frame.render_widget(&popup, area);
Expand Down
20 changes: 9 additions & 11 deletions examples/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,15 @@ impl App {
}

fn popup_widget() -> Popup<'static, Text<'static>> {
Popup::new(
"Popup",
Text::from_iter([
"q: exit",
"r: reset",
"j: move down",
"k: move up",
"h: move left",
"l: move right",
]),
)
Popup::new(Text::from_iter([
"q: exit",
"r: reset",
"j: move down",
"k: move up",
"h: move left",
"l: move right",
]))
.title("Popup")
.style(Style::new().white().on_blue())
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
//! use tui_popup::Popup;
//!
//! fn render_popup(frame: &mut Frame) {
//! let popup = Popup::new("tui-popup demo", "Press any key to exit")
//! let popup = Popup::new("Press any key to exit")
//! .title("tui-popup demo")
//! .style(Style::new().white().on_blue());
//! frame.render_widget(&popup, frame.size());
//! }
Expand All @@ -23,7 +24,6 @@

mod popup;
mod state;
mod widget;

pub use popup::*;
pub use state::*;
85 changes: 73 additions & 12 deletions src/popup.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::fmt::Debug;

use crate::PopupState;
use derive_setters::Setters;
use ratatui::{
prelude::*,
widgets::{Borders, WidgetRef},
prelude::{Buffer, Line, Rect, Style, Text},
widgets::{Block, Borders, Clear, StatefulWidgetRef, Widget, WidgetRef},
};
use std::cmp::min;

/// Configuration for a popup.
///
Expand All @@ -18,7 +20,8 @@ use ratatui::{
/// use tui_popup::Popup;
///
/// fn render_popup(frame: &mut Frame) {
/// let popup = Popup::new("tui-popup demo", "Press any key to exit")
/// let popup = Popup::new("Press any key to exit")
/// .title("tui-popup demo")
/// .style(Style::new().white().on_blue());
/// frame.render_widget(&popup, frame.size());
/// }
Expand All @@ -28,6 +31,7 @@ use ratatui::{
#[non_exhaustive]
pub struct Popup<'content, W: SizedWidgetRef> {
/// The body of the popup.
#[setters(skip)]
pub body: W,
/// The title of the popup.
pub title: Line<'content>,
Expand All @@ -53,8 +57,6 @@ impl<'content, W: SizedWidgetRef> Popup<'content, W> {
///
/// # Parameters
///
/// - `title` - The title of the popup. This can be any type that can be converted into a
/// [`Line`].
/// - `body` - The body of the popup. This can be any type that can be converted into a
/// [`Text`].
///
Expand All @@ -63,17 +65,14 @@ impl<'content, W: SizedWidgetRef> Popup<'content, W> {
/// ```rust
/// use tui_popup::Popup;
///
/// let popup = Popup::new("tui-popup demo", "Press any key to exit");
/// let popup = Popup::new("Press any key to exit").title("tui-popup demo");
/// ```
pub fn new<L>(title: L, body: W) -> Self
where
L: Into<Line<'content>>,
{
pub fn new(body: W) -> Self {
Self {
body,
title: title.into(),
style: Style::default(),
borders: Borders::ALL,
title: Line::default(),
style: Style::default(),
}
}
}
Expand Down Expand Up @@ -120,3 +119,65 @@ impl<W: WidgetRef + Debug> SizedWidgetRef for SizedWrapper<W> {
self.height
}
}

impl<W: SizedWidgetRef> WidgetRef for Popup<'_, W> {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let mut state = PopupState::default();
StatefulWidgetRef::render_ref(self, area, buf, &mut state);
}
}

impl<W: SizedWidgetRef> StatefulWidgetRef for Popup<'_, W> {
type State = PopupState;

fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
let area = if let Some(next) = state.area.take() {
// ensure that the popup remains on screen
let width = min(next.width, area.width);
let height = min(next.height, area.height);
let x = next.x.clamp(buf.area.x, area.right() - width);
let y = next.y.clamp(buf.area.y, area.bottom() - height);

Rect::new(x, y, width, height)
} else {
let border_height = usize::from(self.borders.intersects(Borders::TOP))
+ usize::from(self.borders.intersects(Borders::BOTTOM));
let border_width = usize::from(self.borders.intersects(Borders::LEFT))
+ usize::from(self.borders.intersects(Borders::RIGHT));

let height = self
.body
.height()
.saturating_add(border_height)
.try_into()
.unwrap_or(area.height);
let width = self
.body
.width()
.saturating_add(border_width)
.try_into()
.unwrap_or(area.width);
centered_rect(width, height, area)
};

state.area.replace(area);

Clear.render(area, buf);
let block = Block::default()
.borders(self.borders)
.title(self.title.clone())
.style(self.style);
block.render_ref(area, buf);
self.body.render_ref(block.inner(area), buf);
}
}

/// Create a rectangle centered in the given area.
fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
Rect {
x: area.width.saturating_sub(width) / 2,
y: area.height.saturating_sub(height) / 2,
width: min(width, area.width),
height: min(height, area.height),
}
}
70 changes: 0 additions & 70 deletions src/widget.rs

This file was deleted.

0 comments on commit 1c79c1c

Please sign in to comment.