Fix widget metrics.

pull/8/head
Peter Hinch 2021-06-25 10:57:25 +01:00
rodzic 3b26ab9528
commit 3f37900d12
9 zmienionych plików z 50 dodań i 30 usunięć

Wyświetl plik

@ -49,13 +49,9 @@ target and a C device driver (unless you can acquire a suitable binary).
# Project status
Code has been tested on ESP32, Pi Pico and Pyboard. The API shuld be stable.
Code is new and issues are likely: please report any found. This document is
under review. I plan to add further demos and to upgrade the performance of
some display drivers.
An issue under investigation is that a soft reset is required after a GUI
application is run and before running another. Otherwise the second application
displays correctly but is unresponsive.
Code is new and issues are likely: please report any found. The project is
under development so check for updates. I also plan to upgrade the performance
of some display drivers.
# 0. Contents
@ -392,6 +388,11 @@ Demos are run by issuing (for example):
```python
>>> import gui.demos.simple
```
If shut down cleanly with the "close" button a demo can be re-run with (e.g.):
```python
gui.demos.simple.test()
```
Before running a different demo the host should be reset (ctrl-d) to clear RAM.
These will run on screens of 128x128 pixels or above. The initial ones are
minimal and aim to demonstrate a single technique.
@ -2170,7 +2171,10 @@ class TSeq(Screen):
The "tab order" of widgets on a `Screen` is the order with which they acquire
focus with successive presses of the `Next` button. It is determined by the
order in which they are instantiated.
order in which they are instantiated. Tab order is important for usability but
instantiating in the best order can conflict with program logic. This happens
if a widget's callback refers to others not yet instantiated. See demos
`dropdown.py` and `linked_sliders.py` for one solution.
The obvious layout for the physical buttons is as per a joystick:
@ -2201,13 +2205,12 @@ have the following bound variables, which should be considered read-only:
* `height` As specified. Does not include border.
* `width` Ditto.
* `rows` Height including borders.
* `cols` Width with borders.
* `mrow` Maximum absolute row occupied by the widget.
* `mcol` Maximum absolute col occupied by the widget.
This support is fairly "micro" and does not take account of labels and legends.
This means that `rows` and `cols` for `Dial`, `Meter`, `Slider` and
`HorizSlider` do not necessarily reflect the full amount of space used by the
control.
The `mrow` and `mcol` values enable other widgets to be positioned relative to
the one previously instantiated. In the cases of sliders, `Dial` and `Meter`
widgets these take account of space ocupied by legends or labels.
The `aclock.py` demo provides a simple example of this approach.
@ -2254,4 +2257,6 @@ Hopefully these are self explanatory. The `Display` methods use the `framebuf`
convention of `x, y` coordinates rather than the `row, col` system used by
micro-gui.
The `primitives.py` demo provides a simple example.
###### [Contents](./README.md#0-contents)

Wyświetl plik

@ -274,10 +274,9 @@ class Screen:
cs_new._do_open(cs_old) # Clear and redraw
cs_new.after_open() # Optional subclass method
if cs_old is None: # Initialising
try:
asyncio.run(Screen.monitor()) # Starts and ends uasyncio
finally:
asyncio.new_event_loop()
asyncio.run(Screen.monitor()) # Starts and ends uasyncio
# Don't do asyncio.new_event_loop() as it prevents re-running
# the same app.
@classmethod
async def monitor(cls):
@ -550,8 +549,9 @@ class Widget:
self.col = col
self.height = height
self.width = width
self.rows = height + 4 # For metrics. Default: allow for border.
self.cols = width + 4
# Maximum row and col. Defaults for user metrics. May be overridden
self.mrow = row + height + 2 # in subclass. Allow for border.
self.mcol = col + width + 2
self.visible = True # Used by ButtonList class for invisible buttons
self.draw = True # Signals that obect must be redrawn
self._value = value

Wyświetl plik

@ -25,9 +25,9 @@ from gui.core.colors import *
async def aclock(dial, lbldate, lbltim):
# Return a unit vector of phase phi. Multiplying by this will
# rotate a vector anticlockwise which is mathematically correct.
# Alas clocks modelled on sundials were invented in the northern
# hemisphere. Otherwise they would have rotated widdershins
# in accordance with maths. Hence negative sign when called.
# Alas clocks, modelled on sundials, were invented in the northern
# hemisphere. Otherwise they would have rotated widdershins like
# the maths. Hence negative sign when called.
def uv(phi):
return rect(1, phi)
@ -70,13 +70,14 @@ class BaseScreen(Screen):
}
wri = CWriter(ssd, font, GREEN, BLACK, verbose=False)
gap = 4 # Vertical gap between widgets
dial = Dial(wri, 2, 2, height = 70, ticks = 12,
fgcolor = GREEN, pip = GREEN)
# Set up clock display: instantiate labels
row = dial.rows + gap
# Demo of relative positioning.
gap = 4 # Vertical gap between widgets
row = dial.mrow + gap
lbldate = Label(wri, row, 2, 100, **labels)
row += lbldate.rows + gap
row = lbldate.mrow + gap
lbltim = Label(wri, row, 2, '00.00.00', **labels)
self.reg_task(aclock(dial, lbldate, lbltim))
CloseButton(wri)

