From: mar77i Date: Fri, 14 Feb 2025 09:42:01 +0000 (+0100) Subject: start redoing bookpaint X-Git-Url: https://git.mar77i.info/?a=commitdiff_plain;h=a992af56971241ce9983ef3c48325595708c49d9;p=zenbook_gui start redoing bookpaint --- diff --git a/bookpaint/bookpaint.py b/bookpaint/bookpaint.py index aba202b..7ee8e48 100644 --- a/bookpaint/bookpaint.py +++ b/bookpaint/bookpaint.py @@ -1,255 +1,9 @@ -import sys -from logging import getLogger -from pathlib import Path - import pygame -from ui import Button, Child, FPSWidget, Label, Modal, RepeatButton, Root -from layout.layout import BarLayout - -from .draw_ui import DrawImage - -logger = getLogger(__name__) - - -class BookPaintMenu(Modal): - PAGE_EXT = ".png" - root: "BookPaint" - - def __init__(self, root): - super().__init__(root) - size = self.surf.get_size() - label_bar_layout = BarLayout(size, 1536, 48) - button_bar_layout = BarLayout(size, 1664, 48) - manager = self.root.book_manager - self.page_label = Label( - root, - label_bar_layout.get_rect((256, 96)), - manager.get_page_of_total(), - ) - self.filename_label = Label( - root, - label_bar_layout.get_rect((256, 96)), - manager.file_name.name, - ) - self.nav_children = ( - Button( - root, - button_bar_layout.get_rect((192, 96)), - "|<", - manager.first_page, - ), - RepeatButton( - root, - button_bar_layout.get_rect((192, 96)), - "<", - manager.prev_page, - ), - RepeatButton( - root, - button_bar_layout.get_rect((192, 96)), - ">", - manager.next_page, - ), - Button( - root, - button_bar_layout.get_rect((192, 96)), - ">|", - manager.last_page, - ), - Button( - root, - button_bar_layout.get_rect((192, 96)), - "new", - manager.new_page, - ), - self.page_label, - self.filename_label, - ) - self.hidden = None - self.nav_rect = pygame.Rect((672, 1456), (1536, 288)) - root.children.extend( - ( - Button( - root, - pygame.Rect((size[0] - 128, 0), (128, 96)), - "×", - root.quit, - ), - Button( - root, - pygame.Rect((size[0] - 256, 0), (128, 96)), - "_", - root.iconify, - ), - *self.nav_children, - ), - ) - label_bar_layout() - button_bar_layout() - - def key_escape(self): - self.deactivate() - - KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: key_escape}} - - def update_nav_bar(self, page_of_total, file_name): - self.page_label.value = page_of_total - self.filename_label.value = file_name - root = self.root - self.backsurf.blit(root.draw_image.surface, (0, 0)) - if self.hidden is not None: - return - hidden_children = [ - child - for child in root.children - if child is not self and child not in self.nav_children - ] - for child in hidden_children: - root.children.remove(child) - self.hidden = (self.tintsurf, hidden_children) - self.tintsurf = None - self.dirty = True - - def draw(self): - super().draw() - pygame.draw.rect(self.root.surf, "black", self.nav_rect) - pygame.draw.rect(self.root.surf, "white", self.nav_rect, 1) - - def deactivate(self): - super().deactivate() - self.root.book_paint_menu = None - - def handle_mousemotion(self, ev): - if self.hidden is None or self.nav_rect.collidepoint(ev.pos): - return - self.tintsurf = self.hidden[0] - self.root.children.extend(self.hidden[1]) - self.hidden = None - self.dirty = True - - -class BookManager(Child): - root: "BookPaint" - IMAGE_EXT = ".png" - - @staticmethod - def get_book_dir(argv): - num_args = len(argv) - if num_args > 2: - raise ValueError("Too many arguments") - elif num_args == 2: - book_dir = Path(argv[1]) - if not book_dir.exists() or not book_dir.is_dir(): - raise ValueError(f"Path does not exist or is not a dir: {argv[1]}") - return book_dir - return Path().absolute() +from ui import Root - @classmethod - def get_pages(cls, book_dir): - pages = set() - for file in book_dir.iterdir(): - if file.suffixes != [cls.IMAGE_EXT]: - continue - try: - page_no = int(file.name[:-len(cls.IMAGE_EXT)], 10) - except ValueError: - logger.info(f"Skipping {file.name}: failed to parse page nunber") - continue - pages.add(iter((page_no, file))) - return [next(x) for x in sorted(pages, key=next)] - - @property - def page_zero(self): - return self.book_dir / f"0{self.IMAGE_EXT}" - - def __init__(self, root): - super().__init__(root) - self.book_dir = self.get_book_dir(sys.argv) - self.pages = self.get_pages(self.book_dir) - num_pages = len(self.pages) - if num_pages > 0: - self.current_page = num_pages - 1 - self.file_name = self.pages[self.current_page] - else: - self.current_page = 0 - self.file_name = self.page_zero - self.pages.append(self.file_name) - - def maybe_load(self): - if self.file_name.exists(): - return pygame.image.load(self.file_name) - return None - - def get_page_of_total(self): - return f"{self.current_page + 1} / {len(self.pages)}" - - def get_last_existing_page(self): - page_iter = iter(reversed(self.pages)) - try: - page = next(page_iter) - while not page.exists(): - page = next(page_iter) - except StopIteration: - return self.page_zero - return page - - def new_page(self): - self.current_page = len(self.pages) - last_page = self.get_last_existing_page() - self.file_name = ( - self.book_dir - / f"{int(last_page.name[:-len(self.IMAGE_EXT)], 10) + 1}{self.IMAGE_EXT}" - ) - if self.file_name in self.pages: - self.current_page = self.pages.index(self.file_name) - else: - self.pages.append(self.file_name) - self.root.draw_image.surface.fill(self.root.background_color) - self.dirty = True - self.maybe_update_menu() - - def maybe_update_menu(self): - menu = self.root.book_paint_menu - if menu is not None and menu in self.root.children: - menu.update_nav_bar(self.get_page_of_total(), self.file_name.name) - - def prev_page(self): - if self.current_page == 0: - return - self.update_current_page(self.current_page - 1) - - def next_page(self): - if self.current_page == len(self.pages) - 1: - return - self.update_current_page(self.current_page + 1) - - def first_page(self): - self.update_current_page(0) - - def last_page(self): - if len(self.pages) == 0: - return - self.update_current_page(len(self.pages) - 1) - - def update_current_page(self, current_page): - if self.current_page == current_page: - return - self.current_page = current_page - if self.current_page >= len(self.pages): - self.current_page = max(len(self.pages) - 1, 0) - if self.current_page == 0: - self.file_name = self.page_zero - else: - self.file_name = self.pages[self.current_page] - self.root.draw_image.load_surf(self.maybe_load(), self.root.background_color) - self.dirty = True - self.maybe_update_menu() - - def save(self): - draw_image = self.root.draw_image - pygame.image.save(draw_image.surface, self.file_name) - draw_image.drawing_dirty = False +from .bookpaint_menu import BookPaintMenu +from .draw_image import DrawImage class BookPaint(Root): @@ -258,36 +12,18 @@ class BookPaint(Root): def __init__(self): pygame.init() super().__init__( - pygame.display.set_mode(flags=pygame.FULLSCREEN), + pygame.display.set_mode((0, 0), pygame.FULLSCREEN, display=0), pygame.font.Font(None, size=96), ) - # todo: this should be configurable per book - self.background_color = self.BACKGROUND_COLOR - self.book_manager = BookManager(self) - self.book_paint_menu = None - self.draw_image = DrawImage( - self, - self.surf.get_rect(), - self.BACKGROUND_COLOR, - self.book_manager.maybe_load(), - ) - self.children.extend((self.book_manager, self.draw_image, FPSWidget(self))) + self.background_color = "blue" + self.draw_image = DrawImage(self) + self.draw_image.clear(self.background_color) + self.menu = BookPaintMenu(self) def key_escape(self): - if self.draw_image in self.children: - self.book_paint_menu = BookPaintMenu(self) + self.menu.activate() + + KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: key_escape}} def quit(self): self.running = False - - def iconify(self): - pygame.display.iconify() - - def key_save(self): - if self.draw_image in self.children: - self.book_manager.save() - - KEY_METHODS = { - frozenset(set()): {pygame.K_ESCAPE: key_escape}, - frozenset({pygame.KMOD_CTRL}): {pygame.K_s: key_save}, - } diff --git a/bookpaint/bookpaint_menu.py b/bookpaint/bookpaint_menu.py new file mode 100644 index 0000000..314e0e2 --- /dev/null +++ b/bookpaint/bookpaint_menu.py @@ -0,0 +1,20 @@ +import pygame + +from ui import Button, Modal + + +class BookPaintMenu(Modal): + def __init__(self, parent): + super().__init__(parent) + Button( + self, + pygame.Rect((200, 200), (256, 128)), + "×", + self.root.quit, + ) + + def key_escape(self): + self.deactivate() + self.dirty = True + + KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: key_escape}} diff --git a/bookpaint/draw_image.py b/bookpaint/draw_image.py new file mode 100644 index 0000000..1179854 --- /dev/null +++ b/bookpaint/draw_image.py @@ -0,0 +1,16 @@ +import pygame + +from ui import Child + + +class DrawImage(Child): + def __init__(self, parent): + super().__init__(parent) + self.surface = pygame.Surface(self.surf.get_size(), 0, 24) + self.clear(self.root.BACKGROUND_COLOR) + + def clear(self, background_color): + self.surface.fill(background_color) + + def draw(self): + self.surf.blit(self.surface, (0, 0)) diff --git a/bookpaint/draw_ui.py b/bookpaint/draw_ui.py deleted file mode 100644 index d362368..0000000 --- a/bookpaint/draw_ui.py +++ /dev/null @@ -1,65 +0,0 @@ -import pygame - -from ui import Button, Child - - -class DrawImage(Child): - def __init__(self, parent, rect, background_color=None, load_surf=None): - super().__init__(parent) - self.pos = rect.topleft - self.surface = pygame.Surface(rect.size, 0, 24) - self.load_surf(load_surf, background_color) - self.last_pos = None - self.color = "white" - self.line = pygame.draw.line - self.drawing_dirty = False - - def load_surf(self, load_surf, background_color): - self.drawing_dirty = False - if load_surf is None: - self.surface.fill(background_color) - return - size = self.surface.get_size() - if load_surf.get_size() != size: - load_surf = pygame.transform.scale(load_surf, size) - self.surface.blit(load_surf, (0, 0)) - - def draw_line(self, pos): - self.drawing_dirty = True - if self.last_pos is not None: - self.line(self.surface, self.color, self.last_pos, pos) - else: - self.surface.set_at(pos, self.color) - - def handle_mousebuttondown(self, ev): - self.draw_line(ev.pos) - self.last_pos = ev.pos - self.dirty = True - - def handle_mousemotion(self, ev): - if self.last_pos is None: - return - self.draw_line(ev.pos) - self.last_pos = ev.pos - self.dirty = True - - def handle_mousebuttonup(self, ev): - self.draw_line(ev.pos) - if self.last_pos is not None: - self.last_pos = None - self.dirty = True - - def draw(self): - self.surf.blit(self.surface, self.pos) - - -class ColorButton(Button): - def __init__(self, parent, rect, color, callback, highlight=False): - super().__init__(parent, rect, None, callback, highlight) - self.color = color - - def draw(self): - pygame.draw.rect(self.surf, self.color, self.rect) - pygame.draw.rect( - self.surf, "gray" if self.pushed else "honeydew4", self.rect, 8 - ) diff --git a/ui/modal.py b/ui/modal.py index a9a1f99..e7f612c 100644 --- a/ui/modal.py +++ b/ui/modal.py @@ -8,15 +8,6 @@ from .parent import Parent class Modal(Focusable, Parent, Child): def __init__(self, parent, enabled=False): super().__init__(parent, enabled) - self.activate = self.activate - self.deactivate = self._check_enabled(self.deactivate) - - def _check_enabled(self, method, cmp=True): - def inner(*args, **kwargs): - if self.enabled is cmp: - return method(*args, **kwargs) - return None - return inner def activate(self): if self.enabled: