Skip to content

Commit

Permalink
Improve widget styling options in modalkit-ratatui (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
ulyssa authored Aug 10, 2024
1 parent b71afe6 commit 6fa08b6
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 31 deletions.
30 changes: 27 additions & 3 deletions crates/modalkit-ratatui/src/cmdbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use ratatui::{buffer::Buffer, layout::Rect, text::Span, widgets::StatefulWidget};
use ratatui::{buffer::Buffer, layout::Rect, style::Style, text::Span, widgets::StatefulWidget};

use modalkit::actions::{Action, CommandBarAction, PromptAction, Promptable};
use modalkit::editing::{
Expand Down Expand Up @@ -190,6 +190,8 @@ where
pub struct CommandBar<'a, I: ApplicationInfo> {
focused: bool,
message: Option<Span<'a>>,
style_prompt: Option<Style>,
style_text: Style,

_pc: PhantomData<I>,
}
Expand All @@ -200,7 +202,13 @@ where
{
/// Create a new widget.
pub fn new() -> Self {
CommandBar { focused: false, message: None, _pc: PhantomData }
CommandBar {
focused: false,
message: None,
style_prompt: None,
style_text: Style::default(),
_pc: PhantomData,
}
}

/// Indicate whether the widget is currently focused.
Expand All @@ -209,6 +217,20 @@ where
self
}

/// Set the style to use for the command bar's prompt.
///
/// If one isn't provided, then this is the same style specified with [CommandBar::style].
pub fn prompt_style(mut self, style: Style) -> Self {
self.style_prompt = Some(style);
self
}

/// Set the style to use for the contents of the inner [TextBox].
pub fn style(mut self, style: Style) -> Self {
self.style_text = style;
self
}

/// Set a status string that will be displayed instead of the contents when the widget is not
/// currently focused.
pub fn status(mut self, msg: Option<Span<'a>>) -> Self {
Expand All @@ -225,7 +247,9 @@ where

fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
if self.focused {
let tbox = TextBox::new().prompt(&state.prompt).oneline();
let prompt_style = self.style_prompt.unwrap_or(self.style_text);
let prompt = Span::styled(&state.prompt, prompt_style);
let tbox = TextBox::new().prompt(prompt).style(self.style_text).oneline();
let tbox_state = match state.cmdtype {
CommandType::Command => &mut state.tbox_cmd,
CommandType::Search => &mut state.tbox_search,
Expand Down
59 changes: 56 additions & 3 deletions crates/modalkit-ratatui/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,13 @@ where

borders: bool,
border_style: Style,
border_style_focused: Style,
border_type: BorderType,
cmdbar_style: Style,
cmdbar_prompt_style: Option<Style>,
tab_style: Style,
tab_style_focused: Style,
divider: Span<'a>,
focused: bool,

_p: PhantomData<(W, I)>,
Expand All @@ -721,7 +727,13 @@ where
showmode: None,
borders: false,
border_style: Style::default(),
border_style_focused: Style::default(),
border_type: BorderType::Plain,
cmdbar_style: Style::default(),
cmdbar_prompt_style: None,
tab_style: Style::default(),
tab_style_focused: Style::default(),
divider: Span::raw("|"),
focused: true,
_p: PhantomData,
}
Expand All @@ -733,6 +745,12 @@ where
self
}

/// What [Style] should be used when drawing the border of the selected window.
pub fn border_style_focused(mut self, style: Style) -> Self {
self.border_style_focused = style;
self
}

/// What characters should be used when drawing borders.
pub fn border_type(mut self, border_type: BorderType) -> Self {
self.border_type = border_type;
Expand All @@ -745,6 +763,38 @@ where
self
}

/// What [Style] should be used when drawing borders.
pub fn cmdbar_style(mut self, style: Style) -> Self {
self.cmdbar_style = style;
self
}

/// What [Style] should be used when drawing the border of the selected window.
pub fn cmdbar_prompt_style(mut self, style: Style) -> Self {
self.cmdbar_prompt_style = Some(style);
self
}

/// What [Style] should be used for tab names.
pub fn tab_style(mut self, style: Style) -> Self {
self.tab_style = style;
self
}

/// What [Style] should be used for the focused tab name.
pub fn tab_style_focused(mut self, style: Style) -> Self {
self.tab_style_focused = style;
self
}

/// Set the divider [Span] to place in between tab names.
///
/// This defaults to an unstyled "|".
pub fn divider(mut self, divider: impl Into<Span<'a>>) -> Self {
self.divider = divider.into();
self
}

/// Indicates whether the terminal window is currently focused.
pub fn focus(mut self, focused: bool) -> Self {
self.focused = focused;
Expand Down Expand Up @@ -838,16 +888,17 @@ where
.collect();

Tabs::new(titles)
.style(Style::default().fg(Color::White))
.highlight_style(Style::default().fg(Color::Yellow))
.divider("|")
.style(self.tab_style)
.highlight_style(self.tab_style_focused)
.divider(self.divider)
.select(state.tabs.pos())
.render(tabarea, buf);

if let Ok(tab) = state.current_tab_mut() {
WindowLayout::new(self.store)
.focus(self.focused && focused == CurrentFocus::Window)
.border_style(self.border_style)
.border_style_focused(self.border_style_focused)
.border_type(self.border_type)
.borders(self.borders)
.render(winarea, buf, tab);
Expand Down Expand Up @@ -876,6 +927,8 @@ where
CommandBar::new()
.focus(focused == CurrentFocus::Command)
.status(status)
.style(self.cmdbar_style)
.prompt_style(self.cmdbar_prompt_style.unwrap_or(self.cmdbar_style))
.render(cmdarea, buf, &mut state.cmdbar);

// Render completion list last so it's drawn on top of the windows.
Expand Down
45 changes: 21 additions & 24 deletions crates/modalkit-ratatui/src/textbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use ratatui::{
buffer::Buffer,
layout::Rect,
style::{Modifier, Style},
text::Span,
widgets::{Block, StatefulWidget, Widget},
};

Expand Down Expand Up @@ -106,8 +107,9 @@ pub struct TextBoxState<I: ApplicationInfo = EmptyInfo> {
/// Widget for rendering a multi-line text box.
pub struct TextBox<'a, I: ApplicationInfo = EmptyInfo> {
block: Option<Block<'a>>,
prompt: &'a str,
prompt: Span<'a>,
oneline: bool,
style: Style,

lgutter_width: u16,
rgutter_width: u16,
Expand Down Expand Up @@ -619,8 +621,9 @@ where
pub fn new() -> Self {
TextBox {
block: None,
prompt: "",
prompt: Span::default(),
oneline: false,
style: Style::default(),

lgutter_width: 0,
rgutter_width: 0,
Expand All @@ -629,6 +632,12 @@ where
}
}

/// Set the style to use for rendering text within the [TextBoxState].
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}

/// Wrap this text box in a [Block].
pub fn block(mut self, block: Block<'a>) -> Self {
self.block = Some(block);
Expand All @@ -645,8 +654,8 @@ where
}

/// Display a prompt in the top left of the text box when focused.
pub fn prompt(mut self, prompt: &'a str) -> Self {
self.prompt = prompt;
pub fn prompt(mut self, prompt: impl Into<Span<'a>>) -> Self {
self.prompt = prompt.into();
self
}

Expand All @@ -672,7 +681,7 @@ where
followers: &FollowersInfo,
buf: &mut Buffer,
) {
let hlstyled = Style::default().add_modifier(Modifier::REVERSED);
let hlstyled = self.style.add_modifier(Modifier::REVERSED);
let cs = (line, start);
let ce = (line, end);

Expand All @@ -688,7 +697,7 @@ where
let tx: u16 = x + (h1 - start) as u16;
let selwidth: u16 = (h2 - h1 + 1).try_into().unwrap();

let hlstyled = Style::default().add_modifier(Modifier::REVERSED);
let hlstyled = self.style.add_modifier(Modifier::REVERSED);
let selarea = Rect::new(tx, y, selwidth, 1);

buf.set_style(selarea, hlstyled);
Expand Down Expand Up @@ -724,7 +733,7 @@ where
}
},
TargetShape::LineWise => {
let hlstyled = Style::default().add_modifier(Modifier::REVERSED);
let hlstyled = self.style.add_modifier(Modifier::REVERSED);
let selwidth: u16 = (end - start).try_into().unwrap();
let selarea = Rect::new(x, y, selwidth, 1);

Expand Down Expand Up @@ -773,8 +782,6 @@ where
let cby = state.viewctx.corner.y;
let cbx = state.viewctx.corner.x;

let unstyled = Style::default();

let text = state.buffer.read().unwrap();

let mut wrapped = Vec::new();
Expand Down Expand Up @@ -852,7 +859,7 @@ where
}
}

let _ = buf.set_stringn(x, y, s, width, unstyled);
let _ = buf.set_stringn(x, y, s, width, self.style);

if cursor_line {
let coff = (cursor.x - start) as u16;
Expand Down Expand Up @@ -887,8 +894,6 @@ where
let cby = state.viewctx.corner.y;
let cbx = state.viewctx.corner.x;

let unstyled = Style::default();

let text = state.buffer.read().unwrap();

let mut joined = Vec::new();
Expand Down Expand Up @@ -997,7 +1002,7 @@ where

let s = s.to_string();
let w = (right - x) as usize;
let (xres, _) = buf.set_stringn(x, y, s, w, unstyled);
let (xres, _) = buf.set_stringn(x, y, s, w, self.style);

if cursor_line {
let coff = cursor.x.saturating_sub(start) as u16;
Expand Down Expand Up @@ -1034,8 +1039,6 @@ where
let cby = state.viewctx.corner.y;
let cbx = state.viewctx.corner.x;

let unstyled = Style::default();

let text = state.buffer.read().unwrap();
let mut line = cby;
let mut lines = text.lines(line);
Expand All @@ -1060,7 +1063,7 @@ where
y,
s.slice(CharOff::from(start)..CharOff::from(end)).to_string(),
width,
unstyled,
self.style,
);
}

Expand Down Expand Up @@ -1151,7 +1154,7 @@ where
None => area,
};

let plen = self.prompt.len() as u16;
let plen = self.prompt.width() as u16;
let gutter = Rect::new(area.x, area.y, plen, area.height);

let text_area =
Expand All @@ -1162,13 +1165,7 @@ where
}

