Skip to content

Commit

Permalink
feat(theme): add theme support for multiple select widget
Browse files Browse the repository at this point in the history
- Added `multiple_select` module to `widget.rs` for theme support.
- Implemented `FilterFormTheme` and `SelectFormTheme` for `multiple_select`.
- Updated `MultipleNamespacesDialog` to accept `ThemeConfig`.
- Enhanced `MultipleSelect` to use `MultipleSelectTheme`.
- Refactored `FilterForm` and `SelectForm` to use builders with themes.
  • Loading branch information
sarub0b0 committed Nov 2, 2024
1 parent 5ef11fa commit 7733e4a
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 46 deletions.
22 changes: 21 additions & 1 deletion src/config/theme/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use ratatui::style::{Color, Modifier};
use serde::{Deserialize, Serialize};

use crate::ui::widget::{
single_select, table, InputFormTheme, ListTheme, SearchFormTheme, TextTheme, WidgetTheme,
multiple_select, single_select, table, InputFormTheme, ListTheme, SearchFormTheme, TextTheme,
WidgetTheme,
};

use super::{
Expand Down Expand Up @@ -135,6 +136,16 @@ impl From<WidgetThemeConfig> for table::FilterFormTheme {
}
}

impl From<WidgetThemeConfig> for multiple_select::FilterFormTheme {
fn from(theme: WidgetThemeConfig) -> Self {
let (widget_theme, input_form_theme) = (theme).into();

Self::default()
.widget_theme(widget_theme)
.input_form_theme(input_form_theme)
}
}

