tui: Support container focus

This commit is contained in:
Erik Kundt 2023-06-09 09:55:52 +02:00 committed by Alexis Sellier
parent dcfd481424
commit 3a7cef8cea
No known key found for this signature in database
7 changed files with 95 additions and 25 deletions

View File

@ -111,8 +111,8 @@ impl ViewPage for HomeView {
) -> Result<()> {
if let Message::NavigationChanged(index) = message {
self.active_component = Cid::Home(HomeCid::from(index as usize));
app.active(&self.active_component)?;
}
app.active(&self.active_component)?;
Ok(())
}
@ -148,16 +148,12 @@ impl ViewPage for HomeView {
/// Issue detail page
///
pub struct IssuePage {
active_component: Cid,
issue: (IssueId, Issue),
}
impl IssuePage {
pub fn new(issue: (IssueId, Issue)) -> Self {
IssuePage {
active_component: Cid::Issue(IssueCid::List),
issue,
}
IssuePage { issue }
}
}
@ -186,7 +182,7 @@ impl ViewPage for IssuePage {
app.remount(Cid::Issue(IssueCid::Details), details, vec![])?;
app.remount(Cid::Issue(IssueCid::Shortcuts), shortcuts, vec![])?;
app.active(&self.active_component)?;
app.active(&Cid::Issue(IssueCid::List))?;
Ok(())
}
@ -212,8 +208,14 @@ impl ViewPage for IssuePage {
let details = widget::issue::details(context, theme, (id, issue)).to_boxed();
app.remount(Cid::Issue(IssueCid::Details), details, vec![])?;
}
Message::Issue(IssueMessage::FocusList) => {
app.active(&Cid::Issue(IssueCid::List))?;
}
Message::Issue(IssueMessage::FocusDiscussion) => {
app.active(&Cid::Issue(IssueCid::Discussion))?;
}
_ => {}
}
app.active(&self.active_component)?;
Ok(())
}

View File

@ -36,6 +36,8 @@ pub struct Colors {
pub context_id_fg: Color,
pub context_id_bg: Color,
pub context_id_author_fg: Color,
pub container_border_fg: Color,
pub container_border_focus_fg: Color,
}
#[derive(Debug, Clone)]
@ -105,6 +107,8 @@ pub fn default_dark() -> Theme {
context_id_fg: Color::Cyan,
context_id_bg: COLOR_DEFAULT_DARKEST,
context_id_author_fg: Color::Gray,
container_border_fg: COLOR_DEFAULT_DARKEST,
container_border_focus_fg: COLOR_DEFAULT_DARK,
},
icons: Icons {
property_divider: '',

View File

@ -45,8 +45,8 @@ pub fn container_header(theme: &Theme, label: Widget<Label>) -> Widget<Header<1>
Widget::new(header)
}
pub fn container(_theme: &Theme, component: Box<dyn MockComponent>) -> Widget<Container> {
let container = Container::new(component);
pub fn container(theme: &Theme, component: Box<dyn MockComponent>) -> Widget<Container> {
let container = Container::new(component, theme.clone());
Widget::new(container)
}
@ -59,7 +59,7 @@ pub fn labeled_container(
theme,
label(&format!(" {title} ")).foreground(theme.colors.default_fg),
);
let container = LabeledContainer::new(header, component);
let container = LabeledContainer::new(header, component, theme.clone());
Widget::new(container)
}

View File

