From 95bc45af8bfbe72bac6a3946c522eb32d4dbebbc Mon Sep 17 00:00:00 2001 From: Auric Vente Date: Fri, 19 Jul 2024 00:33:51 -0600 Subject: [PATCH] Mods --- cromulant/ants.py | 38 ++++++++++++++++++------- cromulant/config.py | 1 + cromulant/ruff.toml | 1 + cromulant/window.py | 68 ++++++++++++++++++++++++++++++++------------- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/cromulant/ants.py b/cromulant/ants.py index 217e837..66708b6 100644 --- a/cromulant/ants.py +++ b/cromulant/ants.py @@ -7,6 +7,8 @@ from .config import Config from .utils import Utils from .storage import Storage +from .window import Window + class Ant: def __init__(self) -> None: @@ -61,26 +63,33 @@ class Ants: Ants.get_ants() @staticmethod - def hatch() -> None: + def hatch(num: int = 1) -> None: from .game import Game if len(Ants.ants) >= Config.max_ants: - Utils.print("Too many ants") return now = Utils.now() - ant = Ant() - ant.created = now - ant.updated = now - ant.name = Utils.random_name() - ant.color = Utils.random_color() + for _ in range(num): + ant = Ant() + ant.created = now + ant.updated = now + ant.name = Utils.random_name() + ant.color = Utils.random_color() + + Ants.ants.append(ant) + image_path = Config.hatched_image_path + Game.add_message("Hatched", f"{ant.name} is born", image_path) + + if len(Ants.ants) >= Config.max_ants: + break - Ants.ants.append(ant) Ants.save() - image_path = Config.hatched_image_path - Game.add_message("Hatched", f"{ant.name} is born", image_path) + @staticmethod + def hatch_burst() -> None: + Ants.hatch(Config.hatch_burst) @staticmethod def terminate() -> None: @@ -96,6 +105,15 @@ class Ants: image_path = Config.terminated_image_path Game.add_message("Terminated", f"{ant.name} is gone", image_path) + @staticmethod + def terminate_all() -> None: + def action() -> None: + Ants.ants = [] + Ants.save() + Window.clear_view() + + Window.confirm("Terminate all ants?", action) + @staticmethod def get_random_ant() -> Ant: return random.choice(Ants.ants) diff --git a/cromulant/config.py b/cromulant/config.py index ad66a71..fe0ba13 100644 --- a/cromulant/config.py +++ b/cromulant/config.py @@ -25,6 +25,7 @@ class Config: loop_delay_fast: int = 3_000 loop_delay_normal: int = 20_000 loop_delay_slow: int = 60_000 + hatch_burst: int = 3 @staticmethod def prepare() -> None: diff --git a/cromulant/ruff.toml b/cromulant/ruff.toml index 2c3416d..d9a89b1 100644 --- a/cromulant/ruff.toml +++ b/cromulant/ruff.toml @@ -38,6 +38,7 @@ select = [ ignore = [ "W292", "N802", + "N815", ] exclude = [ diff --git a/cromulant/window.py b/cromulant/window.py index 67e6831..e7b2e28 100644 --- a/cromulant/window.py +++ b/cromulant/window.py @@ -1,5 +1,8 @@ from __future__ import annotations +from typing import Any +from collections.abc import Callable + from PySide6.QtWidgets import QApplication # type: ignore from PySide6.QtWidgets import QMainWindow from PySide6.QtWidgets import QWidget @@ -11,12 +14,25 @@ from PySide6.QtWidgets import QScrollArea from PySide6.QtWidgets import QComboBox from PySide6.QtWidgets import QLayout from PySide6.QtWidgets import QSizePolicy -from PySide6.QtGui import QIcon # type: ignore +from PySide6.QtWidgets import QMessageBox +from PySide6.QtGui import QMouseEvent # type: ignore +from PySide6.QtGui import QIcon from PySide6.QtCore import Qt # type: ignore +from PySide6.QtCore import Signal from .config import Config +class SpecialButton(QPushButton): # type: ignore + middleClicked = Signal() + + def mousePressEvent(self, e: QMouseEvent) -> None: + if e.button() == Qt.MouseButton.MiddleButton: + self.middleClicked.emit() + else: + super().mousePressEvent(e) + + class Window: app: QApplication window: QMainWindow @@ -51,21 +67,23 @@ class Window: @staticmethod def add_buttons() -> None: + from .ants import Ants from .game import Game - btn_hatch = QPushButton("Hatch") - btn_terminate = QPushButton("Terminate") + btn_hatch = SpecialButton("Hatch") + btn_hatch.clicked.connect(lambda e: Ants.hatch()) + btn_hatch.middleClicked.connect(lambda: Ants.hatch_burst()) - btn_close = QPushButton("Close") - - btn_hatch.clicked.connect(Window.hatch) - btn_terminate.clicked.connect(Window.terminate) + btn_terminate = SpecialButton("Terminate") + btn_terminate.clicked.connect(lambda e: Ants.terminate()) + btn_terminate.middleClicked.connect(lambda: Ants.terminate_all()) Window.speed = QComboBox() Window.speed.addItems(["Fast", "Normal", "Slow"]) Window.speed.setCurrentIndex(1) Window.speed.currentIndexChanged.connect(Game.update_speed) + btn_close = QPushButton("Close") btn_close.clicked.connect(Window.close) layout = QHBoxLayout() @@ -90,18 +108,6 @@ class Window: scroll_area.setWidget(container) Window.root.addWidget(scroll_area) - @staticmethod - def hatch() -> None: - from .ants import Ants - - Ants.hatch() - - @staticmethod - def terminate() -> None: - from .ants import Ants - - Ants.terminate() - @staticmethod def start() -> None: Window.window.show() @@ -125,3 +131,27 @@ class Window: @staticmethod def expand(widget: QWidget) -> None: widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) + + @staticmethod + def confirm(message: str, action: Callable[..., Any]) -> None: + msg_box = QMessageBox() + msg_box.setIcon(QMessageBox.Icon.Question) + msg_box.setWindowTitle("Confirm") + msg_box.setText(message) + + msg_box.setStandardButtons( + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No + ) + + msg_box.setDefaultButton(QMessageBox.StandardButton.No) + msg_box.button(QMessageBox.StandardButton.Yes).clicked.connect(action) + msg_box.exec() + + @staticmethod + def clear_view() -> None: + while Window.view.count(): + item = Window.view.takeAt(0) + if item.widget(): + item.widget().deleteLater() + elif item.layout(): + Window.delete_layout(item.layout())