-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: Event Container #12
Open
mmstick
wants to merge
2
commits into
iced-rs:master
Choose a base branch
from
mmstick:event-container
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# Mouse Listener | ||
|
||
## Summary | ||
|
||
A programmable container that intercepts a variety of mouse input events. | ||
|
||
## Motivation | ||
|
||
There are many widgets within a GUI library that need to handle a wider variety of input events than is capable from a button. From a left button press and release, to a right button press and release, middle button press and release, and mouse enter and exit. | ||
|
||
## Guide-level explanation | ||
|
||
### File icon example | ||
|
||
One such use case for the event container is a file icon in a file manager. The left button press initiates a selection and drag, a left button release initiates a drop if the icon was dragged, a right button release opens a context menu, a middle click opens the file, a mouse enter causes the file icon to glow, and a mouse exit stops glowing the icon. | ||
|
||
```rs | ||
for (entity, metadata) in self.files.iter() { | ||
let file = mouse_listener(file_icon(metadata)) | ||
.on_press(Message::Drag(entity)) | ||
.on_release(Message::Drop) | ||
.on_right_release(Message::Context(entity)) | ||
.on_middle_release(Message::OpenFile(entity)) | ||
.on_mouse_enter(Message::IconEnter(entity)) | ||
.on_mouse_exit(Message::IconExit(entity)); | ||
|
||
icon_widgets.push(file.into()); | ||
} | ||
``` | ||
|
||
### Tabs | ||
|
||
A tabbed interface may also want to provide widgets that are draggable with context on a right click: | ||
|
||
```rs | ||
for (entity, metadata) in self.tabs.iter() { | ||
let tab = mouse_listener(tab(metadata)) | ||
.on_press(Message::TabDrag(entity)) | ||
.on_release(Message::TabDrop) | ||
.on_right_release(Message::TabContext(entity)) | ||
.on_middle_release(Message::TabClose(entity)) | ||
.on_mouse_enter(Message::TabHighlight(entity)) | ||
.on_mouse_exit(Message::TabUnhighlight(entity)); | ||
|
||
tabs.push(tab); | ||
} | ||
``` | ||
|
||
### Headerbar example | ||
|
||
Another use case for this widget is a headerbar, which is a container placed at the top of the window to serve as a replacement for a window title bar when server-side decorations are disabled. If any part of the container is clicked that does not intercept that click event, then the container itself will receive the click and make it possible to initiate a window drag. | ||
|
||
```rs | ||
let headerbar = mouse_listener(row(vec![left, center, right])) | ||
.on_press(Message::WindowDrag) | ||
.on_release(Message::WindowMaximize) | ||
.on_right_release(Message::WindowContext); | ||
``` | ||
|
||
## Implementation strategy | ||
|
||
The implementation is simple, and only requires thinly wrapping any existing element to intercept mouse events over it. | ||
|
||
```rs | ||
pub struct MouseListener<'a, Message, Renderer> { | ||
content: Element<'a, Message, Renderer>, | ||
|
||
/// Sets the message to emit on a left mouse button press. | ||
on_press: Option<Message>, | ||
|
||
/// Sets the message to emit on a left mouse button release. | ||
on_release: Option<Message>, | ||
|
||
/// Sets the message to emit on a right mouse button press. | ||
on_right_press: Option<Message>, | ||
|
||
/// Sets the message to emit on a right mouse button release. | ||
on_right_release: Option<Message>, | ||
|
||
/// Sets the message to emit on a middle mouse button press. | ||
on_middle_press: Option<Message>, | ||
|
||
/// Sets the message to emit on a middle mouse button release. | ||
on_middle_release: Option<Message>, | ||
|
||
/// Sets the message to emit when the mouse enters the widget. | ||
on_mouse_enter: Option<Message>, | ||
|
||
/// Sets the messsage to emit when the mouse exits the widget. | ||
on_mouse_exit: Option<Message>, | ||
} | ||
``` | ||
|
||
The update method will emit these messages when their criteria is met. | ||
|
||
## Drawbacks | ||
|
||
N/A | ||
|
||
## Rationale and alternatives | ||
|
||
The alternative is that it'd be required to manually implement the Widget trait whenever you want to have a widget intercept a variety of mouse events outside of the left button release event that the button widget currently provides. This will significantly improve ergonomics for creating more sophisticated widgets. | ||
|
||
## Prior Art | ||
|
||
Similar to `gtk::EventBox` from GTK, which is essentially a `gtk::Box` but with events that can be intercepted and programmed with callbacks. The implementation here is much more ergonomic in comparison. | ||
|
||
## Unresolved questions | ||
|
||
None | ||
|
||
## Future Possibilities | ||
|
||
Enables a large number of more complex and featured widgets. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshedding: I wonder if the name
on_press
would be confusing as it seems to have a different meaning to aButton
'son_press
, since theButton
'son_press
seems to be about themouse_or_touch_down + mouse_or_touch_up
sequence whereasMouseListener
's is just aboutmouse_down
. Do you think this consistency is important enough that we should rename eitherMouseListener
'son_press
or theButton
'son_press
?