Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Auto Reposition Frame for #821 #822

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
33 changes: 33 additions & 0 deletions experimental/re_pos_frame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pyglet

window = pyglet.window.Window(resizable=True)

# create a frame
reposition_frame = pyglet.gui.control.RePositionFrame(window)

# create labels
label = pyglet.text.Label("Hello World", x=0, y=0)
b_label = pyglet.text.Label("Hello World with call back", x=0, y=0)

# create a callback function
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}"

# add the callback function to the frame
reposition_frame.add_callback_func(b_label, callback)

# add the calculate function to the frame
# NOTICE: label need x, y, z, so the function must return a tuple with 3 elements
reposition_frame.add_calculate_func(label, lambda obj, width, height, window: (width/2, height/2, 0))

# draw the labels
@window.event
def on_draw():
window.clear()
label.draw()
b_label.draw()

# run the app
pyglet.app.run()
7 changes: 5 additions & 2 deletions pyglet/gui/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from .widgets import *
from .frame import *
from .widgets import WidgetBase, PushButton, ToggleButton, Slider, TextEntry

from .frame import Frame, MovableFrame

from .control import RePositionFrame, GridFrame
106 changes: 106 additions & 0 deletions pyglet/gui/control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from typing import Callable, Union, Tuple, Dict, TYPE_CHECKING, TypeVar, Optional

if TYPE_CHECKING:
from pyglet.shapes import ShapeBase
from pyglet.window import Window
from pyglet.text import Label
from pyglet.sprite import Sprite
from pyglet.gui.widgets import WidgetBase

Repositionable = Union[ShapeBase, Label, Sprite, WidgetBase] # just for typing
else:
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]

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable 'CallBack' is not used.
IndexType = Union[int, str]

__all__ = [
'RePositionFrame',
'GridFrame',
]

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)


class GridFrame(RePositionFrame):
""" A TKinker grid like frame that allows for repositioning of widgets
and also allow you to auto place the widgets in a grid like fashion
"""

# WIP
4 changes: 4 additions & 0 deletions pyglet/gui/frame.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
__all__ = [
'Frame',
'MovableFrame',
]

class Frame:
"""The base Frame object, implementing a 2D spatial hash.
Expand Down
9 changes: 9 additions & 0 deletions pyglet/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
from pyglet.text.layout import IncrementalTextLayout


__all__ = [
'WidgetBase',
'PushButton',
'ToggleButton',
'Slider',
'TextEntry'
]


class WidgetBase(EventDispatcher):

def __init__(self, x, y, width, height):
Expand Down