Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
lib: Improve widget base
Erik Kundt committed 2 years ago
commit e5eda52f43b538d62b62b9cfd293a708bf904f49
parent 0d43859bcffebae00460a8b5890110a22a1c3df9
6 files changed +92 -81
modified src/ui/widget.rs
@@ -19,8 +19,9 @@ pub type BoxedWidget<S, A> = Box<dyn Widget<State = S, Action = A>>;
pub type UpdateCallback<S> = fn(&S) -> Box<dyn Any>;
pub type EventCallback = fn(&mut dyn Any);

-
/// A `View`s common fields.
-
pub struct BaseView<S, A> {
+
/// A `WidgetBase` provides common functionality to a `Widget`. It's used to store
+
/// event and update callbacks as well sending messages to the UI's message channel.
+
pub struct WidgetBase<S, A> {
    /// Message sender
    pub action_tx: UnboundedSender<A>,
    /// Custom update handler
@@ -29,7 +30,17 @@ pub struct BaseView<S, A> {
    pub on_event: Option<EventCallback>,
}

-
impl<S, A> BaseView<S, A> {
+
impl<S, A> WidgetBase<S, A> {
+
    /// Create a new `WidgetBase` with no callbacks set.
+
    pub fn new(action_tx: UnboundedSender<A>) -> Self {
+
        Self {
+
            action_tx: action_tx.clone(),
+
            on_update: None,
+
            on_event: None,
+
        }
+
    }
+

+
    /// Send a message to the internal channel.
    pub fn send(&self, action: A) -> Result<(), SendError<A>> {
        self.action_tx.send(action)
    }
@@ -107,8 +118,16 @@ pub trait Widget {
    /// Optional render props can be given.
    fn render(&self, frame: &mut Frame, props: RenderProps);

-
    /// Return a mutable reference to this widgets' base view.
-
    fn base_mut(&mut self) -> &mut BaseView<Self::State, Self::Action>;
+
    /// Return a reference to this widgets' base.
+
    fn base(&self) -> &WidgetBase<Self::State, Self::Action>;
+

+
    /// Return a mutable reference to this widgets' base.
+
    fn base_mut(&mut self) -> &mut WidgetBase<Self::State, Self::Action>;
+

+
    /// Send a message to the widgets' base channel.
+
    fn send(&self, action: Self::Action) -> Result<(), SendError<Self::Action>> {
+
        self.base().send(action)
+
    }

    /// Should set the optional custom event handler.
    fn on_event(mut self, callback: EventCallback) -> Self
@@ -135,13 +154,6 @@ pub trait Widget {
    {
        Box::new(self)
    }
-

-
    fn downcast_ref(any: &dyn Any) -> Option<&Self>
-
    where
-
        Self: Sized + 'static,
-
    {
-
        any.downcast_ref::<Self>()
-
    }
}

/// Needs to be implemented for items that are supposed to be rendered in tables.
modified src/ui/widget/container.rs
@@ -10,7 +10,7 @@ use ratatui::widgets::{Block, BorderType, Borders, Row};
use crate::ui::ext::{FooterBlock, FooterBlockType, HeaderBlock};
use crate::ui::theme::style;

-
use super::{BaseView, BoxedAny, BoxedWidget, Properties, RenderProps, Widget};
+
use super::{BoxedAny, BoxedWidget, Properties, RenderProps, Widget, WidgetBase};

#[derive(Clone, Debug)]
pub struct Column<'a> {
@@ -71,7 +71,7 @@ pub struct Header<'a: 'static, S, A> {
    /// Internal props
    props: HeaderProps<'a>,
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
}

impl<'a, S, A> Header<'a, S, A> {
@@ -93,11 +93,7 @@ impl<'a: 'static, S, A> Widget for Header<'a, S, A> {

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: HeaderProps::default(),
        }
    }
@@ -170,7 +166,11 @@ impl<'a: 'static, S, A> Widget for Header<'a, S, A> {
        frame.render_widget(header, header_layout[0]);
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
@@ -212,7 +212,7 @@ pub struct Footer<'a, S, A> {
    /// Internal props
    props: FooterProps<'a>,
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
}

impl<'a, S, A> Footer<'a, S, A> {
@@ -256,11 +256,7 @@ impl<'a: 'static, S, A> Widget for Footer<'a, S, A> {

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: FooterProps::default(),
        }
    }
@@ -309,7 +305,11 @@ impl<'a: 'static, S, A> Widget for Footer<'a, S, A> {
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
@@ -331,7 +331,7 @@ impl BoxedAny for ContainerProps {}

pub struct Container<S, A> {
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal props
    props: ContainerProps,
    /// Container header
@@ -368,12 +368,7 @@ impl<S, A> Widget for Container<S, A> {
        Self: Sized,
    {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-

-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: ContainerProps::default(),
            header: None,
            content: None,
@@ -451,7 +446,11 @@ impl<S, A> Widget for Container<S, A> {
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
@@ -482,7 +481,7 @@ impl BoxedAny for SectionGroupProps {}

pub struct SectionGroup<S, A> {
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal table properties
    props: SectionGroupProps,
    /// All sections
@@ -522,11 +521,7 @@ impl<S: 'static, A: 'static> Widget for SectionGroup<S, A> {

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: SectionGroupProps::default(),
            sections: vec![],
            state: SectionGroupState { focus: Some(0) },
@@ -584,7 +579,11 @@ impl<S: 'static, A: 'static> Widget for SectionGroup<S, A> {
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
modified src/ui/widget/input.rs
@@ -6,7 +6,7 @@ use ratatui::layout::{Constraint, Layout};
use ratatui::style::Stylize;
use ratatui::text::{Line, Span};

-
use super::{BaseView, BoxedAny, Properties, RenderProps, Widget};
+
use super::{BoxedAny, Properties, RenderProps, Widget, WidgetBase};

#[derive(Clone)]
pub struct TextFieldProps {
@@ -58,7 +58,7 @@ impl BoxedAny for TextFieldState {}

pub struct TextField<S, A> {
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal props
    props: TextFieldProps,
    /// Internal state
@@ -137,11 +137,7 @@ impl<S: 'static, A: 'static> Widget for TextField<S, A> {

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: TextFieldProps::default(),
            state: TextFieldState {
                text: None,
@@ -238,7 +234,11 @@ impl<S: 'static, A: 'static> Widget for TextField<S, A> {
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
modified src/ui/widget/list.rs
@@ -14,7 +14,7 @@ use crate::ui::theme::style;
use crate::ui::{layout, span};

use super::BoxedAny;
-
use super::{container::Column, BaseView, Properties, RenderProps, ToRow, Widget};
+
use super::{container::Column, Properties, RenderProps, ToRow, Widget, WidgetBase};

#[derive(Clone, Debug)]
pub struct TableProps<'a, R, const W: usize>
@@ -93,7 +93,7 @@ where
    R: ToRow<W>,
{
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal table properties
    props: TableProps<'a, R, W>,
    /// Internal selection and offset state
@@ -168,11 +168,7 @@ where

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: TableProps::default(),
            state: TableState::default().with_selected(Some(0)),
        }
@@ -277,7 +273,11 @@ where
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
modified src/ui/widget/text.rs
@@ -5,7 +5,7 @@ use termion::event::Key;
use ratatui::layout::{Constraint, Layout};
use ratatui::text::Text;

-
use super::{BaseView, BoxedAny, Properties, RenderProps, Widget};
+
use super::{BoxedAny, Properties, RenderProps, Widget, WidgetBase};

#[derive(Clone)]
pub struct ParagraphProps<'a> {
@@ -55,7 +55,7 @@ impl BoxedAny for ParagraphState {}

pub struct Paragraph<'a, S, A> {
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal props
    props: ParagraphProps<'a>,
    /// Internal state
@@ -145,11 +145,7 @@ impl<'a: 'static, S: 'static, A: 'static> Widget for Paragraph<'a, S, A> {
        Self: Sized,
    {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: ParagraphProps::default(),
            state: ParagraphState {
                offset: 0,
@@ -204,7 +200,11 @@ impl<'a: 'static, S: 'static, A: 'static> Widget for Paragraph<'a, S, A> {
        frame.render_widget(content, content_area);
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
modified src/ui/widget/window.rs
@@ -12,7 +12,7 @@ use ratatui::widgets::Row;

use crate::ui::theme::style;

-
use super::{BaseView, BoxedAny, BoxedWidget, Properties, RenderProps, Widget};
+
use super::{BoxedAny, BoxedWidget, Properties, RenderProps, Widget, WidgetBase};

#[derive(Clone)]
pub struct WindowProps<Id> {
@@ -37,7 +37,7 @@ impl<Id> BoxedAny for WindowProps<Id> {}

pub struct Window<S, A, Id> {
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
    /// Internal properties
    props: WindowProps<Id>,
    /// All pages known
@@ -66,11 +66,7 @@ where
        Self: Sized,
    {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: WindowProps::default(),
            pages: HashMap::new(),
        }
@@ -117,7 +113,11 @@ where
        }
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}
@@ -159,7 +159,7 @@ pub struct Shortcuts<S, A> {
    /// Internal properties
    props: ShortcutsProps,
    /// Internal base
-
    base: BaseView<S, A>,
+
    base: WidgetBase<S, A>,
}

impl<S, A> Shortcuts<S, A> {
@@ -185,11 +185,7 @@ impl<S, A> Widget for Shortcuts<S, A> {

    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
        Self {
-
            base: BaseView {
-
                action_tx: action_tx.clone(),
-
                on_update: None,
-
                on_event: None,
-
            },
+
            base: WidgetBase::new(action_tx.clone()),
            props: ShortcutsProps::default(),
        }
    }
@@ -239,7 +235,11 @@ impl<S, A> Widget for Shortcuts<S, A> {
        frame.render_widget(table, props.area);
    }

-
    fn base_mut(&mut self) -> &mut BaseView<S, A> {
+
    fn base(&self) -> &WidgetBase<S, A> {
+
        &self.base
+
    }
+

+
    fn base_mut(&mut self) -> &mut WidgetBase<S, A> {
        &mut self.base
    }
}