impl From<WidgetThemeConfig> for single_select::FilterFormTheme {
fn from(theme: WidgetThemeConfig) -> Self {
let (widget_theme, input_form_theme) = (theme).into();
Expand All @@ -153,6 +164,15 @@ impl From<WidgetThemeConfig> for ListTheme {
}
}

impl From<WidgetThemeConfig> for multiple_select::SelectFormTheme {
fn from(theme: WidgetThemeConfig) -> Self {
Self {
list_theme: theme.clone().into(),
widget_theme: theme.into(),
}
}
}

impl From<WidgetThemeConfig> for single_select::SelectFormTheme {
fn from(theme: WidgetThemeConfig) -> Self {
Self {
Expand Down
32 changes: 27 additions & 5 deletions src/features/namespace/view/multiple_namespaces_dialog.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crossbeam::channel::Sender;

use crate::{
config::theme::ThemeConfig,
features::{
component_id::{
CONFIG_RAW_DATA_WIDGET_ID, CONFIG_WIDGET_ID, EVENT_WIDGET_ID, LIST_WIDGET_ID,
Expand All @@ -12,7 +13,12 @@ use crate::{
message::Message,
ui::{
event::EventResult,
widget::{multiple_select::SelectForm, LiteralItem, MultipleSelect, Widget, WidgetBase},
widget::{
multiple_select::{
FilterForm, FilterFormTheme, MultipleSelectTheme, SelectForm, SelectFormTheme,
},
LiteralItem, MultipleSelect, Widget, WidgetBase, WidgetTheme,
},
Window,
},
};
Expand All @@ -22,23 +28,39 @@ pub struct MultipleNamespacesDialog {
}

impl MultipleNamespacesDialog {
pub fn new(tx: &Sender<Message>) -> Self {
pub fn new(tx: &Sender<Message>, theme: ThemeConfig) -> Self {
Self {
widget: widget(tx.clone()),
widget: widget(tx.clone(), theme),
}
}
}

fn widget(tx: Sender<Message>) -> Widget<'static> {
fn widget(tx: Sender<Message>, theme: ThemeConfig) -> Widget<'static> {
let widget_theme = WidgetTheme::from(theme.component.clone());
let filter_theme = FilterFormTheme::from(theme.component.clone());
let select_theme = SelectFormTheme::from(theme.component.clone());
let multiple_select_theme =
MultipleSelectTheme::default().status_style(theme.component.list.status);

let filter_form = FilterForm::builder().theme(filter_theme).build();

let select_form = SelectForm::builder()
.theme(select_theme)
.on_select_selected(on_select(tx.clone()))
.on_select_unselected(on_select(tx))
.build();

let widget_base = WidgetBase::builder()
.title("Namespace")
.theme(widget_theme)
.build();

MultipleSelect::builder()
.id(MULTIPLE_NAMESPACES_DIALOG_ID)
.widget_base(WidgetBase::builder().title("Namespace").build())
.widget_base(widget_base)
.filter_form(filter_form)
.select_form(select_form)
.theme(multiple_select_theme)
.build()
.into()
}
Expand Down
2 changes: 1 addition & 1 deletion src/ui/widget/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ mod inner_item {
define_callback!(pub OnSelectCallback, Fn(&mut Window, &LiteralItem) -> EventResult);
define_callback!(pub RenderBlockInjection, Fn(&List, bool) -> Block<'static>);

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ListTheme {
pub selected: Style,
}
Expand Down
32 changes: 27 additions & 5 deletions src/ui/widget/multiple_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::rc::Rc;
use ratatui::{
crossterm::event::{KeyCode, KeyEvent, MouseEvent},
layout::{Constraint, Direction, Layout, Rect},
style::Style,
widgets::{Block, Paragraph},
Frame,
};
Expand All @@ -20,18 +21,31 @@ use crate::{
},
};

pub use filter::FilterForm;
pub use filter::{FilterForm, FilterFormTheme};
use item::SelectItems;
pub use select::SelectForm;
pub use select::{SelectForm, SelectFormTheme};

define_callback!(pub RenderBlockInjection, Fn(&MultipleSelect, bool) -> Block<'static>);

#[derive(Debug, Default)]
pub struct MultipleSelectTheme {
status_style: Style,
}

impl MultipleSelectTheme {
pub fn status_style(mut self, status_style: impl Into<Style>) -> Self {
self.status_style = status_style.into();
self
}
}

#[derive(Debug, Default)]
pub struct MultipleSelectBuilder {
id: String,
widget_base: WidgetBase,
select_form: SelectForm<'static>,
filter_form: FilterForm,
theme: MultipleSelectTheme,
block_injection: Option<RenderBlockInjection>,
}

Expand All @@ -57,6 +71,11 @@ impl MultipleSelectBuilder {
self
}

pub fn theme(mut self, theme: impl Into<MultipleSelectTheme>) -> Self {
self.theme = theme.into();
self
}

pub fn block_injection<F>(mut self, block_injection: F) -> Self
where
F: Into<RenderBlockInjection>,
Expand All @@ -77,10 +96,11 @@ impl MultipleSelectBuilder {
MultipleSelect {
id: self.id,
widget_base: self.widget_base,
layout,
filter_form: self.filter_form,
select_form: self.select_form,
theme: self.theme,
layout,
block_injection: self.block_injection,
filter_form: FilterForm::default(),
inner_chunks: Rc::new([]),
..Default::default()
}
Expand All @@ -97,6 +117,7 @@ pub struct MultipleSelect<'a> {
widget_base: WidgetBase,
filter_form: FilterForm,
select_form: SelectForm<'a>,
theme: MultipleSelectTheme,
layout: Layout,
chunk: Rect,
inner_chunks: Rc<[Rect]>,
Expand All @@ -110,6 +131,7 @@ impl Default for MultipleSelect<'_> {
widget_base: Default::default(),
filter_form: Default::default(),
select_form: Default::default(),
theme: Default::default(),
layout: Default::default(),
chunk: Default::default(),
inner_chunks: Rc::new([Rect::default()]),
Expand All @@ -135,7 +157,7 @@ impl RenderTrait for MultipleSelect<'_> {

let status = self.select_form.status();
f.render_widget(
Paragraph::new(format!("[{}/{}]", status.0, status.1)),
Paragraph::new(format!("[{}/{}]", status.0, status.1)).style(self.theme.status_style),
self.layout.split(inner_chunk)[LAYOUT_INDEX_FOR_STATUS],
);
self.select_form.render(f);
Expand Down
58 changes: 52 additions & 6 deletions src/ui/widget/multiple_select/filter.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,67 @@
use std::ops::{Deref, DerefMut};

use crate::ui::widget::InputForm;
use crate::ui::widget::{InputForm, InputFormTheme, WidgetTheme};

use super::WidgetBase;

#[derive(Debug, Default)]
pub struct FilterFormTheme {
widget_theme: WidgetTheme,
input_form_theme: InputFormTheme,
}

impl FilterFormTheme {
pub fn widget_theme(mut self, theme: impl Into<WidgetTheme>) -> Self {
self.widget_theme = theme.into();
self
}

pub fn input_form_theme(mut self, theme: impl Into<InputFormTheme>) -> Self {
self.input_form_theme = theme.into();
self
}
}

#[derive(Debug, Default)]
pub struct FilterFormBuilder {
theme: FilterFormTheme,
}

impl FilterFormBuilder {
pub fn theme(mut self, theme: impl Into<FilterFormTheme>) -> Self {
self.theme = theme.into();
self
}

pub fn build(self) -> FilterForm {
let widget_base = WidgetBase::builder()
.theme(self.theme.widget_theme)
.title("Filter")
.build();

let input_form = InputForm::builder()
.widget_base(widget_base)
.theme(self.theme.input_form_theme)
.build();

FilterForm { input_form }
}
}

#[derive(Debug)]
pub struct FilterForm {
input_form: InputForm,
}

impl Default for FilterForm {
fn default() -> Self {
Self {
input_form: InputForm::builder()
.widget_base(WidgetBase::builder().title("Filter").build())
.build(),
}
FilterFormBuilder::default().build()
}
}

impl FilterForm {
pub fn builder() -> FilterFormBuilder {
FilterFormBuilder::default()
}
}

Expand Down
54 changes: 27 additions & 27 deletions src/ui/widget/multiple_select/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use crate::ui::{
widget::{
list::{OnSelectCallback, RenderBlockInjection},
styled_graphemes::StyledGraphemes,
Item, List, LiteralItem, RenderTrait as _, WidgetBase, WidgetTrait as _,
Item, List, ListTheme, LiteralItem, RenderTrait as _, WidgetBase, WidgetTheme,
WidgetTrait as _,
},
};

Expand All @@ -26,33 +27,27 @@ use super::SelectItems;
const LIST_FORM_ID: usize = 0;
const SELECTED_FORM_ID: usize = 1;

#[derive(Debug, Default)]
pub struct SelectFormTheme {
pub list_theme: ListTheme,
pub widget_theme: WidgetTheme,
}

#[derive(Debug, Default)]
pub struct SelectFormBuilder {
widget_base_selected: WidgetBase,
theme: SelectFormTheme,

on_select_selected: Option<OnSelectCallback>,
block_injection_selected: Option<RenderBlockInjection>,

widget_base_unselected: WidgetBase,
on_select_unselected: Option<OnSelectCallback>,
block_injection_unselected: Option<RenderBlockInjection>,
}

impl Default for SelectFormBuilder {
fn default() -> Self {
Self {
widget_base_selected: WidgetBase::builder().title("Selected").build(),
on_select_selected: None,
block_injection_selected: None,
widget_base_unselected: WidgetBase::builder().title("Items").build(),
on_select_unselected: None,
block_injection_unselected: None,
}
}
}

#[allow(dead_code)]
impl SelectFormBuilder {
pub fn widget_base_selected(mut self, widget_base: WidgetBase) -> Self {
self.widget_base_selected = widget_base;
pub fn theme(mut self, theme: SelectFormTheme) -> Self {
self.theme = theme;
self
}

Expand All @@ -69,11 +64,6 @@ impl SelectFormBuilder {
self
}

pub fn widget_base_unselected(mut self, widget_base: WidgetBase) -> Self {
self.widget_base_unselected = widget_base;
self
}

pub fn on_select_unselected(mut self, on_select: impl Into<OnSelectCallback>) -> Self {
self.on_select_unselected = Some(on_select.into());
self
Expand All @@ -89,9 +79,14 @@ impl SelectFormBuilder {

pub fn build(self) -> SelectForm<'static> {
let selected_widget = {
let mut builder = List::builder();
let mut builder = List::builder().theme(self.theme.list_theme.clone());

let widget_base = WidgetBase::builder()
.theme(self.theme.widget_theme.clone())
.title("Selected")
.build();

builder = builder.widget_base(self.widget_base_selected);
builder = builder.widget_base(widget_base);

if let Some(on_select) = self.on_select_unselected {
builder = builder.on_select(on_select);
Expand All @@ -105,9 +100,14 @@ impl SelectFormBuilder {
};

let unselected_widget = {
let mut builder = List::builder();
let mut builder = List::builder().theme(self.theme.list_theme);

let widget_base = WidgetBase::builder()
.theme(self.theme.widget_theme)
.title("Items")
.build();

builder = builder.widget_base(self.widget_base_unselected);
builder = builder.widget_base(widget_base);

if let Some(on_select) = self.on_select_selected {
builder = builder.on_select(on_select);
Expand Down
2 changes: 1 addition & 1 deletion src/workers/render/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ impl WindowInit {

let MultipleNamespacesDialog {
widget: multiple_namespaces_dialog,
} = MultipleNamespacesDialog::new(&self.tx);
} = MultipleNamespacesDialog::new(&self.tx, self.theme.clone());

let HelpDialog {
widget: help_dialog,
Expand Down

0 comments on commit 7733e4a

Please sign in to comment.