Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
lib: Improve event callback
Erik Kundt committed 2 years ago
commit 2c88e8f9a3a608a3a9dd24263a3cb83514ca5424
parent f6ae35af8affb4f4fe95bdee49419c27a3a427ac
5 files changed +37 -25
modified src/ui/widget.rs
@@ -6,6 +6,7 @@ pub mod window;

use std::any::Any;

+
use tokio::sync::mpsc::error::SendError;
use tokio::sync::mpsc::UnboundedSender;

use termion::event::Key;
@@ -16,7 +17,7 @@ use ratatui::widgets::Cell;
pub type BoxedWidget<S, A> = Box<dyn Widget<State = S, Action = A>>;

pub type UpdateCallback<S> = fn(&S) -> Box<dyn Any>;
-
pub type EventCallback<A> = fn(Box<dyn Any>, UnboundedSender<A>);
+
pub type EventCallback = fn(&mut dyn Any);

/// A `View`s common fields.
pub struct BaseView<S, A> {
@@ -25,7 +26,13 @@ pub struct BaseView<S, A> {
    /// Custom update handler
    pub on_update: Option<UpdateCallback<S>>,
    /// Additional custom event handler
-
    pub on_event: Option<EventCallback<A>>,
+
    pub on_event: Option<EventCallback>,
+
}
+

+
impl<S, A> BaseView<S, A> {
+
    pub fn send(&self, action: A) -> Result<(), SendError<A>> {
+
        self.action_tx.send(action)
+
    }
}

/// General properties that specify how a `Widget` is rendered.
@@ -104,7 +111,7 @@ pub trait Widget {
    fn base_mut(&mut self) -> &mut BaseView<Self::State, Self::Action>;

    /// Should set the optional custom event handler.
-
    fn on_event(mut self, callback: EventCallback<Self::Action>) -> Self
+
    fn on_event(mut self, callback: EventCallback) -> Self
    where
        Self: Sized,
    {
@@ -128,6 +135,13 @@ 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
@@ -516,7 +516,7 @@ impl<S, A> SectionGroup<S, A> {
    }
}

-
impl<S, A> Widget for SectionGroup<S, A> {
+
impl<S: 'static, A: 'static> Widget for SectionGroup<S, A> {
    type State = S;
    type Action = A;

@@ -555,10 +555,7 @@ impl<S, A> Widget for SectionGroup<S, A> {
        }

        if let Some(on_event) = self.base.on_event {
-
            (on_event)(
-
                self.state.clone().to_boxed_any(),
-
                self.base.action_tx.clone(),
-
            );
+
            (on_event)(self);
        }
    }

modified src/ui/widget/input.rs
@@ -49,7 +49,7 @@ impl Default for TextFieldProps {
impl Properties for TextFieldProps {}

#[derive(Clone)]
-
pub struct TextFieldState {
+
struct TextFieldState {
    pub text: Option<String>,
    pub cursor_position: usize,
}
@@ -66,6 +66,10 @@ pub struct TextField<S, A> {
}

impl<S, A> TextField<S, A> {
+
    pub fn text(&self) -> Option<&String> {
+
        self.state.text.as_ref()
+
    }
+

    fn move_cursor_left(&mut self) {
        let cursor_moved_left = self.state.cursor_position.saturating_sub(1);
        self.state.cursor_position = self.clamp_cursor(cursor_moved_left);
@@ -127,7 +131,7 @@ impl<S, A> TextField<S, A> {
    }
}

-
impl<S, A> Widget for TextField<S, A> {
+
impl<S: 'static, A: 'static> Widget for TextField<S, A> {
    type Action = A;
    type State = S;

@@ -168,10 +172,7 @@ impl<S, A> Widget for TextField<S, A> {
        }

        if let Some(on_event) = self.base.on_event {
-
            (on_event)(
-
                self.state.clone().to_boxed_any(),
-
                self.base.action_tx.clone(),
-
            );
+
            (on_event)(self);
        }
    }

@@ -241,3 +242,5 @@ impl<S, A> Widget for TextField<S, A> {
        &mut self.base
    }
}
+

+
impl<S, A> BoxedAny for TextField<S, A> {}
modified src/ui/widget/list.rs
@@ -104,6 +104,10 @@ impl<'a, S, A, R, const W: usize> Table<'a, S, A, R, W>
where
    R: ToRow<W>,
{
+
    pub fn selected(&self) -> Option<usize> {
+
        self.state.selected()
+
    }
+

    fn prev(&mut self) -> Option<usize> {
        let selected = self
            .state
@@ -155,7 +159,7 @@ where
    }
}

-
impl<'a: 'static, S, A, R, const W: usize> Widget for Table<'a, S, A, R, W>
+
impl<'a: 'static, S: 'static, A: 'static, R, const W: usize> Widget for Table<'a, S, A, R, W>
where
    R: ToRow<W> + Clone + 'static,
{
@@ -200,10 +204,7 @@ where
        self.props.selected = self.state.selected();

        if let Some(on_event) = self.base.on_event {
-
            (on_event)(
-
                self.state.clone().to_boxed_any(),
-
                self.base.action_tx.clone(),
-
            );
+
            (on_event)(self);
        }
    }

modified src/ui/widget/text.rs
@@ -44,7 +44,7 @@ impl<'a: 'static> Properties for ParagraphProps<'a> {}
impl<'a: 'static> BoxedAny for ParagraphProps<'a> {}

#[derive(Clone)]
-
pub struct ParagraphState {
+
struct ParagraphState {
    /// Internal offset
    pub offset: usize,
    /// Internal progress
@@ -136,7 +136,7 @@ impl<'a, S, A> Paragraph<'a, S, A> {
    }
}

-
impl<'a: 'static, S, A> Widget for Paragraph<'a, S, A> {
+
impl<'a: 'static, S: 'static, A: 'static> Widget for Paragraph<'a, S, A> {
    type Action = A;
    type State = S;

@@ -185,10 +185,7 @@ impl<'a: 'static, S, A> Widget for Paragraph<'a, S, A> {
        }

        if let Some(on_event) = self.base.on_event {
-
            (on_event)(
-
                self.state.clone().to_boxed_any(),
-
                self.base.action_tx.clone(),
-
            );
+
            (on_event)(self);
        }
    }