themes: add inheritance, and use themes when initializing grids

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/469/head
Manos Pitsidianakis 2 months ago
parent 036586a2f7
commit 6be5fd2610
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

@ -358,10 +358,16 @@ pub struct ThemeAttributeInner {
impl Default for ThemeAttributeInner {
fn default() -> Self {
Self::inherited("theme_default")
}
}
impl ThemeAttributeInner {
pub fn inherited(key: &'static str) -> Self {
Self {
fg: "theme_default".into(),
bg: "theme_default".into(),
attrs: "theme_default".into(),
fg: key.into(),
bg: key.into(),
attrs: key.into(),
}
}
}
@ -399,8 +405,14 @@ enum ThemeValue<T: ThemeLink> {
}
impl From<&'static str> for ThemeValue<Color> {
fn from(from: &'static str) -> Self {
Self::Link(from.into(), ColorField::LikeSelf)
fn from(s: &'static str) -> Self {
if let Some(stripped) = s.strip_suffix(".fg") {
Self::Link(Cow::Borrowed(stripped), ColorField::Fg)
} else if let Some(stripped) = s.strip_suffix(".bg") {
Self::Link(Cow::Borrowed(stripped), ColorField::Bg)
} else {
Self::Link(s.into(), ColorField::LikeSelf)
}
}
}
@ -703,6 +715,8 @@ impl<'de> Deserialize<'de> for Themes {
#[derive(Default, Deserialize)]
#[serde(deny_unknown_fields)]
struct ThemeAttributeInnerOptions {
#[serde(default)]
from: Option<Cow<'static, str>>,
#[serde(default)]
fg: Option<ThemeValue<Color>>,
#[serde(default)]
@ -712,133 +726,59 @@ impl<'de> Deserialize<'de> for Themes {
}
let mut ret = Self::default();
let mut s = <ThemesOptions>::deserialize(deserializer)?;
for tk in s.other_themes.keys() {
ret.other_themes.insert(tk.clone(), ret.dark.clone());
}
for (k, v) in ret.light.iter_mut() {
if let Some(mut att) = s.light.keys.shift_remove(k) {
if let Some(att) = att.fg.take() {
v.fg = att;
}
if let Some(att) = att.bg.take() {
v.bg = att;
}
if let Some(att) = att.attrs.take() {
v.attrs = att;
}
}
}
if !s.light.keys.is_empty() {
return Err(de::Error::custom(format!(
"light theme contains unrecognized theme keywords: {}",
s.light
.keys
.keys()
.map(|k| k.as_ref())
.collect::<SmallVec<[_; 128]>>()
.join(", ")
)));
}
ret.light.color_aliases = s.light.color_aliases;
ret.light.attr_aliases = s.light.attr_aliases;
for (k, v) in s.light.text_format_regexps {
let mut acc = SmallVec::new();
for (rs, v) in v {
match RegexValue::new_with_options(&rs, v.o) {
Ok(regexp) => {
acc.push(TextFormatterSetting {
regexp,
fg: v.rest.fg,
bg: v.rest.bg,
attrs: v.rest.attrs,
priority: v.priority,
});
}
Err(err) => {
return Err(de::Error::custom(err.to_string()));
}
}
}
ret.light.text_format_regexps.insert(k, acc);
}
for (k, v) in ret.dark.iter_mut() {
if let Some(mut att) = s.dark.keys.shift_remove(k) {
if let Some(att) = att.fg.take() {
v.fg = att;
}
if let Some(att) = att.bg.take() {
v.bg = att;
}
if let Some(att) = att.attrs.take() {
v.attrs = att;
}
}
}
if !s.dark.keys.is_empty() {
return Err(de::Error::custom(format!(
"dark theme contains unrecognized theme keywords: {}",
s.dark
.keys
.keys()
.map(|k| k.as_ref())
.collect::<SmallVec<[_; 128]>>()
.join(", ")
)));
}
ret.dark.color_aliases = s.dark.color_aliases;
ret.dark.attr_aliases = s.dark.attr_aliases;
for (k, v) in s.dark.text_format_regexps {
let mut acc = SmallVec::new();
for (rs, v) in v {
match RegexValue::new_with_options(&rs, v.o) {
Ok(regexp) => {
acc.push(TextFormatterSetting {
regexp,
fg: v.rest.fg,
bg: v.rest.bg,
attrs: v.rest.attrs,
priority: v.priority,
});
}
Err(err) => {
return Err(de::Error::custom(err.to_string()));
}
}
}
ret.dark.text_format_regexps.insert(k, acc);
}
for (tk, t) in ret.other_themes.iter_mut() {
let mut theme = s.other_themes.shift_remove(tk).unwrap();
for (k, v) in t.iter_mut() {
if let Some(mut att) = theme.keys.shift_remove(k) {
if let Some(att) = att.fg.take() {
let ThemesOptions {
light,
dark,
other_themes,
} = <ThemesOptions>::deserialize(deserializer)?;
fn construct_theme<'de, D>(
name: Cow<'_, str>,
theme: &mut Theme,
mut s: ThemeOptions,
) -> std::result::Result<(), D::Error>
where
D: Deserializer<'de>,
{
for (k, v) in theme.iter_mut() {
if let Some(ThemeAttributeInnerOptions {
from,
fg,
bg,
attrs,
}) = s.keys.shift_remove(k)
{
if let Some(att) = fg {
v.fg = att;
} else if let Some(ref parent) = from {
v.fg = ThemeValue::Link(parent.clone(), ColorField::LikeSelf);
}
if let Some(att) = att.bg.take() {
if let Some(att) = bg {
v.bg = att;
} else if let Some(ref parent) = from {
v.bg = ThemeValue::Link(parent.clone(), ColorField::LikeSelf);
}
if let Some(att) = att.attrs.take() {
if let Some(att) = attrs {
v.attrs = att;
} else if let Some(parent) = from {
v.attrs = ThemeValue::Link(parent, ());
}
}
}
if !theme.keys.is_empty() {
if !s.keys.is_empty() {
return Err(de::Error::custom(format!(
"{} theme contains unrecognized theme keywords: {}",
tk,
theme
.keys
name,
s.keys
.keys()
.map(|k| k.as_ref())
.collect::<SmallVec<[_; 128]>>()
.join(", ")
)));
}
t.color_aliases = theme.color_aliases;
t.attr_aliases = theme.attr_aliases;
for (k, v) in theme.text_format_regexps {
theme.color_aliases = s.color_aliases;
theme.attr_aliases = s.attr_aliases;
for (k, v) in s.text_format_regexps {
let mut acc = SmallVec::new();
for (rs, v) in v {
match RegexValue::new_with_options(&rs, v.o) {
@ -856,8 +796,17 @@ impl<'de> Deserialize<'de> for Themes {
}
}
}
t.text_format_regexps.insert(k, acc);
theme.text_format_regexps.insert(k, acc);
}
Ok(())
}
construct_theme::<D>(Cow::Borrowed(self::DARK), &mut ret.dark, dark)?;
construct_theme::<D>(Cow::Borrowed(self::LIGHT), &mut ret.light, light)?;
for (name, theme_opts) in other_themes {
let mut theme = ret.dark.clone();
construct_theme::<D>(Cow::Borrowed(&name), &mut theme, theme_opts)?;
ret.other_themes.insert(name, theme);
}
Ok(ret)
}
@ -1153,6 +1102,12 @@ impl Default for Themes {
let other_themes = IndexMap::default();
macro_rules! add {
($key:literal from $parent_key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => {
add!($key);
$($theme.insert($key.into(), ThemeAttributeInner {
$($name: $val.into()),*
,..ThemeAttributeInner::inherited($parent_key) }));*
};
($key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => {
add!($key);
$($theme.insert($key.into(), ThemeAttributeInner {
@ -1179,7 +1134,7 @@ impl Default for Themes {
add!("text.highlight", dark = { fg: Color::Blue, bg: "theme_default", attrs: Attr::REVERSE }, light = { fg: Color::Blue, bg: "theme_default", attrs: Attr::REVERSE });
/* rest */
add!("highlight", dark = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD }, light = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD });
add!("highlight", dark = { fg: "theme_default.bg", bg: "theme_default.fg", attrs: Attr::BOLD }, light = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD });
add!("status.bar", dark = { fg: Color::Byte(123), bg: Color::Byte(26) }, light = { fg: Color::Byte(123), bg: Color::Byte(26) });
add!("status.command_bar", dark = { fg: Color::Byte(219), bg: Color::Byte(88) }, light = { fg: Color::Byte(219), bg: Color::Byte(88) });
@ -1221,11 +1176,11 @@ impl Default for Themes {
attrs: Attr::BOLD,
}
);
add!("mail.sidebar_unread_count", dark = { fg: Color::Byte(243) });
add!("mail.sidebar_index", dark = { fg: Color::Byte(243) });
add!("mail.sidebar_highlighted", dark = { fg: Color::Byte(233), bg: Color::Byte(15) });
add!("mail.sidebar_unread_count" from "mail.sidebar", dark = { fg: Color::Byte(243) });
add!("mail.sidebar_index" from "mail.sidebar", dark = { fg: Color::Byte(243) });
add!("mail.sidebar_highlighted" from "mail.sidebar", dark = { fg: Color::Byte(233), bg: Color::Byte(15) });
add!(
"mail.sidebar_highlighted_unread_count",
"mail.sidebar_highlighted_unread_count" from "mail.sidebar_highlighted",
light = {
fg: "mail.sidebar_highlighted",
bg: "mail.sidebar_highlighted"
@ -1236,7 +1191,7 @@ impl Default for Themes {
}
);
add!(
"mail.sidebar_highlighted_index",
"mail.sidebar_highlighted_index" from "mail.sidebar_highlighted",
light = {
fg: "mail.sidebar_index",
bg: "mail.sidebar_highlighted",
@ -1247,14 +1202,14 @@ impl Default for Themes {
},
);
add!(
"mail.sidebar_highlighted_account",
"mail.sidebar_highlighted_account" from "mail.sidebar_highlighted",
dark = {
fg: Color::Byte(15),
bg: Color::Byte(233),
}
);
add!(
"mail.sidebar_highlighted_account_name",
"mail.sidebar_highlighted_account_name" from "mail.sidebar_highlighted",
dark = {
fg: "mail.sidebar_highlighted_account",
bg: "mail.sidebar_highlighted_account",
@ -1267,7 +1222,7 @@ impl Default for Themes {
}
);
add!(
"mail.sidebar_highlighted_account_unread_count",
"mail.sidebar_highlighted_account_unread_count" from "mail.sidebar_highlighted",
light = {
fg: "mail.sidebar_unread_count",
bg: "mail.sidebar_highlighted_account",
@ -1278,7 +1233,7 @@ impl Default for Themes {
}
);
add!(
"mail.sidebar_highlighted_account_index",
"mail.sidebar_highlighted_account_index" from "mail.sidebar_highlighted",
light = {
fg: "mail.sidebar_index",
bg: "mail.sidebar_highlighted_account"

@ -65,7 +65,7 @@ impl ContactManager {
mode: ViewMode::Edit,
form: FormWidget::default(),
account_pos: 0,
content: Screen::<Virtual>::new(),
content: Screen::<Virtual>::new(theme_default),
theme_default,
dirty: true,
has_changes: false,

@ -88,6 +88,7 @@ impl ContactList {
index: i,
})
.collect();
let theme_default = crate::conf::value(context, "theme_default");
Self {
accounts,
cursor_pos: 0,
@ -96,8 +97,8 @@ impl ContactList {
account_pos: 0,
id_positions: Vec::new(),
mode: ViewMode::List,
data_columns: DataColumns::default(),
theme_default: crate::conf::value(context, "theme_default"),
data_columns: DataColumns::new(theme_default),
theme_default,
highlight_theme: crate::conf::value(context, "highlight"),
initialized: false,
dirty: true,
@ -251,7 +252,6 @@ impl ContactList {
} else {
self.theme_default
};
theme.fg = self.theme_default.fg;
if !grid.use_color {
theme.attrs |= Attr::REVERSE;
}

@ -90,7 +90,7 @@ impl JobManager {
..ThemeAttribute::default()
}
};
let mut data_columns = DataColumns::default();
let mut data_columns = DataColumns::new(theme_default);
data_columns.theme_config.set_single_theme(theme_default);
Self {
cursor_pos: 0,

@ -20,6 +20,7 @@
*/
use std::{
borrow::Cow,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
convert::TryFrom,
fs::File,
@ -2812,7 +2813,7 @@ impl Listing {
account: 0,
menu: MenuEntryCursor::Mailbox(0),
},
menu: Screen::<Virtual>::new(),
menu: Screen::<Virtual>::new(crate::conf::value(context, "mail.sidebar")),
menu_scrollbar_show_timer: context.main_loop_handler.job_executor.clone().create_timer(
std::time::Duration::from_secs(0),
std::time::Duration::from_millis(1200),
@ -3028,7 +3029,6 @@ impl Listing {
} else {
crate::conf::value(context, "mail.sidebar_account_name")
};
// Print account name first
self.menu.grid_mut().write_string(
&self.accounts[aidx].name,
@ -3053,7 +3053,6 @@ impl Listing {
);
return 0;
}
area = self.menu.area().skip_rows(account_y);
let lines_len = lines.len();
let mut idx = 0;
@ -3131,6 +3130,7 @@ impl Listing {
crate::conf::value(context, "mail.sidebar_unread_count"),
)
};
self.menu.grid_mut().change_theme(area.nth_row(y + 1), att);
// Calculate how many columns the mailbox index tags should occupy with right
// alignment, eg.
@ -3257,19 +3257,21 @@ impl Listing {
None,
)
.0
+ x;
+ x
+ 1;
area = self.menu.area().skip_rows(account_y);
// Unread message count
let count_string = match (l.count, l.collapsed_count) {
(None, None) => " ...".to_string(),
(Some(0), None) => String::new(),
(Some(0), Some(0)) | (None, Some(0)) => " v".to_string(),
(Some(0), Some(coll)) => format!(" ({}) v", coll),
(Some(c), Some(0)) => format!(" {} v", c),
(Some(c), Some(coll)) => format!(" {} ({}) v", c, coll),
(Some(c), None) => format!(" {}", c),
(None, Some(coll)) => format!(" ({}) v", coll),
let count_string: Cow<'static, str> = match (l.count, l.collapsed_count) {
(None, None) if context.settings.terminal.ascii_drawing => "...".into(),
(None, None) => "…".into(),
(Some(0), None) => "".into(),
(Some(0), Some(0)) | (None, Some(0)) => "v".into(),
(Some(0), Some(coll)) => format!("({}) v", coll).into(),
(Some(c), Some(0)) => format!("{} v", c).into(),
(Some(c), Some(coll)) => format!("{} ({}) v", c, coll).into(),
(Some(c), None) => format!("{}", c).into(),
(None, Some(coll)) => format!("({}) v", coll).into(),
};
let skip_cols = {
@ -3282,7 +3284,7 @@ impl Listing {
}
};
let (x, _) = self.menu.grid_mut().write_string(
&count_string,
count_string.as_ref(),
unread_count_att.fg,
unread_count_att.bg,
unread_count_att.attrs
@ -3462,7 +3464,7 @@ impl Listing {
let coordinates = self.component.coordinates();
std::mem::replace(
&mut self.component,
Plain(PlainListing::new(self.id, coordinates)),
Plain(PlainListing::new(self.id, coordinates, context)),
)
}
IndexStyle::Threaded => {
@ -3482,7 +3484,7 @@ impl Listing {
let coordinates = self.component.coordinates();
std::mem::replace(
&mut self.component,
Compact(CompactListing::new(self.id, coordinates)),
Compact(CompactListing::new(self.id, coordinates, context)),
)
}
IndexStyle::Conversations => {

@ -877,7 +877,12 @@ impl std::fmt::Display for CompactListing {
}
impl CompactListing {
pub fn new(parent: ComponentId, coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
pub fn new(
parent: ComponentId,
coordinates: (AccountHash, MailboxHash),
context: &Context,
) -> Box<Self> {
let color_cache = ColorCache::new(context, IndexStyle::Compact);
Box::new(Self {
cursor_pos: (AccountHash::default(), MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
@ -891,12 +896,12 @@ impl CompactListing {
filtered_selection: Vec::new(),
filtered_order: HashMap::default(),
focus: Focus::None,
data_columns: DataColumns::default(),
data_columns: DataColumns::new(color_cache.theme_default),
rows_drawn: SegmentTree::default(),
rows: RowsState::default(),
dirty: true,
force_draw: true,
color_cache: ColorCache::default(),
color_cache,
movement: None,
modifier_active: false,
modifier_command: None,

@ -623,7 +623,12 @@ impl std::fmt::Display for PlainListing {
}
impl PlainListing {
pub fn new(parent: ComponentId, coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
pub fn new(
parent: ComponentId,
coordinates: (AccountHash, MailboxHash),
context: &Context,
) -> Box<Self> {
let color_cache = ColorCache::new(context, IndexStyle::Plain);
Box::new(Self {
cursor_pos: (AccountHash::default(), MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
@ -637,11 +642,11 @@ impl PlainListing {
select_job: None,
filtered_selection: Vec::new(),
filtered_order: HashMap::default(),
data_columns: DataColumns::default(),
data_columns: DataColumns::new(color_cache.theme_default),
dirty: true,
force_draw: true,
focus: Focus::None,
color_cache: ColorCache::default(),
color_cache,
movement: None,
modifier_active: false,
modifier_command: None,

@ -757,14 +757,15 @@ impl ThreadListing {
coordinates: (AccountHash, MailboxHash),
context: &Context,
) -> Box<Self> {
let color_cache = ColorCache::new(context, IndexStyle::Threaded);
Box::new(Self {
cursor_pos: (coordinates.0, MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
subsort: (Default::default(), Default::default()),
color_cache: ColorCache::new(context, IndexStyle::Threaded),
data_columns: DataColumns::default(),
data_columns: DataColumns::new(color_cache.theme_default),
color_cache,
rows_drawn: SegmentTree::default(),
rows: RowsState::default(),
seen_cache: IndexMap::default(),

@ -44,15 +44,7 @@ impl std::fmt::Display for AccountStatus {
impl AccountStatus {
pub fn new(account_pos: usize, theme_default: ThemeAttribute) -> Self {
let default_cell = {
let mut ret = Cell::with_char(' ');
ret.set_fg(theme_default.fg)
.set_bg(theme_default.bg)
.set_attrs(theme_default.attrs);
ret
};
let mut content = Screen::<Virtual>::new();
content.grid_mut().default_cell = default_cell;
let mut content = Screen::<Virtual>::new(theme_default);
content.grid_mut().set_growable(true);
_ = content.resize(80, 20);

@ -751,7 +751,7 @@ impl Component for EnvelopeView {
if sticky || skip_header_ctr == 0 {
if y <= area.height() {
grid.clear_area(
area.skip_rows(y),
area.skip_rows(y).take_rows(1),
hdr_area_theme,
);
let (_x, _y) =
@ -993,19 +993,12 @@ impl Component for EnvelopeView {
}
}
}
for c in grid.row_iter(area, (x + 1)..area.width(), y) {
grid[c]
.set_ch(' ')
.set_fg(hdr_area_theme.fg)
.set_bg(hdr_area_theme.bg);
}
y += 1;
}
}
self.force_draw_headers = false;
grid.clear_area(area.nth_row(y), hdr_area_theme);
context.dirty_areas.push_back(area.take_rows(y + 3));
if !self.view_settings.sticky_headers {
let height_p = self.pager.size().1;

@ -86,6 +86,7 @@ impl ThreadView {
focus: Option<ThreadViewFocus>,
context: &mut Context,
) -> Self {
let theme_default = crate::conf::value(context, "theme_default");
let mut view = Self {
reversed: false,
coordinates,
@ -110,7 +111,7 @@ impl ThreadView {
new_expanded_pos: 0,
visible_entries: vec![],
movement: None,
content: Screen::<Virtual>::default(),
content: Screen::<Virtual>::new(theme_default),
};
view.initiate(expanded_hash, go_to_first_unread, context);
view.new_cursor_pos = view.new_expanded_pos;

@ -94,7 +94,7 @@ impl MailboxManager {
pub fn new(context: &Context, account_pos: usize) -> Self {
let account_hash = context.accounts[account_pos].hash();
let theme_default = crate::conf::value(context, "theme_default");
let mut data_columns = DataColumns::default();
let mut data_columns = DataColumns::new(theme_default);
data_columns.theme_config.set_single_theme(theme_default);
Self {
cursor_pos: 0,

@ -427,7 +427,8 @@ impl State {
let working = Arc::new(());
let control = Arc::downgrade(&working);
let mut screen = Box::new(Screen::<Tty>::new().with_cols_and_rows(cols, rows));
let mut screen =
Box::new(Screen::<Tty>::new(Default::default()).with_cols_and_rows(cols, rows));
screen
.tty_mut()
.set_mouse(settings.terminal.use_mouse.is_true())

@ -1155,6 +1155,17 @@ impl Default for Cell {
}
}
impl From<ThemeAttribute> for Cell {
fn from(ThemeAttribute { fg, bg, attrs, .. }: ThemeAttribute) -> Self {
Self {
fg,
bg,
attrs,
..Self::default()
}
}
}
bitflags::bitflags! {
/// The attributes of a `Cell`.
///
@ -1407,7 +1418,7 @@ impl Attr {
///
/// ```rust,no_run
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// for c in screen.grid().row_iter(area, 0..area.width(), 2) {
@ -1425,7 +1436,7 @@ pub struct RowIterator {
///
/// ```rust,no_run
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// for row in screen.grid().bounds_iter(area) {
@ -1991,7 +2002,7 @@ mod tests {
#[test]
fn test_bounds_iter() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);

@ -225,7 +225,7 @@ impl Default for EmbeddedGrid {
impl EmbeddedGrid {
#[inline]
pub fn new() -> Self {
let normal_screen = Box::new(Screen::<Virtual>::new());
let normal_screen = Box::new(Screen::<Virtual>::new(Default::default()));
Self {
cursor: (0, 0),
scroll_region: ScrollRegion {
@ -236,7 +236,7 @@ impl EmbeddedGrid {
},
terminal_size: (0, 0),
initialized: false,
alternate_screen: Box::new(Screen::<Virtual>::new()),
alternate_screen: Box::new(Screen::<Virtual>::new(Default::default())),
state: State::Normal,
fg_color: Color::Default,
bg_color: Color::Default,

@ -32,7 +32,7 @@ use crate::{
EnableMouse, EnableSGRMouse, Pos, RestoreWindowTitleIconFromStack,
SaveWindowTitleIconToStack,
},
Attr, Context,
Attr, Context, ThemeAttribute,
};
pub type StateStdout = termion::screen::AlternateScreen<
@ -168,7 +168,7 @@ impl<D: private::Sealed> std::fmt::Debug for Screen<D> {
impl<D: private::Sealed> Screen<D> {
#[inline]
pub fn init(display: D) -> Self {
pub fn init(display: D, theme_default: ThemeAttribute) -> Self {
let area = Area {
offset: (0, 0),
upper_left: (0, 0),
@ -178,14 +178,17 @@ impl<D: private::Sealed> Screen<D> {
canvas_rows: 0,
generation: ScreenGeneration::NIL,
};
Self {
let mut retval = Self {
cols: 0,
rows: 0,
grid: CellBuffer::nil(area),
overlay_grid: CellBuffer::nil(area),
display,
generation: ScreenGeneration::NIL,
}
};
retval.grid_mut().default_cell = theme_default.into();
retval.overlay_grid_mut().default_cell = theme_default.into();
retval
}
#[inline]
@ -269,12 +272,15 @@ impl Clone for Screen<Virtual> {
impl Screen<Tty> {
#[inline]
pub fn new() -> Self {
Self::init(Tty {
stdout: None,
mouse: false,
draw_horizontal_segment_fn: Self::draw_horizontal_segment,
})
pub fn new(theme_default: ThemeAttribute) -> Self {
Self::init(
Tty {
stdout: None,
mouse: false,
draw_horizontal_segment_fn: Self::draw_horizontal_segment,
},
theme_default,
)
}
#[inline]
@ -484,16 +490,10 @@ impl Screen<Tty> {
}
}
impl Default for Screen<Virtual> {
fn default() -> Self {
Self::new()
}
}
impl Screen<Virtual> {
#[inline]
pub fn new() -> Self {
Self::init(Virtual)
pub fn new(theme_default: ThemeAttribute) -> Self {
Self::init(Virtual, theme_default)
}
#[must_use]
@ -772,7 +772,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -803,7 +803,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -849,7 +849,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -872,7 +872,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -909,7 +909,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -942,7 +942,7 @@ impl Area {
///
/// ```rust
/// # use meli::terminal::{Screen, Virtual, Area};
/// # let mut screen = Screen::<Virtual>::new();
/// # let mut screen = Screen::<Virtual>::new(Default::default());
/// # assert!(screen.resize(120, 20));
/// # let area = screen.area();
/// assert_eq!(area.width(), 120);
@ -1081,7 +1081,7 @@ mod tests {
#[test]
fn test_skip_rows() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1103,7 +1103,7 @@ mod tests {
#[test]
fn test_skip_rows_from_end() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1120,7 +1120,7 @@ mod tests {
#[test]
fn test_skip_cols() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1142,7 +1142,7 @@ mod tests {
#[test]
fn test_skip_cols_from_end() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1159,7 +1159,7 @@ mod tests {
#[test]
fn test_take_rows() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1176,7 +1176,7 @@ mod tests {
#[test]
fn test_take_cols() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1193,7 +1193,7 @@ mod tests {
#[test]
fn test_nth_area() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1222,7 +1222,7 @@ mod tests {
#[test]
fn test_place_inside_area() {
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);
@ -1251,7 +1251,7 @@ mod tests {
const ALIGNMENTS: [Alignment; 4] = [Fill, Start, End, Center];
let mut screen = Screen::<Virtual>::new();
let mut screen = Screen::<Virtual>::new(Default::default());
assert!(screen.resize(120, 20));
let area = screen.area();
assert_eq!(area.width(), 120);

@ -864,9 +864,10 @@ pub struct Tabbed {
impl Tabbed {
pub fn new(children: Vec<Box<dyn Component>>, context: &Context) -> Self {
let pinned = children.len();
let theme_default = crate::conf::value(context, "theme_default");
let mut ret = Self {
help_view: HelpView {
content: Screen::<Virtual>::new(),
content: Screen::<Virtual>::new(theme_default),
curr_views: children
.first()
.map(|c| c.shortcuts(context))
@ -874,7 +875,7 @@ impl Tabbed {
cursor: (0, 0),
search: None,
},
theme_default: crate::conf::value(context, "theme_default"),
theme_default,
pinned,
children,
cursor_pos: 0,

@ -521,6 +521,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
identifiers[0].1 = true;
}
let theme_default = crate::conf::value(context, "theme_default");
let mut ret = Self {
single_only,
entries: identifiers,
@ -531,12 +532,12 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
vertical_alignment: Alignment::Center,
horizontal_alignment: Alignment::Center,
title: title.to_string(),
content: Screen::<Virtual>::new(),
content: Screen::<Virtual>::new(theme_default),
initialized: false,
done: false,
done_fn,
dirty: true,
theme_default: Default::default(),
theme_default,
id: ComponentId::default(),
};
ret.initialise(context);

@ -65,13 +65,19 @@ impl TableRowFormat {
}
*/
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct TableThemeConfig {
pub theme: TableTheme,
//pub row_formats: HashMap<usize, SmallVec<[(u8, TableRowFormat); 6]>>,
}
impl TableThemeConfig {
pub fn new(theme_default: ThemeAttribute) -> Self {
Self {
theme: TableTheme::Single(theme_default),
}
}
pub fn set_single_theme(&mut self, value: ThemeAttribute) -> &mut Self {
self.theme = TableTheme::Single(value);
self
@ -92,19 +98,20 @@ pub enum TableTheme {
},
}
impl Default for TableTheme {
fn default() -> Self {
Self::Single(ThemeAttribute::default())
}
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct TableCursorConfig {
pub handle: bool,
pub theme: TableTheme,
}
impl TableCursorConfig {
pub fn new(theme_default: ThemeAttribute) -> Self {
Self {
handle: false,
theme: TableTheme::Single(theme_default),
}
}
pub fn set_handle(&mut self, value: bool) -> &mut Self {
self.handle = value;
self
@ -136,8 +143,8 @@ pub struct DataColumns<const N: usize> {
// Workaround because Default derive doesn't work for const generic array
// lengths yet.
impl<const N: usize> Default for DataColumns<N> {
fn default() -> Self {
impl<const N: usize> DataColumns<N> {
pub fn new(theme_default: ThemeAttribute) -> Self {
fn init_array<T, const N: usize>(cl: impl Fn() -> T) -> [T; N] {
// https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element
let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
@ -149,9 +156,9 @@ impl<const N: usize> Default for DataColumns<N> {
}
Self {
cursor_config: TableCursorConfig::default(),
theme_config: TableThemeConfig::default(),
columns: Box::new(init_array(|| Screen::init(Virtual))),
cursor_config: TableCursorConfig::new(theme_default),
theme_config: TableThemeConfig::new(theme_default),
columns: Box::new(init_array(|| Screen::init(Virtual, theme_default))),
widths: [0_usize; N],
elasticities: [ColumnElasticity::default(); N],
x_offset: 0,

Loading…
Cancel
Save