namerena-rs/maker-py/control.py
2024-04-06 17:45:30 +08:00

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