kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
Doc Menu class. Various fixes/improvements.
rodzic
5fa17bb085
commit
cad9767688
150
README.md
150
README.md
|
@ -61,8 +61,6 @@ 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
|
under development so check for updates. I also plan to upgrade the performance
|
||||||
of some display drivers.
|
of some display drivers.
|
||||||
|
|
||||||
The encoder interface is under development and currently is rather erratic.
|
|
||||||
|
|
||||||
# 0. Contents
|
# 0. Contents
|
||||||
|
|
||||||
1. [Basic concepts](./README.md#1-basic-concepts) Including installation and test.
|
1. [Basic concepts](./README.md#1-basic-concepts) Including installation and test.
|
||||||
|
@ -113,18 +111,19 @@ The encoder interface is under development and currently is rather erratic.
|
||||||
19. [ScaleLog widget](./README.md#19-scalelog-widget) Wide dynamic range 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.
|
20. [Dial widget](./README.md#20-dial-widget) Display multiple vectors.
|
||||||
21. [Knob widget](./README.md#21-knob-widget) Rotary potentiometer float entry.
|
21. [Knob widget](./README.md#21-knob-widget) Rotary potentiometer float entry.
|
||||||
22. [Graph plotting](./README.md#22-graph-plotting) Widgets for Cartesian and polar graphs.
|
22. [Menu class](./README.md#22-menu-class)
|
||||||
22.1 [Concepts](./README.md#221-concepts)
|
23. [Graph plotting](./README.md#22-graph-plotting) Widgets for Cartesian and polar graphs.
|
||||||
22.1.1 [Graph classes](./README.md#2211-graph-classes)
|
23.1 [Concepts](./README.md#231-concepts)
|
||||||
22.1.2 [Curve classes](./README.md#2212-curve-classes)
|
23.1.1 [Graph classes](./README.md#2311-graph-classes)
|
||||||
22.1.3 [Coordinates](./README.md#2213-coordinates)
|
23.1.2 [Curve classes](./README.md#2312-curve-classes)
|
||||||
22.2 [Graph classes](./README.md#221-graph-classes)
|
23.1.3 [Coordinates](./README.md#2313-coordinates)
|
||||||
22.2.1 [Class CartesianGraph](./README.md#2221-class-cartesiangraph)
|
23.2 [Graph classes](./README.md#231-graph-classes)
|
||||||
22.2.2 [Class PolarGraph](./README.md#2222-class-polargraph)
|
23.2.1 [Class CartesianGraph](./README.md#2321-class-cartesiangraph)
|
||||||
22.3 [Curve classes](./README.md#223-curve-classes)
|
23.2.2 [Class PolarGraph](./README.md#2322-class-polargraph)
|
||||||
22.3.1 [Class Curve](./README.md#2231-class-curve)
|
23.3 [Curve classes](./README.md#233-curve-classes)
|
||||||
22.3.2 [Class PolarCurve](./README.md#2232-class-polarcurve)
|
23.3.1 [Class Curve](./README.md#2331-class-curve)
|
||||||
22.4 [Class TSequence](./README.md#224-class-tsequence) Plotting realtime, time sequential data.
|
23.3.2 [Class PolarCurve](./README.md#2332-class-polarcurve)
|
||||||
|
23.4 [Class TSequence](./README.md#234-class-tsequence) Plotting realtime, time sequential data.
|
||||||
[Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives
|
[Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives
|
||||||
|
|
||||||
# 1. Basic concepts
|
# 1. Basic concepts
|
||||||
|
@ -441,7 +440,7 @@ minimal and aim to demonstrate a single technique.
|
||||||
* `aclock.py` An analog clock using the `Dial` vector display. Also shows
|
* `aclock.py` An analog clock using the `Dial` vector display. Also shows
|
||||||
screen layout using widget metrics. Has a simple `uasyncio` task.
|
screen layout using widget metrics. Has a simple `uasyncio` task.
|
||||||
* `tbox.py` Text boxes and user-controlled scrolling.
|
* `tbox.py` Text boxes and user-controlled scrolling.
|
||||||
* `tstat.py` A demo of the `Tstat` class.
|
* `tstat.py` A demo of the `Meter` class with data sensitive regions.
|
||||||
|
|
||||||
### 1.11.2 Test scripts
|
### 1.11.2 Test scripts
|
||||||
|
|
||||||
|
@ -616,18 +615,33 @@ PALE_YELLOW = create_color(12, 150, 150, 0) # index, r, g, b
|
||||||
If a 4-bit driver is in use, the color `rgb(150, 150, 0)` will be assigned to
|
If a 4-bit driver is in use, the color `rgb(150, 150, 0)` will be assigned to
|
||||||
"spare" color number 12. Any color number in range `0 <= n <= 15` may be
|
"spare" color number 12. Any color number in range `0 <= n <= 15` may be
|
||||||
used, implying that predefined colors may be reassigned. It is recommended
|
used, implying that predefined colors may be reassigned. It is recommended
|
||||||
that `BLACK` (0) and `WHITE` (15) are not changed. `GREY` (6) and `YELLOW` (5)
|
that `BLACK` (0) and `WHITE` (15) are not changed. If an 8-bit or larger driver
|
||||||
are GUI defaults for "greyed out" widgets and for "precision mode" borders, so
|
is in use, the color umber is ignored and there is no practical restriction on
|
||||||
changing these will have obvious effects.
|
the number of colors that may be created.
|
||||||
|
|
||||||
If an 8-bit or larger driver is in use, the first `index` arg is ignored and
|
|
||||||
there is no practical restriction on the number of colors that may be created.
|
|
||||||
|
|
||||||
In the above example, regardless of the display driver, the `PALE_YELLOW`
|
In the above example, regardless of the display driver, the `PALE_YELLOW`
|
||||||
variable may be used to refer to the color. An example of custom color
|
variable may be used to refer to the color. An example of custom color
|
||||||
definition may be found in
|
definition may be found in
|
||||||
[this nano-gui demo](https://github.com/peterhinch/micropython-nano-gui/blob/4ef0e20da27ef7c0b5c34136dcb372200f0e5e66/gui/demos/color15.py#L92).
|
[this nano-gui demo](https://github.com/peterhinch/micropython-nano-gui/blob/4ef0e20da27ef7c0b5c34136dcb372200f0e5e66/gui/demos/color15.py#L92).
|
||||||
|
|
||||||
|
There are five default colors which are defined by a `color_map` list. These
|
||||||
|
may be reassigned in user code. For example the following will cause the border
|
||||||
|
of any control with the focus to be red:
|
||||||
|
```python
|
||||||
|
from colors import *
|
||||||
|
color_map[FOCUS] = RED
|
||||||
|
```
|
||||||
|
The `color_map` index constants and default colors (defined in `colors.py`)
|
||||||
|
are:
|
||||||
|
|
||||||
|
| Index | Color | Purpose |
|
||||||
|
|:---------:|:------:|:-----------------------------------------:|
|
||||||
|
| FOCUS | WHITE | Border of control with focus |
|
||||||
|
| PRECISION | YELLOW | Border in precision mode |
|
||||||
|
| FG | WHITE | Window foreground default |
|
||||||
|
| BG | BLACK | Background default including screen clear |
|
||||||
|
| GREY_OUT | GREY | Color to render greyed-out controls |
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
### 2.3.1 Monochrome displays
|
### 2.3.1 Monochrome displays
|
||||||
|
@ -678,22 +692,35 @@ along with the `Pin` instances used for input; also whether an encoder is used.
|
||||||
Pins are arbitrary, but should be defined as inputs with pullups. Pushbuttons
|
Pins are arbitrary, but should be defined as inputs with pullups. Pushbuttons
|
||||||
are connected between `Gnd` and the relevant pin.
|
are connected between `Gnd` and the relevant pin.
|
||||||
|
|
||||||
The constructor takes the following args:
|
The constructor takes the following positional args:
|
||||||
1. `objssd` The `SSD` instance. A reference to the display driver.
|
1. `objssd` The `SSD` instance. A reference to the display driver.
|
||||||
2. `nxt` A `Pin` instance for the `next` button.
|
2. `nxt` A `Pin` instance for the `next` button.
|
||||||
3. `sel` A `Pin` instance for the `select` button.
|
3. `sel` A `Pin` instance for the `select` button.
|
||||||
4. `prev=None` A `Pin` instance for the `previous` button (if used).
|
4. `prev=None` A `Pin` instance for the `previous` button (if used).
|
||||||
5. `up=None` A `Pin` instance for the `increase` button (if used).
|
5. `incr=None` A `Pin` instance for the `increase` button (if used).
|
||||||
6. `down=None` A `Pin` instance for the `decrease` button (if used).
|
6. `decr=None` A `Pin` instance for the `decrease` button (if used).
|
||||||
7. `encoder=False` If an encoder is used, an integer must be passed. This
|
7. `encoder=False` If an encoder is used, an integer must be passed.
|
||||||
represents the division ratio. A value of 1 provides the native rate of the
|
|
||||||
encoder. I found the Adafruit encoder overly sensitive. A value of 5 slows it
|
Class variables:
|
||||||
down improving usability.
|
* `verbose=True` Causes a message to be printed indicating whether an encoder
|
||||||
|
was specified.
|
||||||
|
|
||||||
|
#### Encoder usage
|
||||||
|
|
||||||
If an encoder is used, it should be connected to the pins assigned to
|
If an encoder is used, it should be connected to the pins assigned to
|
||||||
`increase` and `decrease`. If the direction of movement is wrong, these pins
|
`increase` and `decrease`. If the direction of movement is wrong, these pins
|
||||||
should be transposed (physically or in code).
|
should be transposed (physically or in code).
|
||||||
|
|
||||||
|
To specify to the GUI that an encoder is in use an integer should be passed to
|
||||||
|
the `Display` constructor `encoder` arg. Its value represents the division
|
||||||
|
ratio. A value of 1 defines the native rate of the encoder; if the native rate
|
||||||
|
is 32 pulses per revolution, a value of 4 would yield a virtual device with
|
||||||
|
8 pulses per rev. I found the Adafruit encoder to be too sensitive. A value of 5
|
||||||
|
improved usability.
|
||||||
|
|
||||||
|
If an encoder is used but the `encoder` arg is `False`, response to the encoder
|
||||||
|
will be erratic.
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
# 4. Screen class
|
# 4. Screen class
|
||||||
|
@ -2078,7 +2105,50 @@ value changes. This enables dynamic color change.
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
# 22. Graph Plotting
|
# 22 Menu class
|
||||||
|
|
||||||
|
```python
|
||||||
|
from gui.widgets.menu import Menu
|
||||||
|
```
|
||||||
|
|
||||||
|
This enables the creation of single or two level menus. The top level of the
|
||||||
|
menu consists of a row of `Button` instances at the top of the screen. Each
|
||||||
|
button can either call a callback or instantiate a dropdown list comprising the
|
||||||
|
second menu level.
|
||||||
|
|
||||||
|
Constructor mandatory positional arg:
|
||||||
|
1. `writer` The `Writer` instance (defines font) to use.
|
||||||
|
|
||||||
|
Keyword only args:
|
||||||
|
* `height=25` Height of top level menu buttons.
|
||||||
|
* `bgcolor=None`
|
||||||
|
* `fgcolor=None`
|
||||||
|
* `textcolor=None`
|
||||||
|
* `select_color=DARKBLUE`
|
||||||
|
* `args` This should be a tuple containing a tuple of args for each entry in
|
||||||
|
the top level menu. Each tuple should be of one of two forms:
|
||||||
|
1. `(text, cb, (args,))` A single-level entry: the top level `Button` with
|
||||||
|
text `text` runs the callback `cb` with positional args defined by the
|
||||||
|
supplied tuple (which may be `()`). The callback receives an initial arg
|
||||||
|
being the `Button` instance.
|
||||||
|
2. `(text, cb, (args,), (elements,))` In this instance the top level `Button`
|
||||||
|
triggers a dropdown list comprising a tuple of strings in `elements`. The
|
||||||
|
callback `cb` is triggered if the user selects an entry. The callback
|
||||||
|
receives an initial arg which is a `Listbox` instance: the chosen entry may
|
||||||
|
be retrieved by running `lb.value()` or `lb.textvalue()`.
|
||||||
|
|
||||||
|
In this example the first two items trigger submenus, the third runs a
|
||||||
|
callback. In this example the two submenus share a callback (`cb_sm`), which
|
||||||
|
uses the passed arg to determine which menu it was called from.
|
||||||
|
```python
|
||||||
|
mnu = (('Gas', cb_sm, (0,), ('Helium','Neon','Argon','Krypton','Xenon','Radon')),
|
||||||
|
('Metal', cb_sm, (1,), ('Lithium', 'Sodium', 'Potassium','Rubidium','Caesium')),
|
||||||
|
('View', cb, (2,)))
|
||||||
|
```
|
||||||
|
|
||||||
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
|
# 23. Graph Plotting
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
|
from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
|
||||||
|
@ -2091,7 +2161,7 @@ from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSe
|
||||||
|
|
||||||
For example code see `gui/demos/plot.py`.
|
For example code see `gui/demos/plot.py`.
|
||||||
|
|
||||||
## 22.1 Concepts
|
## 23.1 Concepts
|
||||||
|
|
||||||
Data for Cartesian graphs constitutes a sequence of x, y pairs, for polar
|
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
|
graphs it is a sequence of complex `z` values. The module supports three
|
||||||
|
@ -2101,13 +2171,13 @@ common cases:
|
||||||
3. One or more `y` values arrive gradually. The `X` axis represents time. This
|
3. One or more `y` values arrive gradually. The `X` axis represents time. This
|
||||||
is a simplifying case of 2.
|
is a simplifying case of 2.
|
||||||
|
|
||||||
### 22.1.1 Graph classes
|
### 23.1.1 Graph classes
|
||||||
|
|
||||||
A user program first instantiates a graph object (`PolarGraph` or
|
A user program first instantiates a graph object (`PolarGraph` or
|
||||||
`CartesianGraph`). This creates an empty graph image upon which one or more
|
`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.
|
curves may be plotted. Graphs are passive widgets so cannot accept user input.
|
||||||
|
|
||||||
### 22.1.2 Curve classes
|
### 23.1.2 Curve classes
|
||||||
|
|
||||||
The user program then instantiates one or more curves (`Curve` or
|
The user program then instantiates one or more curves (`Curve` or
|
||||||
`PolarCurve`) as appropriate to the graph. Curves may be assigned colors to
|
`PolarCurve`) as appropriate to the graph. Curves may be assigned colors to
|
||||||
|
@ -2122,7 +2192,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
|
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.
|
line to be drawn connecting the point to the last one drawn.
|
||||||
|
|
||||||
### 22.1.3 Coordinates
|
### 23.1.3 Coordinates
|
||||||
|
|
||||||
`PolarGraph` and `CartesianGraph` objects are subclassed from `Widget` and are
|
`PolarGraph` and `CartesianGraph` objects are subclassed from `Widget` and are
|
||||||
positioned accordingly by `row` and `col` with a 2-pixel outside border. The
|
positioned accordingly by `row` and `col` with a 2-pixel outside border. The
|
||||||
|
@ -2138,9 +2208,9 @@ unit circle but will be clipped to the rectangular graph boundary.
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
## 22.2 Graph classes
|
## 23.2 Graph classes
|
||||||
|
|
||||||
### 22.2.1 Class CartesianGraph
|
### 23.2.1 Class CartesianGraph
|
||||||
|
|
||||||
Constructor.
|
Constructor.
|
||||||
Mandatory positional arguments:
|
Mandatory positional arguments:
|
||||||
|
@ -2167,7 +2237,7 @@ Keyword only arguments (all optional):
|
||||||
Method:
|
Method:
|
||||||
* `show` No args. Redraws the empty graph. Used when plotting time sequences.
|
* `show` No args. Redraws the empty graph. Used when plotting time sequences.
|
||||||
|
|
||||||
### 22.2.2 Class PolarGraph
|
### 23.2.2 Class PolarGraph
|
||||||
|
|
||||||
Constructor.
|
Constructor.
|
||||||
Mandatory positional arguments:
|
Mandatory positional arguments:
|
||||||
|
@ -2192,9 +2262,9 @@ Method:
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
## 22.3 Curve classes
|
## 23.3 Curve classes
|
||||||
|
|
||||||
### 22.3.1 Class Curve
|
### 23.3.1 Class Curve
|
||||||
|
|
||||||
The Cartesian curve constructor takes the following positional arguments:
|
The Cartesian curve constructor takes the following positional arguments:
|
||||||
|
|
||||||
|
@ -2234,7 +2304,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
|
and the `excursion` x value to 3000. The `excursion` values scale the plotted
|
||||||
values to fit the corresponding axis.
|
values to fit the corresponding axis.
|
||||||
|
|
||||||
### 22.3.2 Class PolarCurve
|
### 23.3.2 Class PolarCurve
|
||||||
|
|
||||||
The constructor takes the following positional arguments:
|
The constructor takes the following positional arguments:
|
||||||
|
|
||||||
|
@ -2268,7 +2338,7 @@ Complex points should lie within the unit circle to be drawn within the grid.
|
||||||
|
|
||||||
###### [Contents](./README.md#0-contents)
|
###### [Contents](./README.md#0-contents)
|
||||||
|
|
||||||
## 22.4 Class TSequence
|
## 23.4 Class TSequence
|
||||||
|
|
||||||
A common task is the acquisition and plotting of real time data against time,
|
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
|
such as hourly temperature and air pressure readings. This class facilitates
|
||||||
|
|
|
@ -46,9 +46,13 @@ else:
|
||||||
DARKBLUE = SSD.rgb(0, 0, 90)
|
DARKBLUE = SSD.rgb(0, 0, 90)
|
||||||
WHITE = SSD.rgb(255, 255, 255)
|
WHITE = SSD.rgb(255, 255, 255)
|
||||||
|
|
||||||
# Color used when clearing the screen
|
|
||||||
BGCOLOR = BLACK
|
|
||||||
|
|
||||||
CIRCLE = 1
|
CIRCLE = 1
|
||||||
RECTANGLE = 2
|
RECTANGLE = 2
|
||||||
CLIPPED_RECT = 3
|
CLIPPED_RECT = 3
|
||||||
|
|
||||||
|
FOCUS = 0
|
||||||
|
PRECISION = 1
|
||||||
|
FG = 2
|
||||||
|
BG = 3
|
||||||
|
GREY_OUT = 4
|
||||||
|
color_map = [WHITE, YELLOW, WHITE, BLACK, GREY]
|
||||||
|
|
|
@ -21,7 +21,7 @@ display = None # Singleton instance
|
||||||
ssd = None
|
ssd = None
|
||||||
|
|
||||||
gc.collect()
|
gc.collect()
|
||||||
__version__ = (0, 1, 1)
|
__version__ = (0, 1, 2)
|
||||||
|
|
||||||
# Null function
|
# Null function
|
||||||
dolittle = lambda *_ : None
|
dolittle = lambda *_ : None
|
||||||
|
@ -37,8 +37,9 @@ _LAST = const(3)
|
||||||
|
|
||||||
# Wrapper for ssd providing buttons and framebuf compatible methods
|
# Wrapper for ssd providing buttons and framebuf compatible methods
|
||||||
class Display:
|
class Display:
|
||||||
|
verbose = True
|
||||||
|
|
||||||
def __init__(self, objssd, nxt, sel, prev=None, up=None, down=None, encoder=False):
|
def __init__(self, objssd, nxt, sel, prev=None, incr=None, decr=None, encoder=False):
|
||||||
global display, ssd
|
global display, ssd
|
||||||
self._next = Switch(nxt)
|
self._next = Switch(nxt)
|
||||||
self._sel = Switch(sel)
|
self._sel = Switch(sel)
|
||||||
|
@ -58,18 +59,20 @@ class Display:
|
||||||
self._prev = Switch(prev)
|
self._prev = Switch(prev)
|
||||||
self._prev.close_func(self._closure, (self._prev, Screen.ctrl_move, _PREV))
|
self._prev.close_func(self._closure, (self._prev, Screen.ctrl_move, _PREV))
|
||||||
if encoder:
|
if encoder:
|
||||||
if up is None or down is None:
|
self.verbose and print('Using encoder.')
|
||||||
|
if incr is None or decr is None:
|
||||||
raise ValueError('Must specify pins for encoder.')
|
raise ValueError('Must specify pins for encoder.')
|
||||||
from gui.primitives.encoder import Encoder
|
from gui.primitives.encoder import Encoder
|
||||||
self._enc = Encoder(up, down, div=encoder, callback=Screen.adjust)
|
self._enc = Encoder(incr, decr, div=encoder, callback=Screen.adjust)
|
||||||
else:
|
else:
|
||||||
# Up and down methods get the button as an arg.
|
self.verbose and print('Using switches.')
|
||||||
if up is not None:
|
# incr and decr methods get the button as an arg.
|
||||||
sup = Switch(up)
|
if incr is not None:
|
||||||
|
sup = Switch(incr)
|
||||||
sup.close_func(self._closure, (sup, Screen.adjust, 1))
|
sup.close_func(self._closure, (sup, Screen.adjust, 1))
|
||||||
if down is not None:
|
if decr is not None:
|
||||||
sdown = Switch(down)
|
sdn = Switch(decr)
|
||||||
sdown.close_func(self._closure, (sdown, Screen.adjust, -1))
|
sdn.close_func(self._closure, (sdn, Screen.adjust, -1))
|
||||||
self._is_grey = False # Not greyed-out
|
self._is_grey = False # Not greyed-out
|
||||||
display = self # Populate globals
|
display = self # Populate globals
|
||||||
ssd = objssd
|
ssd = objssd
|
||||||
|
@ -85,7 +88,7 @@ class Display:
|
||||||
sl = writer.stringlen(text)
|
sl = writer.stringlen(text)
|
||||||
writer.set_textpos(ssd, y - writer.height // 2, x - sl // 2)
|
writer.set_textpos(ssd, y - writer.height // 2, x - sl // 2)
|
||||||
if self._is_grey:
|
if self._is_grey:
|
||||||
fgcolor = GREY
|
fgcolor = color_map[GREY_OUT]
|
||||||
writer.setcolor(fgcolor, bgcolor)
|
writer.setcolor(fgcolor, bgcolor)
|
||||||
writer.printstring(text, invert)
|
writer.printstring(text, invert)
|
||||||
writer.setcolor() # Restore defaults
|
writer.setcolor() # Restore defaults
|
||||||
|
@ -93,7 +96,7 @@ class Display:
|
||||||
def print_left(self, writer, x, y, txt, fgcolor=None, bgcolor=None, invert=False):
|
def print_left(self, writer, x, y, txt, fgcolor=None, bgcolor=None, invert=False):
|
||||||
writer.set_textpos(ssd, y, x)
|
writer.set_textpos(ssd, y, x)
|
||||||
if self._is_grey:
|
if self._is_grey:
|
||||||
fgcolor = GREY
|
fgcolor = color_map[GREY_OUT]
|
||||||
writer.setcolor(fgcolor, bgcolor)
|
writer.setcolor(fgcolor, bgcolor)
|
||||||
writer.printstring(txt, invert)
|
writer.printstring(txt, invert)
|
||||||
writer.setcolor() # Restore defaults
|
writer.setcolor() # Restore defaults
|
||||||
|
@ -102,7 +105,7 @@ class Display:
|
||||||
# It would be possible to do better with RGB565 but would need inverse transformation
|
# It would be possible to do better with RGB565 but would need inverse transformation
|
||||||
# to (r, g, b), scale and re-convert to integer.
|
# to (r, g, b), scale and re-convert to integer.
|
||||||
def _getcolor(self, color): # Takes in an integer color, bit size dependent on driver
|
def _getcolor(self, color): # Takes in an integer color, bit size dependent on driver
|
||||||
return GREY if self._is_grey and color != BGCOLOR else color
|
return color_map[GREY_OUT] if self._is_grey and color != color_map[BG] else color
|
||||||
|
|
||||||
def usegrey(self, val): # display.usegrey(True) sets greyed-out
|
def usegrey(self, val): # display.usegrey(True) sets greyed-out
|
||||||
self._is_grey = val
|
self._is_grey = val
|
||||||
|
@ -113,7 +116,7 @@ class Display:
|
||||||
# These methods support greying out color overrides.
|
# These methods support greying out color overrides.
|
||||||
# Clear screen.
|
# Clear screen.
|
||||||
def clr_scr(self):
|
def clr_scr(self):
|
||||||
ssd.fill_rect(0, 0, self.width - 1, self.height - 1, BGCOLOR)
|
ssd.fill_rect(0, 0, self.width - 1, self.height - 1, color_map[BG])
|
||||||
|
|
||||||
def rect(self, x1, y1, w, h, color):
|
def rect(self, x1, y1, w, h, color):
|
||||||
ssd.rect(x1, y1, w, h, self._getcolor(color))
|
ssd.rect(x1, y1, w, h, self._getcolor(color))
|
||||||
|
@ -251,8 +254,7 @@ class Screen:
|
||||||
cs_old.on_hide() # Optional method in subclass
|
cs_old.on_hide() # Optional method in subclass
|
||||||
if forward:
|
if forward:
|
||||||
if isinstance(cls_new_screen, type):
|
if isinstance(cls_new_screen, type):
|
||||||
# Instantiate new screen. __init__ must terminate
|
if isinstance(cs_old, Window):
|
||||||
if cs_old is not None and cs_old.__name__ == 'Window':
|
|
||||||
raise ValueError('Windows are modal.')
|
raise ValueError('Windows are modal.')
|
||||||
new_screen = cls_new_screen(*args, **kwargs)
|
new_screen = cls_new_screen(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
|
@ -353,7 +355,7 @@ class Screen:
|
||||||
# If opening a Screen from a Window just blank and redraw covered area
|
# If opening a Screen from a Window just blank and redraw covered area
|
||||||
if isinstance(old_screen, Window):
|
if isinstance(old_screen, Window):
|
||||||
x0, y0, x1, y1, w, h = old_screen._list_dims()
|
x0, y0, x1, y1, w, h = old_screen._list_dims()
|
||||||
dev.fill_rect(x0, y0, w, h, BGCOLOR) # Blank to screen BG
|
dev.fill_rect(x0, y0, w, h, color_map[BG]) # Blank to screen BG
|
||||||
for obj in [z for z in self.displaylist if z.overlaps(x0, y0, x1, y1)]:
|
for obj in [z for z in self.displaylist if z.overlaps(x0, y0, x1, y1)]:
|
||||||
if obj.visible:
|
if obj.visible:
|
||||||
obj.draw_border()
|
obj.draw_border()
|
||||||
|
@ -484,8 +486,8 @@ class Window(Screen):
|
||||||
self.height = height
|
self.height = height
|
||||||
self.width = width
|
self.width = width
|
||||||
self.draw_border = draw_border
|
self.draw_border = draw_border
|
||||||
self.fgcolor = fgcolor if fgcolor is not None else WHITE
|
self.fgcolor = fgcolor if fgcolor is not None else color_map[FG]
|
||||||
self.bgcolor = bgcolor if bgcolor is not None else BGCOLOR
|
self.bgcolor = bgcolor if bgcolor is not None else color_map[BG]
|
||||||
|
|
||||||
def _do_open(self, old_screen):
|
def _do_open(self, old_screen):
|
||||||
dev = display.usegrey(False)
|
dev = display.usegrey(False)
|
||||||
|
@ -596,7 +598,7 @@ class Widget:
|
||||||
dev = display.usegrey(self._greyed_out)
|
dev = display.usegrey(self._greyed_out)
|
||||||
x = self.col
|
x = self.col
|
||||||
y = self.row
|
y = self.row
|
||||||
dev.fill_rect(x, y, self.width, self.height, BGCOLOR if black else self.bgcolor)
|
dev.fill_rect(x, y, self.width, self.height, color_map[BG] if black else self.bgcolor)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Called by Screen.show(). Draw background and bounding box if required.
|
# Called by Screen.show(). Draw background and bounding box if required.
|
||||||
|
@ -609,7 +611,7 @@ class Widget:
|
||||||
w = self.width + 4
|
w = self.width + 4
|
||||||
h = self.height + 4
|
h = self.height + 4
|
||||||
if self.has_focus():
|
if self.has_focus():
|
||||||
color = WHITE
|
color = color_map[FOCUS]
|
||||||
if hasattr(self, 'precision') and self.precision and self.prcolor is not None:
|
if hasattr(self, 'precision') and self.precision and self.prcolor is not None:
|
||||||
color = self.prcolor
|
color = self.prcolor
|
||||||
dev.rect(x, y, w, h, color)
|
dev.rect(x, y, w, h, color)
|
||||||
|
@ -617,7 +619,7 @@ class Widget:
|
||||||
else:
|
else:
|
||||||
if isinstance(self.bdcolor, bool): # No border
|
if isinstance(self.bdcolor, bool): # No border
|
||||||
if self.has_border: # Border exists: erase it
|
if self.has_border: # Border exists: erase it
|
||||||
dev.rect(x, y, w, h, BGCOLOR)
|
dev.rect(x, y, w, h, color_map[BG])
|
||||||
self.has_border = False
|
self.has_border = False
|
||||||
elif self.bdcolor: # Border is required
|
elif self.bdcolor: # Border is required
|
||||||
dev.rect(x, y, w, h, self.bdcolor)
|
dev.rect(x, y, w, h, self.bdcolor)
|
||||||
|
@ -695,7 +697,7 @@ class LinearIO(Widget):
|
||||||
# Precision mode can only be entered when the active control has focus.
|
# Precision mode can only be entered when the active control has focus.
|
||||||
# In this state it will have a white border. By default this turns yellow
|
# In this state it will have a white border. By default this turns yellow
|
||||||
# but subclass can be defeat this with WHITE or another color
|
# but subclass can be defeat this with WHITE or another color
|
||||||
self.prcolor = YELLOW if prcolor is None else prcolor
|
self.prcolor = color_map[PRECISION] if prcolor is None else prcolor
|
||||||
|
|
||||||
# Adjust widget's value. Args: button pressed, amount of increment
|
# Adjust widget's value. Args: button pressed, amount of increment
|
||||||
def do_adj(self, button, val):
|
def do_adj(self, button, val):
|
||||||
|
|
|
@ -29,8 +29,8 @@ class BaseScreen(Screen):
|
||||||
Screen.change(DialogBox, kwargs = kwargs)
|
Screen.change(DialogBox, kwargs = kwargs)
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
mnu = (('Gas', cb_sm, (0,), ('Argon','Neon','Xenon','Radon')),
|
mnu = (('Gas', cb_sm, (0,), ('Helium','Neon','Argon','Krypton','Xenon','Radon')),
|
||||||
('Metal', cb_sm, (1,), ('Caesium', 'Lithium', 'Sodium', 'Potassium')),
|
('Metal', cb_sm, (1,), ('Lithium', 'Sodium', 'Potassium','Rubidium','Caesium')),
|
||||||
('View', cb, (2,)))
|
('View', cb, (2,)))
|
||||||
wri = CWriter(ssd, freesans20, GREEN, BLACK, verbose=False)
|
wri = CWriter(ssd, freesans20, GREEN, BLACK, verbose=False)
|
||||||
Menu(wri, bgcolor=BLUE, textcolor=WHITE, args = mnu)
|
Menu(wri, bgcolor=BLUE, textcolor=WHITE, args = mnu)
|
||||||
|
|
|
@ -25,7 +25,6 @@ import uasyncio as asyncio
|
||||||
import utime
|
import utime
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
defaults['focus'] = YELLOW
|
|
||||||
|
|
||||||
class FooScreen(Screen):
|
class FooScreen(Screen):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -18,8 +18,8 @@ class SubMenu(Window):
|
||||||
|
|
||||||
def __init__(self, menu, button, elements, cb, args): # menu is parent Menu
|
def __init__(self, menu, button, elements, cb, args): # menu is parent Menu
|
||||||
wri = menu.writer
|
wri = menu.writer
|
||||||
row = 10
|
row = button.height + 2
|
||||||
col = button.col + 4 # Drop down below top level menu button
|
col = button.col # Drop down below top level menu button
|
||||||
# Need to determine Window dimensions from size of Listbox, which
|
# Need to determine Window dimensions from size of Listbox, which
|
||||||
# depends on number and length of elements.
|
# depends on number and length of elements.
|
||||||
entry_height, lb_height, textwidth = Listbox.dimensions(wri, elements)
|
entry_height, lb_height, textwidth = Listbox.dimensions(wri, elements)
|
||||||
|
@ -41,9 +41,10 @@ class SubMenu(Window):
|
||||||
|
|
||||||
# A Menu is a set of Button objects at the top of the screen. On press, Buttons either run the
|
# A Menu is a set of Button objects at the top of the screen. On press, Buttons either run the
|
||||||
# user callback or instantiate a SubMenu
|
# user callback or instantiate a SubMenu
|
||||||
|
# args: ((text, cb, (args,)),(text, cb, (args,), (elements,)), ...)
|
||||||
class Menu:
|
class Menu:
|
||||||
|
|
||||||
def __init__(self, writer, *, height=25, bgcolor=None, fgcolor=None, textcolor=None, select_color=DARKBLUE, args): # ((text, cb, (args,)),(text, cb, (args,), (elements,)), ...)
|
def __init__(self, writer, *, height=25, bgcolor=None, fgcolor=None, textcolor=None, select_color=DARKBLUE, args):
|
||||||
self.writer = writer
|
self.writer = writer
|
||||||
self.select_color = select_color
|
self.select_color = select_color
|
||||||
row = 2
|
row = 2
|
||||||
|
|
|
@ -51,4 +51,4 @@ sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current control
|
||||||
prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
|
prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
|
||||||
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
|
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
|
||||||
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
|
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
|
||||||
display = Display(ssd, nxt, sel, prev, increase, decrease)
|
display = Display(ssd, nxt, sel, prev, increase, decrease, 5)
|
||||||
|
|
Ładowanie…
Reference in New Issue