107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
|
from typing import Callable, Union, Tuple, Dict, TYPE_CHECKING, TypeVar, Optional
|
||
|
|
||
|
if TYPE_CHECKING:
|
||
|
from pyglet.text import Label
|
||
|
from pyglet.window import Window
|
||
|
from pyglet.sprite import Sprite
|
||
|
from pyglet.shapes import ShapeBase
|
||
|
from pyglet.gui.widgets import WidgetBase
|
||
|
|
||
|
Repositionable = Union[ShapeBase, Label, Sprite, WidgetBase] # just for typing
|
||
|
else:
|
||
|
Window = TypeVar("Window") # for type checking
|
||
|
Repositionable = TypeVar("Repositionable") # for type checking
|
||
|
|
||
|
Num = Union[int, float]
|
||
|
|
||
|
PotitionTuple = Union[Tuple[Num, Num], Tuple[Num, Num, Num]]
|
||
|
|
||
|
CallBackFunc = Callable[[Repositionable, int, int, Window], None]
|
||
|
CalculateFunc = Callable[[Repositionable, int, int, Window], PotitionTuple]
|
||
|
|
||
|
CallBack = Union[CallBackFunc, CalculateFunc]
|
||
|
IndexType = Union[int, str]
|
||
|
|
||
|
__all__ = [
|
||
|
"RePositionFrame",
|
||
|
]
|
||
|
|
||
|
|
||
|
class RePositionFrame:
|
||
|
"""A Frame Like Object that allows for repositioning of widgets
|
||
|
you can give A function and A widget/shape to let it reposition itself
|
||
|
when the function is called
|
||
|
|
||
|
>>> import pyglet
|
||
|
>>> window = pyglet.window.Window(resizable=True)
|
||
|
>>> reposition_frame = pyglet.gui.frame.RePositionFrame(window)
|
||
|
>>> label = pyglet.text.Label("Hello World", x=0, y=0)
|
||
|
>>> b_label = pyglet.text.Label("Hello World with call back", x=0, y=0)
|
||
|
>>> def callback(obj, width, height, window):
|
||
|
>>> obj.x = width/3
|
||
|
>>> obj.y = height/3
|
||
|
>>> obj.text = f"Hello World with call back, width: {width}, height: {height}"
|
||
|
>>> reposition_frame.add_calculate_func(label, lambda obj, width, height, window: (width/2, height/2, 0))
|
||
|
>>> reposition_frame.add_callback_func(b_label, callback)
|
||
|
>>> @window.event
|
||
|
>>> def on_draw():
|
||
|
>>> window.clear()
|
||
|
>>> label.draw()
|
||
|
>>> b_label.draw()
|
||
|
>>> pyglet.app.run()
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self, window):
|
||
|
window.push_handlers(self)
|
||
|
self.window = window
|
||
|
self.callback_dict: Dict[IndexType, Tuple[Repositionable, CallBackFunc]] = {}
|
||
|
self.calculate_dict: Dict[IndexType, Tuple[Repositionable, CalculateFunc]] = {}
|
||
|
|
||
|
def add_callback_func(
|
||
|
self, obj: Repositionable, func: CallBackFunc, index: Optional[IndexType] = None
|
||
|
) -> IndexType:
|
||
|
"""Add A callback function to the frame
|
||
|
|
||
|
:param obj: The object that will be repositioned
|
||
|
:param func: The function that will be called
|
||
|
:param index: The index of the object
|
||
|
"""
|
||
|
if index is None:
|
||
|
index = hash(obj)
|
||
|
self.callback_dict[index] = (obj, func)
|
||
|
return index
|
||
|
|
||
|
def add_calculate_func(
|
||
|
self,
|
||
|
obj: Repositionable,
|
||
|
func: CalculateFunc,
|
||
|
index: Optional[IndexType] = None,
|
||
|
) -> IndexType:
|
||
|
"""Add A calculate function to the frame
|
||
|
|
||
|
:param obj: The object that will be repositioned
|
||
|
:param func: The function that will be called
|
||
|
:param index: The index of the object
|
||
|
"""
|
||
|
if index is None:
|
||
|
index = hash(obj)
|
||
|
self.calculate_dict[index] = (obj, func)
|
||
|
return index
|
||
|
|
||
|
def remove_callback_func(self, index: IndexType):
|
||
|
if index in self.callback_dict:
|
||
|
self.callback_dict.pop(index)
|
||
|
|
||
|
def remove_calculate_func(self, index: IndexType):
|
||
|
if index in self.calculate_dict:
|
||
|
self.calculate_dict.pop(index)
|
||
|
|
||
|
def on_resize(self, width: int, height: int):
|
||
|
"""Call all the functions when the window is resized"""
|
||
|
for _, (obj, func) in self.callback_dict.items():
|
||
|
func(obj, width, height, self.window)
|
||
|
|
||
|
for _, (obj, func) in self.calculate_dict.items():
|
||
|
obj.position = func(obj, width, height, self.window) # type: ignore
|