Spaces:
Runtime error
Runtime error
class Frame: | |
"""The base Frame object, implementing a 2D spatial hash. | |
A `Frame` provides an efficient way to handle dispatching | |
keyboard and mouse events to Widgets. This is done by | |
implementing a 2D spatial hash. Only Widgets that are in the | |
vicinity of the mouse pointer will be passed Window events, | |
which can greatly improve efficiency when a large quantity | |
of Widgets are in use. | |
""" | |
def __init__(self, window, cell_size=64, order=0): | |
"""Create an instance of a Frame. | |
:Parameters: | |
`window` : `~pyglet.window.Window` | |
The SpatialHash will recieve events from this Window. | |
Appropriate events will be passed on to all added Widgets. | |
`cell_size` : int | |
The cell ("bucket") size for each cell in the hash. | |
Widgets may span multiple cells. | |
`order` : int | |
Widgets use internal OrderedGroups for draw sorting. | |
This is the base value for these Groups. | |
""" | |
window.push_handlers(self) | |
self._cell_size = cell_size | |
self._cells = {} | |
self._active_widgets = set() | |
self._order = order | |
self._mouse_pos = 0, 0 | |
def _hash(self, x, y): | |
"""Normalize position to cell""" | |
return int(x / self._cell_size), int(y / self._cell_size) | |
def add_widget(self, widget): | |
"""Add a Widget to the spatial hash.""" | |
min_vec, max_vec = self._hash(*widget.aabb[0:2]), self._hash(*widget.aabb[2:4]) | |
for i in range(min_vec[0], max_vec[0] + 1): | |
for j in range(min_vec[1], max_vec[1] + 1): | |
self._cells.setdefault((i, j), set()).add(widget) | |
widget.update_groups(self._order) | |
def remove_widget(self, widget): | |
"""Remove a Widget from the spatial hash.""" | |
min_vec, max_vec = self._hash(*widget.aabb[0:2]), self._hash(*widget.aabb[2:4]) | |
for i in range(min_vec[0], max_vec[0] + 1): | |
for j in range(min_vec[1], max_vec[1] + 1): | |
self._cells.get((i, j)).remove(widget) | |
def on_mouse_press(self, x, y, buttons, modifiers): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(x, y), set()): | |
widget.on_mouse_press(x, y, buttons, modifiers) | |
self._active_widgets.add(widget) | |
def on_mouse_release(self, x, y, buttons, modifiers): | |
"""Pass the event to any widgets that are currently active""" | |
for widget in self._active_widgets: | |
widget.on_mouse_release(x, y, buttons, modifiers) | |
self._active_widgets.clear() | |
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): | |
"""Pass the event to any widgets that are currently active""" | |
for widget in self._active_widgets: | |
widget.on_mouse_drag(x, y, dx, dy, buttons, modifiers) | |
self._mouse_pos = x, y | |
def on_mouse_scroll(self, x, y, index, direction): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(x, y), set()): | |
widget.on_mouse_scroll(x, y, index, direction) | |
def on_mouse_motion(self, x, y, dx, dy): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(x, y), set()): | |
widget.on_mouse_motion(x, y, dx, dy) | |
self._mouse_pos = x, y | |
def on_text(self, text): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(*self._mouse_pos), set()): | |
widget.on_text(text) | |
def on_text_motion(self, motion): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(*self._mouse_pos), set()): | |
widget.on_text_motion(motion) | |
def on_text_motion_select(self, motion): | |
"""Pass the event to any widgets within range of the mouse""" | |
for widget in self._cells.get(self._hash(*self._mouse_pos), set()): | |
widget.on_text_motion_select(motion) | |
class MovableFrame(Frame): | |
"""A Frame that allows Widget repositioning. | |
When a specified modifier key is held down, Widgets can be | |
repositioned by dragging them. Examples of modifier keys are | |
Ctrl, Alt, Shift. These are defined in the `pyglet.window.key` | |
module, and start witih `MOD_`. For example:: | |
from pyglet.window.key import MOD_CTRL | |
frame = pyglet.gui.frame.MovableFrame(mywindow, modifier=MOD_CTRL) | |
For more information, see the `pyglet.window.key` submodule | |
API documentation. | |
""" | |
def __init__(self, window, order=0, modifier=0): | |
super().__init__(window, order=order) | |
self._modifier = modifier | |
self._moving_widgets = set() | |
def on_mouse_press(self, x, y, buttons, modifiers): | |
if self._modifier & modifiers > 0: | |
for widget in self._cells.get(self._hash(x, y), set()): | |
if widget._check_hit(x, y): | |
self._moving_widgets.add(widget) | |
for widget in self._moving_widgets: | |
self.remove_widget(widget) | |
else: | |
super().on_mouse_press(x, y, buttons, modifiers) | |
def on_mouse_release(self, x, y, buttons, modifiers): | |
for widget in self._moving_widgets: | |
self.add_widget(widget) | |
self._moving_widgets.clear() | |
super().on_mouse_release(x, y, buttons, modifiers) | |
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): | |
for widget in self._moving_widgets: | |
wx, wy = widget.position | |
widget.position = wx + dx, wy + dy | |
super().on_mouse_drag(x, y, dx, dy, buttons, modifiers) | |