jhanarato / uposatha-inky

Display the uposatha on a Pimoroni Inky display
MIT License
0 stars 0 forks source link

Drawing module #6

Closed jhanarato closed 1 year ago

jhanarato commented 1 year ago

Currently image components have a method to draw themselves. I've felt for a long time that they should instead be drawn on something. I think the way to do this is to TDD a drawing layer. It should have the following features:

This could work like so:

@dataclass
class Text:
    text: str
    font_name: str
    font_size: int
    colour: str

heading = Text("Uposatha", "Roboto", "20", "Black")

drawing.draw(heading)

Using functools.singledispatch() we can pass in different types such as Line, Circle etc.

We also need to handle composite types like the DayOfWeekIcon. This has a filled circle and text. This could simply be a sequence of primitives to draw with their offsets.

And we need a way of getting component sizes.

jhanarato commented 1 year ago

Dale has cast shade on this idea and recommends looking at the double dispatch pattern:

Overall, I think I like the final plan, in particular the notion of having a class that carries an ImageDraw around. I've never used singledispatch, but it certainly seems like it would eliminate a lot of draw_foo methods.

You could address this with a "double-dispatch pattern", ie

class Drawable(Protocol): # or ABC, as you prefer
    def draw(self, imageDraw): ...
class Drawing:
    def __init__(self, image: ImageDraw):
        self._image = image
    def draw(self, other: Drawable):
        other.draw(self._image) # or maybe just self?
class Text:
    ...
    def draw(self, image):
        # however you draw the text on the image
class OtherDrawable: ...
# and so on

This tends to be a bit boiler-plate heavy, but you already (I think) need the Text, etc, classes so it's just changing where the real draw method lives. I've never used double-dispatch (to my recollection) but I think it might be the "classic" oo approach here. As I noted, instead of passing an ImageDraw to the drawables, if Drawing maintains some sort of state, like a defalt color, current position, default font, ..., you might want to pass a Drawing instead.

jhanarato commented 1 year ago

That's a misunderstanding. Double dispatch doesn't solve any problems. I think I'm OK with single dispatch.