README needs updating.

pull/16/head
Peter Hinch 2022-05-21 18:56:04 +01:00
rodzic 447e87bad1
commit 3f7be4ebba
6 zmienionych plików z 245 dodań i 171 usunięć

152
README.md
Wyświetl plik

@ -109,39 +109,42 @@ a workround if it's impossible to upgrade. See
5.1 [Constructor](./README.md#51-constructor)
5.2 [Class method](./README.md#52-class-method)
5.3 [Popup windows](./README.md#53-popup-windows)
6. [Label widget](./README.md#6-label-widget) Single line text display.
7. [LED widget](./README.md#7-led-widget) Display Boolean values.
8. [Checkbox widget](./README.md#8-checkbox-widget) Enter Boolean values.
9. [Button and CloseButton widgets](./README.md#9-button-and-closebutton-widgets) Pushbutton emulation.
10. [ButtonList object](./README.md#10-buttonlist-object) Pushbuttons with multiple states.
11. [RadioButtons object](./README.md#11-radiobuttons-object) One-of-N pushbuttons.
12. [Listbox widget](./README.md#12-listbox-widget)
13. [Dropdown widget](./README.md#13-dropdown-widget) Dropdown lists.
14. [DialogBox class](./README.md#14-dialogbox-class) Pop-up modal dialog boxes.
15. [Textbox widget](./README.md#15-textbox-widget) Scrolling text display.
16. [Meter widget](./README.md#16-meter-widget) Display floats on an analog meter, with data driven callbacks.
16.1 [Region class](./README.md#161-region-class)
17. [Slider and HorizSlider widgets](./README.md#17-slider-and-horizslider-widgets) Linear potentiometer float data entry and display
18. [Scale widget](./README.md#18-scale-widget) High precision float entry and display.
19. [ScaleLog widget](./README.md#19-scalelog-widget) Wide dynamic range float entry and display.
20. [Dial widget](./README.md#20-dial-widget) Display multiple vectors.
21. [Knob widget](./README.md#21-knob-widget) Rotary potentiometer float entry.
22. [Adjuster widget](./README.md#22-adjuster-widget) Space saving way to enter floats.
23. [Menu class](./README.md#23-menu-class)
24. [Graph plotting](./README.md#24-graph-plotting) Widgets for Cartesian and polar graphs.
24.1 [Concepts](./README.md#241-concepts)
     24.1.1 [Graph classes](./README.md#2411-graph-classes)
     24.1.2 [Curve classes](./README.md#2412-curve-classes)
     24.1.3 [Coordinates](./README.md#2413-coordinates)
24.2 [Graph classes](./README.md#242-graph-classes)
     24.2.1 [Class CartesianGraph](./README.md#2421-class-cartesiangraph)
     24.2.2 [Class PolarGraph](./README.md#2422-class-polargraph)
24.3 [Curve classes](./README.md#243-curve-classes)
     24.3.1 [Class Curve](./README.md#2431-class-curve)
     24.3.2 [Class PolarCurve](./README.md#2432-class-polarcurve)
24.4 [Class TSequence](./README.md#244-class-tsequence) Plotting realtime, time sequential data.
25. [Old firmware](./README.md#25-old-firmware) For users of color displays who can't run current firmware.
26. [Realtime applications](./README.md#26-realtime-applications) Accommodating tasks requiring fast RT performance.
6. [Widgets](./README.md#6-widgets) Displayable objects.
6.1 [Label widget](./README.md#61-label-widget) Single line text display.
6.2 [LED widget](./README.md#62-led-widget) Display Boolean values.
6.3 [Checkbox widget](./README.md#63-checkbox-widget) Enter Boolean values.
6.4 [Button and CloseButton widgets](./README.md#64-button-and-closebutton-widgets) Pushbutton emulation.
6.5 [ButtonList object](./README.md#65-buttonlist-object) Pushbuttons with multiple states.
6.6 [RadioButtons object](./README.md#66-radiobuttons-object) One-of-N pushbuttons.
6.7 [Listbox widget](./README.md#67-listbox-widget)
6.8 [Dropdown widget](./README.md#68-dropdown-widget) Dropdown lists.
6.9 [DialogBox class](./README.md#69-dialogbox-class) Pop-up modal dialog boxes.
6.10 [Textbox widget](./README.md#610-textbox-widget) Scrolling text display.
6.11 [Meter widget](./README.md#611-meter-widget) Display floats on an analog meter, with data driven callbacks.
     6.11.1 [Region class](./README.md#161-region-class)
6.12 [Slider and HorizSlider widgets](./README.md#612-slider-and-horizslider-widgets) Linear potentiometer float data entry and display
6.13 [Scale widget](./README.md#613-scale-widget) High precision float entry and display.
6.14 [ScaleLog widget](./README.md#614-scalelog-widget) Wide dynamic range float entry and display.
6.15 [Dial widget](./README.md#615-dial-widget) Display multiple vectors.
6.16 [Knob widget](./README.md#616-knob-widget) Rotary potentiometer float entry.
6.17 [Adjuster widget](./README.md#617-adjuster-widget) Space saving way to enter floats.
6.18 [Menu class](./README.md#618-menu-class)
6.19 [BitMap widget](./README.md#619-bitmap-widget) Draw bitmaps from files.__
6.20 [QRMap widget](./README.md#620-qrmap-widget) Draw QR codes.__
7. [Graph plotting](./README.md#7-graph-plotting) Widgets for Cartesian and polar graphs.
7.1 [Concepts](./README.md#71-concepts)
     7.1.1 [Graph classes](./README.md#711-graph-classes)
     7.1.2 [Curve classes](./README.md#712-curve-classes)
     7.1.3 [Coordinates](./README.md#713-coordinates)
7.2 [Graph classes](./README.md#72-graph-classes)
     7.2.1 [Class CartesianGraph](./README.md#721-class-cartesiangraph)
     7.2.2 [Class PolarGraph](./README.md#722-class-polargraph)
7.3 [Curve classes](./README.md#73-curve-classes)
     7.3.1 [Class Curve](./README.md#731-class-curve)
     7.3.2 [Class PolarCurve](./README.md#732-class-polarcurve)
7.4 [Class TSequence](./README.md#74-class-tsequence) Plotting realtime, time sequential data.
8. [Old firmware](./README.md#8-old-firmware) For users of color displays who can't run current firmware.
9. [Realtime applications](./README.md#9-realtime-applications) Accommodating tasks requiring fast RT performance.
[Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives
# 1. Basic concepts
@ -960,7 +963,9 @@ constructor and is closed by issuing the `close()` static method.
###### [Contents](./README.md#0-contents)
# 6. Label widget
# 6. Widgets
## 6.1 Label widget
```python
from gui.widgets import Label
@ -1046,7 +1051,7 @@ Screen.change(BaseScreen)
###### [Contents](./README.md#0-contents)
# 7. LED widget
## 6.2 LED widget
```python
from gui.widgets import LED
@ -1085,7 +1090,7 @@ controlled with `led(True)` or `led(False)`.
###### [Contents](./README.md#0-contents)
# 8. Checkbox widget
## 6.3 Checkbox widget
```python
from gui.widgets import Checkbox
@ -1126,7 +1131,7 @@ Methods:
###### [Contents](./README.md#0-contents)
# 9. Button and CloseButton widgets
## 6.4 Button and CloseButton widgets
```python
from gui.core.colors import * # Colors and shapes
@ -1203,7 +1208,7 @@ Optional keyword only arguments:
###### [Contents](./README.md#0-contents)
# 10. ButtonList object
## 6.5 ButtonList object
```python
from gui.core.colors import * # Colors and shapes
@ -1262,7 +1267,7 @@ for t in table: # Buttons overlay each other at same location
###### [Contents](./README.md#0-contents)
# 11. RadioButtons object
## 6.6 RadioButtons object
```python
from gui.core.colors import * # Colors and shapes
@ -1310,7 +1315,7 @@ for t in table:
###### [Contents](./README.md#0-contents)
# 12. Listbox widget
## 6.7 Listbox widget
```python
from gui.widgets import Listbox
@ -1419,7 +1424,7 @@ Screen.change(BaseScreen)
###### [Contents](./README.md#0-contents)
# 13. Dropdown widget
## 6.8 Dropdown widget
```python
from gui.widgets import Dropdown
@ -1534,7 +1539,7 @@ Screen.change(BaseScreen)
```
###### [Contents](./README.md#0-contents)
# 14. DialogBox class
## 6.9 DialogBox class
```python
from gui.widgets import DialogBox
@ -1588,7 +1593,7 @@ in `gui/demos/screens.py`.
###### [Contents](./README.md#0-contents)
# 15. Textbox widget
## 6.10 Textbox widget
```python
from gui.widgets import Textbox
@ -1655,7 +1660,7 @@ the oldest (topmost) being discarded as required.
###### [Contents](./README.md#0-contents)
# 16. Meter widget
## 6.11 Meter widget
This `passive` widget displays a single floating point value on a vertical
linear scale. Optionally it can support data dependent callbacks.
@ -1749,7 +1754,7 @@ behaves similarly for data values between 0.9 and 1.0.
###### [Contents](./README.md#0-contents)
## 16.1 Region class
### 6.11.1 Region class
```python
from gui.widgets import Region
@ -1809,7 +1814,7 @@ callbacks to run as appropriate.
###### [Contents](./README.md#0-contents)
# 17. Slider and HorizSlider widgets
## 6.12 Slider and HorizSlider widgets
```python
from gui.widgets import Slider, HorizSlider
@ -1887,7 +1892,7 @@ around sliders to display all legends.
###### [Contents](./README.md#0-contents)
# 18. Scale widget
## 6.13 Scale widget
```python
from gui.widgets import Scale
@ -2024,7 +2029,7 @@ precision. Each visible division on the control represents 10 integer units.
###### [Contents](./README.md#0-contents)
# 19. ScaleLog widget
## 6.14 ScaleLog widget
```python
from gui.widgets import ScaleLog
@ -2164,7 +2169,7 @@ def tickcb(f, c):
###### [Contents](./README.md#0-contents)
# 20. Dial widget
## 6.15 Dial widget
```python
from gui.widgets import Dial, Pointer
@ -2280,7 +2285,7 @@ Screen.change(BaseScreen)
###### [Contents](./README.md#0-contents)
# 21. Knob widget
## 6.16 Knob widget
```python
from gui.widgets import Knob
@ -2338,7 +2343,7 @@ value changes. This enables dynamic color change.
###### [Contents](./README.md#0-contents)
# 22. Adjuster widget
## 6.17 Adjuster widget
```python
from gui.widgets import Adjuster
@ -2404,7 +2409,7 @@ basis. See code comments for further details.
###### [Contents](./README.md#0-contents)
# 23 Menu class
## 6.18 Menu class
```python
from gui.widgets import Menu
@ -2512,7 +2517,22 @@ different callback if the application required it.
###### [Contents](./README.md#0-contents)
# 24. Graph Plotting
## 6.19 BitMap Widget
This renders a monochrome bitmap stored in a file to a rectangular region. The
bitmap file format is C source code generated by the Linux `bitmap` editor. The
data may be rendered in any color. Data and colors can be changed at run time.
Not suitable for animation due to blocking time.
Question generator in coroutine.
###### [Contents](./README.md#0-contents)
## 6.20 QRMap Widget
###### [Contents](./README.md#0-contents)
# 7. Graph Plotting
```python
from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
@ -2525,7 +2545,7 @@ from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSe
For example code see `gui/demos/plot.py`.
## 24.1 Concepts
## 7.1 Concepts
Data for Cartesian graphs constitutes a sequence of x, y pairs, for polar
graphs it is a sequence of complex `z` values. The module supports three
@ -2535,13 +2555,13 @@ common cases:
3. One or more `y` values arrive gradually. The `X` axis represents time. This
is a simplifying case of 2.
### 24.1.1 Graph classes
### 7.1.1 Graph classes
A user program first instantiates a graph object (`PolarGraph` or
`CartesianGraph`). This creates an empty graph image upon which one or more
curves may be plotted. Graphs are passive widgets so cannot accept user input.
### 24.1.2 Curve classes
### 7.1.2 Curve classes
The user program then instantiates one or more curves (`Curve` or
`PolarCurve`) as appropriate to the graph. Curves may be assigned colors to
@ -2556,7 +2576,7 @@ Where it is required to plot realtime data as it arrives, this is achieved
via calls to the curve's `point` method. If a prior point exists it causes a
line to be drawn connecting the point to the last one drawn.
### 24.1.3 Coordinates
### 7.1.3 Coordinates
`PolarGraph` and `CartesianGraph` objects are subclassed from `Widget` and are
positioned accordingly by `row` and `col` with a 2-pixel outside border. The
@ -2572,9 +2592,9 @@ unit circle but will be clipped to the rectangular graph boundary.
###### [Contents](./README.md#0-contents)
## 24.2 Graph classes
## 7.2 Graph classes
### 24.2.1 Class CartesianGraph
### 7.2.1 Class CartesianGraph
Constructor.
Mandatory positional arguments:
@ -2601,7 +2621,7 @@ Keyword only arguments (all optional):
Method:
* `show` No args. Redraws the empty graph. Used when plotting time sequences.
### 24.2.2 Class PolarGraph
### 7.2.2 Class PolarGraph
Constructor.
Mandatory positional arguments:
@ -2626,9 +2646,9 @@ Method:
###### [Contents](./README.md#0-contents)
## 24.3 Curve classes
## 7.3 Curve classes
### 24.3.1 Class Curve
### 7.3.1 Class Curve
The Cartesian curve constructor takes the following positional arguments:
@ -2668,7 +2688,7 @@ To plot x values from 1000 to 4000 we would set the `origin` x value to 1000
and the `excursion` x value to 3000. The `excursion` values scale the plotted
values to fit the corresponding axis.
### 24.3.2 Class PolarCurve
### 7.3.2 Class PolarCurve
The constructor takes the following positional arguments:
@ -2702,7 +2722,7 @@ Complex points should lie within the unit circle to be drawn within the grid.
###### [Contents](./README.md#0-contents)
## 24.4 Class TSequence
## 7.4 Class TSequence
A common task is the acquisition and plotting of real time data against time,
such as hourly temperature and air pressure readings. This class facilitates
@ -2766,7 +2786,7 @@ class TSeq(Screen):
```
###### [Contents](./README.md#0-contents)
# 25. Old firmware
# 8. Old firmware
Current firmware is highly recommended. For users of color displays who cannot
run V1.17 or later it is possible to run under V1.15+. This involves copying
@ -2774,7 +2794,7 @@ run V1.17 or later it is possible to run under V1.15+. This involves copying
to `gui/core/writer.py`. This uses Python code to render text if the firmware
or driver are unable to support fast rendering.
# 26. Realtime applications
# 9. Realtime applications
Screen refresh is performed in a continuous loop with yields to the scheduler.
In normal applications this works well, however a significant proportion of

Wyświetl plik

@ -1,20 +1,12 @@
# bitmap.py Minimal micro-gui demo.
# bitmap.py Display a changing bitmap via the BitMap widget.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2022 Peter Hinch
# hardware_setup must be imported before other modules because of RAM use.
import gc
import uasyncio as asyncio
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton, BMG
# Create buffer for bitmapped graphic before fragmentation sets in
scale = 1
qr_ht = 100
qr_wd = 100
qr_buf = BMG.make_buffer(qr_ht, qr_wd)
gc.collect()
from gui.widgets import Label, Button, CloseButton, BitMap
from gui.core.writer import CWriter
import gui.fonts.arial10 as arial10
from gui.core.colors import *
@ -29,19 +21,21 @@ class BaseScreen(Screen):
col = 2
row = 2
Label(wri, row, col, "Bitmap Demo.")
row = 50
self.graphic = BMG(wri, row, col, qr_ht, qr_wd, scale, fgcolor=WHITE, bgcolor=BLACK, buf=qr_buf)
#Button(wri, row, col, text="URL", callback=my_callback, args=(graphic, qr))
asyncio.create_task(self.animate())
row = 25
self.graphic = BitMap(wri, row, col, 99, 99, fgcolor=WHITE, bgcolor=BLACK)
col = 120
Button(wri, row, col, text="Next", callback=self.cb)
CloseButton(wri) # Quit the application
self.image = 0
async def animate(self):
while True:
for n in range(13):
fn = f"/moon/m{n}.c"
#print(fn)
await asyncio.sleep_ms(200)
self.graphic.value(fn)
def cb(self, _):
self.graphic.value(f"/moon/m{self.image:02d}")
self.image += 1
self.image %= 28
if self.image == 3:
self.graphic.color(BLUE)
else:
self.graphic.color(WHITE)
def test():
print("Bitmap demo.")

Wyświetl plik

@ -8,12 +8,12 @@ import gc
import hardware_setup # Create a display instance
from uQR import QRCode
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton, BMG
from gui.widgets import Label, Button, CloseButton, QRMap
# Create buffer for bitmapped graphic before fragmentation sets in
scale = 3 # Magnification of graphic
qr_ht = scale * 41
qr_wd = scale *41
qr_buf = BMG.make_buffer(qr_ht, qr_wd)
qr_wd = scale * 41
qr_buf = QRMap.make_buffer(qr_ht, qr_wd)
gc.collect()
from gui.core.writer import CWriter
import gui.fonts.arial10 as arial10
@ -35,7 +35,7 @@ class BaseScreen(Screen):
row = 2
Label(wri, row, col, "QR code Demo.")
row = 50
graphic = BMG(wri, row, col, qr_ht, qr_wd, scale, fgcolor=BLACK, bgcolor=WHITE, buf=qr_buf)
graphic = QRMap(wri, row, col, (qr_ht, qr_wd), scale, fgcolor=BLACK, bgcolor=WHITE, buf=qr_buf)
qr = QRCode(version=4) # Gives 41x41 matrix
qr.add_data("uQR rocks!")
graphic.value(qr.get_matrix())

Wyświetl plik

@ -23,7 +23,8 @@ _attrs = {
"Slider": "sliders",
"HorizSlider": "sliders",
"Textbox": "textbox",
"BMG": "bitmap",
"BitMap": "bitmap",
"QRMap": "qrcode",
}
# Lazy loader, effectively does:

Wyświetl plik

@ -1,96 +1,49 @@
# bitmap.py Provides the BMG (bitmapped graphics) class
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2022 Peter Hinch
import gc
from framebuf import FrameBuffer, MONO_HLSB
# Graphics are files created by Linux bitmap utility.
# Widget writes data direct to the FrameBuffer.
# There is no scaling: declared size of the widget must exactly
# match the size of the bitmap.
from gui.core.ugui import Widget
from gui.core.colors import *
from gui.core.ugui import ssd
def rbit8(v):
v = (v & 0x0f) << 4 | (v & 0xf0) >> 4
v = (v & 0x33) << 2 | (v & 0xcc) >> 2
return (v & 0x55) << 1 | (v & 0xaa) >> 1
class BMG(Widget):
class BitMap(Widget):
@staticmethod
def make_buffer(height, width):
w = (width >> 3) + int(width & 7 > 0)
return bytearray(height * w)
def __init__(self, writer, row, col, height, width, scale=1, *, fgcolor=None, bgcolor=None, bdcolor=RED, buf=None):
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False)
if buf is None:
buf = BMG.make_buffer(height, width)
self._fb = FrameBuffer(buf, width, height, MONO_HLSB)
self._scale = scale
self._buf = buf
def __init__(self, writer, row, col, height, width, *, fgcolor=None, bgcolor=None, bdcolor=RED):
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
def show(self):
if super().show(True): # Draw or erase border
palette = ssd.palette
palette.bg(self.bgcolor)
palette.fg(self.fgcolor)
ssd.blit(self._fb, self.col, self.row, -1, palette)
if not super().show(True): # Draw or erase border
return
if self._value is None:
return
with open(self._value, "r") as f:
g = self.gen_bytes(f)
bit = 1
wrap = False
for row in range(self.height):
if not wrap:
byte = next(g) # Each row starts on a new byte
bit = 1
for col in range(self.width):
c = self.fgcolor if byte & bit else self.bgcolor
ssd.pixel(self.col + col, self.row + row, c)
wrap = (bit := bit << 1) == 0x100
if wrap:
byte = next(g)
bit = 1
def color(self, fgcolor=None, bgcolor=None):
if fgcolor is not None:
self.fgcolor = fgcolor
if bgcolor is not None:
self.bgcolor = bgcolor
self.draw = True
def value(self, obj):
if isinstance(obj, list): # 2d list of booleans
self._fb.fill(1)
s = self._scale
wd = len(obj[0])
ht = len(obj)
if wd * s > self.width or ht * s > self.height:
print('Object too large for buffer', wd * s, self.width, ht * s, self.height)
else:
print(f"Object is {wd} x {ht}")
for row in range(ht):
for col in range(wd):
v = obj[row][col]
for nc in range(s):
for nr in range(s):
self._fb.pixel(col * s + nc, row * s + nr, v)
elif isinstance(obj, str): # Assume filename
try:
with open(obj, "r") as f:
g = self.handle_stream(f)
n = 0
for x in g:
self._buf[n] = rbit8(x)
n += 1
except OSError:
print(f"Failed to input from {obj}")
self.draw = True
gc.collect()
# TODO graphic must be exactly the right size. Get dims from file in app, pass stream?
def handle_stream(self, f):
m = self._scale
s = f.readline()
elements = s.split(" ")
if elements[1].endswith("width"):
wd = int(elements[2])
else:
raise OSError
s = f.readline()
elements = s.split(" ")
if elements[1].endswith("height"):
ht = int(elements[2])
else:
raise OSError
if wd * m > self.width or ht * m > self.height:
print("Object too large for buffer", wd * m, self.width, ht * m, self.height)
raise OSError
def gen_bytes(self, f): # Yield data bytes from file stream
f.readline()
f.readline() # Advance file pointer to data start
s = f.readline()
if not s.startswith("static"):
raise OSError
raise ValueError("Bad file format.")
while s := f.readline():
if (lb := s.find("}")) != -1:
s = s[:lb] # Strip trailing };
@ -98,3 +51,31 @@ class BMG(Widget):
for x in p:
if x:
yield int(x, 16)
# Get height/width dimension from file stream.
def _get_dim(self, f, name):
s = f.readline()
elements = s.split(" ")
if not elements[1].endswith(name):
raise ValueError("Bad file format.")
return int(elements[2])
def _validate(self, fn):
if not isinstance(fn, str):
raise ValueError("Value must be a filename.")
with open(fn, "r") as f:
wd = self._get_dim(f, "width")
ht = self._get_dim(f, "height")
if not (wd == self.width and ht == self.height):
raise ValueError(f"Object dimensions {ht}x{wd} do not match widget {self.height}x{self.width}")
def value(self, fn):
self._validate(fn) # Throws on failure
super().value(fn)
def color(self, fgcolor=None, bgcolor=None):
if fgcolor is not None:
self.fgcolor = fgcolor
if bgcolor is not None:
self.bgcolor = bgcolor
self.draw = True

Wyświetl plik

@ -0,0 +1,78 @@
# qrcode.py Provides the QRMap widget to display the output of uQR library.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2022 Peter Hinch
import gc
from framebuf import FrameBuffer, MONO_HLSB
from gui.core.ugui import Widget
from gui.core.colors import *
from gui.core.ugui import ssd
class QRMap(Widget):
@staticmethod
def make_buffer(height, width): # Given dimensions in pixels
w = (width >> 3) + int(width & 7 > 0)
return bytearray(height * w)
def __init__(self, writer, row, col, image, scale=1, *, fgcolor=None, bgcolor=None, bdcolor=RED, buf=None):
self._scale = scale
self._image = image
try:
height, width = self.dimensions()
except OSError:
print(f"Failed to access {obj}.")
raise
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False)
if buf is None:
buf = QRMap.make_buffer(height, width)
else:
if len(buf) != ((width >> 3) + int(width & 7 > 0)) * height:
raise OSError("Buffer size does not match width and height.")
self._fb = FrameBuffer(buf, width, height, MONO_HLSB)
if isinstance(image, list):
self.value(image)
def show(self):
if super().show(True): # Draw or erase border
palette = ssd.palette
palette.bg(self.bgcolor)
palette.fg(self.fgcolor)
ssd.blit(self._fb, self.col, self.row, -1, palette)
def color(self, fgcolor=None, bgcolor=None):
if fgcolor is not None:
self.fgcolor = fgcolor
if bgcolor is not None:
self.bgcolor = bgcolor
self.draw = True
def dimensions(self): # Dimensions of current image in pixels
obj = self._image
if isinstance(obj, list): # 2d list of booleans
return len(obj) * self._scale, len(obj[0] * self._scale)
if isinstance(obj, tuple):
return obj
raise OSError
def value(self, obj):
self._image = obj
self._fb.fill(self.bgcolor) # In case tuple was passed or image smaller than buffer
if isinstance(obj, list): # 2d list of booleans
wd, ht = self.dimensions()
s = self._scale
if wd > self.width or ht > self.height:
print('Object too large for buffer', wd, self.width, ht, self.height)
else:
print(f"Object is {wd} x {ht} pixels")
for row in range(ht//s):
for col in range(wd//s):
v = obj[row][col]
for nc in range(s):
for nr in range(s):
self._fb.pixel(col * s + nc, row * s + nr, v)
else:
print(f"Invalid QR code {obj}.")
self.draw = True
gc.collect()