Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve widget styling options in modalkit-ratatui #145

Merged
merged 1 commit into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading