diff --git a/g13gui/g13gui/bitwidgets/__init__.py b/g13gui/g13gui/bitwidgets/__init__.py index e69de29..efc2194 100644 --- a/g13gui/g13gui/bitwidgets/__init__.py +++ b/g13gui/g13gui/bitwidgets/__init__.py @@ -0,0 +1,2 @@ +DISPLAY_WIDTH = 160 +DISPLAY_HEIGHT = 48 diff --git a/g13gui/g13gui/bitwidgets/button.py b/g13gui/g13gui/bitwidgets/button.py new file mode 100644 index 0000000..6893a1d --- /dev/null +++ b/g13gui/g13gui/bitwidgets/button.py @@ -0,0 +1,119 @@ +import enum + +from builtins import property +from g13gui.bitwidgets import DISPLAY_WIDTH +from g13gui.bitwidgets import DISPLAY_HEIGHT +from g13gui.bitwidgets.widget import Widget +from g13gui.observer import ChangeType + + +GLYPH_WIDTH = 5 +GLYPH_HEIGHT = 5 + + +class Glyphs(enum.Enum): + DOWN_ARROW = [(2, 0), (2, 4), (0, 2), (4, 2), (2, 4)] + UP_ARROW = [(2, 4), (2, 0), (4, 2), (0, 2), (2, 0)] + CHECKMARK = [(0, 3), (1, 4), (4, 1), (1, 4)] + XMARK = [(0, 0), (4, 4), (2, 2), (4, 0), (0, 4)] + + def transformTo(self, offsetx, offsety): + return [(offsetx + x, offsety + y) for (x, y) in self.value] + + +class ButtonBar(Widget): + MAX_BUTTONS = 4 + TOP_LINE = 33 + + def __init__(self): + Widget.__init__(self) + self._children = [None] * ButtonBar.MAX_BUTTONS + self.position = (0, ButtonBar.TOP_LINE) + self.bounds = (DISPLAY_WIDTH, DISPLAY_HEIGHT - ButtonBar.TOP_LINE) + + def button(self, buttonNum): + return self._children[buttonNum] + + def setButton(self, buttonNum, button): + if self._children[buttonNum]: + self.removeChild(self._children[buttonNum]) + + self._children[buttonNum] = button + position = self._positionForButton(buttonNum) + button.position = position + button.parent = self + + self.addChange(ChangeType.ADD, 'child', button) + self.notifyChanged() + + def addChild(self, button): + buttonNum = self._children.index(None) + if buttonNum > ButtonBar.MAX_BUTTONS: + raise ValueError('Can\'t store another button!') + self.setButton(buttonNum, button) + + def removeChild(self, button): + buttonNum = self._children.index(button) + button = self._children[buttonNum] + self._children[buttonNum] = None + button.parent = None + + self.addChange(ChangeType.REMOVE, 'child', button) + self.notifyChanged() + + def _positionForSlot(self, buttonNum): + slotWidth = DISPLAY_WIDTH / ButtonBar.MAX_BUTTONS + slotX = (buttonNum * slotWidth) + slotY = ButtonBar.TOP_LINE + 2 + + return (slotX, slotY) + + def _positionForButton(self, buttonNum): + (slotX, slotY) = self._positionForSlot(buttonNum) + slotWidth = DISPLAY_WIDTH / ButtonBar.MAX_BUTTONS + slotHeight = DISPLAY_HEIGHT - ButtonBar.TOP_LINE - 2 + + (width, height) = self._children[buttonNum].bounds + x_pos = int(slotX + (slotWidth / 2) - (width / 2)) + y_pos = int(slotY + (slotHeight / 2) - (height / 2)) + + return (x_pos, y_pos) + + def draw(self, ctx): + if self.visible: + for child in self._children: + if child and child.visible: + child.draw(ctx) + + # Top line + ctx.line(self.position + (DISPLAY_WIDTH, + ButtonBar.TOP_LINE), + fill=1) + + # Dividing lines + for slot in range(0, ButtonBar.MAX_BUTTONS): + position = list(self._positionForSlot(slot)) + position[0] -= 2 + ctx.line(tuple(position) + (position[0], DISPLAY_HEIGHT), + fill=1) + + +class Button(Widget): + def __init__(self, glyph, fill=True): + Widget.__init__(self) + self.glyph = glyph + self.fill = fill + self.bounds = (5, 5) + + def draw(self, ctx): + if self._visible: + xformedGlyph = self._glyph.transformTo(*self._position) + ctx.line(xformedGlyph, fill=self.fill) + + @property + def glyph(self): + return self._glyph + + @glyph.setter + def glyph(self, glyph): + self.setProperty('glyph', glyph) diff --git a/g13gui/g13gui/bitwidgets/button_tests.py b/g13gui/g13gui/bitwidgets/button_tests.py new file mode 100644 index 0000000..cea2a66 --- /dev/null +++ b/g13gui/g13gui/bitwidgets/button_tests.py @@ -0,0 +1,68 @@ +import unittest +import time + +from g13gui.bitwidgets.display import Display +from g13gui.bitwidgets.x11displaydevice import X11DisplayDevice +from g13gui.bitwidgets.screen import Screen +from g13gui.bitwidgets.button import Button +from g13gui.bitwidgets.button import Glyphs +from g13gui.bitwidgets.label import Label +from g13gui.bitwidgets.fonts import Fonts + + +class ButtonTests(unittest.TestCase): + def setUp(self): + self.dd = X11DisplayDevice(self.__class__.__name__) + self.dd.start() + time.sleep(0.25) + self.display = Display(self.dd) + self.screen = Screen(self.display) + + def tearDown(self): + time.sleep(1) + self.dd.shutdown() + self.dd.join() + + def testExButton(self): + ctx = self.display.getContext() + exButton = Button(Glyphs.XMARK) + exButton.show() + exButton.draw(ctx) + upButton = Button(Glyphs.UP_ARROW) + upButton.position = (10, 0) + upButton.show() + upButton.draw(ctx) + downButton = Button(Glyphs.DOWN_ARROW) + downButton.position = (20, 0) + downButton.show() + downButton.draw(ctx) + checkButton = Button(Glyphs.CHECKMARK) + checkButton.position = (30, 0) + checkButton.show() + checkButton.draw(ctx) + + self.display.commit() + + def testButtonBar(self): + exButton = Button(Glyphs.XMARK) + upButton = Button(Glyphs.UP_ARROW) + downButton = Button(Glyphs.DOWN_ARROW) + checkButton = Button(Glyphs.CHECKMARK) + + self.screen.buttonBar.addChild(exButton) + self.screen.buttonBar.addChild(upButton) + self.screen.buttonBar.addChild(downButton) + self.screen.buttonBar.addChild(checkButton) + self.screen.buttonBar.show_all() + + self.screen.nextFrame() + + def testLabelButton(self): + testButton = Label(0, 0, "Test", font=Fonts.TINY) + self.screen.buttonBar.addChild(testButton) + self.screen.buttonBar.show_all() + self.screen.nextFrame() + + +if __name__ == '__main__': + unittest.main() diff --git a/g13gui/g13gui/bitwidgets/display.py b/g13gui/g13gui/bitwidgets/display.py index a599991..0ca4e8e 100644 --- a/g13gui/g13gui/bitwidgets/display.py +++ b/g13gui/g13gui/bitwidgets/display.py @@ -1,65 +1,24 @@ -import struct import PIL.ImageDraw import PIL.PyAccess -import sys -from io import BytesIO from PIL import Image from g13gui.observer import Subject -from g13gui.observer import ChangeType - - -class DisplayMetrics(object): - WIDTH_PIXELS = 160 - HEIGHT_PIXELS = 48 - - -LPBM_LENGTH = 960 - - -def ImageToLPBM(image): - i = PIL.PyAccess.new(image, readonly=True) - bio = BytesIO() - - maxBytes = (DisplayMetrics.WIDTH_PIXELS * DisplayMetrics.HEIGHT_PIXELS // 8) - row = 0 - col = 0 - - for byteNum in range(0, maxBytes): - b = int() - - if row == 40: - maxSubrow = 3 - else: - maxSubrow = 8 - - for subrow in range(0, maxSubrow): - b |= i[col, row + subrow] << subrow - - bio.write(struct.pack('