// First, draw the prompt in the gutter.
let _ = buf.set_stringn(
gutter.left(),
gutter.top(),
self.prompt,
gutter.width as usize,
Style::default(),
);
let _ = buf.set_span(gutter.left(), gutter.top(), &self.prompt, gutter.width);

// Now draw the text.
self._render_lines(text_area, buf, state);
Expand Down
14 changes: 13 additions & 1 deletion crates/modalkit-ratatui/src/windows/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1941,6 +1941,7 @@ pub struct WindowLayout<'a, W: Window<I>, I: ApplicationInfo> {

borders: bool,
border_style: Style,
border_style_focused: Style,
border_type: BorderType,

_pw: PhantomData<(W, I)>,
Expand All @@ -1958,6 +1959,7 @@ where
focused: false,
borders: false,
border_style: Style::default(),
border_style_focused: Style::default(),
border_type: BorderType::Plain,
_pw: PhantomData,
}
Expand All @@ -1969,6 +1971,12 @@ where
self
}

/// What [Style] should be used when drawing the border of the selected window.
pub fn border_style_focused(mut self, style: Style) -> Self {
self.border_style_focused = style;
self
}

/// What characters should be used when drawing borders.
pub fn border_type(mut self, border_type: BorderType) -> Self {
self.border_type = border_type;
Expand Down Expand Up @@ -2010,7 +2018,11 @@ where
let block = Block::default()
.title(title)
.borders(Borders::ALL)
.border_style(self.border_style)
.border_style(if focused {
self.border_style_focused
} else {
self.border_style
})
.border_type(self.border_type);
let inner = block.inner(info.area);

Expand Down

0 comments on commit 6fa08b6

Please sign in to comment.