lib: Move label builders to widget module

This commit is contained in:
Erik Kundt
2024-01-12 14:39:32 +01:00
parent ddc10a45e7
commit ea91de73cc
8 changed files with 125 additions and 124 deletions
+21 -21
View File
@@ -22,7 +22,7 @@ use tui::ui::widget::{Widget, WidgetComponent};
use tui::ui::widget::container::{Container, Tabs};
use tui::ui::widget::context::{ContextBar, Progress};
use tui::ui::widget::form::{Form, TextArea, TextField};
use tui::ui::widget::label::Textarea;
use tui::ui::widget::label::{self, Textarea};
use tui::ui::widget::list::{ColumnWidth, List, Property, Table};
pub const FORM_ID_EDIT: &str = "edit-form";
@@ -35,13 +35,13 @@ pub struct IssueBrowser {
impl IssueBrowser {
pub fn new(context: &Context, theme: &Theme, selected: Option<(IssueId, Issue)>) -> Self {
let header = [
tui::ui::label(" ● "),
tui::ui::label("ID"),
tui::ui::label("Title"),
tui::ui::label("Author"),
tui::ui::label("Tags"),
tui::ui::label("Assignees"),
tui::ui::label("Opened"),
label::default(" ● ").style(style::reset_dim()),
label::default("ID").style(style::reset_dim()),
label::default("Title").style(style::reset_dim()),
label::default("Author").style(style::reset_dim()),
label::default("Tags").style(style::reset_dim()),
label::default("Assignees").style(style::reset_dim()),
label::default("Opened").style(style::reset_dim()),
];
let widths = [
@@ -172,8 +172,8 @@ impl IssueHeader {
let item = IssueItem::from((context.profile(), repo, id, issue.clone()));
let title = Property::new(
tui::ui::label("Title").style(style::cyan()),
tui::ui::label(item.title()).style(style::reset()),
label::default("Title").style(style::cyan()),
label::default(item.title()).style(style::reset()),
);
let author_style = match alias {
@@ -181,23 +181,23 @@ impl IssueHeader {
None => style::magenta_dim(),
};
let author = tui::ui::label(&cob::format_author(issue.author().id(), &alias, by_you))
let author = label::default(&cob::format_author(issue.author().id(), &alias, by_you))
.style(author_style);
let author = Property::new(tui::ui::label("Author").style(style::cyan()), author);
let author = Property::new(label::default("Author").style(style::cyan()), author);
let issue_id = Property::new(
tui::ui::label("Issue").style(style::cyan()),
tui::ui::label(&id.to_string()).style(style::gray()),
label::default("Issue").style(style::cyan()),
label::default(&id.to_string()).style(style::gray()),
);
let labels = Property::new(
tui::ui::label("Labels").style(style::cyan()),
tui::ui::label(&cob::format_labels(item.labels())).style(style::lightblue()),
label::default("Labels").style(style::cyan()),
label::default(&cob::format_labels(item.labels())).style(style::lightblue()),
);
let assignees = Property::new(
tui::ui::label("Assignees").style(style::cyan()),
tui::ui::label(&cob::format_assignees(
label::default("Assignees").style(style::cyan()),
label::default(&cob::format_assignees(
&item
.assignees()
.iter()
@@ -208,8 +208,8 @@ impl IssueHeader {
);
let state = Property::new(
tui::ui::label("Status").style(style::cyan()),
tui::ui::label(&item.state().to_string()).style(style::reset()),
label::default("Status").style(style::cyan()),
label::default(&item.state().to_string()).style(style::reset()),
);
let table = tui::ui::property_table(
@@ -330,7 +330,7 @@ impl WidgetComponent for CommentBody {
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
tui::ui::tabs(
theme,
vec![tui::ui::reversable_label("Issues").style(style::magenta())],
vec![label::reversable("Issues").style(style::magenta())],
)
}
+28 -27
View File
@@ -13,6 +13,7 @@ use tui::ui::widget::{Widget, WidgetComponent};
use tui::ui::widget::container::Tabs;
use tui::ui::widget::context::{ContextBar, Progress};
use tui::ui::widget::label::{self};
use tui::ui::widget::list::{ColumnWidth, Table};
pub struct PatchBrowser {
@@ -23,14 +24,14 @@ pub struct PatchBrowser {
impl PatchBrowser {
pub fn new(context: &Context, theme: &Theme, selected: Option<(PatchId, Patch)>) -> Self {
let header = [
tui::ui::label(" ● ").style(style::reset_dim()),
tui::ui::label("ID").style(style::reset_dim()),
tui::ui::label("Title").style(style::reset_dim()),
tui::ui::label("Author").style(style::reset_dim()),
tui::ui::label("Head").style(style::reset_dim()),
tui::ui::label("+").style(style::reset_dim()),
tui::ui::label("-").style(style::reset_dim()),
tui::ui::label("Updated").style(style::reset_dim()),
label::default(" ● ").style(style::reset_dim()),
label::default("ID").style(style::reset_dim()),
label::default("Title").style(style::reset_dim()),
label::default("Author").style(style::reset_dim()),
label::default("Head").style(style::reset_dim()),
label::default("+").style(style::reset_dim()),
label::default("-").style(style::reset_dim()),
label::default("Updated").style(style::reset_dim()),
];
let widths = [
@@ -96,7 +97,7 @@ impl WidgetComponent for PatchBrowser {
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
tui::ui::tabs(
theme,
vec![tui::ui::reversable_label("Patches").style(style::cyan())],
vec![label::reversable("Patches").style(style::cyan())],
)
}
@@ -110,7 +111,6 @@ pub fn patches(
pub fn browse_context(context: &Context, _theme: &Theme, progress: Progress) -> Widget<ContextBar> {
use radicle::cob::patch::State;
use tui::ui::{label, label_group};
let mut draft = 0;
let mut open = 0;
@@ -130,29 +130,30 @@ pub fn browse_context(context: &Context, _theme: &Theme, progress: Progress) ->
}
}
let context = label(" Patches ").style(style::magenta_reversed());
let divider = label(" | ").style(style::default_reversed());
let context = label::default(" Patches ").style(style::magenta_reversed());
let divider = label::default(" | ").style(style::default_reversed());
let draft_n = label(&format!("{draft}")).style(style::default_reversed());
let draft = label(" Draft").style(style::default_reversed());
let draft_n = label::default(&format!("{draft}")).style(style::default_reversed());
let draft = label::default(" Draft").style(style::default_reversed());
let open_n = label(&format!("{open}")).style(style::green_default_reversed());
let open = label(" Open").style(style::default_reversed());
let open_n = label::default(&format!("{open}")).style(style::green_default_reversed());
let open = label::default(" Open").style(style::default_reversed());
let archived_n = label(&format!("{archived}")).style(style::yellow_default_reversed());
let archived = label(" Archived").style(style::default_reversed());
let archived_n = label::default(&format!("{archived}")).style(style::yellow_default_reversed());
let archived = label::default(" Archived").style(style::default_reversed());
let merged_n = label(&format!("{merged}")).style(style::cyan_default_reversed());
let merged = label(" Merged ").style(style::default_reversed());
let merged_n = label::default(&format!("{merged}")).style(style::cyan_default_reversed());
let merged = label::default(" Merged ").style(style::default_reversed());
let progress = label(&format!(" {} ", progress.to_string())).style(style::magenta_reversed());
let spacer = label("").style(style::default_reversed());
let progress =
label::default(&format!(" {} ", progress.to_string())).style(style::magenta_reversed());
let spacer = label::default("").style(style::default_reversed());
let context_bar = ContextBar::new(
label_group(&[context]),
label_group(&[spacer.clone()]),
label_group(&[spacer]),
label_group(&[
label::group(&[context]),
label::group(&[spacer.clone()]),
label::group(&[spacer]),
label::group(&[
draft_n,
draft,
divider.clone(),
@@ -165,7 +166,7 @@ pub fn browse_context(context: &Context, _theme: &Theme, progress: Progress) ->
merged_n,
merged,
]),
label_group(&[progress]),
label::group(&[progress]),
);
Widget::new(context_bar).height(1)
+14 -14
View File
@@ -16,7 +16,7 @@ use tui::ui::widget::{Widget, WidgetComponent};
use tui::ui::widget::container::Tabs;
use tui::ui::widget::context::{ContextBar, Progress};
use tui::ui::widget::label::Label;
use tui::ui::widget::label::{self, Label};
use tui::ui::widget::list::{ColumnWidth, Table};
pub struct PatchBrowser {
@@ -27,14 +27,14 @@ pub struct PatchBrowser {
impl PatchBrowser {
pub fn new(context: &Context, theme: &Theme, selected: Option<(PatchId, Patch)>) -> Self {
let header = [
tui::ui::label(" ● "),
tui::ui::label("ID"),
tui::ui::label("Title"),
tui::ui::label("Author"),
tui::ui::label("Head"),
tui::ui::label("+"),
tui::ui::label("-"),
tui::ui::label("Updated"),
label::default(" ● ").style(style::reset_dim()),
label::default("ID").style(style::reset_dim()),
label::default("Title").style(style::reset_dim()),
label::default("Author").style(style::reset_dim()),
label::default("Head").style(style::reset_dim()),
label::default("+").style(style::reset_dim()),
label::default("-").style(style::reset_dim()),
label::default("Updated").style(style::reset_dim()),
];
let widths = [
@@ -162,7 +162,7 @@ impl WidgetComponent for Files {
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
tui::ui::tabs(
theme,
vec![tui::ui::reversable_label("Patches").style(style::magenta())],
vec![label::reversable("Patches").style(style::magenta())],
)
}
@@ -170,8 +170,8 @@ pub fn navigation(theme: &Theme) -> Widget<Tabs> {
tui::ui::tabs(
theme,
vec![
tui::ui::reversable_label("Activity").style(style::magenta()),
tui::ui::reversable_label("Files").style(style::magenta()),
label::reversable("Activity").style(style::magenta()),
label::reversable("Files").style(style::magenta()),
],
)
}
@@ -185,14 +185,14 @@ pub fn patches(
}
pub fn activity(_theme: &Theme) -> Widget<Activity> {
let not_implemented = tui::ui::label("not implemented").style(style::reset());
let not_implemented = label::default("not implemented").style(style::reset());
let activity = Activity::new(not_implemented);
Widget::new(activity)
}
pub fn files(_theme: &Theme) -> Widget<Files> {
let not_implemented = tui::ui::label("not implemented").style(style::reset());
let not_implemented = label::default("not implemented").style(style::reset());
let files = Files::new(not_implemented);
Widget::new(files)
+17 -44
View File
@@ -14,13 +14,11 @@ use widget::container::{
VerticalLine,
};
use widget::context::{Shortcut, Shortcuts};
use widget::label::{Label, Textarea};
use widget::label::{self, Label, Textarea};
use widget::list::{ColumnWidth, Property, PropertyList, PropertyTable};
use widget::Widget;
use self::theme::{style, Theme};
use self::widget::label::LabelGroup;
use theme::{style, Theme};
use super::context::Context;
@@ -28,35 +26,6 @@ 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;
Widget::new(Label)
.content(AttrValue::String(content.to_string()))
.height(1)
.width(width)
}
pub fn label_group(labels: &[Widget<Label>]) -> Widget<LabelGroup> {
let group = LabelGroup::new(labels);
let width = labels.iter().fold(0, |total, label| {
total
+ label
.query(Attribute::Width)
.unwrap_or(AttrValue::Size(0))
.unwrap_size()
});
Widget::new(group).width(width)
}
pub fn reversable_label(content: &str) -> Widget<Label> {
let content = &format!(" {content} ");
label(content)
}
pub fn container_header(theme: &Theme, label: Widget<Label>) -> Widget<Header<1>> {
let header = Header::new([label], [ColumnWidth::Grow], theme.clone());
@@ -73,16 +42,19 @@ pub fn labeled_container(
title: &str,
component: Box<dyn MockComponent>,
) -> Widget<LabeledContainer> {
let header = container_header(theme, label(&format!(" {title} ")).style(style::reset()));
let header = container_header(
theme,
label::default(&format!(" {title} ")).style(style::reset()),
);
let container = LabeledContainer::new(header, component, theme.clone());
Widget::new(container)
}
pub fn shortcut(theme: &Theme, short: &str, long: &str) -> Widget<Shortcut> {
let short = label(short).style(style::gray());
let long = label(long).style(style::gray_dim());
let divider = label(&theme.icons.whitespace.to_string());
let short = label::default(short).style(style::gray());
let long = label::default(long).style(style::gray_dim());
let divider = label::default(&theme.icons.whitespace.to_string());
// TODO: Remove when size constraints are implemented
let short_w = short.query(Attribute::Width).unwrap().unwrap_size();
@@ -96,16 +68,17 @@ pub fn shortcut(theme: &Theme, short: &str, long: &str) -> Widget<Shortcut> {
}
pub fn shortcuts(theme: &Theme, shortcuts: Vec<Widget<Shortcut>>) -> Widget<Shortcuts> {
let divider = label(&format!(" {} ", theme.icons.shortcutbar_divider)).style(style::gray_dim());
let divider =
label::default(&format!(" {} ", theme.icons.shortcutbar_divider)).style(style::gray_dim());
let shortcut_bar = Shortcuts::new(shortcuts, divider);
Widget::new(shortcut_bar).height(1)
}
pub fn property(theme: &Theme, name: &str, value: &str) -> Widget<Property> {
let name = label(name).style(style::cyan());
let divider = label(&format!(" {} ", theme.icons.property_divider));
let value = label(value).style(style::reset());
let name = label::default(name).style(style::cyan());
let divider = label::default(&format!(" {} ", theme.icons.property_divider));
let value = label::default(value).style(style::reset());
// TODO: Remove when size constraints are implemented
let name_w = name.query(Attribute::Width).unwrap().unwrap_size();
@@ -137,8 +110,8 @@ pub fn tabs(_theme: &Theme, tabs: Vec<Widget<Label>>) -> Widget<Tabs> {
}
pub fn app_info(context: &Context) -> Widget<AppInfo> {
let project = label(context.project().name()).style(style::cyan());
let rid = label(&format!(" ({})", context.id())).style(style::yellow());
let project = label::default(context.project().name()).style(style::cyan());
let rid = label::default(&format!(" ({})", context.id())).style(style::yellow());
let project_w = project
.query(Attribute::Width)
@@ -158,7 +131,7 @@ pub fn app_header(
theme: &Theme,
nav: Option<Widget<Tabs>>,
) -> Widget<AppHeader> {
let line = label(&theme.icons.tab_overline.to_string()).style(style::magenta());
let line = label::default(&theme.icons.tab_overline.to_string()).style(style::magenta());
let line = Widget::new(VerticalLine::new(line));
let info = app_info(context);
let header = AppHeader::new(nav, info, line);
+11 -13
View File
@@ -3,7 +3,7 @@ use tuirealm::props::{AttrValue, Attribute, Props};
use tuirealm::tui::layout::Rect;
use tuirealm::{Frame, MockComponent, State};
use super::label::{Label, LabelGroup};
use super::label::{self, Label, LabelGroup};
use crate::ui::layout;
use crate::ui::theme::{style, Theme};
@@ -215,19 +215,17 @@ pub fn bar(
label_3: &str,
label_4: &str,
) -> Widget<ContextBar> {
use crate::ui::{label, label_group};
let label_0 = label::default(&format!(" {label_0} ")).style(style::magenta_reversed());
let label_1 = label::default(&format!(" {label_1} ")).style(style::default_reversed());
let label_2 = label::default(&format!(" {label_2} ")).style(style::default_reversed());
let label_3 = label::default(&format!(" {label_3} ")).style(style::default_reversed());
let label_4 = label::default(&format!(" {label_4} ")).style(style::default_reversed());
let label_0 = label(&format!(" {label_0} ")).style(style::magenta_reversed());
let label_1 = label(&format!(" {label_1} ")).style(style::default_reversed());
let label_2 = label(&format!(" {label_2} ")).style(style::default_reversed());
let label_3 = label(&format!(" {label_3} ")).style(style::default_reversed());
let label_4 = label(&format!(" {label_4} ")).style(style::default_reversed());
let label_0 = label_group(&[label_0]);
let label_1 = label_group(&[label_1]);
let label_2 = label_group(&[label_2]);
let label_3 = label_group(&[label_3]);
let label_4 = label_group(&[label_4]);
let label_0 = label::group(&[label_0]);
let label_1 = label::group(&[label_1]);
let label_2 = label::group(&[label_2]);
let label_3 = label::group(&[label_3]);
let label_4 = label::group(&[label_4]);
let context_bar = ContextBar::new(label_0, label_1, label_2, label_3, label_4);
+3 -3
View File
@@ -10,7 +10,7 @@ use crate::ui::theme::{style, Theme};
use crate::ui::widget::{Widget, WidgetComponent};
use super::container::Container;
use super::label::Label;
use super::label::{self, Label};
pub struct TextField {
input: Widget<Container>,
@@ -29,7 +29,7 @@ impl TextField {
Self {
input: container,
placeholder: crate::ui::label(title).style(style::gray_dim()),
placeholder: label::default(title).style(style::gray_dim()),
show_placeholder: true,
}
}
@@ -103,7 +103,7 @@ impl TextArea {
Self {
input: container,
placeholder: crate::ui::label(title).style(style::gray_dim()),
placeholder: label::default(title).style(style::gray_dim()),
show_placeholder: true,
}
}
+29
View File
@@ -8,6 +8,35 @@ use crate::ui::layout;
use crate::ui::theme::style;
use crate::ui::widget::{Widget, WidgetComponent};
pub fn default(content: &str) -> Widget<Label> {
// TODO: Remove when size constraints are implemented
let width = content.chars().count() as u16;
Widget::new(Label)
.content(AttrValue::String(content.to_string()))
.height(1)
.width(width)
}
pub fn group(labels: &[Widget<Label>]) -> Widget<LabelGroup> {
let group = LabelGroup::new(labels);
let width = labels.iter().fold(0, |total, label| {
total
+ label
.query(Attribute::Width)
.unwrap_or(AttrValue::Size(0))
.unwrap_size()
});
Widget::new(group).width(width)
}
pub fn reversable(content: &str) -> Widget<Label> {
let content = &format!(" {content} ");
default(content)
}
/// 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, Default)]
+2 -2
View File
@@ -10,7 +10,7 @@ use crate::ui::theme::{style, Theme};
use crate::ui::widget::{utils, Widget, WidgetComponent};
use super::container::Header;
use super::label::Label;
use super::label::{self, Label};
/// A generic item that can be displayed in a table with [`const W: usize`] columns.
pub trait TableItem<const W: usize> {
@@ -47,7 +47,7 @@ pub struct Property {
impl Property {
pub fn new(name: Widget<Label>, value: Widget<Label>) -> Self {
let divider = crate::ui::label("");
let divider = label::default("");
Self {
name,
divider,