kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Add Textbox widget. Minor API change to Scale.
rodzic
6691d4f790
commit
ec87b5db69
|
@ -0,0 +1,67 @@
|
||||||
|
# tbox.py Test/demo of Textbox widget for nano-gui
|
||||||
|
|
||||||
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
|
# Copyright (c) 2020 Peter Hinch
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# import gui.demos.tbox
|
||||||
|
|
||||||
|
# Initialise hardware and framebuf before importing modules.
|
||||||
|
from color_setup import ssd # Create a display instance
|
||||||
|
|
||||||
|
from gui.core.nanogui import refresh
|
||||||
|
from gui.core.writer import CWriter
|
||||||
|
|
||||||
|
import uasyncio as asyncio
|
||||||
|
from gui.core.colors import *
|
||||||
|
import gui.fonts.arial10 as arial10
|
||||||
|
from gui.widgets.label import Label
|
||||||
|
from gui.widgets.textbox import Textbox
|
||||||
|
|
||||||
|
# Args common to both Textbox instances
|
||||||
|
# Positional
|
||||||
|
pargs = (2, 2, 124, 7) # Row, Col, Width, nlines
|
||||||
|
|
||||||
|
# Keyword
|
||||||
|
tbargs = {'fgcolor' : YELLOW,
|
||||||
|
'bdcolor' : RED,
|
||||||
|
'bgcolor' : DARKGREEN,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def wrap(wri):
|
||||||
|
s = '''The textbox displays multiple lines of text in a field of fixed dimensions. \
|
||||||
|
Text may be clipped to the width of the control or may be word-wrapped. If the number \
|
||||||
|
of lines of text exceeds the height available, scrolling may be performed \
|
||||||
|
by calling a method.
|
||||||
|
'''
|
||||||
|
tb = Textbox(wri, *pargs, clip=False, **tbargs)
|
||||||
|
tb.append(s, ntrim = 100, line = 0)
|
||||||
|
refresh(ssd)
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
if not tb.scroll(1):
|
||||||
|
break
|
||||||
|
refresh(ssd)
|
||||||
|
|
||||||
|
async def clip(wri):
|
||||||
|
ss = ('clip demo', 'short', 'longer line', 'much longer line with spaces',
|
||||||
|
'antidisestablishmentarianism', 'line with\nline break', 'Done')
|
||||||
|
tb = Textbox(wri, *pargs, clip=True, **tbargs)
|
||||||
|
for s in ss:
|
||||||
|
tb.append(s, ntrim = 100) # Default line=None scrolls to show most recent
|
||||||
|
refresh(ssd)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
async def main(wri):
|
||||||
|
await wrap(wri)
|
||||||
|
await clip(wri)
|
||||||
|
|
||||||
|
def test():
|
||||||
|
refresh(ssd) # Initialise and clear display.
|
||||||
|
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||||
|
wri = CWriter(ssd, arial10, verbose=False)
|
||||||
|
wri.set_clip(True, True, False)
|
||||||
|
asyncio.run(main(wri))
|
||||||
|
|
||||||
|
test()
|
|
@ -0,0 +1,126 @@
|
||||||
|
# textbox.py Extension to nanogui providing the Textbox class
|
||||||
|
|
||||||
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
|
# Copyright (c) 2020 Peter Hinch
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# from gui.widgets.textbox import Textbox
|
||||||
|
|
||||||
|
from gui.core.nanogui import DObject
|
||||||
|
from gui.core.writer import Writer
|
||||||
|
|
||||||
|
# Reason for no tab support in private/reason_for_no_tabs
|
||||||
|
|
||||||
|
class Textbox(DObject):
|
||||||
|
def __init__(self, writer, row, col, width, nlines, *, bdcolor=None, fgcolor=None,
|
||||||
|
bgcolor=None, clip=True):
|
||||||
|
height = nlines * writer.height
|
||||||
|
devht = writer.device.height
|
||||||
|
devwd = writer.device.width
|
||||||
|
if ((row + height + 2) > devht) or ((col + width + 2) > devwd):
|
||||||
|
raise ValueError('Textbox extends beyond physical screen.')
|
||||||
|
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||||
|
self.nlines = nlines
|
||||||
|
self.clip = clip
|
||||||
|
self.lines = []
|
||||||
|
self.start = 0 # Start line for display
|
||||||
|
|
||||||
|
def _add_lines(self, s):
|
||||||
|
width = self.width
|
||||||
|
font = self.writer.font
|
||||||
|
n = -1 # Index into string
|
||||||
|
newline = True
|
||||||
|
while True:
|
||||||
|
n += 1
|
||||||
|
if newline:
|
||||||
|
newline = False
|
||||||
|
ls = n # Start of line being processed
|
||||||
|
col = 0 # Column relative to text area
|
||||||
|
if n >= len(s): # End of string
|
||||||
|
if n > ls:
|
||||||
|
self.lines.append(s[ls :])
|
||||||
|
return
|
||||||
|
c = s[n] # Current char
|
||||||
|
if c == '\n':
|
||||||
|
self.lines.append(s[ls : n])
|
||||||
|
newline = True
|
||||||
|
continue # Line fits window
|
||||||
|
col += font.get_ch(c)[2] # width of current char
|
||||||
|
if col > width:
|
||||||
|
if self.clip:
|
||||||
|
p = s[ls :].find('\n') # end of 1st line
|
||||||
|
if p == -1:
|
||||||
|
self.lines.append(s[ls : n]) # clip, discard all to right
|
||||||
|
return
|
||||||
|
self.lines.append(s[ls : n]) # clip, discard to 1st newline
|
||||||
|
n = p # n will move to 1st char after newline
|
||||||
|
elif c == ' ': # Easy word wrap
|
||||||
|
self.lines.append(s[ls : n])
|
||||||
|
else: # Edge splits a word
|
||||||
|
p = s.rfind(' ', ls, n + 1)
|
||||||
|
if p >= 0: # spacechar in line: wrap at space
|
||||||
|
assert (p > 0), 'space char in position 0'
|
||||||
|
self.lines.append(s[ls : p])
|
||||||
|
n = p
|
||||||
|
else: # No spacechar: wrap at end
|
||||||
|
self.lines.append(s[ls : n])
|
||||||
|
n -= 1 # Don't skip current char
|
||||||
|
newline = True
|
||||||
|
|
||||||
|
def _print_lines(self):
|
||||||
|
if len(self.lines) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
dev = self.device
|
||||||
|
wri = self.writer
|
||||||
|
col = self.col
|
||||||
|
row = self.row
|
||||||
|
left = col
|
||||||
|
ht = wri.height
|
||||||
|
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||||
|
# Print the first (or last?) lines that fit widget's height
|
||||||
|
#for line in self.lines[-self.nlines : ]:
|
||||||
|
for line in self.lines[self.start : self.start + self.nlines]:
|
||||||
|
Writer.set_textpos(dev, row, col)
|
||||||
|
wri.printstring(line)
|
||||||
|
row += ht
|
||||||
|
col = left
|
||||||
|
wri.setcolor() # Restore defaults
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
dev = self.device
|
||||||
|
super().show()
|
||||||
|
self._print_lines()
|
||||||
|
|
||||||
|
def append(self, s, ntrim=None, line=None):
|
||||||
|
self._add_lines(s)
|
||||||
|
if ntrim is None: # Default to no. of lines that can fit
|
||||||
|
ntrim = self.nlines
|
||||||
|
if len(self.lines) > ntrim:
|
||||||
|
self.lines = self.lines[-ntrim:]
|
||||||
|
self.goto(line)
|
||||||
|
|
||||||
|
def scroll(self, n): # Relative scrolling
|
||||||
|
value = len(self.lines)
|
||||||
|
if n == 0 or value <= self.nlines: # Nothing to do
|
||||||
|
return False
|
||||||
|
s = self.start
|
||||||
|
self.start = max(0, min(self.start + n, value - self.nlines))
|
||||||
|
if s != self.start:
|
||||||
|
self.show()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def value(self):
|
||||||
|
return len(self.lines)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.lines = []
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def goto(self, line=None): # Absolute scrolling
|
||||||
|
if line is None:
|
||||||
|
self.start = max(0, len(self.lines) - self.nlines)
|
||||||
|
else:
|
||||||
|
self.start = max(0, min(line, len(self.lines) - self.nlines))
|
||||||
|
self.show()
|
Ładowanie…
Reference in New Issue