Replies: 6 comments 1 reply
-
Alternatively, we could add a impl Widget for &mut App {
fn draw(self, area: Rect, buf: &mut Frame) {
//
}
} this will give each widget access to the "frame count" as well. |
Beta Was this translation helpful? Give feedback.
-
Ideally the render function would have a context param instead of just the buffer that would allow for carrying extra properties like this, but I think that ship has sailed without considering this as a rewrite. |
Beta Was this translation helpful? Give feedback.
-
I'm not 100% sure we should do this btw. It seems like an odd place to put a cursor when we have it already on Terminal and Frame. |
Beta Was this translation helpful? Give feedback.
-
What do you think about adding a new trait member function like struct Context {
frame_count: usize,
cursor_position: Option<u16, u16>,
}
impl Widget {
fn render_with_context(self, area: Rect, buf: &mut Buffer, ctx: &mut Context) {
self.render(area, self.buffer);
}
}
|
Beta Was this translation helpful? Give feedback.
-
Maybe it is not worth the maintenance effort + teaching people how and when they should use this, in which case feel free to close it. |
Beta Was this translation helpful? Give feedback.
-
Probably adding One approach to implementing this nicely without any Ratatui change is to set up some sort of shared Focus / Cursor state type, which any widget that needs to interact with those can add as a field (wrapped in the appropriate Rc/Arc/Mutex/RwLock shenanigans). Alternatively set up a specific mspc channel that accepts messages and deals with it at the end of rendering. Neither of those approaches requires a full blown component approach, just some shared code. E.g.: (locks ommitted, but possibly necessary) #[derive(Clone)]
struct CursorState {
position: Rc<Position>,
}
struct App {
cursor_state: CursorState,
...
}
struct MyTextField {
cursor_state: CursorState,
}
impl App {
fn render(self, frame: Frame) {
frame.render_widget(MyTextField { cursor_state: self.cursor_state.clone() }, ...);
...
frame.set_cursor(cursor_state.position.x, cursor_state.position.y);
}
}
impl Widget for &mut MyTextField {
fn render(self, area: Rect, buf &mut Buffer) {
...
self.cursor_state.set_position((x, y).into()); // or something like this.
}
} I'd like to work out what that shared state looks like in https://github.com/joshka/ratatui-widgets/ so cursor and focus handling can be done across a bunch of interactive widgets. It feeds into the idea of letting widgets communicate back state and accept events. https://github.com/sephiroth74/tui-confirm-dialog has an approach that works specifically using channels for getting back state and an approach for handling key events. I'm not sure if that's the right approach for building on top of yet, so I want to experiment more with several approaches based on this, particularly your work with components, async, events, actions, and with some other ideas (shared state, trait implementations, etc.) |
Beta Was this translation helpful? Give feedback.
-
Problem
With the new
impl Widget for &mut App
paradigm, it would be useful for havingset_cursor
on the buffer as well. This will make composition of widgets easier.Currently, rendering an "input" widget needs to be done where you have access to the
Frame
to be able to set the cursor appropriately. e.g.:Currently I don't believe it is possible to do this instead:
Solution
Add a
set_cursor
inBuffer
Additional context
This will negate the need for me to have a
Component
style architecture since users can compose reusable widgets.Beta Was this translation helpful? Give feedback.
All reactions