Spaces:
Runtime error
Runtime error
File size: 5,770 Bytes
d82cf6a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
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)
|