diff --git a/cromulant/ants.py b/cromulant/ants.py index 459e9f8..57de992 100644 --- a/cromulant/ants.py +++ b/cromulant/ants.py @@ -56,12 +56,7 @@ class Ants: @staticmethod def prepare() -> None: - objs = Storage.get_ants() - - for obj in objs: - ant = Ant() - ant.from_dict(obj) - Ants.ants.append(ant) + Ants.get_ants() @staticmethod def hatch() -> None: @@ -83,7 +78,7 @@ class Ants: Ants.save() image_path = Config.hatched_image_path - Game.add_message(f"{ant.name} is born", image_path) + Game.add_message("Hatched", f"{ant.name} is born", image_path) @staticmethod def terminate() -> None: @@ -97,7 +92,7 @@ class Ants: Ants.save() image_path = Config.terminated_image_path - Game.add_message(f"{ant.name} was terminated", image_path) + Game.add_message("Terminated", f"{ant.name} is gone", image_path) @staticmethod def get_random_ant() -> Ant: @@ -115,6 +110,7 @@ class Ants: def get_lazy() -> Ant: return min(Ants.ants, key=lambda ant: ant.updated) + @staticmethod def set_status(ant: Ant, status: str) -> None: from .game import Game @@ -128,6 +124,16 @@ class Ants: Game.add_status(ant) Ants.save() + @staticmethod def get_other(ant: Ant) -> Ant: ants = [a for a in Ants.ants if a.name != ant.name] - return random.choice(ants) \ No newline at end of file + return random.choice(ants) + + @staticmethod + def get_ants() -> None: + objs = Storage.get_ants() + + for obj in objs: + ant = Ant() + ant.from_dict(obj) + Ants.ants.append(ant) \ No newline at end of file diff --git a/cromulant/config.py b/cromulant/config.py index 1aefaab..d4c2cd5 100644 --- a/cromulant/config.py +++ b/cromulant/config.py @@ -19,8 +19,10 @@ class Config: names_json: Path background_color: str = "#2c2c2c" text_color: str = "#ffffff" - image_size: int = 50 + image_size: int = 80 space_1: int = 25 + max_messages: int = 120 + loop_delay: int = 2_000 @staticmethod def prepare() -> None: diff --git a/cromulant/game.py b/cromulant/game.py index e24a227..ba9b8f6 100644 --- a/cromulant/game.py +++ b/cromulant/game.py @@ -5,8 +5,10 @@ from pathlib import Path from PySide6.QtCore import Qt # type: ignore from PySide6.QtWidgets import QHBoxLayout +from PySide6.QtWidgets import QVBoxLayout from PySide6.QtWidgets import QLabel from PySide6.QtGui import QPixmap # type: ignore +from PySide6.QtCore import QTimer from wonderwords import RandomSentence # type: ignore @@ -18,33 +20,56 @@ from .window import Window class Game: + timer: QTimer + + @staticmethod + def prepare() -> None: + Game.initial_fill() + @staticmethod def add_status(ant: Ant) -> None: container = QHBoxLayout() image_label = Game.get_image(Config.status_image_path, ant.color) - name = QLabel(ant.name) - status = QLabel(ant.status) + right_container = Game.make_right_container(ant.name, ant.status) container.addWidget(image_label) container.addSpacing(Config.space_1) - container.addWidget(name) - container.addSpacing(Config.space_1) - container.addWidget(status) - - Window.view.insertLayout(0, container) + container.addLayout(right_container) + Game.add_view_container(container) @staticmethod - def add_message(message: str, image_path: Path) -> None: + def add_message(title: str, message: str, image_path: Path) -> None: container = QHBoxLayout() image_label = Game.get_image(image_path, (255, 255, 255)) - message_label = QLabel(message) + right_container = Game.make_right_container(title, message) container.addWidget(image_label) container.addSpacing(Config.space_1) - container.addWidget(message_label) + container.addLayout(right_container) + Game.add_view_container(container) + @staticmethod + def add_view_container(container: QHBoxLayout) -> None: Window.view.insertLayout(0, container) + while Window.view.count() > Config.max_messages: + item = Window.view.takeAt(Window.view.count() - 1) + if item.widget(): + item.widget().deleteLater() + elif item.layout(): + Window.delete_layout(item.layout()) + + @staticmethod + def make_right_container(title: str, message: str) -> QVBoxLayout: + container = QVBoxLayout() + container.setAlignment(Qt.AlignTop) + title_label = QLabel(title) + title_label.setStyleSheet("font-weight: bold;") + message_label = QLabel(message) + container.addWidget(title_label) + container.addWidget(message_label) + return container + @staticmethod def get_image(image_path: Path, border_color: tuple[int, int, int]) -> QLabel: image_label = QLabel() @@ -91,3 +116,20 @@ class Game: status = s.sentence() Ants.set_status(ant, status) + + @staticmethod + def initial_fill() -> None: + if not len(Ants.ants): + return + + ants = sorted(Ants.ants, key=lambda ant: ant.updated) + + for ant in ants: + Game.add_status(ant) + + @staticmethod + def start_loop() -> None: + interval_ms = Config.loop_delay + Game.timer = QTimer() + Game.timer.timeout.connect(Game.get_status) + Game.timer.start(interval_ms) \ No newline at end of file diff --git a/cromulant/main.py b/cromulant/main.py index 86bd654..2b38b45 100644 --- a/cromulant/main.py +++ b/cromulant/main.py @@ -4,6 +4,7 @@ from .config import Config from .utils import Utils from .ants import Ants from .window import Window +from .game import Game def main() -> None: @@ -11,6 +12,9 @@ def main() -> None: Utils.prepare() Ants.prepare() Window.prepare() + Game.prepare() + Game.start_loop() + Window.start() if __name__ == "__main__": diff --git a/cromulant/window.py b/cromulant/window.py index 7234c52..b4e467f 100644 --- a/cromulant/window.py +++ b/cromulant/window.py @@ -11,7 +11,6 @@ from PySide6.QtWidgets import QHBoxLayout from PySide6.QtWidgets import QScrollArea from PySide6.QtGui import QIcon from PySide6.QtCore import Qt # type: ignore -from PySide6.QtCore import QTimer from .config import Config @@ -22,15 +21,12 @@ class Window: root: QHBoxLayout view: QGraphicsView view_scene: QGraphicsScene - timer: QTimer @staticmethod def prepare() -> None: Window.make() Window.add_buttons() Window.add_view() - Window.start_timer() - Window.start() @staticmethod def make() -> None: @@ -94,15 +90,6 @@ class Window: Ants.terminate() - @staticmethod - def start_timer() -> None: - from .game import Game - - interval_ms = 3_000 - Window.timer = QTimer() - Window.timer.timeout.connect(Game.get_status) - Window.timer.start(interval_ms) - @staticmethod def start() -> None: Window.window.show() @@ -111,3 +98,14 @@ class Window: @staticmethod def close() -> None: Window.app.quit() + + @staticmethod + def delete_layout(layout): + while layout.count(): + item = layout.takeAt(0) + if item.widget(): + item.widget().deleteLater() + elif item.layout(): + Window.delete_layout(item.layout()) + + layout.deleteLater()