L3-Bataille-Navale/source/gui/widget/Scroller.py

132 lines
3.5 KiB
Python

from typing import TYPE_CHECKING, Callable, Any, Type
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class Scroller(BoxWidget):
"""
A scroller widget with a background texture, a scroller and a label.
The cursor can be moved between the "from" and the "to" value
"""
def __init__(self, scene: "Scene",
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
width: Distance = None,
height: Distance = None,
from_: float = 0,
value: float = 0.5,
to: float = 1,
cursor_width: Distance = 0.1,
text_transform: Callable[[float], Any] = lambda value: value,
**kwargs):
super().__init__(scene, x, y, width, height)
self.style = style
self.cursor_width = cursor_width
self.text_transform = text_transform
self.background = Sprite(
img=self.style.get("background"),
**dict_filter_prefix("background_", kwargs)
)
self.cursor = Sprite(
img=self.style.get("cursor"),
**dict_filter_prefix("cursor_", kwargs)
)
self.label = pyglet.text.Label(
anchor_x="center", anchor_y="center",
**dict_filter_prefix("label_", kwargs)
)
self.add_listener("on_click_release", lambda _, rel_x, *__: self._refresh_cursor(rel_x))
self._from = from_
self._to = to
self.value = value
# refresh
def _refresh(self):
# background
self.background.x, self.background.y = self.xy
self.background.width, self.background.height = self.size
# cursor
self.cursor.width = self.width * self.cursor_width
self.cursor.height = self.height
self.cursor.y = self.y
self.cursor.x = (
# the base offset
self.x
# position the cursor relatively to the start and the end of the range
+ (self.value - self.from_) / (self.to - self.from_) * self.background.width
# center the cursor with its own width
- (self.cursor.width / 2)
)
# label
self.label.x, self.label.y = self.center
self.label.text = str(self.text_transform(self.value))
def _refresh_cursor(self, rel_x: int):
self.value = rel_x / self.width
# property
@property
def value(self):
return self._value
@value.setter
def value(self, value: float):
if not self.from_ <= value <= self.to: raise ValueError(f"The value is not in range")
self._value = value
self.trigger_event("on_value_change")
self._refresh()
@property
def from_(self):
return self._from
@from_.setter
def from_(self, from_: float):
self._from = from_
self._refresh()
@property
def to(self):
return self._to
@to.setter
def to(self, to: float):
self._to = to
self._refresh()
# event
def on_resize(self, width: int, height: int):
self._refresh()
def draw(self):
self.background.draw()
self.cursor.draw()
self.label.draw()