Wyświetl plik

@ -47,12 +47,13 @@ class BaseScreen(Screen):
self.vslider = Slider(wri, 2, 2, callback=self.slider_cb,
bdcolor=RED, slotcolor=BLUE,
legends=('0.0', '0.5', '1.0'), value=0.5)
#Label(wri, 2, self.vslider.mcol, 'FF')
col = 80
row = 15
self.hslider = HorizSlider(wri, row, col, callback=self.slider_cb,
bdcolor=GREEN, slotcolor=BLUE,
legends=('0.0', '0.5', '1.0'), value=0.7)
Label(wri, self.hslider.mrow, self.hslider.mcol, 'FF')
row += 30
self.scale = Scale(wri, row, col, width = 150, tickcb = tickcb,
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN,

Wyświetl plik

@ -61,8 +61,11 @@ class FooScreen(Screen):
m0 = Meter(wri, 10, 240, divisions = 4, ptcolor=YELLOW, height=80, width=15,
label='Meter example', style=Meter.BAR, legends=('0.0', '0.5', '1.0'))
#Label(wri, 2, m0.mcol, 'FF')
# Instantiate displayable objects. bgcolor forces complete redraw.
dial = Dial(wri, 2, 2, height = 75, ticks = 12, bgcolor=BLACK, bdcolor=None, label=120) # Border in fg color
#Label(wri, dial.mrow, 2, 'FF')
#Label(wri, dial.mrow, dial.mcol, 'FF')
scale = Scale(wri, 2, 100, width = 124, tickcb = tickcb,
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN)

Wyświetl plik

@ -41,7 +41,10 @@ async def ptr_test(dial):
ptr = Pointer(dial)
v = 0j
steps = 20 # No. of interpolation steps
grv = lambda : urandom.getrandbits(16) / 2**15 - 1 # Random: range -1.0 to +1.0
# BUG getting a weird visual flicker on occasion, with yellow
# being briefly displayed. Where is that coming from?
# Does not seem to be affected by max value. TODO
grv = lambda : urandom.getrandbits(16) / 2**15 - 1 # Random: range -1.0 to +0.999
while True:
v1 = grv() + 1j * grv() # Random vector
dv = (v1 - v) / steps # Interpolation vector

Wyświetl plik

@ -67,8 +67,9 @@ class Dial(Widget):
self.pip = self.fgcolor if pip is None else pip
if label is not None:
self.label = Label(writer, row + height + 3, col, label)
#self.cols = max(self.cols, self.label.cols)
#self.rows += 3 + self.label.rows
# Adjust metrics
self.mrow = self.label.mrow - 2 # Label never has border
self.mcol = max(self.mcol, self.label.mcol - 2)
radius = int(height / 2)
self.radius = radius
self.ticks = ticks

Wyświetl plik

@ -24,6 +24,7 @@ class Meter(Widget):
self.style = style
self.ptcolor = ptcolor if ptcolor is not None else self.fgcolor
if legends is not None: # Legends are static
mcol = 0
x = col + width + 4
y = row + height
dy = 0 if len(legends) <= 1 else height / (len(legends) -1)
@ -31,6 +32,8 @@ class Meter(Widget):
for legend in legends:
l = Label(writer, round(yl), x, legend)
yl -= dy
mcol = max(mcol, l.mcol)
self.mcol = mcol - 2 # For metrics. Legends never have border.
self.value(value)
def value(self, n=None, color=None):

Wyświetl plik

@ -28,6 +28,9 @@ class Slider(LinearIO):
super()._set_callbacks(callback, args)
self.divisions = divisions
self.legends = legends
if legends is not None: # Adjust column metric
ml = max((writer.stringlen(l) for l in legends))
self.mcol += ml + 2 # Strings are rendered 2 pixels right of border
self.fontcolor = self.fgcolor if fontcolor is None else fontcolor
self.slotcolor = self.bgcolor if slotcolor is None else slotcolor
# Define slider