|
|
@ -53,11 +53,14 @@ class Dimensions: |
|
|
|
self.width = width |
|
|
|
self.height = height |
|
|
|
|
|
|
|
def __add__(self, dimensions: Self): |
|
|
|
return Dimensions(self.width + dimensions.width, self.height + dimensions.height) |
|
|
|
|
|
|
|
def as_tuple(self): |
|
|
|
return (self.width, self.height) |
|
|
|
return self.width, self.height |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def from_tuple(tuple): |
|
|
|
def from_tuple(tuple: Tuple): |
|
|
|
return Dimensions(tuple[0], tuple[1]) |
|
|
|
|
|
|
|
|
|
|
@ -69,6 +72,10 @@ class Drawable: |
|
|
|
self.surface.blit(drawable.surface, position.as_tuple()) |
|
|
|
|
|
|
|
def clear(self, color = Color(0, 0, 0)): |
|
|
|
if color is None: |
|
|
|
self.surface.fill(pygame.Color(0, 0, 0, 0)) |
|
|
|
return |
|
|
|
|
|
|
|
self.surface.fill(color.as_tuple()) |
|
|
|
|
|
|
|
def get_image(self): |
|
|
@ -80,6 +87,9 @@ class Drawable: |
|
|
|
def get_dimensions(self) -> Dimensions: |
|
|
|
return Dimensions.from_tuple(self.surface.get_size()) |
|
|
|
|
|
|
|
def set_transparency(self, transparency: float): |
|
|
|
self.surface.set_alpha(255 - 255 * transparency) |
|
|
|
|
|
|
|
|
|
|
|
class Image(Drawable): |
|
|
|
def __init__(self, path = None): |
|
|
@ -98,6 +108,7 @@ class Screen: |
|
|
|
def __init__(self, title: str, resolution: Dimensions): |
|
|
|
self.resolution = resolution |
|
|
|
self.screen = pygame.display.set_mode(resolution.as_tuple(), pygame.NOFRAME | pygame.FULLSCREEN | pygame.DOUBLEBUF) |
|
|
|
|
|
|
|
pygame.display.set_caption(title) |
|
|
|
|
|
|
|
def get_canvas(self): |
|
|
@ -106,9 +117,6 @@ class Screen: |
|
|
|
|
|
|
|
return canvas |
|
|
|
|
|
|
|
def get_image(self): |
|
|
|
image = Image() |
|
|
|
|
|
|
|
def update(self) -> None: |
|
|
|
pygame.dispay.flip() |
|
|
|
|
|
|
@ -122,14 +130,20 @@ class Screen: |
|
|
|
return resolutions |
|
|
|
|
|
|
|
|
|
|
|
class Visualization(): |
|
|
|
def __init__(self, surface: Canvas, position: Position): |
|
|
|
self.surface = surface |
|
|
|
class Visualization: |
|
|
|
def __init__(self, canvas: Canvas, position: Position): |
|
|
|
self.canvas = canvas |
|
|
|
self.position = position |
|
|
|
self.on_hover = lambda : None |
|
|
|
|
|
|
|
def draw(self, canvas: Canvas) -> None: |
|
|
|
canvas.draw_inside(self.surface, self.position) |
|
|
|
canvas.draw_inside(self.canvas, self.position) |
|
|
|
|
|
|
|
def set_transparency(self, transparency: float): |
|
|
|
self.canvas.set_transparency(transparency) |
|
|
|
|
|
|
|
def get_dimensions(self) -> Dimensions: |
|
|
|
return self.canvas.get_dimensions() |
|
|
|
|
|
|
|
def is_inside(self, position: Position) -> bool: |
|
|
|
if position.x < self.position.x: |
|
|
@ -138,7 +152,7 @@ class Visualization(): |
|
|
|
if position.y < self.position.y: |
|
|
|
return False |
|
|
|
|
|
|
|
dimensions = self.surface.get_dimensions() |
|
|
|
dimensions = self.canvas.get_dimensions() |
|
|
|
|
|
|
|
if position.x > self.position.x + dimensions.width: |
|
|
|
return False |
|
|
@ -161,33 +175,21 @@ class Clickable(Visualization): |
|
|
|
class Dragable(Clickable): |
|
|
|
def __init__(self, canvas: Canvas, position: Position): |
|
|
|
Clickable.__init__(self, canvas, position) |
|
|
|
self.on_drag = lambda : None |
|
|
|
self.on_drop = lambda : None |
|
|
|
self.on_fail = lambda drag : None |
|
|
|
self.on_drag = lambda: None |
|
|
|
self.on_drop = lambda dropable: None |
|
|
|
self.on_fail = lambda drag: None |
|
|
|
|
|
|
|
def drag(self) -> None: |
|
|
|
self.on_drag() |
|
|
|
|
|
|
|
def drop(self) -> None: |
|
|
|
self.on_drop() |
|
|
|
def drop(self, dropable: 'Dropable') -> None: |
|
|
|
self.on_drop(dropable) |
|
|
|
|
|
|
|
def fail(self, drag: 'Drag'): |
|
|
|
self.on_fail(drag) |
|
|
|
|
|
|
|
|
|
|
|
class Dropable(Visualization): |
|
|
|
def __init__(self, canvas: Canvas, position: Position): |
|
|
|
Visualization.__init__(self, canvas, position) |
|
|
|
self.on_drop = lambda dragable: None |
|
|
|
|
|
|
|
def drop(self, dragable: Dragable) -> None: |
|
|
|
self.on_drop(dragable) |
|
|
|
|
|
|
|
|
|
|
|
class Container(Visualization): |
|
|
|
ROWS = 0 |
|
|
|
COLUMNS = 1 |
|
|
|
|
|
|
|
def __init__(self, position: Position, dimensions: Dimensions): |
|
|
|
Visualization.__init__(self, Canvas(dimensions), position) |
|
|
|
|
|
|
@ -195,18 +197,19 @@ class Container(Visualization): |
|
|
|
self.background_color = Color(0, 0, 0) |
|
|
|
self.visualizations = [] |
|
|
|
self.clickables = [] |
|
|
|
self.dropables = [] |
|
|
|
|
|
|
|
def set_background_image(self, image: Image) -> None: |
|
|
|
self.background_image = image |
|
|
|
|
|
|
|
def render(self) -> None: |
|
|
|
self.surface.clear(self.background_color) |
|
|
|
self.canvas.clear(self.background_color) |
|
|
|
|
|
|
|
if self.background_image is not None: |
|
|
|
self.surface.draw_inside(self.background_image, Dimensions(0, 0)) |
|
|
|
self.canvas.draw_inside(self.background_image, Dimensions(0, 0)) |
|
|
|
|
|
|
|
for visualization in self.visualizations: |
|
|
|
visualization.draw(self.surface) |
|
|
|
visualization.draw(self.canvas) |
|
|
|
|
|
|
|
def add_visualization(self, visualization: Visualization) -> None: |
|
|
|
self.visualizations.append(visualization) |
|
|
@ -215,6 +218,33 @@ class Container(Visualization): |
|
|
|
self.add_visualization(clickable) |
|
|
|
self.clickables.append(clickable) |
|
|
|
|
|
|
|
def add_dropable(self, dropable: 'Dropable'): |
|
|
|
self.add_visualization(dropable) |
|
|
|
self.dropables.append(dropable) |
|
|
|
|
|
|
|
|
|
|
|
class Dropable(Container): |
|
|
|
def __init__(self, position: Position, dimensions: Dimensions): |
|
|
|
Container.__init__(self, position, dimensions) |
|
|
|
self.on_drop = lambda dragable: None |
|
|
|
|
|
|
|
def drop(self, dragable: Dragable) -> None: |
|
|
|
self.on_drop(dragable) |
|
|
|
|
|
|
|
|
|
|
|
class Text(Visualization, Drawable): |
|
|
|
def __init__(self, text: str, size: int = 12, font_family: str = 'freesansbold.ttf', color: Color = Color(255, 255, 255)): |
|
|
|
font = pygame.font.Font(font_family, size) |
|
|
|
self.surface = font.render(text, True, color.as_tuple()) |
|
|
|
|
|
|
|
Visualization.__init__( |
|
|
|
self, |
|
|
|
Canvas(Dimensions.from_tuple(self.surface.get_size())), |
|
|
|
Position(0, 0) |
|
|
|
) |
|
|
|
|
|
|
|
self.canvas.surface = self.surface |
|
|
|
|
|
|
|
|
|
|
|
class Drag: |
|
|
|
def __init__(self, dragable: Dragable, cursor_offset: Position): |
|
|
@ -234,10 +264,10 @@ class UI: |
|
|
|
self.drag = None |
|
|
|
self.containers = [] |
|
|
|
|
|
|
|
def init(self): |
|
|
|
def init(self) -> None: |
|
|
|
pass |
|
|
|
|
|
|
|
def update(self): |
|
|
|
def update(self) -> None: |
|
|
|
self.canvas.clear() |
|
|
|
|
|
|
|
for container in self.containers: |
|
|
@ -246,13 +276,13 @@ class UI: |
|
|
|
|
|
|
|
pygame.display.update() |
|
|
|
|
|
|
|
def add_container(self, container: Container): |
|
|
|
def add_container(self, container: Container) -> None: |
|
|
|
self.containers.append(container) |
|
|
|
|
|
|
|
def exit(self): |
|
|
|
def exit(self) -> None: |
|
|
|
self.is_running = False |
|
|
|
|
|
|
|
def main(self): |
|
|
|
def main(self) -> None: |
|
|
|
while self.is_running: |
|
|
|
event = pygame.event.wait() |
|
|
|
|
|
|
@ -284,7 +314,7 @@ class UI: |
|
|
|
|
|
|
|
clickable = clickables_clicked[-1] |
|
|
|
|
|
|
|
if type(clickable) is Dragable: |
|
|
|
if self._is_in_filter(clickable, [Dragable]): |
|
|
|
self.drag = Drag( |
|
|
|
clickable, |
|
|
|
Position.from_tuple(event.pos) - clickable.position |
|
|
@ -292,7 +322,7 @@ class UI: |
|
|
|
|
|
|
|
clickable.click() |
|
|
|
|
|
|
|
def _handle_drag(self, event: pygame.event.Event): |
|
|
|
def _handle_drag(self, event: pygame.event.Event) -> None: |
|
|
|
position_cursor = Position.from_tuple(event.pos) |
|
|
|
|
|
|
|
position = position_cursor - self.drag.cursor_offset |
|
|
@ -300,7 +330,7 @@ class UI: |
|
|
|
self.drag.dragable.position = position |
|
|
|
self.drag.dragable.drag() |
|
|
|
|
|
|
|
def _handle_drop(self, event: pygame.event.Event): |
|
|
|
def _handle_drop(self, event: pygame.event.Event) -> None: |
|
|
|
if self.drag is None: |
|
|
|
return |
|
|
|
|
|
|
@ -317,11 +347,11 @@ class UI: |
|
|
|
|
|
|
|
self.drag = None |
|
|
|
|
|
|
|
def _handle_mouse_motion(self, event: pygame.event.Event): |
|
|
|
def _handle_mouse_motion(self, event: pygame.event.Event) -> None: |
|
|
|
if type(self.drag) is Drag: |
|
|
|
self._handle_drag(event) |
|
|
|
|
|
|
|
def _get_visualizations_hovered(self, cursor_position: Position, filter: list = []): |
|
|
|
def _get_visualizations_hovered(self, cursor_position: Position, filter: list = []) -> list[Visualization]: |
|
|
|
containers_hovered = [] |
|
|
|
visualizations_hovered = [] |
|
|
|
|
|
|
@ -341,13 +371,17 @@ class UI: |
|
|
|
|
|
|
|
return visualizations_hovered |
|
|
|
|
|
|
|
def _get_clickables_clicked(self, event: pygame.event.Event): |
|
|
|
return self._get_visualizations_hovered( |
|
|
|
def _get_clickables_clicked(self, event: pygame.event.Event) -> list[Clickable]: |
|
|
|
clickables = self._get_visualizations_hovered( |
|
|
|
Position.from_tuple(event.pos), |
|
|
|
[Clickable, Dragable] |
|
|
|
) |
|
|
|
|
|
|
|
def _is_in_filter(self, visualization: Visualization, filter: list = []) -> bool: |
|
|
|
print(clickables) |
|
|
|
|
|
|
|
return clickables |
|
|
|
|
|
|
|
def _is_in_filter(self, visualization: Visualization, filter: list[Visualization] = []) -> bool: |
|
|
|
if len(filter) == 0: |
|
|
|
return True |
|
|
|
|
|
|
@ -359,20 +393,27 @@ class UI: |
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
class IconButton(Clickable): |
|
|
|
def __init__(self, icon: Image, icon_hover = None): |
|
|
|
self.icon = icon |
|
|
|
self.icon_hover = icon_hover |
|
|
|
class ListItem(Dragable): |
|
|
|
def __init__(self, canvas: Canvas): |
|
|
|
Dragable.__init__(self, canvas, Position(0, 0)) |
|
|
|
|
|
|
|
|
|
|
|
class ItemList(Dropable): |
|
|
|
def __init__(self, position: Position, dimensions: Dimensions): |
|
|
|
Dropable.__init__(self, position, dimensions) |
|
|
|
|
|
|
|
def add_item(self, item: ListItem) -> None: |
|
|
|
self.add_dropable(item) |
|
|
|
|
|
|
|
|
|
|
|
class ResourceContainer: |
|
|
|
def __init__(self): |
|
|
|
self.images = {} |
|
|
|
|
|
|
|
def add_image(self, name, url): |
|
|
|
def add_image(self, name, url) -> None: |
|
|
|
self.images[name] = Image(url) |
|
|
|
|
|
|
|
def get_image(self, name): |
|
|
|
def get_image(self, name) -> Image: |
|
|
|
return self._get_resource(self.images, name) |
|
|
|
|
|
|
|
def _get_resource(self, resources: list, name: str): |
|
|
@ -382,7 +423,7 @@ class ResourceContainer: |
|
|
|
raise Exception('Resource "%s" not found!' % (name)) |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def from_json_file(json_file): |
|
|
|
def from_json_file(json_file) -> Self: |
|
|
|
with open(json_file, 'r') as file: |
|
|
|
data = json.loads(file.read()) |
|
|
|
|
|
|
|