from pyglet.event import EVENT_HANDLED, EVENT_UNHANDLED
from typing_extensions import override
import arcade
from arcade.gui.events import UIMouseDragEvent, UIMouseEvent, UIMousePressEvent, UIMouseReleaseEvent
from arcade.gui.widgets import UILayout, UIWidget
[docs]
class UIDraggableMixin(UILayout):
"""UIDraggableMixin can be used to make any :class:`UIWidget` draggable.
Example, create a draggable Frame, with a background, useful for window like constructs:
class DraggablePane(UITexturePane, UIDraggableMixin):
...
This will not work when placed in a layout, as the layout will overwrite the position.
warning:
This mixin in its current form is not recommended for production use.
It is a quick way to get a draggable window like widget.
It does not respect the layout system and can break other widgets
which rely on the layout system.
"""
_dragging = False
[docs]
@override
def do_layout(self):
# FIXME this breaks core UI rules "Widgets are placed by parents", let us not do this
rect = self.rect
super().do_layout()
self.rect = self.rect.align_top(rect.top).align_left(rect.left)
[docs]
@override
def on_event(self, event) -> bool | None:
"""Handle dragging of the widget."""
if isinstance(event, UIMousePressEvent):
if event.button == arcade.MOUSE_BUTTON_LEFT and self.rect.point_in_rect(event.pos):
self._dragging = True
return EVENT_HANDLED
if isinstance(event, UIMouseDragEvent) and self._dragging:
self.rect = self.rect.move(event.dx, event.dy)
self.trigger_full_render()
return EVENT_HANDLED
if isinstance(event, UIMouseReleaseEvent):
if event.button == arcade.MOUSE_BUTTON_LEFT and self._dragging:
self._dragging = False
self.trigger_full_render()
return EVENT_HANDLED
return super().on_event(event)
[docs]
class UIMouseFilterMixin(UIWidget):
""":class:`UIMouseFilterMixin` can be used to catch all mouse events which occur
inside this widget.
Useful for window like widgets, :class:`UIMouseEvents` should not trigger
effects which are under the widget.
"""
[docs]
@override
def on_event(self, event) -> bool | None:
"""Catch all mouse events, that are inside this widget."""
if super().on_event(event):
return EVENT_HANDLED
if isinstance(event, UIMouseEvent):
# Catch all mouse events, that are inside this widget, to act like a window
if self.rect.point_in_rect(event.pos):
return EVENT_HANDLED
return EVENT_UNHANDLED
[docs]
class UIWindowLikeMixin(UIMouseFilterMixin, UIDraggableMixin, UIWidget):
"""Makes a widget window like:
- handles all mouse events that occur within the widgets boundaries
- can be dragged
"""