tui: Support property lists
Signed-off-by: Erik Kundt <erik@zirkular.io>
This commit is contained in:
parent
bd4efee897
commit
897f4c5250
|
|
@ -6,9 +6,13 @@ pub mod widget;
|
||||||
use tuirealm::props::Attribute;
|
use tuirealm::props::Attribute;
|
||||||
use tuirealm::{MockComponent, StateValue};
|
use tuirealm::{MockComponent, StateValue};
|
||||||
|
|
||||||
use components::{GlobalListener, Label, Shortcut, ShortcutBar};
|
use components::{GlobalListener, Label, Property, PropertyList, Shortcut, ShortcutBar};
|
||||||
use widget::Widget;
|
use widget::Widget;
|
||||||
|
|
||||||
|
pub fn global_listener() -> Widget<GlobalListener> {
|
||||||
|
Widget::new(GlobalListener::default())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn label(content: &str) -> Widget<Label> {
|
pub fn label(content: &str) -> Widget<Label> {
|
||||||
// TODO: Remove when size constraints are implemented
|
// TODO: Remove when size constraints are implemented
|
||||||
let width = content.chars().count() as u16;
|
let width = content.chars().count() as u16;
|
||||||
|
|
@ -41,6 +45,27 @@ pub fn shortcut_bar(theme: &theme::Theme, shortcuts: Vec<Widget<Shortcut>>) -> W
|
||||||
Widget::new(shortcut_bar).height(1)
|
Widget::new(shortcut_bar).height(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_listener() -> Widget<GlobalListener> {
|
pub fn property(theme: &theme::Theme, name: &str, value: &str) -> Widget<Property> {
|
||||||
Widget::new(GlobalListener::default())
|
let name = label(name).foreground(theme.colors.property_name_fg);
|
||||||
|
let divider = label(&format!(" {} ", theme.icons.property_divider));
|
||||||
|
let value = label(value).foreground(theme.colors.default_fg);
|
||||||
|
|
||||||
|
// TODO: Remove when size constraints are implemented
|
||||||
|
let name_w = name.query(Attribute::Width).unwrap().unwrap_size();
|
||||||
|
let divider_w = divider.query(Attribute::Width).unwrap().unwrap_size();
|
||||||
|
let value_w = value.query(Attribute::Width).unwrap().unwrap_size();
|
||||||
|
let width = name_w.saturating_add(divider_w).saturating_add(value_w);
|
||||||
|
|
||||||
|
let property = Property::new(name, divider, value);
|
||||||
|
|
||||||
|
Widget::new(property).height(1).width(width)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn property_list(
|
||||||
|
_theme: &theme::Theme,
|
||||||
|
properties: Vec<Widget<Property>>,
|
||||||
|
) -> Widget<PropertyList> {
|
||||||
|
let property_list = PropertyList::new(properties);
|
||||||
|
|
||||||
|
Widget::new(property_list)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use tui_realm_stdlib::Phantom;
|
||||||
|
|
||||||
use tuirealm::command::{Cmd, CmdResult};
|
use tuirealm::command::{Cmd, CmdResult};
|
||||||
use tuirealm::props::{AttrValue, Attribute, Color, Props};
|
use tuirealm::props::{AttrValue, Attribute, Color, Props};
|
||||||
use tuirealm::tui::layout::Rect;
|
use tuirealm::tui::layout::Rect;
|
||||||
|
|
@ -24,6 +26,14 @@ impl WidgetComponent for GlobalListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Some user events need to be handled globally (e.g. user presses key `q` to quit
|
||||||
|
/// the application). This component can be used in conjunction with SubEventClause
|
||||||
|
/// to handle those events.
|
||||||
|
#[derive(Default, MockComponent)]
|
||||||
|
pub struct GlobalPhantom {
|
||||||
|
component: Phantom,
|
||||||
|
}
|
||||||
|
|
||||||
/// A label that can be styled using a foreground color and text modifiers.
|
/// A label that can be styled using a foreground color and text modifiers.
|
||||||
/// Its height is fixed, its width depends on the length of the text it displays.
|
/// Its height is fixed, its width depends on the length of the text it displays.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -167,3 +177,90 @@ impl WidgetComponent for ShortcutBar {
|
||||||
CmdResult::None
|
CmdResult::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A component that displays a labeled property.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Property {
|
||||||
|
label: Widget<Label>,
|
||||||
|
divider: Widget<Label>,
|
||||||
|
property: Widget<Label>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Property {
|
||||||
|
pub fn new(label: Widget<Label>, divider: Widget<Label>, property: Widget<Label>) -> Self {
|
||||||
|
Self {
|
||||||
|
label,
|
||||||
|
divider,
|
||||||
|
property,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetComponent for Property {
|
||||||
|
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
|
||||||
|
let display = properties
|
||||||
|
.get_or(Attribute::Display, AttrValue::Flag(true))
|
||||||
|
.unwrap_flag();
|
||||||
|
|
||||||
|
if display {
|
||||||
|
let labels: Vec<Box<dyn MockComponent>> = vec![
|
||||||
|
self.label.clone().to_boxed(),
|
||||||
|
self.divider.clone().to_boxed(),
|
||||||
|
self.property.clone().to_boxed(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let layout = layout::h_stack(labels, area);
|
||||||
|
for (mut label, area) in layout {
|
||||||
|
label.view(frame, area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> State {
|
||||||
|
State::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform(&mut self, _cmd: Cmd) -> CmdResult {
|
||||||
|
CmdResult::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A component that can display lists of labeled properties
|
||||||
|
pub struct PropertyList {
|
||||||
|
properties: Vec<Widget<Property>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropertyList {
|
||||||
|
pub fn new(properties: Vec<Widget<Property>>) -> Self {
|
||||||
|
Self { properties }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetComponent for PropertyList {
|
||||||
|
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
|
||||||
|
let display = properties
|
||||||
|
.get_or(Attribute::Display, AttrValue::Flag(true))
|
||||||
|
.unwrap_flag();
|
||||||
|
|
||||||
|
if display {
|
||||||
|
let properties = self
|
||||||
|
.properties
|
||||||
|
.iter()
|
||||||
|
.map(|property| property.clone().to_boxed() as Box<dyn MockComponent>)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let layout = layout::v_stack(properties, area);
|
||||||
|
for (mut property, area) in layout {
|
||||||
|
property.view(frame, area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> State {
|
||||||
|
State::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform(&mut self, _cmd: Cmd) -> CmdResult {
|
||||||
|
CmdResult::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
use tuirealm::props::{AttrValue, Attribute};
|
use tuirealm::props::{AttrValue, Attribute};
|
||||||
use tuirealm::tui::layout::Rect;
|
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
|
||||||
|
|
||||||
use tuirealm::tui::layout::{Constraint, Direction, Layout};
|
|
||||||
use tuirealm::MockComponent;
|
use tuirealm::MockComponent;
|
||||||
|
|
||||||
pub fn v_stack(
|
pub fn v_stack(
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ use tuirealm::props::Color;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Colors {
|
pub struct Colors {
|
||||||
|
pub default_fg: Color,
|
||||||
|
pub property_name_fg: Color,
|
||||||
|
pub property_divider_fg: Color,
|
||||||
pub shortcut_short_fg: Color,
|
pub shortcut_short_fg: Color,
|
||||||
pub shortcut_long_fg: Color,
|
pub shortcut_long_fg: Color,
|
||||||
pub shortcutbar_divider_fg: Color,
|
pub shortcutbar_divider_fg: Color,
|
||||||
|
|
@ -9,16 +12,18 @@ pub struct Colors {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Icons {
|
pub struct Icons {
|
||||||
pub whitespace: char,
|
pub property_divider: char,
|
||||||
pub shortcutbar_divider: char,
|
pub shortcutbar_divider: char,
|
||||||
|
pub whitespace: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Radicle TUI theme. Can be defined in a JSON config file. e.g.:
|
/// The Radicle TUI theme. Will be defined in a JSON config file in the
|
||||||
///
|
/// future. e.g.:
|
||||||
/// {
|
/// {
|
||||||
/// "name": "Radicle Dark",
|
/// "name": "Radicle Dark",
|
||||||
/// "colors": {
|
/// "colors": {
|
||||||
/// "foreground": "#ffffff",
|
/// "foreground": "#ffffff",
|
||||||
|
/// "propertyForeground": "#ffffff",
|
||||||
/// "highlightedBackground": "#000000",
|
/// "highlightedBackground": "#000000",
|
||||||
/// },
|
/// },
|
||||||
/// "icons": {
|
/// "icons": {
|
||||||
|
|
@ -37,13 +42,17 @@ pub fn default_dark() -> Theme {
|
||||||
Theme {
|
Theme {
|
||||||
name: String::from("Radicle Dark"),
|
name: String::from("Radicle Dark"),
|
||||||
colors: Colors {
|
colors: Colors {
|
||||||
|
default_fg: Color::Rgb(200, 200, 200),
|
||||||
|
property_name_fg: Color::Rgb(85, 85, 255),
|
||||||
|
property_divider_fg: Color::Rgb(10, 206, 209),
|
||||||
shortcut_short_fg: Color::Rgb(100, 100, 100),
|
shortcut_short_fg: Color::Rgb(100, 100, 100),
|
||||||
shortcut_long_fg: Color::Rgb(70, 70, 70),
|
shortcut_long_fg: Color::Rgb(70, 70, 70),
|
||||||
shortcutbar_divider_fg: Color::Rgb(70, 70, 70),
|
shortcutbar_divider_fg: Color::Rgb(70, 70, 70),
|
||||||
},
|
},
|
||||||
icons: Icons {
|
icons: Icons {
|
||||||
whitespace: ' ',
|
property_divider: '∙',
|
||||||
shortcutbar_divider: '∙',
|
shortcutbar_divider: '∙',
|
||||||
|
whitespace: ' ',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue