mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-10-27 23:30:38 +08:00
bin: Use improved widget base interface
This commit is contained in:
@@ -22,7 +22,7 @@ use tui::ui::widget::input::{TextField, TextFieldProps};
|
||||
use tui::ui::widget::list::{Table, TableProps, TableUtils};
|
||||
use tui::ui::widget::text::{Paragraph, ParagraphProps};
|
||||
use tui::ui::widget::window::{Shortcuts, ShortcutsProps};
|
||||
use tui::ui::widget::{BaseView, BoxedAny, Properties, RenderProps, Widget};
|
||||
use tui::ui::widget::{BoxedAny, Properties, RenderProps, Widget, WidgetBase};
|
||||
|
||||
use tui::Selection;
|
||||
|
||||
@@ -113,7 +113,7 @@ impl<'a> BoxedAny for BrowserProps<'a> {}
|
||||
|
||||
pub struct Browser<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserProps<'a>,
|
||||
/// Notification widget
|
||||
@@ -130,11 +130,7 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
let props = BrowserProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: props.clone(),
|
||||
notifications: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -155,8 +151,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
table
|
||||
.downcast_mut::<Table<State, Action, NotificationItem, 9>>()
|
||||
.and_then(|table| {
|
||||
let selected = table.selected();
|
||||
table.base_mut().send(Action::Select { selected }).ok()
|
||||
table
|
||||
.send(Action::Select {
|
||||
selected: table.selected(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
@@ -196,7 +195,7 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
} else {
|
||||
match key {
|
||||
Key::Char('/') => {
|
||||
let _ = self.base.send(Action::OpenSearch);
|
||||
let _ = self.send(Action::OpenSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
self.props
|
||||
@@ -260,7 +259,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -302,7 +305,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}
|
||||
|
||||
pub struct BrowserPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserPageProps<'a>,
|
||||
/// Sections widget
|
||||
@@ -319,11 +322,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
let props = BrowserPageProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: props.clone(),
|
||||
sections: SectionGroup::new(state, action_tx.clone())
|
||||
.section(Browser::new(state, action_tx.clone()).to_boxed())
|
||||
@@ -350,10 +349,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
if self.props.handle_keys {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::OpenHelp);
|
||||
let _ = self.send(Action::OpenHelp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -384,11 +383,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::BrowserPageSize(page_size));
|
||||
let _ = self.send(Action::BrowserPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -399,7 +402,7 @@ impl Properties for SearchProps {}
|
||||
|
||||
pub struct Search {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
_props: SearchProps,
|
||||
/// Search input field
|
||||
@@ -414,44 +417,39 @@ impl Widget for Search {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let input = TextField::new(state, action_tx.clone())
|
||||
.on_event(|field| {
|
||||
field
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
let text = field.text().unwrap_or(&String::new()).to_string();
|
||||
field
|
||||
.base_mut()
|
||||
.send(Action::UpdateSearch { value: text })
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed();
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
_props: SearchProps {},
|
||||
input,
|
||||
input: TextField::new(state, action_tx.clone())
|
||||
.on_event(|widget| {
|
||||
widget
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
field
|
||||
.send(Action::UpdateSearch {
|
||||
value: field.text().unwrap_or(&String::new()).to_string(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc => {
|
||||
let _ = self.base.send(Action::CloseSearch);
|
||||
let _ = self.send(Action::CloseSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
let _ = self.base.send(Action::ApplySearch);
|
||||
let _ = self.send(Action::ApplySearch);
|
||||
}
|
||||
_ => {
|
||||
self.input.handle_event(key);
|
||||
@@ -471,7 +469,11 @@ impl Widget for Search {
|
||||
self.input.render(frame, RenderProps::from(layout[0]));
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -501,7 +503,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}
|
||||
|
||||
pub struct HelpPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: HelpPageProps<'a>,
|
||||
/// Content widget
|
||||
@@ -519,11 +521,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
Self: Sized,
|
||||
{
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: HelpPageProps::from(state),
|
||||
content: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -541,10 +539,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
paragraph
|
||||
.downcast_mut::<Paragraph<'_, State, Action>>()
|
||||
.and_then(|paragraph| {
|
||||
let progress = paragraph.progress();
|
||||
paragraph
|
||||
.base_mut()
|
||||
.send(Action::ScrollHelp { progress })
|
||||
.send(Action::ScrollHelp {
|
||||
progress: paragraph.progress(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
@@ -593,10 +591,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::LeavePage);
|
||||
let _ = self.send(Action::LeavePage);
|
||||
}
|
||||
_ => {
|
||||
self.content.handle_event(key);
|
||||
@@ -624,11 +622,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::HelpPageSize(page_size));
|
||||
let _ = self.send(Action::HelpPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use tui::ui::widget::input::{TextField, TextFieldProps};
|
||||
use tui::ui::widget::list::{Table, TableProps, TableUtils};
|
||||
use tui::ui::widget::text::{Paragraph, ParagraphProps};
|
||||
use tui::ui::widget::window::{Shortcuts, ShortcutsProps};
|
||||
use tui::ui::widget::{BaseView, BoxedAny, Properties, RenderProps, Widget};
|
||||
use tui::ui::widget::{BoxedAny, Properties, RenderProps, Widget, WidgetBase};
|
||||
|
||||
use tui::Selection;
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<'a> BoxedAny for BrowserProps<'a> {}
|
||||
|
||||
pub struct Browser<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserProps<'a>,
|
||||
/// Notifications widget
|
||||
@@ -150,11 +150,7 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
let props = BrowserProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: BrowserProps::from(state),
|
||||
issues: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -169,8 +165,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
table
|
||||
.downcast_mut::<Table<State, Action, IssueItem, 8>>()
|
||||
.and_then(|table| {
|
||||
let selected = table.selected();
|
||||
table.base_mut().send(Action::Select { selected }).ok()
|
||||
table
|
||||
.send(Action::Select {
|
||||
selected: table.selected(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
@@ -212,7 +211,7 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
} else {
|
||||
match key {
|
||||
Key::Char('/') => {
|
||||
let _ = self.base.send(Action::OpenSearch);
|
||||
let _ = self.send(Action::OpenSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
let operation = match self.props.mode {
|
||||
@@ -279,7 +278,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -321,7 +324,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}
|
||||
|
||||
pub struct BrowserPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserPageProps<'a>,
|
||||
/// Sections widget
|
||||
@@ -338,11 +341,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
let props = BrowserPageProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: props.clone(),
|
||||
sections: SectionGroup::new(state, action_tx.clone())
|
||||
.section(Browser::new(state, action_tx.clone()).to_boxed())
|
||||
@@ -369,10 +368,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
if self.props.handle_keys {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::OpenHelp);
|
||||
let _ = self.send(Action::OpenHelp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -403,11 +402,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::BrowserPageSize(page_size));
|
||||
let _ = self.send(Action::BrowserPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -418,7 +421,7 @@ impl Properties for SearchProps {}
|
||||
|
||||
pub struct Search {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
_props: SearchProps,
|
||||
/// Search input field
|
||||
@@ -433,44 +436,39 @@ impl Widget for Search {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let input = TextField::new(state, action_tx.clone())
|
||||
.on_event(|field| {
|
||||
field
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
let text = field.text().unwrap_or(&String::new()).to_string();
|
||||
field
|
||||
.base_mut()
|
||||
.send(Action::UpdateSearch { value: text })
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed();
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
_props: SearchProps {},
|
||||
input,
|
||||
input: TextField::new(state, action_tx.clone())
|
||||
.on_event(|widget| {
|
||||
widget
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
field
|
||||
.send(Action::UpdateSearch {
|
||||
value: field.text().unwrap_or(&String::new()).to_string(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc => {
|
||||
let _ = self.base.send(Action::CloseSearch);
|
||||
let _ = self.send(Action::CloseSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
let _ = self.base.send(Action::ApplySearch);
|
||||
let _ = self.send(Action::ApplySearch);
|
||||
}
|
||||
_ => {
|
||||
self.input.handle_event(key);
|
||||
@@ -490,7 +488,11 @@ impl Widget for Search {
|
||||
self.input.render(frame, RenderProps::from(layout[0]));
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -517,7 +519,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}
|
||||
|
||||
pub struct HelpPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: HelpPageProps<'a>,
|
||||
/// Content widget
|
||||
@@ -535,11 +537,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
Self: Sized,
|
||||
{
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: HelpPageProps::from(state),
|
||||
content: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -553,6 +551,17 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
)
|
||||
.content(
|
||||
Paragraph::new(state, action_tx.clone())
|
||||
.on_event(|paragraph| {
|
||||
paragraph
|
||||
.downcast_mut::<Paragraph<'_, State, Action>>()
|
||||
.and_then(|paragraph| {
|
||||
paragraph
|
||||
.send(Action::ScrollHelp {
|
||||
progress: paragraph.progress(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
let props = HelpPageProps::from(state);
|
||||
|
||||
@@ -561,17 +570,6 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
.page_size(props.page_size)
|
||||
.to_boxed()
|
||||
})
|
||||
.on_event(|paragraph| {
|
||||
paragraph
|
||||
.downcast_mut::<Paragraph<'_, State, Action>>()
|
||||
.and_then(|paragraph| {
|
||||
let progress = paragraph.progress();
|
||||
paragraph
|
||||
.base_mut()
|
||||
.send(Action::ScrollHelp { progress })
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.to_boxed(),
|
||||
)
|
||||
.footer(
|
||||
@@ -609,10 +607,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::LeavePage);
|
||||
let _ = self.send(Action::LeavePage);
|
||||
}
|
||||
_ => {
|
||||
self.content.handle_event(key);
|
||||
@@ -640,11 +638,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::HelpPageSize(page_size));
|
||||
let _ = self.send(Action::HelpPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use tui::ui::widget::input::{TextField, TextFieldProps};
|
||||
use tui::ui::widget::list::{Table, TableProps, TableUtils};
|
||||
use tui::ui::widget::text::{Paragraph, ParagraphProps};
|
||||
use tui::ui::widget::window::{Shortcuts, ShortcutsProps};
|
||||
use tui::ui::widget::{BaseView, BoxedAny, Properties, RenderProps, Widget};
|
||||
use tui::ui::widget::{BoxedAny, Properties, RenderProps, Widget, WidgetBase};
|
||||
|
||||
use tui::Selection;
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<'a: 'static> BoxedAny for BrowserProps<'a> {}
|
||||
|
||||
pub struct Browser<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserProps<'a>,
|
||||
/// Patches widget
|
||||
@@ -150,11 +150,7 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
let props = BrowserProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: props.clone(),
|
||||
patches: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -169,8 +165,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
table
|
||||
.downcast_mut::<Table<State, Action, PatchItem, 9>>()
|
||||
.and_then(|table| {
|
||||
let selected = table.selected();
|
||||
table.base_mut().send(Action::Select { selected }).ok()
|
||||
table
|
||||
.send(Action::Select {
|
||||
selected: table.selected(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
@@ -212,13 +211,13 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
} else {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::OpenHelp);
|
||||
let _ = self.send(Action::OpenHelp);
|
||||
}
|
||||
Key::Char('/') => {
|
||||
let _ = self.base.send(Action::OpenSearch);
|
||||
let _ = self.send(Action::OpenSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
let operation = match self.props.mode {
|
||||
@@ -301,7 +300,11 @@ impl<'a: 'static> Widget for Browser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -344,7 +347,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}
|
||||
|
||||
pub struct BrowserPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: BrowserPageProps<'a>,
|
||||
/// Sections widget
|
||||
@@ -361,11 +364,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
let props = BrowserPageProps::from(state);
|
||||
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: props.clone(),
|
||||
sections: SectionGroup::new(state, action_tx.clone())
|
||||
.section(Browser::new(state, action_tx.clone()).to_boxed())
|
||||
@@ -392,10 +391,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
if self.props.handle_keys {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::OpenHelp);
|
||||
let _ = self.send(Action::OpenHelp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -426,11 +425,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::BrowserPageSize(page_size));
|
||||
let _ = self.send(Action::BrowserPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -441,7 +444,7 @@ impl Properties for SearchProps {}
|
||||
|
||||
pub struct Search {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
_props: SearchProps,
|
||||
/// Search input field
|
||||
@@ -456,44 +459,39 @@ impl Widget for Search {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let input = TextField::new(state, action_tx.clone())
|
||||
.on_event(|field| {
|
||||
field
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
let text = field.text().unwrap_or(&String::new()).to_string();
|
||||
field
|
||||
.base_mut()
|
||||
.send(Action::UpdateSearch { value: text })
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed();
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
_props: SearchProps {},
|
||||
input,
|
||||
input: TextField::new(state, action_tx.clone())
|
||||
.on_event(|widget| {
|
||||
widget
|
||||
.downcast_mut::<TextField<State, Action>>()
|
||||
.and_then(|field| {
|
||||
field
|
||||
.send(Action::UpdateSearch {
|
||||
value: field.text().unwrap_or(&String::new()).to_string(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
.on_update(|state| {
|
||||
TextFieldProps::default()
|
||||
.text(&state.browser.search.read().to_string())
|
||||
.title("Search")
|
||||
.inline(true)
|
||||
.to_boxed()
|
||||
})
|
||||
.to_boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc => {
|
||||
let _ = self.base.send(Action::CloseSearch);
|
||||
let _ = self.send(Action::CloseSearch);
|
||||
}
|
||||
Key::Char('\n') => {
|
||||
let _ = self.base.send(Action::ApplySearch);
|
||||
let _ = self.send(Action::ApplySearch);
|
||||
}
|
||||
_ => {
|
||||
self.input.handle_event(key);
|
||||
@@ -513,7 +511,11 @@ impl Widget for Search {
|
||||
self.input.render(frame, RenderProps::from(layout[0]));
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
@@ -540,7 +542,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}
|
||||
|
||||
pub struct HelpPage<'a> {
|
||||
/// Internal base
|
||||
base: BaseView<State, Action>,
|
||||
base: WidgetBase<State, Action>,
|
||||
/// Internal props
|
||||
props: HelpPageProps<'a>,
|
||||
/// Content widget
|
||||
@@ -558,11 +560,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
Self: Sized,
|
||||
{
|
||||
Self {
|
||||
base: BaseView {
|
||||
action_tx: action_tx.clone(),
|
||||
on_update: None,
|
||||
on_event: None,
|
||||
},
|
||||
base: WidgetBase::new(action_tx.clone()),
|
||||
props: HelpPageProps::from(state),
|
||||
content: Container::new(state, action_tx.clone())
|
||||
.header(
|
||||
@@ -580,10 +578,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
paragraph
|
||||
.downcast_mut::<Paragraph<'_, State, Action>>()
|
||||
.and_then(|paragraph| {
|
||||
let progress = paragraph.progress();
|
||||
paragraph
|
||||
.base_mut()
|
||||
.send(Action::ScrollHelp { progress })
|
||||
.send(Action::ScrollHelp {
|
||||
progress: paragraph.progress(),
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
})
|
||||
@@ -632,10 +630,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
fn handle_event(&mut self, key: termion::event::Key) {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => {
|
||||
let _ = self.base.send(Action::Exit { selection: None });
|
||||
let _ = self.send(Action::Exit { selection: None });
|
||||
}
|
||||
Key::Char('?') => {
|
||||
let _ = self.base.send(Action::LeavePage);
|
||||
let _ = self.send(Action::LeavePage);
|
||||
}
|
||||
_ => {
|
||||
self.content.handle_event(key);
|
||||
@@ -662,11 +660,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
|
||||
.render(frame, RenderProps::from(shortcuts_area));
|
||||
|
||||
if page_size != self.props.page_size {
|
||||
let _ = self.base.send(Action::HelpPageSize(page_size));
|
||||
let _ = self.send(Action::HelpPageSize(page_size));
|
||||
}
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut BaseView<State, Action> {
|
||||
fn base(&self) -> &WidgetBase<State, Action> {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user