@ -1,7 +1,5 @@
use tuirealm::command::{Cmd, CmdResult};
use tuirealm::props::{
AttrValue, Attribute, BorderSides, BorderType, Color, Props, Style, TextModifiers,
};
use tuirealm::props::{AttrValue, Attribute, BorderSides, BorderType, Props, Style, TextModifiers};
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
use tuirealm::tui::widgets::{Block, Cell, Row};
use tuirealm::{Frame, MockComponent, State, StateValue};
@ -276,10 +274,20 @@ impl<const W: usize> WidgetComponent for Header<W> {
let display = properties
.get_or(Attribute::Display, AttrValue::Flag(true))
.unwrap_flag();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let color = if focus {
self.theme.colors.container_border_focus_fg
} else {
self.theme.colors.container_border_fg
};
if display {
let block = HeaderBlock::default()
.borders(BorderSides::all())
.border_style(Style::default().fg(Color::Rgb(48, 48, 48)))
.border_style(Style::default().fg(color))
.border_type(BorderType::Rounded);
frame.render_widget(block, area);
@ -322,11 +330,12 @@ impl<const W: usize> WidgetComponent for Header<W> {
pub struct Container {
component: Box<dyn MockComponent>,
theme: Theme,
}
impl Container {
pub fn new(component: Box<dyn MockComponent>) -> Self {
Self { component }
pub fn new(component: Box<dyn MockComponent>, theme: Theme) -> Self {
Self { component, theme }
}
}
@ -335,6 +344,15 @@ impl WidgetComponent for Container {
let display = properties
.get_or(Attribute::Display, AttrValue::Flag(true))
.unwrap_flag();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let color = if focus {
self.theme.colors.container_border_focus_fg
} else {
self.theme.colors.container_border_fg
};
if display {
// Make some space on the left
@ -349,7 +367,7 @@ impl WidgetComponent for Container {
let block = Block::default()
.borders(BorderSides::ALL)
.border_style(Style::default().fg(Color::Rgb(48, 48, 48)))
.border_style(Style::default().fg(color))
.border_type(BorderType::Rounded);
frame.render_widget(block, area);
}
@ -367,11 +385,16 @@ impl WidgetComponent for Container {
pub struct LabeledContainer {
header: Widget<Header<1>>,
component: Box<dyn MockComponent>,
theme: Theme,
}
impl LabeledContainer {
pub fn new(header: Widget<Header<1>>, component: Box<dyn MockComponent>) -> Self {
Self { header, component }
pub fn new(header: Widget<Header<1>>, component: Box<dyn MockComponent>, theme: Theme) -> Self {
Self {
header,
component,
theme,
}
}
}
@ -380,6 +403,16 @@ impl WidgetComponent for LabeledContainer {
let display = properties
.get_or(Attribute::Display, AttrValue::Flag(true))
.unwrap_flag();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let color = if focus {
self.theme.colors.container_border_focus_fg
} else {
self.theme.colors.container_border_fg
};
let header_height = self
.header
.query(Attribute::Height)
@ -399,14 +432,17 @@ impl WidgetComponent for LabeledContainer {
.constraints(vec![Constraint::Length(1), Constraint::Min(0)].as_ref())
.split(layout[1]);
// reverse draw order: child needs to be drawn first?
self.component.attr(Attribute::Focus, AttrValue::Flag(focus));
self.component.view(frame, inner_layout[1]);
let block = Block::default()
.borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
.border_style(Style::default().fg(Color::Rgb(48, 48, 48)))
.border_style(Style::default().fg(color))
.border_type(BorderType::Rounded);
frame.render_widget(block, layout[1]);
self.header.attr(Attribute::Focus, AttrValue::Flag(focus));
self.header.view(frame, layout[0]);
}
}

View File

@ -225,6 +225,16 @@ where
.get_or(Attribute::HighlightedColor, AttrValue::Color(Color::Reset))
.unwrap_color();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let color = if focus {
self.theme.colors.container_border_focus_fg
} else {
self.theme.colors.container_border_fg
};
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(3), Constraint::Min(1)])
@ -241,7 +251,7 @@ where
.block(
Block::default()
.borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
.border_style(Style::default().fg(Color::Rgb(48, 48, 48)))
.border_style(Style::default().fg(color))
.border_type(BorderType::Rounded),
)
.highlight_style(Style::default().bg(highlight))
@ -253,7 +263,10 @@ where
self.widths,
self.theme.clone(),
));
header.attr(Attribute::Focus, AttrValue::Flag(focus));
header.view(frame, layout[0]);
frame.render_stateful_widget(table, layout[1], &mut TableState::from(&self.state));
}

View File

@ -106,14 +106,19 @@ impl IssueBrowser {
}
impl WidgetComponent for IssueBrowser {
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
let shortcuts_h = self
.shortcuts
.query(Attribute::Height)
.unwrap_or(AttrValue::Size(0))
.unwrap_size();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let layout = layout::root_component(area, shortcuts_h);
self.table.attr(Attribute::Focus, AttrValue::Flag(focus));
self.table.view(frame, layout[0]);
self.shortcuts.view(frame, layout[1])
}
@ -187,14 +192,19 @@ impl PatchBrowser {
}
impl WidgetComponent for PatchBrowser {
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
let shortcuts_h = self
.shortcuts
.query(Attribute::Height)
.unwrap_or(AttrValue::Size(0))
.unwrap_size();
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
let layout = layout::root_component(area, shortcuts_h);
self.table.attr(Attribute::Focus, AttrValue::Flag(focus));
self.table.view(frame, layout[0]);
self.shortcuts.view(frame, layout[1]);
}

View File

@ -56,7 +56,12 @@ impl LargeList {
}
impl WidgetComponent for LargeList {
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
let focus = properties
.get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag();
self.list.attr(Attribute::Focus, AttrValue::Flag(focus));
self.list.view(frame, area);
}