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::{MockComponent, StateValue};
|
||||
|
||||
use components::{GlobalListener, Label, Shortcut, ShortcutBar};
|
||||
use components::{GlobalListener, Label, Property, PropertyList, Shortcut, ShortcutBar};
|
||||
use widget::Widget;
|
||||
|
||||
pub fn global_listener() -> Widget<GlobalListener> {
|
||||
Widget::new(GlobalListener::default())
|
||||
}
|
||||
|
||||
pub fn label(content: &str) -> Widget<Label> {
|
||||
// TODO: Remove when size constraints are implemented
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn global_listener() -> Widget<GlobalListener> {
|
||||
Widget::new(GlobalListener::default())
|
||||
pub fn property(theme: &theme::Theme, name: &str, value: &str) -> Widget<Property> {
|
||||
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::props::{AttrValue, Attribute, Color, Props};
|
||||
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.
|
||||
/// Its height is fixed, its width depends on the length of the text it displays.
|
||||
#[derive(Clone)]
|
||||
|
|
@ -167,3 +177,90 @@ impl WidgetComponent for ShortcutBar {
|
|||
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::tui::layout::Rect;
|
||||
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout};
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use tuirealm::MockComponent;
|
||||
|
||||
pub fn v_stack(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ use tuirealm::props::Color;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Colors {
|
||||
pub default_fg: Color,
|
||||
pub property_name_fg: Color,
|
||||
pub property_divider_fg: Color,
|
||||
pub shortcut_short_fg: Color,
|
||||
pub shortcut_long_fg: Color,
|
||||
pub shortcutbar_divider_fg: Color,
|
||||
|
|
@ -9,16 +12,18 @@ pub struct Colors {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Icons {
|
||||
pub whitespace: char,
|
||||
pub property_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",
|
||||
/// "colors": {
|
||||
/// "foreground": "#ffffff",
|
||||
/// "propertyForeground": "#ffffff",
|
||||
/// "highlightedBackground": "#000000",
|
||||
/// },
|
||||
/// "icons": {
|
||||
|
|
@ -37,13 +42,17 @@ pub fn default_dark() -> Theme {
|
|||
Theme {
|
||||
name: String::from("Radicle Dark"),
|
||||
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_long_fg: Color::Rgb(70, 70, 70),
|
||||
shortcutbar_divider_fg: Color::Rgb(70, 70, 70),
|
||||
},
|
||||
icons: Icons {
|
||||
whitespace: ' ',
|
||||
property_divider: '∙',
|
||||
shortcutbar_divider: '∙',
|
||||
whitespace: ' ',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue