-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):
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},
- }
+++ /dev/null
-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
- )