def __init__(self):
     self.lcd = Screen(
         4)  # Same amount as in printline_decoder.py for debugging with it
     sw, sh = self.lcd.dimensions()
     screensize = (int(self.square * sw + 0.5), int(self.square * sh + 0.5))
     self.screen = pygame.display.set_mode(screensize)
     self.lcddraw = Pgdraw(self.square, self.screen)
     self.source = pygame.image.load(sys.argv[1])
     self.drawmode = self.DRAW_CIRCLE
     self.drawsize = 20
     self.lastmouse = None
     self.lcd.import_pic(self.source, self.square)
     self.repaint()
 def __init__(self):
     self.lcd = Screen(4)  # Same amount as in printline_decoder.py for debugging with it
     sw, sh = self.lcd.dimensions()
     screensize = (int(self.square * sw + 0.5), int(self.square * sh + 0.5))
     self.screen = pygame.display.set_mode(screensize)
     self.lcddraw = Pgdraw(self.square, self.screen)
     self.source = pygame.image.load(sys.argv[1])
     self.drawmode = self.DRAW_CIRCLE
     self.drawsize = 20
     self.lastmouse = None
     self.lcd.import_pic(self.source, self.square)
     self.repaint()
class App(object):
    """The drawing app, not _directly_ related to metro screen bit handling"""
    square = 20  # Width of one lcd column in pixels
    # bit masks, or'd together
    DRAW_ENABLED = 1  # affect bits?
    DRAW_PAINT = 2  # paint bits on or off?
    DRAW_CIRCLE = 4  # circle mode?

    def __init__(self):
        self.lcd = Screen(
            4)  # Same amount as in printline_decoder.py for debugging with it
        sw, sh = self.lcd.dimensions()
        screensize = (int(self.square * sw + 0.5), int(self.square * sh + 0.5))
        self.screen = pygame.display.set_mode(screensize)
        self.lcddraw = Pgdraw(self.square, self.screen)
        self.source = pygame.image.load(sys.argv[1])
        self.drawmode = self.DRAW_CIRCLE
        self.drawsize = 20
        self.lastmouse = None
        self.lcd.import_pic(self.source, self.square)
        self.repaint()

    def repaint(self):
        """Paint the whole screen again"""
        self.screen.blit(self.source, (0, 0))
        self.lcd.draw(self.lcddraw)
        if self.drawmode & self.DRAW_CIRCLE:
            self.plot_circle()
        pygame.display.flip()

    def click_bit(self, pos):
        """Toggle just one bit and repaint the corresponding column"""
        pos = self.lcddraw.map_from(pos)
        bit = self.lcd.flipbit(pos, self.drawmode & self.DRAW_PAINT)

        if bit is not None:
            if not self.drawmode & self.DRAW_PAINT:
                # print background
                col = bit // Column.BITS
                topleft = (self.square * col * Column.REALWIDTH, 0)
                rect = topleft + (self.square * Column.REALWIDTH,
                                  self.square * Column.height())
                self.screen.blit(self.source, topleft, rect)

            # this prints whole column
            self.lcd.draw(self.lcddraw, bit)
            pygame.display.flip()

    def apply_click(self, pos):
        """Do something when mouse has been clicked"""
        if self.drawmode & self.DRAW_CIRCLE:
            self.click_bits(pos)
        else:
            self.click_bit(pos)

    def plot_circle(self):
        """Print the helpful circle brush, if the point is available"""
        if self.lastmouse is not None:
            pygame.gfxdraw.circle(self.screen,
                                  self.lastmouse[0], self.lastmouse[1],
                                  int(self.drawsize), (255, 0, 255))

    def click_bits(self, pos):
        """Toggle all bits inside the mouse circle and repaint them"""
        if self.lastmouse is None:
            # skip initial draw with nothing to clear
            self.lastmouse = pos
            return
        # need to update all interior bits
        # just repaint the whole columns that the updated region overlaps
        # note that we need to wipe out the last circle also
        mousex0 = min(self.lastmouse[0], pos[0])
        mousex1 = max(self.lastmouse[0], pos[0])
        mousey0 = min(self.lastmouse[1], pos[1])
        mousey1 = max(self.lastmouse[1], pos[1])

        # map background positions to column borders
        x0 = int(
            (mousex0 - self.drawsize) / float(self.square) / Column.REALWIDTH)
        x1 = int((mousex1 + self.drawsize) / float(self.square) /
                 Column.REALWIDTH) + 1
        x0 *= Column.REALWIDTH
        x1 *= Column.REALWIDTH
        w = x1 - x0

        #self.screen.fill(0) # debug mode
        rectpos = (int(self.square * x0), 0)
        rectsiz = (int(self.square * w), ceil(self.square * Column.height()))
        self.screen.blit(self.source, rectpos, rectpos + rectsiz)

        if self.drawmode & self.DRAW_ENABLED:
            # update bit values, no drawing yet
            mousepos = self.lcddraw.map_from(pos)
            r = self.drawsize / float(self.square)
            yes = self.drawmode & self.DRAW_PAINT
            self.lcd.flipbits(mousepos, r, yes)

        # redraw the column data
        region = [(mousex0 - self.drawsize, mousey0 - self.drawsize),
                  (mousex1 + self.drawsize, mousey1 + self.drawsize)]
        region = map(self.lcddraw.map_from, region)
        self.lcd.draw(self.lcddraw, region=region)

        self.lastmouse = pos
        self.plot_circle()

        pygame.display.flip()

    def doevent(self, e):
        """Pygame event handler"""
        # assume just one mouse button at once
        if e.type == pygame.QUIT:
            return False
        elif e.type == pygame.KEYDOWN:
            if e.key == pygame.K_ESCAPE:
                return False
            if e.key == pygame.K_SPACE:
                print "\n".join(self.lcd.machinebits())
        elif e.type == pygame.MOUSEBUTTONDOWN:
            if e.button == 1:
                self.drawmode |= self.DRAW_PAINT | self.DRAW_ENABLED
                self.apply_click(e.pos)
            if e.button == 2:
                self.drawmode ^= self.DRAW_CIRCLE
                self.repaint()
            elif e.button == 3:
                self.drawmode |= self.DRAW_ENABLED
                self.lastmouse = e.pos
                self.apply_click(e.pos)
            elif e.button == 4:
                if self.drawsize < self.square * Column.height() / 2:
                    self.drawsize *= 1.1
                    self.repaint()
            elif e.button == 5:
                if self.drawsize > 5:
                    self.drawsize /= 1.1
                    self.repaint()
        elif e.type == pygame.MOUSEMOTION:
            if self.drawmode:
                self.apply_click(e.pos)
        elif e.type == pygame.MOUSEBUTTONUP:
            self.drawmode &= ~(self.DRAW_PAINT | self.DRAW_ENABLED)
        return True

    def run(self):
        while self.doevent(pygame.event.wait()):
            pass
