def change_image(self, image_path: str) -> None: try: self.image.load_image(image_path) except ValueError: self.clear_image() PUBLISHER.queue_message("ImageLoadingError") self.update_image()
def image_selection(self, image_path: str) -> None: try: self.validator.validate_resolution() self.image.scaled_resolution = int(self.state.resolution) except ValueError: return self.image.overlay.clear() PUBLISHER.queue_message("ImageChangeRequest", image_path=image_path)
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("FramerateChangeRequest", function=self.set_framerate), Subscriber("ResolutionChangeRequest", function=self.set_resolution), ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("ImageChangeRequest", function=self.change_image), Subscriber("ImageUpdateRequest", function=self.update_image), Subscriber("ImagePixelReplaceRequest", function=self.replace_pixels), ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def save_command(self) -> None: filename = filedialog.asksaveasfilename( title="Save Image", defaultextension="png", filetypes=[("PNG", ".png"), ("JPG", ".jpg"), ("JPEG", ".jpeg")], ) if not filename: return PUBLISHER.queue_message("ImageSaveRequest", image_path=filename)
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("ImageSelectionRequest", function=self.image_selection), Subscriber("ImageResetRequest", function=self.image_reset), Subscriber("ImageSaveRequest", function=self.image_save), Subscriber("ImageLoadingError", function=self.image_loading_error), ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def maze_solve(self) -> None: try: self.validator.validate_image() self.validator.validate_framerate() except ValueError: return self.image.reset_result() PUBLISHER.queue_process_message("Maze", start=True, state=self.state) self.state.working = True
def maze_reset(self) -> None: PUBLISHER.queue_process_message( "Maze", reset=True, wait_for_response=True, message_timeout=0.2, response_timeout=0.2, ) self.state.working = False
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("MazeSolveRequest", function=self.maze_solve), Subscriber("MazeStopRequest", function=self.maze_stop), Subscriber("MazeResumeRequest", function=self.maze_resume), Subscriber("MazeCancelRequest", function=self.maze_reset), Subscriber("MazeSolveDone", function=self.maze_solve_done), ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def _image_clicked(self, event: tk.Event) -> None: if not self.image.loaded: return x: int = event.x # type: ignore[attr-defined] y: int = event.y # type: ignore[attr-defined] scaled_width, scaled_height = self._get_scaled_size() height, width, _ = self.image.pixels.shape real_x = int(x * (width / scaled_width)) real_y = int(y * (height / scaled_height)) PUBLISHER.queue_message("ImageClicked", x=real_x, y=real_y)
def validate_framerate(self) -> None: try: integer_framerate = int(self.framerate) except ValueError: self.show_framerate_error() PUBLISHER.queue_message("FramerateResetRequest") raise ValueError(f"Invalid Framerate: {self.framerate}") if not isInRange(integer_framerate, MIN_FRAMERATE, MAX_FRAMERATE): PUBLISHER.queue_message("FramerateResetRequest") self.show_framerate_error() raise ValueError(f"Invalid Framerate: {self.framerate}")
def validate_resolution(self) -> None: try: integer_resolution = int(self.resolution) except ValueError: PUBLISHER.queue_message("ResolutionResetRequest") self.show_resolution_error() raise ValueError(f"Invalid Resolution: {self.resolution}") if not isInRange(integer_resolution, MIN_RESOLUTION, MAX_RESOLUTION): PUBLISHER.queue_message("ResolutionResetRequest") self.show_resolution_error() raise ValueError(f"Invalid Resolution: {self.resolution}")
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("PointChangeRequest", function=self.set_status), Subscriber("ImageClicked", function=self.set_point), Subscriber( "ImageChangeRequest", function=lambda *args, **kwargs: self.reset_points(), ), ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def set_point(self, x: int, y: int) -> None: if self.state.working or not self.state.image.loaded: return if self.status == PointStatus.START: self.start_point = Point(x, y) elif self.status == PointStatus.END: self.end_point = Point(x, y) if self.status != PointStatus.NONE: self.image.reset_result() self.image.overlay.clear() self._set_start_point() self._set_end_point() PUBLISHER.queue_message("ImageUpdateRequest") self.status = PointStatus.NONE
def select_image(self) -> None: filename = filedialog.askopenfilename(title="Select an Image") if not filename: return PUBLISHER.queue_message("MazeCancelRequest") PUBLISHER.queue_message("ImageSelectionRequest", image_path=filename)
def solve_command(self) -> None: PUBLISHER.queue_message("MazeSolveRequest")
def stop_command(self) -> None: PUBLISHER.queue_message("MazeStopRequest")
def maze_resume(self) -> None: PUBLISHER.queue_process_message("Maze", resume=True)
def maze_stop(self) -> None: PUBLISHER.queue_process_message("Maze", stop=True)
def resume_command(self) -> None: PUBLISHER.queue_message("MazeResumeRequest")
def _setup_subscribers(self) -> None: subscribers = [ Subscriber("FramerateResetRequest", function=self.reset) ] for subscriber in subscribers: PUBLISHER.register_subscriber(subscriber)
def image_reset(self) -> None: self.image.reset_result() PUBLISHER.queue_message("ImageUpdateRequest")
def start_point_command(self) -> None: PUBLISHER.queue_message("PointChangeRequest", kind="start")
def end_point_command(self) -> None: PUBLISHER.queue_message("PointChangeRequest", kind="end")
def _entry_changed(self, *_: Any) -> None: resolution = self.string_var.get() PUBLISHER.queue_message("ResolutionChangeRequest", resolution=resolution)
def _periodic_refresh(self) -> None: PUBLISHER.send_messages() self.root.after(1000 // 60, self._periodic_refresh)
def cancel_command(self) -> None: PUBLISHER.queue_message("MazeCancelRequest")
from mazesolver.controller import ApplicationController from mazesolver.gui import ApplicationGui from mazesolver.solver import Solver from mazesolver.pubsub import PUBLISHER, ProcessSubscriber from mazesolver.image import MazeImage if __name__ == "__main__": image = MazeImage() controller = ApplicationController(image) gui = ApplicationGui(image) solver = Solver() subscriber = ProcessSubscriber("Maze", worker=solver) PUBLISHER.register_subscriber(subscriber) gui.start()
def _entry_changed(self, *_: Any) -> None: framerate = self.string_var.get() PUBLISHER.queue_message("FramerateChangeRequest", framerate=framerate)