diff --git a/triditko/__init__.py b/triditko/__init__.py index da63cc8..77cdf37 100644 --- a/triditko/__init__.py +++ b/triditko/__init__.py @@ -1 +1,7 @@ __version__ = '0.0.1a1' + +import abc +import pygame +class Renderer(abc.ABC): + @abc.abstractmethod + def render(self, item: str, w: int, h: int) -> pygame.Surface: ... diff --git a/triditko/__main__.py b/triditko/__main__.py index 830f59d..3997126 100644 --- a/triditko/__main__.py +++ b/triditko/__main__.py @@ -1,5 +1,99 @@ +import pygame as pg +import pygame.freetype as pgft +from triditko.renderers import DrawItemNameRenderer +from triditko.utils import align +import json +import importlib + +def get_base_surface(screen_size, categories) -> (pg.Surface, (int, int)): + """Returns a surface template with legend, suitable as a basis for rendering the rest. + + Very barebones, will need to be remade for advanced features.""" + w, h = screen_size + result = pg.Surface((w, h)) + result.fill((0,0,0)) + + label_height = h//5 + label_width = w//len(categories) + label_pos_y = label_height*4 + renderer = DrawItemNameRenderer() + # NOTE: I wanted them to have a border, but too lazy. + for i, cat in enumerate(categories): + label = renderer.render(cat, label_width, label_height) + result.blit(label, (i*label_width, label_pos_y)) + return result, (w, label_pos_y) def main(): - print('hi') + # Inspired by quickstart at + pg.init() + initial_screen_size = (800, 600) + screen = pg.display.set_mode( + initial_screen_size, # size + pg.RESIZABLE, # flags; TODO: pg.OPENGL? + ) + clock = pg.time.Clock() + font = pgft.Font(None) + + #TODO: use argparse and reasonable stuff + categories = ['good', 'bad', 'ugly'] + bindings = { + pg.K_1: 'good', + pg.K_2: 'bad', + pg.K_3: 'ugly', + } + escape_char = pg.K_ESCAPE + items = [f'item_{i}' for i in range(20)] + renderer = 'triditko.renderers:DrawItemNameRenderer' + outputfile = '/dev/stdout' + + result = {k: [] for k in categories} + + # dafuq boilerplate? + renderer_module, renderer_path = renderer.split(':') + renderer_module = importlib.import_module(renderer_module) + for sgmt in renderer_path.split('.'): + renderer_module = getattr(renderer_module, sgmt) + renderer = renderer_module() # FIXME: not a module anymore. + + # TODO: draw first or at least create an event to do so? + + base_surface, (item_w, item_h) = get_base_surface(initial_screen_size, categories) + current_item = 0 + running = True + pressed = False + while running: + # event loop, yada yada + for event in pg.event.get(): + if event.type == pg.QUIT: + running = False # The while is too outer :-/ + elif event.type == pg.KEYDOWN and not pressed: + # We need to do our own press handling + pressed = True + if event.key == escape_char: + running = False + elif event.key in bindings: + cat = bindings[event.key] + result[cat].append(items[current_item]) + current_item += 1 + # FIXME: too hacky error handling! + running = current_item < len(items) + elif pressed and event.type == pg.KEYUP: + # FIXME: does not work for multiple presses! + pressed = False + # FIXME: hacky + if not running: continue + # It is unnecessary (bad, even) to redraw the item every tick, but good for PoC + item_sfc = base_surface.copy() + item_rendered = renderer.render(items[current_item], item_w, item_h) + pos = align((item_w, item_h), item_rendered, 'cc') + item_sfc.blit(item_rendered, pos) + screen.blit(item_sfc, (0,0)) + pg.display.flip() + clock.tick(60) + + with open(outputfile, 'wt') as f: + json.dump(result, f) + pg.quit() + if __name__ == '__main__': main() diff --git a/triditko/renderers.py b/triditko/renderers.py new file mode 100644 index 0000000..caa09e0 --- /dev/null +++ b/triditko/renderers.py @@ -0,0 +1,14 @@ +from triditko import Renderer +from triditko.utils import align +import pygame as pg +import pygame.freetype as pgft + +class DrawItemNameRenderer(Renderer): + def render(self, item, w, h): + result = pg.Surface((w, h)) + font = pgft.Font(None, size=25) + rendered, _brect = font.render(item, fgcolor=(255,255,255)) #white. + pos = align(result, rendered) + result.blit(rendered, pos) + return result + diff --git a/triditko/utils.py b/triditko/utils.py new file mode 100644 index 0000000..988c440 --- /dev/null +++ b/triditko/utils.py @@ -0,0 +1,37 @@ +import pygame as pg + +def _get_dimen(obj) -> (int, int): + """Gets width, height from various representations. + + Permitted representations: + - pg.Surface + - (w, h) tuple + - tbd + """ + if isinstance(obj, pg.Surface): + return obj.get_size() + if isinstance(obj, tuple): + assert isinstance(obj[0], int) + assert isinstance(obj[1], int) + return obj[0], obj[1] + raise NotImplementedError(f"bad input {obj} for {__name__}._get_dimen") + +def align(bottom, top, alignment='cc'): + """Returns the position for top surface so that it is aligned to the bottom one in the specified way. + + alignment is t/c/b × l/c/r.""" # Go figure what that means lol. + # Somehow this is not part of pygame? + valign, halign = alignment + bw, bh = _get_dimen(bottom) + tw, th = _get_dimen(top) + x = { + 'l': 0, + 'r': bw - tw, + 'c': (bw//2) - (tw//2), + }[halign] + y = { + 't': 0, + 'b': bh - th, + 'c': (bh//2) - (th//2), + }[valign] + return x, y