class App(object):
    """The drawing app, not _directly_ related to metro screen bit handling"""

    square = 20  # Width of one lcd column in pixels
    # bit masks, or'd together
    DRAW_ENABLED = 1  # affect bits?
    DRAW_PAINT = 2  # paint bits on or off?
    DRAW_CIRCLE = 4  # circle mode?

    def __init__(self):
        self.lcd = Screen(4)  # Same amount as in printline_decoder.py for debugging with it
        sw, sh = self.lcd.dimensions()
        screensize = (int(self.square * sw + 0.5), int(self.square * sh + 0.5))
        self.screen = pygame.display.set_mode(screensize)
        self.lcddraw = Pgdraw(self.square, self.screen)
        self.source = pygame.image.load(sys.argv[1])
        self.drawmode = self.DRAW_CIRCLE
        self.drawsize = 20
        self.lastmouse = None
        self.lcd.import_pic(self.source, self.square)
        self.repaint()

    def repaint(self):
        """Paint the whole screen again"""
        self.screen.blit(self.source, (0, 0))
        self.lcd.draw(self.lcddraw)
        if self.drawmode & self.DRAW_CIRCLE:
            self.plot_circle()
        pygame.display.flip()

    def click_bit(self, pos):
        """Toggle just one bit and repaint the corresponding column"""
        pos = self.lcddraw.map_from(pos)
        bit = self.lcd.flipbit(pos, self.drawmode & self.DRAW_PAINT)

        if bit is not None:
            if not self.drawmode & self.DRAW_PAINT:
                # print background
                col = bit // Column.BITS
                topleft = (self.square * col * Column.REALWIDTH, 0)
                rect = topleft + (self.square * Column.REALWIDTH, self.square * Column.height())
                self.screen.blit(self.source, topleft, rect)

            # this prints whole column
            self.lcd.draw(self.lcddraw, bit)
            pygame.display.flip()

    def apply_click(self, pos):
        """Do something when mouse has been clicked"""
        if self.drawmode & self.DRAW_CIRCLE:
            self.click_bits(pos)
        else:
            self.click_bit(pos)

    def plot_circle(self):
        """Print the helpful circle brush, if the point is available"""
        if self.lastmouse is not None:
            pygame.gfxdraw.circle(self.screen, self.lastmouse[0], self.lastmouse[1], int(self.drawsize), (255, 0, 255))

    def click_bits(self, pos):
        """Toggle all bits inside the mouse circle and repaint them"""
        if self.lastmouse is None:
            # skip initial draw with nothing to clear
            self.lastmouse = pos
            return
        # need to update all interior bits
        # just repaint the whole columns that the updated region overlaps
        # note that we need to wipe out the last circle also
        mousex0 = min(self.lastmouse[0], pos[0])
        mousex1 = max(self.lastmouse[0], pos[0])
        mousey0 = min(self.lastmouse[1], pos[1])
        mousey1 = max(self.lastmouse[1], pos[1])

        # map background positions to column borders
        x0 = int((mousex0 - self.drawsize) / float(self.square) / Column.REALWIDTH)
        x1 = int((mousex1 + self.drawsize) / float(self.square) / Column.REALWIDTH) + 1
        x0 *= Column.REALWIDTH
        x1 *= Column.REALWIDTH
        w = x1 - x0

        # self.screen.fill(0) # debug mode
        rectpos = (int(self.square * x0), 0)
        rectsiz = (int(self.square * w), ceil(self.square * Column.height()))
        self.screen.blit(self.source, rectpos, rectpos + rectsiz)

        if self.drawmode & self.DRAW_ENABLED:
            # update bit values, no drawing yet
            mousepos = self.lcddraw.map_from(pos)
            r = self.drawsize / float(self.square)
            yes = self.drawmode & self.DRAW_PAINT
            self.lcd.flipbits(mousepos, r, yes)

        # redraw the column data
        region = [
            (mousex0 - self.drawsize, mousey0 - self.drawsize),
            (mousex1 + self.drawsize, mousey1 + self.drawsize),
        ]
        region = map(self.lcddraw.map_from, region)
        self.lcd.draw(self.lcddraw, region=region)

        self.lastmouse = pos
        self.plot_circle()

        pygame.display.flip()

    def doevent(self, e):
        """Pygame event handler"""
        # assume just one mouse button at once
        if e.type == pygame.QUIT:
            return False
        elif e.type == pygame.KEYDOWN:
            if e.key == pygame.K_ESCAPE:
                return False
            if e.key == pygame.K_SPACE:
                print "\n".join(self.lcd.machinebits())
        elif e.type == pygame.MOUSEBUTTONDOWN:
            if e.button == 1:
                self.drawmode |= self.DRAW_PAINT | self.DRAW_ENABLED
                self.apply_click(e.pos)
            if e.button == 2:
                self.drawmode ^= self.DRAW_CIRCLE
                self.repaint()
            elif e.button == 3:
                self.drawmode |= self.DRAW_ENABLED
                self.lastmouse = e.pos
                self.apply_click(e.pos)
            elif e.button == 4:
                if self.drawsize < self.square * Column.height() / 2:
                    self.drawsize *= 1.1
                    self.repaint()
            elif e.button == 5:
                if self.drawsize > 5:
                    self.drawsize /= 1.1
                    self.repaint()
        elif e.type == pygame.MOUSEMOTION:
            if self.drawmode:
                self.apply_click(e.pos)
        elif e.type == pygame.MOUSEBUTTONUP:
            self.drawmode &= ~(self.DRAW_PAINT | self.DRAW_ENABLED)
        return True

    def run(self):
        while self.doevent(pygame.event.wait()):
            pass