tui-rs
tui-rs copied to clipboard
Add click events in the widgets?
I look at gocui and seems to have support for click events on the widgets. I would want to see this implemented, is there any reason why this is not implemented. I'd try to get this to work, but I first I'd like to know if someone has tried doing and see if it's not worth adding?
Currently events are not handled by the crate itself. Since the current architecture is not retained, supporting mouse events can be challenging. Some possible solutions could be providing the id of the widget where a hit happen or a way to define callbacks when those events are fired. Both imply a major change in the architecture and maybe in the api, so I would consider this a possible future improvement.
The fork I have https://github.com/ivanceras/itui make the widgets hold the area they are in, instead of passing it every draw call. The event listener is also attached to the widget. Since, all the events is triggered from the application level, the way to let widgets it is the target is by checking the area if it was hit (if it is a mouseclick). All the widgets are check against the event (ie. mouseevent) to match the coordinate (x,y) if it hits the widget area and the event name/type is the same. The event listener is then emitted/called when the conditions are met.
I have yet to release the overall code of that glue all of this. Meanwhile this what it looks like https://twitter.com/ivanceras/status/1150841336590786562
Hi, first thanks for this really cool library. Do you still consider handling click event a possible future improvement ? Perhaps even more generally having the possibily to pass an event handler ? with some defaults event handlers ? Since that widget can now be stateful, it seems the logical next step to handle behaviors like switching tabs. I'm just starting to learn rust but I'm willing to help on the subject.
Thanks for your interest in the library. While recent additions to the crate might ease the processing of some user inputs, we are still far from a support of click events unfortunately. I still have not made up my mind about the way to implement this. As one can see, the library is very open regarding how, when and why you decide to draw to the terminal, especially because it does not manage an event loop. It is a nice property in a lot of cases but it also falls short for others, such as click events.
Given the current architecture of the project, I would be more inclined to provide some interface to let people check whether a particular widget was clicked than having event callback on the widget themselves because the latter imply that we have access to those events.
I would also point out that I'm not familiar with all the details and innovations that have been pushed out in the field of declarative and reactive UI recently so I may not be in the best position to provide the nicest solution to this problem =). I would thus be more than happy to see informed opinions about this matter.
Something else to consider: currently it's impossible(?) to implement click to select for list items, as offset
is private in ListState
.
I can keep a mapping of clickable targets to their respective area (Rect
), and figure out which Rect
contains the clicked point (col, row). By extension, I can imagine splitting the Rect
further to determine which displayed index is clicked on. However, there seems to be no way to map this back to actual index since we don't know the offset.
Or am I missing something?
EDIT: It's possible to select a list item by using selected + n
/ selected - n
.
EDIT 2: Actually no... selected()
gives the actual index, not the displayed index. So there's still no way to map that.
@teohhanhui No that's not possible at the moment but it would definitively be taken into account in a solution to improve the mouse events integration. I'm still exploring different solutions but I've yet to come up with an api that I like. I'm might open an RFC with different solutions so that an open design discussion can happen on this subject.
@teohhanhui @fdehau What would you think of adding a method index_of_item_at(&self, point: (u16, u16), area: Rect, state: ListState) -> Option<usize>
for List
that returns the index of the item at the given point? This should be a method of List
instead of ListState
because the list can hold a border which affects the calculation.
@henkkuli There's already an Index
trait in core
/ std
.
@henkkuli There's already an
Index
trait incore
/std
.
Sorry, I don't follow what you mean by this? There is std::ops::Index
, but I don't see what it has to do with my proposal.
I was thinking something like:
list.index((x, y))
but now I see it needs to be:
list.index(((x, y), area, state))
which probably doesn't make sense. So nevermind. 🙈