Add missing writer_gui.py

pull/16/head
Peter Hinch 2019-02-03 14:30:50 +00:00
rodzic 55075023f4
commit 24e3d2a1a7
2 zmienionych plików z 243 dodań i 1 usunięć

Wyświetl plik

@ -253,7 +253,7 @@ Possible future enhancements:
2. Extend word wrapping to cases where words are separated by tabs or hyphens.
3. An asynchronous version.
As stated above the official SSD1306 drriver is incompatible with hardware I2C
As stated above the official SSD1306 driver is incompatible with hardware I2C
and this problem cannot efficiently be fixed. [PR4020](https://github.com/micropython/micropython/pull/4020)
proposes an enhncement which will facilitate an improved SSD1306 driver capable
of using hard or soft I2C.

Wyświetl plik

@ -0,0 +1,242 @@
# writer_gui.py Displayable objects based on the Writer and CWriter classes
# V0.3 Peter Hinch 26th Aug 2018
# The MIT License (MIT)
#
# Copyright (c) 2018 Peter Hinch
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# Base class for a displayable object. Subclasses must implement .show() and .value()
# Has position, colors and border definition.
# border: False no border None use bgcolor, int: treat as color
from writer import Writer
import framebuf
def _circle(dev, x0, y0, r, color): # Single pixel circle
x = -r
y = 0
err = 2 -2*r
while x <= 0:
dev.pixel(x0 -x, y0 +y, color)
dev.pixel(x0 +x, y0 +y, color)
dev.pixel(x0 +x, y0 -y, color)
dev.pixel(x0 -x, y0 -y, color)
e2 = err
if (e2 <= y):
y += 1
err += y*2 +1
if (-x == y and e2 <= x):
e2 = 0
if (e2 > x):
x += 1
err += x*2 +1
def circle(dev, x0, y0, r, color, width =1): # Draw circle
x0, y0, r = int(x0), int(y0), int(r)
for r in range(r, r -width, -1):
dev._circle(x0, y0, r, color)
def fillcircle(dev, x0, y0, r, color): # Draw filled circle
x0, y0, r = int(x0), int(y0), int(r)
x = -r
y = 0
err = 2 -2*r
while x <= 0:
dev.line(x0 -x, y0 -y, x0 -x, y0 +y, color)
dev.line(x0 +x, y0 -y, x0 +x, y0 +y, color)
e2 = err
if (e2 <= y):
y +=1
err += y*2 +1
if (-x == y and e2 <= x):
e2 = 0
if (e2 > x):
x += 1
err += x*2 +1
class DObject():
def __init__(self, writer, row, col, height, width, fgcolor, bgcolor, bordercolor):
writer.set_clip(True, True, False) # Disable scrolling text
self.writer = writer
device = writer.device
self.device = device
if row < 0:
row = 0
self.warning()
elif row + height >= device.height:
row = device.height - height - 1
self.warning()
if col < 0:
col = 0
self.warning()
elif col + width >= device.width:
row = device.width - width - 1
self.warning()
self.row = row
self.col = col
self.width = width
self.height = height
self._value = None # Type depends on context but None means don't display.
# Current colors
if fgcolor is None:
fgcolor = writer.fgcolor
if bgcolor is None:
bgcolor = writer.bgcolor
if bordercolor is None:
bordercolor = fgcolor
self.fgcolor = fgcolor
self.bgcolor = bgcolor
# bordercolor is False if no border is to be drawn
self.bdcolor = bordercolor
# Default colors allow restoration after dynamic change
self.def_fgcolor = fgcolor
self.def_bgcolor = bgcolor
self.def_bdcolor = bordercolor
# has_border is True if a border was drawn
self.has_border = False
def warning(self):
print('Warning: attempt to create {} outside screen dimensions.'.format(self.__class__.__name__))
# Draw a border if .bdcolor specifies a color. If False, erase an existing border
def show(self):
wri = self.writer
dev = wri.device
if isinstance(self.bdcolor, bool): # No border
if self.has_border: # Border exists: erase it
dev.rect(self.col - 2, self.row - 2, self.width + 4, self.height + 4, self.bgcolor)
self.has_border = False
elif self.bdcolor: # Border is required
dev.rect(self.col - 2, self.row - 2, self.width + 4, self.height + 4, self.bdcolor)
self.has_border = True
def value(self, v = None):
if v is not None:
self._value = v
return self._value
# text: str display string int save width
class Label(DObject):
def __init__(self, writer, row, col, text, invert=False, fgcolor=None, bgcolor=None, bordercolor=False):
# Determine width of object
if isinstance(text, int):
width = text
text = None
else:
width = writer.stringlen(text)
height = writer.height
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bordercolor)
if text is not None:
self.value(text, invert)
def value(self, text=None, invert=False, fgcolor=None, bgcolor=None, bordercolor=None):
txt = super().value(text)
# Redraw even if no text supplied: colors may have changed.
self.invert = invert
self.fgcolor = self.def_fgcolor if fgcolor is None else fgcolor
self.bgcolor = self.def_bgcolor if bgcolor is None else bgcolor
if bordercolor is False:
self.def_bdcolor = False
self.bdcolor = self.def_bdcolor if bordercolor is None else bordercolor
self.show()
return txt
def show(self):
txt = super().value()
if txt is None: # No content to draw. Future use.
return
super().show() # Draw or erase border
wri = self.writer
dev = self.device
wri.setcolor(self.fgcolor, self.bgcolor)
dev.fill_rect(self.col, self.row, self.width, wri.height, wri.bgcolor) # Blank text field
Writer.set_textpos(dev, self.row, self.col)
wri.setcolor(self.fgcolor, self.bgcolor)
wri.printstring(txt, self.invert)
wri.setcolor() # Restore defaults
class Meter(DObject):
def __init__(self, writer, row, col, *, height=50, width=10,
fgcolor=None, bgcolor=None, pointercolor=None, bordercolor=None,
divisions=5, legends=None, value=None):
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bordercolor)
self.divisions = divisions
self.legends = legends
self.pointercolor = pointercolor if pointercolor is not None else self.fgcolor
self.value(value)
def value(self, n=None):
if n is None:
return super().value()
n = super().value(min(1, max(0, n)))
self.show()
return n
def show(self):
super().show() # Draw or erase border
val = super().value()
wri = self.writer
dev = self.device
width = self.width
height = self.height
legends = self.legends
x0 = self.col
x1 = self.col + width
y0 = self.row
y1 = self.row + height
dev.fill_rect(self.col, self.row, width, height, self.bgcolor) # Blank field
if self.divisions > 0:
dy = height / (self.divisions) # Tick marks
for tick in range(self.divisions + 1):
ypos = int(y0 + dy * tick)
dev.hline(x0 + 2, ypos, x1 - x0 - 4, self.fgcolor)
if legends is not None: # Legends
dy = 0 if len(legends) <= 1 else height / (len(legends) -1)
yl = y1 - wri.height / 2 # Start at bottom
for legend in legends:
Label(wri, int(yl), x1 + 4, legend)
yl -= dy
y = int(y1 - val * height) # y position of slider
dev.hline(x0, y, width, self.pointercolor) # Draw pointer
class LED(DObject):
def __init__(self, writer, row, col, *, height=15,
fgcolor=None, bgcolor=None, bordercolor=None, legend=None):
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bordercolor)
self.legend = legend
self.radius = self.height // 2
def color(self, c):
self.fgcolor = c
self.show()
def show(self):
super().show()
wri = self.writer
dev = self.device
r = self.radius
fillcircle(dev, self.col + r, self.row + r, r, self.fgcolor)
if self.legend is not None:
Label(wri, self.row + self.height - wri.height, self.col + self.width + 1, self.legend)