Simplify setup. README fixes (still WIP).

pull/8/head
Peter Hinch 2021-06-20 16:46:14 +01:00
rodzic a9967e79e9
commit 8d3171334c
14 zmienionych plików z 169 dodań i 147 usunięć

225
README.md
Wyświetl plik

@ -195,7 +195,6 @@ 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)
setup(display)
``` ```
Display drivers are documented Display drivers are documented
@ -270,6 +269,11 @@ the pushbutton GPIO lines. According to the
[ESP32 gurus](https://randomnerdtutorials.com/esp32-pinout-reference-gpios/) [ESP32 gurus](https://randomnerdtutorials.com/esp32-pinout-reference-gpios/)
pins 36-39 do not have pullup support. pins 36-39 do not have pullup support.
On a Pyboard 1.1 with 320x240 ili9341 display it was necessary to use frozen
bytecode: in this configuration running the "various" demo there was 29K of
free RAM. Note that, at 37.5KiB, this display is the worst-case in terms of
RAM usage. A smaller display or a Pyboard D would offer more headroom.
## 1.9 Firmware and dependencies ## 1.9 Firmware and dependencies
Firmware should be V1.15 or later. The source tree includes all dependencies. Firmware should be V1.15 or later. The source tree includes all dependencies.
@ -374,8 +378,8 @@ Note that the import of `hardware_setup.py` is the first line of code. This is
because the frame buffer is created here, with a need for a substantial block because the frame buffer is created here, with a need for a substantial block
of contiguous RAM. of contiguous RAM.
```python ```python
from hardware_setup import ssd # Instantiate display, setup color LUT (if present) import hardware_setup # Instantiate display, setup color LUT (if present)
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.widgets.label import Label from gui.widgets.label import Label
from gui.widgets.buttons import Button, CloseButton from gui.widgets.buttons import Button, CloseButton
@ -539,6 +543,10 @@ In normal use the following methods only are required:
passing positional and keyword arguments to the constructor of the new, user passing positional and keyword arguments to the constructor of the new, user
defined, screen. defined, screen.
* `back(cls)` Restore previous screen. * `back(cls)` Restore previous screen.
* `value(cls, val=None)` The `val` arg can be any Python type. It allows
widgets on a `Screen` to store information in a way which can be accessed from
the calling screen. This typically occurs after the screen has closed and no
longer exists as an instance, hence the use of a classmethod.
These are uncommon:__ These are uncommon:__
* `shutdown(cls)` Clear the screen and shut down the GUI. Normally done by a * `shutdown(cls)` Clear the screen and shut down the GUI. Normally done by a
@ -663,7 +671,6 @@ Methods:
* `bdcolor=None` Border color. As per above except that if `False` is * `bdcolor=None` Border color. As per above except that if `False` is
passed, no border is displayed. This clears a previously drawn border. passed, no border is displayed. This clears a previously drawn border.
Returns the current text string. Returns the current text string.
2. `show` No args. (Re)draws the label. Primarily for internal use by GUI.
If populating a label would cause it to extend beyond the screen boundary a If populating a label would cause it to extend beyond the screen boundary a
warning is printed at the console. The label may appear at an unexpected place. warning is printed at the console. The label may appear at an unexpected place.
@ -728,7 +735,6 @@ Methods:
* `bgcolor=None` Background color, as per foreground. * `bgcolor=None` Background color, as per foreground.
* `bdcolor=None` Border color. As per above except that if `False` is * `bdcolor=None` Border color. As per above except that if `False` is
passed, no border is displayed. This clears a previously drawn border. passed, no border is displayed. This clears a previously drawn border.
3. `show` No args. (Re)draws the LED. Primarily for internal use by GUI.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)
@ -763,9 +769,9 @@ Optional keyword only arguments:
* `active=True` By default user input is accepted. * `active=True` By default user input is accepted.
Methods: Methods:
* `greyed_out` Optional Boolean argument `val` default `None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise, if current 'greyed out' status of the control. Otherwise enables or disables it,
the widget is `active`, enables or disables it, showing it in its new state. showing it in its new state.
* `value` Optional Boolean argument `val`. If the provided value does not * `value` Optional Boolean argument `val`. If the provided value does not
correspond to the control's current value, updates it; the checkbox is correspond to the control's current value, updates it; the checkbox is
re-drawn and the callback executed. Always returns the control's value. re-drawn and the callback executed. Always returns the control's value.
@ -813,7 +819,7 @@ Optional keyword only arguments:
pushbutton is released otherwise it will occur when pressed. pushbutton is released otherwise it will occur when pressed.
Method: Method:
* `greyed_out=None` Optional Boolean argument `val`. If `None` returns the * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
current 'greyed out' status of the control. Otherwise enables or disables it, current 'greyed out' status of the control. Otherwise enables or disables it,
showing it in its new state. showing it in its new state.
@ -866,7 +872,7 @@ Methods:
* `add_button` Adds a button to the `ButtonList`. Arguments: as per the * `add_button` Adds a button to the `ButtonList`. Arguments: as per the
`Button` constructor. `Button` constructor.
Returns the button object. Returns the button object.
* `greyed_out=None` Optional Boolean argument `val`. If `None` returns the * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
current 'greyed out' status of the control. Otherwise enables or disables it, current 'greyed out' status of the control. Otherwise enables or disables it,
showing it in its new state. showing it in its new state.
* `value` Optional args `button=None`, `new_cb=False`. The `button` arg, if * `value` Optional args `button=None`, `new_cb=False`. The `button` arg, if
@ -919,12 +925,12 @@ Constructor positional arguments:
Methods: Methods:
* `add_button` Adds a button. Arguments: as per the `Button` constructor. * `add_button` Adds a button. Arguments: as per the `Button` constructor.
Returns the Button instance. Returns the Button instance.
* `greyed_out=None` Optional Boolean argument `val`. If `None` returns the * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
current 'greyed out' status of the control. Otherwise enables or disables it, current 'greyed out' status of the control. Otherwise enables or disables it,
showing it in its new state. showing it in its new state.
* `value` Optional argument: a button in the set. If supplied, and the * `value` Optional argument: a button in the set. If supplied, and the
button is not currently active, the currency changes to the supplied button button is not currently active, the supplied button receives the focus and its
and its callback is run. Always returns the currently active button. callback is run. Always returns the currently active button.
Typical usage: Typical usage:
```python ```python
@ -950,7 +956,7 @@ for t in table:
# 12. Listbox widget # 12. Listbox widget
```python ```python
from gui.widgets.listbox import Listbox, ON_MOVE, ON_LEAVE from gui.widgets.listbox import Listbox
``` ```
A `Listbox` is an active widget. Its height is determined by the number of A `Listbox` is an active widget. Its height is determined by the number of
@ -977,29 +983,26 @@ Optional keyword only arguments:
default is used. default is used.
* `bdcolor=False` Color of border. If `False` no border will be drawn. If a * `bdcolor=False` Color of border. If `False` no border will be drawn. If a
color is provided, a border line will be drawn around the control. color is provided, a border line will be drawn around the control.
* `fontcolor` Text color. Defaults to system text color. * `fontcolor=None` Text color. Defaults to system text color.
* `select_color` Background color for selected item in list. Default * `select_color=DARKBLUE` Background color for selected item in list.
`LIGHTBLUE`. * `callback=dolittle` Callback function which runs when `select` is pressed.
* `callback` Callback function which runs when `select` is pressed. * `args=[]` A list/tuple of arguments for above callback.
* `args` A list/tuple of arguments for above callback. Default `[]`. * `also=0` Options are `Listbox.ON_MOVE` or `Listbox.ON_LEAVE`. By default the
* `also=0` Options are `ON_MOVE` or `ON_LEAVE`. By default the callback runs callback runs only when the `select` button is pressed. The `ON_LEAVE` value
only when the `select` button is pressed. The `ON_LEAVE` value meanse that it causes it also to run when the focus moves from the control if the currently
will also run when the focus moves from the control if the currently selected selected element has changed. The `ON_MOVE` arg causes the callback to run
element has been changed. The `ON_MOVE` arg causes the callback to run every every time the highlighted element is changed.
time the highlighted element is changed.
Methods: Methods:
* `greyed_out` Optional boolean argument `val` default `None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise current 'greyed out' status of the control. Otherwise enables or disables it,
enables or disables it, showing it in its new state. showing it in its new state.
* `value` Argument `val` default `None`. If the argument is provided * `value` Argument `val=None`. If a provided argument is a valid index for the list, that entry becomes current and the callback is executed. Always returns
which is a valid index into the list that entry becomes current and the the index of the currently active entry.
callback is executed. Always returns the index of the currently active entry. * `textvalue` Argument `text=None`. If a string argument is provided and is in
* `textvalue` Argument `text` a string default `None`. If the argument the control's list, that item becomes current. Normally returns the current
is provided and is in the control's list, that item becomes current. Returns string. If a provided arg did not match any list item, the control's state is
the current string, unless the arg was provided but did not correspond to any not changed and `None` is returned.
list item. In this event the control's state is not changed and `None` is
returned.
The callback's first argument is the listbox instance followed by any args The callback's first argument is the listbox instance followed by any args
specified to the constructor. The currently selected item may be retrieved by specified to the constructor. The currently selected item may be retrieved by
@ -1024,7 +1027,8 @@ Open dropdown list.
A dropdown list. The list, when active, is drawn below the control. The height A dropdown list. The list, when active, is drawn below the control. The height
of the control is determined by the height of the font in use. The height of of the control is determined by the height of the font in use. The height of
the list is determined by the number of entries in it and the font in use. the list is determined by the number of entries in it and the font in use.
Scrolling is not supported. Scrolling is not supported. The dropdown should be placed high enough on the
screen to ensure that the list can be displayed
Constructor mandatory positional args: Constructor mandatory positional args:
1. `writer` The `Writer` instance (defines font) to use. 1. `writer` The `Writer` instance (defines font) to use.
@ -1038,7 +1042,7 @@ Mandatory keyword only argument:
Optional keyword only arguments: Optional keyword only arguments:
* `width=None` Control width in pixels. By default this is calculated to * `width=None` Control width in pixels. By default this is calculated to
accommodate all elements. accommodate all elements.
* `value=0` Index of currently selected list item. Default 0. * `value=0` Index of currently selected list item.
* `fgcolor=None` Color of foreground (the control itself). If `None` the * `fgcolor=None` Color of foreground (the control itself). If `None` the
`Writer` foreground default is used. `Writer` foreground default is used.
* `bgcolor=None` Background color of object. If `None` the `Writer` background * `bgcolor=None` Background color of object. If `None` the `Writer` background
@ -1051,17 +1055,16 @@ Optional keyword only arguments:
* `args=[]` A list/tuple of arguments for above callback. * `args=[]` A list/tuple of arguments for above callback.
Methods: Methods:
* `greyed_out` Optional boolean argument `val` default `None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise current 'greyed out' status of the control. Otherwise enables or disables it,
enables or disables it, showing it in its new state. showing it in its new state.
* `value` Argument `val` default `None`. If the argument is provided * `value` Argument `val=None`. If a provided arg is a valid index into the
which is a valid index into the list that entry becomes current and the list, that entry becomes current and the callback is executed. Always returns
callback is executed. Always returns the index of the currently active entry. the index of the currently active entry.
* `textvalue` Argument `text` a string default `None`. If the argument * `textvalue` Argument `text=None`. If a string argument is provided and is in
is provided and is in the control's list, that item becomes current. Returns the control's list, that item becomes current. Normally returns the current
the current string, unless the arg was provided but did not correspond to any string. If a provided arg did not match any list item, the control's state is
list item. In this event the control's state is not changed and `None` is not changed and `None` is returned.
returned.
If `select` is pressed when the `Dropdown` has focus, the list is displayed. If `select` is pressed when the `Dropdown` has focus, the list is displayed.
The `increase` and `decrease` buttons move the list currency. If `select` is The `increase` and `decrease` buttons move the list currency. If `select` is
@ -1091,10 +1094,10 @@ calculated from the strings assigned to the buttons. This ensures that buttons
are evenly spaced and identically sized. Typically used for simple queries such are evenly spaced and identically sized. Typically used for simple queries such
as "yes/no/cancel". as "yes/no/cancel".
Constructor mandatory positional args: Constructor positional args:
1. `writer` The `Writer` instance (defines font) to use. 1. `writer` The `Writer` instance (defines font) to use.
2. `row` Location on screen. 2. `row=20` Location on screen.
3. `col` 3. `col=20`
Mandatory keyword only arg: Mandatory keyword only arg:
* `elements` A list or tuple of 2-tuples. Each defines the text and color of * `elements` A list or tuple of 2-tuples. Each defines the text and color of
@ -1111,16 +1114,18 @@ Optional keyword only args:
* `callback=dolittle` * `callback=dolittle`
* `args=[]` * `args=[]`
The `DialogBox` is a `Window` subclass. Pressing any button closes the dialog Classmethod (inherited from `Screen`):
and sets the `Window` value to the text of the button pressed or "Close" in the * `value(cls, val=None)` The `val` arg can be any Python type.
The `DialogBox` is a `Screen` subclass. Pressing any button closes the dialog
and sets the `Screen` value to the text of the button pressed or "Close" in the
case of the `close` button. The outcome can therefore be tested by running case of the `close` button. The outcome can therefore be tested by running
`Window.value()` or by implementing the callback. The latter receives the `Screen.value()` or by implementing the callback. The latter receives the
`DialogBox` instance as a first arg, followed by any args supplied to the `DialogBox` instance as a first arg, followed by any args supplied to the
constructor. constructor.
Note that dialog boxes can also be constructed manually, allowing for more Note that dialog boxes can also be constructed manually, enabling more flexible designs. For example these might have widgets other than pushbuttons. The
flexible designs. For example these might have widgets other than pushbuttons. approach is to write a user subclass of `Window`. Example code may be found
The approach is to write a user subclass of `Window`. Example code may be found
in `gui/demos/screens.py`. in `gui/demos/screens.py`.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)
@ -1143,12 +1148,12 @@ fonts.
Constructor mandatory positional arguments: Constructor mandatory positional arguments:
1. `writer` The `Writer` instance (font and screen) to use. 1. `writer` The `Writer` instance (font and screen) to use.
2. `row` Location on screen. 2. `row` Location on screen.
3. `col` 3. `col`
4. `width` Width of the object in pixels. 4. `width` Width of the object in pixels.
5. `nlines` Number of lines of text to display. The object's height is 5. `nlines` Number of lines of text to display. The object's height is
determined from the height of the font: determined from the height of the font:
`height in pixels = nlines*font_height` `height in pixels = nlines*font_height`
As per most widgets the border is drawn two pixels beyond the control's As per all widgets the border is drawn two pixels beyond the control's
boundary. boundary.
Keyword only arguments: Keyword only arguments:
@ -1207,14 +1212,13 @@ Constructor mandatory positional args:
2. `row` Location on screen. 2. `row` Location on screen.
3. `col` 3. `col`
Keyword only args: Keyword only args:
* `height=50` Height of meter. * `height=50` Height of meter.
* `width=10` Width. * `width=10` Width.
* `fgcolor=None` Color of foreground (the control itself). If `None` the * `fgcolor=None` Color of foreground (the control itself). If `None` the
`Writer` foreground default is used. `Writer` foreground default is used.
* `bgcolor=None` Background color of object. If `None` the `Writer` background * `bgcolor=BLACK` Background color of meter. If `None` the `Writer` background
default is used. is used.
* `bdcolor=False` Color of border. If `False` no border will be drawn. If a * `bdcolor=False` Color of border. If `False` no border will be drawn. If a
color is provided, a border line will be drawn around the control. color is provided, a border line will be drawn around the control.
* `ptcolor=None` Color of meter pointer or bar. Default is foreground color. * `ptcolor=None` Color of meter pointer or bar. Default is foreground color.
@ -1226,8 +1230,7 @@ Keyword only args:
* `legends=None` If a tuple of strings is passed, `Label` instances will be * `legends=None` If a tuple of strings is passed, `Label` instances will be
displayed to the right hand side of the meter, starting at the bottom. E.G. displayed to the right hand side of the meter, starting at the bottom. E.G.
`('0.0', '0.5', '1.0')` `('0.0', '0.5', '1.0')`
* `value=None` Initial value. If `None` the meter will not be drawn until * `value=0` Initial value.
its `value()` method is called.
Methods: Methods:
1. `value` Args: `n=None, color=None`. 1. `value` Args: `n=None, color=None`.
@ -1244,7 +1247,6 @@ Methods:
* `bgcolor=None` Background color, as per foreground. * `bgcolor=None` Background color, as per foreground.
* `bdcolor=None` Border color. As per above except that if `False` is * `bdcolor=None` Border color. As per above except that if `False` is
passed, no border is displayed. This clears a previously drawn border. passed, no border is displayed. This clears a previously drawn border.
3. `show` No args. (Re)draws the meter. Primarily for internal use by GUI.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)
@ -1274,43 +1276,43 @@ Optional keyword only arguments:
* `height` Dimension of the bounding box. Default 100 pixels (v), 20 (h). * `height` Dimension of the bounding box. Default 100 pixels (v), 20 (h).
* `width` Dimension of the bounding box. Default 20 pixels (v), 100 (h). * `width` Dimension of the bounding box. Default 20 pixels (v), 100 (h).
* `divisions=10` Number of graduations on the scale. * `divisions=10` Number of graduations on the scale.
* `legends=None` A tuple of strings to display near the slider. These `Label` * `legends=None` A tuple of strings to display near the slider. These will be
instances will be distributed evenly along its length, starting at the bottom distributed evenly along its length, starting at the bottom (v) or left (h).
(v) or left (h).
* `fgcolor=None` Color of foreground (the control itself). If `None` the * `fgcolor=None` Color of foreground (the control itself). If `None` the
`Writer` foreground default is used. `Writer` foreground default is used.
* `bgcolor=None` Background color of object. If `None` the `Writer` background * `bgcolor=None` Background color of object. If `None` the `Writer` background
default is used. default is used.
* `fontcolor=None` Text color. Defaults to foreground color.
* `bdcolor=False` Color of border. If `False` no border will be drawn. If a * `bdcolor=False` Color of border. If `False` no border will be drawn. If a
color is provided, a border line will be drawn around the control. color is provided, a border line will be drawn around the control.
* `prcolor=None` If `active`, in precision mode the white focus border changes
to yellow to for a visual indication. An alternative color can be provided.
`WHITE` will defeat this change.
* `fontcolor=None` Text color. Defaults to foreground color.
* `slotcolor=None` Color for the slot: this is a thin rectangular region in * `slotcolor=None` Color for the slot: this is a thin rectangular region in
the centre of the control along which the slider moves. Defaults to the the centre of the control along which the slider moves. Defaults to the
background color. background color.
* `prcolor=None` If `active`, in precision mode the white focus border changes
to yellow to for a visual indication. An alternative color can be provided.
`WHITE` will defeat this change.
* `callback=dolittle` Callback function which runs whenever the control's * `callback=dolittle` Callback function which runs whenever the control's
value changes. If the control is `active` it also runs on instantiation. This value changes. If the control is `active` it also runs on instantiation. This
enables dynamic color changes. Default is a null function. enables dynamic color changes. Default is a null function.
* `args=[]` A list/tuple of arguments for above callback. * `args=[]` A list/tuple of arguments for above callback.
* `value` The initial value. Default 0.0: slider will be at the bottom (v), * `value=0.0` The initial value: slider will be at the bottom (v), left (h).
left (h).
* `active=True` Determines whether the control can accept user input. * `active=True` Determines whether the control can accept user input.
Methods: Methods:
* `greyed_out` Optional argument, boolean or default `val=None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise current 'greyed out' status of the control. Otherwise enables or disables it,
enables or disables it, showing it in its new state. showing it in its new state.
* `value=None` Optional float argument. If supplied the slider moves to show * `value=None` Optional float argument. If supplied the slider moves to show
the new value and the callback is triggered. The method constrains the range the new value and the callback is triggered. The method constrains the range
to 0.0 to 1.0. The method always returns the control's value. to 0.0 to 1.0. The method always returns the control's value.
* `color` Mandatory arg `color` The control is rendered in the selected * `color` Mandatory arg `color` The control is rendered in the selected
color. This supports dynamic color changes. color. This supports dynamic color changes.
When the widget has focus, the `increase` and `decrease` buttons adjust the If instantiated as `active`, the floating point widget behaves as per
value. Brief presses make small changes, longer presses cause accelerating [section 1.12](./README.md#112-floating-point-widgets). When the widget has
change. focus, `increase` and `decrease` buttons adjust the value. Brief presses cause
small changes, longer presses cause accelerating change. A long press of
`select` invokes high precision mode.
The callback receives an initial arg being the slider instance followed by any The callback receives an initial arg being the slider instance followed by any
user supplied args. They can be a bound methods, typically of a `Screen` user supplied args. They can be a bound methods, typically of a `Screen`
@ -1351,12 +1353,12 @@ Constructor mandatory positional args:
2. `row` Location on screen. 2. `row` Location on screen.
3. `col` 3. `col`
Keyword only arguments (all optional): Optional keyword only arguments:
* `ticks=200` Number of "tick" divisions on scale. Must be divisible by 2. * `ticks=200` Number of "tick" divisions on scale. Must be divisible by 2.
* `legendcb=None` Callback for populating scale legends (see below). * `legendcb=None` Callback for populating scale legends (see below).
* `tickcb=None` Callback for setting tick colors (see below). * `tickcb=None` Callback for setting tick colors (see below).
* `height=0` Pass 0 for a minimum height based on the font height. * `height=0` Pass 0 for a minimum height based on the font height.
* `width=200` * `width=100`
* `fgcolor=None` Color of foreground (the control itself). If `None` the * `fgcolor=None` Color of foreground (the control itself). If `None` the
`Writer` foreground default is used. `Writer` foreground default is used.
* `bgcolor=None` Background color of object. If `None` the `Writer` background * `bgcolor=None` Background color of object. If `None` the `Writer` background
@ -1368,17 +1370,19 @@ Keyword only arguments (all optional):
`WHITE` will defeat this change. `WHITE` will defeat this change.
* `pointercolor=None` Color of pointer. Defaults to `.fgcolor`. * `pointercolor=None` Color of pointer. Defaults to `.fgcolor`.
* `fontcolor=None` Color of legends. Default `fgcolor`. * `fontcolor=None` Color of legends. Default `fgcolor`.
* `callback=dolittle` Callback function which runs whenever the control's
value changes. If the control is `active` it also runs on instantiation. This
enables dynamic color changes. Default is a null function.
* `args=[]` A list/tuple of arguments for above callback.
* `value=0.0` Initial value. * `value=0.0` Initial value.
* `active=False` By default the widget is passive. By setting `active=True` * `active=False` By default the widget is passive. By setting `active=True`
the widget can acquire focus. When current, the value can be changed with the the widget can acquire focus; its value can then be adjusted with the
`increase` and `decrease` buttons. An accelerating algorithm allows rapid `increase` and `decrease` buttons.
changes with a long button push. Short pushes change the value by a small
amount, currently 0.01.
Methods: Methods:
* `greyed_out` Optional argument, boolean or default `val=None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise current 'greyed out' status of the control. Otherwise enables or disables it,
enables or disables it, showing it in its new state. showing it in its new state.
* `value=None` Set or get the current value. Always returns the current value. * `value=None` Set or get the current value. Always returns the current value.
A passed `float` is constrained to the range -1.0 <= V <= 1.0 and becomes the A passed `float` is constrained to the range -1.0 <= V <= 1.0 and becomes the
`Scale`'s current value. The `Scale` is updated. Passing `None` enables `Scale`'s current value. The `Scale` is updated. Passing `None` enables
@ -1386,6 +1390,12 @@ Methods:
For example code see `gui/demos/active.py`. For example code see `gui/demos/active.py`.
If instantiated as `active`, the floating point widget behaves as per
[section 1.12](./README.md#112-floating-point-widgets). When the widget has
focus, `increase` and `decrease` buttons adjust the value. Brief presses cause
small changes, longer presses cause accelerating change. A long press of
`select` invokes high precision mode.
### Callback legendcb ### Callback legendcb
The display window contains 20 ticks comprising two divisions; by default a The display window contains 20 ticks comprising two divisions; by default a
@ -1500,8 +1510,7 @@ Keyword only arguments (all optional):
arguments are the `ScaleLog` instance, followed by any user supplied args. arguments are the `ScaleLog` instance, followed by any user supplied args.
* `value=1.0` Initial value. * `value=1.0` Initial value.
* `delta=0.01` This determines the smallest amount of change which can be * `delta=0.01` This determines the smallest amount of change which can be
achieved with a brief button press. The value is multiplied or divided by achieved with a brief button press. See Control Algorithm below.
`1+delta`.
* `active=False` Determines whether the widget accepts user input. * `active=False` Determines whether the widget accepts user input.
Methods: Methods:
@ -1509,20 +1518,28 @@ Methods:
A passed `float` is constrained to the range `1.0 <= V <= 10**decades` and A passed `float` is constrained to the range `1.0 <= V <= 10**decades` and
becomes the control's current value. The `ScaleLog` is updated. Always returns becomes the control's current value. The `ScaleLog` is updated. Always returns
the control's current value. See note below on precision. the control's current value. See note below on precision.
* `greyed_out` Optional Boolean argument `val` default `None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise current 'greyed out' status of the control. Otherwise enables or disables it,
enables or disables it, showing it in its new state. showing it in its new state.
For example code see `gui/demos/active.py`. For example code see `gui/demos/active.py`.
### Control algorithm ### Control algorithm
When `increase` or `decrease` buttons are briefly pressed, the widget's value If instantiated as `active`, the floating point widget behaves as per
is multiplied or divided by `(1 + delta)`. A long press causes an accelerating [section 1.12](./README.md#112-floating-point-widgets). When the widget has
change. This facilitates both small and large changes. The value of `delta` focus, `increase` and `decrease` buttons adjust the value. Brief presses cause
determines the minimum change possible and hence the level of precision that small changes, longer presses cause accelerating change. A long press of
the widget can achieve. The choice of `delta` represents a compromise between `select` invokes high precision mode.
precision and usability.
In normal mode, the amount of change caused by a brief button press is
controlled by the constructor arg `delta`; the choice of this value represents
a compromise between precision and usability.
Owing to the logarithmic nature of the control, a small positive change is
defined by multiplication of the value by `(1 + delta)` and a negative change
corresponds to division by `(1 + delta)`. In precision mode `delta` is
reduced by a factor of 10.
### Callback ### Callback
@ -1720,9 +1737,9 @@ Optional keyword only arguments:
* `active=True` Enable user input via the `increase` and `decrease` buttons. * `active=True` Enable user input via the `increase` and `decrease` buttons.
Methods: Methods:
* `greyed_out` Optional Boolean argument `val` default `None`. If * `greyed_out` Optional Boolean argument `val=None`. If `None` returns the
`None` returns the current 'greyed out' status of the control. Otherwise, if current 'greyed out' status of the control. Otherwise enables or disables it,
the widget is `active`, enables or disables it, showing it in its new state. showing it in its new state.
* `value` Optional argument `val`. If set, adjusts the pointer to * `value` Optional argument `val`. If set, adjusts the pointer to
correspond to the new value. The move callback will run. The method constrains correspond to the new value. The move callback will run. The method constrains
the range to 0.0 to 1.0. Always returns the control's value. the range to 0.0 to 1.0. Always returns the control's value.

Wyświetl plik

@ -16,6 +16,10 @@ from hardware_setup import ssd
from gui.primitives.delay_ms import Delay_ms from gui.primitives.delay_ms import Delay_ms
from gui.primitives.switch import Switch from gui.primitives.switch import Switch
# Globally available singleton objects
display = None # Singleton instance
ssd = None
gc.collect() gc.collect()
__version__ = (0, 1, 0) __version__ = (0, 1, 0)
@ -26,10 +30,6 @@ async def _g():
pass pass
type_coro = type(_g()) type_coro = type(_g())
def setup(d):
global display
display = d
_FIRST = const(0) _FIRST = const(0)
_NEXT = const(1) _NEXT = const(1)
_PREV = const(2) _PREV = const(2)
@ -38,7 +38,8 @@ _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:
def __init__(self, ssd, nxt, sel, prev=None, up=None, down=None): def __init__(self, objssd, nxt, sel, prev=None, up=None, down=None):
global display, ssd
self._next = Switch(nxt) self._next = Switch(nxt)
self._sel = Switch(sel) self._sel = Switch(sel)
self._last = None # Last switch pressed. self._last = None # Last switch pressed.
@ -48,8 +49,8 @@ class Display:
self._sel.close_func(self._closure, (self._sel, Screen.sel_ctrl)) self._sel.close_func(self._closure, (self._sel, Screen.sel_ctrl))
self._sel.open_func(Screen.unsel) self._sel.open_func(Screen.unsel)
self.height = ssd.height self.height = objssd.height
self.width = ssd.width self.width = objssd.width
# Optional buttons # Optional buttons
self._prev = None self._prev = None
@ -66,6 +67,8 @@ class Display:
self._down = Switch(down) self._down = Switch(down)
self._down.close_func(self._closure, (self._down, self.do_down)) self._down.close_func(self._closure, (self._down, self.do_down))
self._is_grey = False # Not greyed-out self._is_grey = False # Not greyed-out
display = self # Populate globals
ssd = objssd
# Reject button presses where a button is already pressed. # Reject button presses where a button is already pressed.
# Execute if initialising, if same switch re-pressed or if last switch released # Execute if initialising, if same switch re-pressed or if last switch released
@ -199,6 +202,15 @@ class Display:
class Screen: class Screen:
current_screen = None current_screen = None
is_shutdown = Event() is_shutdown = Event()
_value = None
# Allow a Screen to store an arbitrary object. Retrieval may be
# done by caller, after the Screen instance was deleted
@classmethod
def value(cls, val=None):
if val is not None:
cls._value = val
return cls._value
@classmethod @classmethod
def next_ctrl(cls): def next_ctrl(cls):
@ -480,7 +492,7 @@ class Screen:
# Very basic window class. Cuts a rectangular hole in a screen on which content may be drawn # Very basic window class. Cuts a rectangular hole in a screen on which content may be drawn
class Window(Screen): class Window(Screen):
_value = None
def __init__(self, row, col, height, width, *, draw_border=True, bgcolor=None, fgcolor=None): def __init__(self, row, col, height, width, *, draw_border=True, bgcolor=None, fgcolor=None):
Screen.__init__(self) Screen.__init__(self)
self.row = row self.row = row
@ -507,12 +519,6 @@ class Window(Screen):
y = self.row y = self.row
return x, y, x + w, y + h, w, h return x, y, x + w, y + h, w, h
@classmethod
def value(cls, val=None): # Mechanism for testing the outcome of a dialog box
if val is not None:
cls._value = val
return cls._value
# Base class for all displayable objects # Base class for all displayable objects
class Widget: class Widget:

Wyświetl plik

@ -1,8 +1,8 @@
# active.py micro-gui demo of widgets that respond to user control # active.py micro-gui demo of widgets that respond to user control
# Create SSD instance. Must be done first because of RAM use. # Create SSD instance. Must be done first because of RAM use.
from hardware_setup import ssd import hardware_setup
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.core.writer import CWriter from gui.core.writer import CWriter
import gui.fonts.arial10 as arial10 # Font for CWriter import gui.fonts.arial10 as arial10 # Font for CWriter
from gui.core.colors import * from gui.core.colors import *

Wyświetl plik

@ -8,7 +8,7 @@
# Copyright (c) 2021 Peter Hinch # Copyright (c) 2021 Peter Hinch
# Create SSD instance. Must be done first because of RAM use. # Create SSD instance. Must be done first because of RAM use.
from hardware_setup import ssd import hardware_setup
import cmath import cmath
import math import math
@ -16,7 +16,7 @@ import uasyncio as asyncio
from collections import OrderedDict from collections import OrderedDict
from gui.core.writer import Writer, CWriter from gui.core.writer import Writer, CWriter
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
from gui.widgets.label import Label from gui.widgets.label import Label
from gui.widgets.buttons import Button, CloseButton from gui.widgets.buttons import Button, CloseButton

Wyświetl plik

@ -1,12 +1,12 @@
# screens.py micro-gui demo of multiple screens, dropdowns etc # screens.py micro-gui demo of multiple screens, dropdowns etc
# Create SSD instance. Must be done first because of RAM use. # Create SSD instance. Must be done first because of RAM use.
from hardware_setup import ssd # Create a display instance import hardware_setup # Create a display instance
from gui.core.ugui import Screen, Window from gui.core.ugui import Screen, Window, ssd
from gui.widgets.label import Label from gui.widgets.label import Label
from gui.widgets.buttons import Button, RadioButtons, CloseButton from gui.widgets.buttons import Button, RadioButtons, CloseButton
from gui.widgets.listbox import Listbox, ON_LEAVE from gui.widgets.listbox import Listbox
from gui.widgets.dropdown import Dropdown from gui.widgets.dropdown import Dropdown
from gui.widgets.dialog import DialogBox from gui.widgets.dialog import DialogBox
from gui.core.writer import CWriter from gui.core.writer import CWriter
@ -80,7 +80,8 @@ class BaseScreen(Screen):
row = 2 row = 2
Listbox(wri, row, col, callback=lbcb, Listbox(wri, row, col, callback=lbcb,
elements = ('cat', 'dog', 'aardvark', 'goat', 'pig', 'mouse'), elements = ('cat', 'dog', 'aardvark', 'goat', 'pig', 'mouse'),
bdcolor = GREEN, bgcolor = DARKGREEN, also = ON_LEAVE) bdcolor = GREEN, bgcolor = DARKGREEN,
also = Listbox.ON_LEAVE)
col = 70 col = 70
Dropdown(wri, row, col, callback=ddcb, Dropdown(wri, row, col, callback=ddcb,
elements = ('hydrogen', 'helium', 'neon', 'xenon', 'new screen'), elements = ('hydrogen', 'helium', 'neon', 'xenon', 'new screen'),

Wyświetl plik

@ -1,8 +1,8 @@
# simple.py Minimal micro-gui demo. # simple.py Minimal micro-gui demo.
# Initialise hardware and framebuf before importing modules. # Initialise hardware and framebuf before importing modules.
# Import SSD and Display instances. Must be done first because of RAM use. # Import SSD and Display instances. Must be done first because of RAM use.
from hardware_setup import ssd # Create a display instance import hardware_setup # Create a display instance
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.widgets.label import Label from gui.widgets.label import Label
from gui.widgets.buttons import Button, CloseButton from gui.widgets.buttons import Button, CloseButton

Wyświetl plik

@ -7,9 +7,9 @@
# import gui.demos.tbox # import gui.demos.tbox
# Initialise hardware and framebuf before importing modules. # Initialise hardware and framebuf before importing modules.
from hardware_setup import ssd # Create a display instance import hardware_setup # Create a display instance
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.core.writer import CWriter from gui.core.writer import CWriter
import uasyncio as asyncio import uasyncio as asyncio

Wyświetl plik

@ -2,9 +2,9 @@
# Initialise hardware and framebuf before importing modules. # Initialise hardware and framebuf before importing modules.
# Create SSD instance. Must be done first because of RAM use. # Create SSD instance. Must be done first because of RAM use.
from hardware_setup import ssd import hardware_setup
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.core.writer import CWriter from gui.core.writer import CWriter
import gui.fonts.arial10 as arial10 # Font for CWriter import gui.fonts.arial10 as arial10 # Font for CWriter
from gui.core.colors import * from gui.core.colors import *

Wyświetl plik

@ -4,14 +4,14 @@
# Copyright (c) 2021 Peter Hinch # Copyright (c) 2021 Peter Hinch
# Create SSD instance. Must be done first because of RAM use. # Create SSD instance. Must be done first because of RAM use.
from hardware_setup import ssd import hardware_setup
import urandom import urandom
import time import time
from cmath import rect, pi from cmath import rect, pi
import uasyncio as asyncio import uasyncio as asyncio
from gui.core.ugui import Screen from gui.core.ugui import Screen, ssd
from gui.core.writer import CWriter from gui.core.writer import CWriter
from gui.fonts import font10 from gui.fonts import font10
from gui.core.colors import * from gui.core.colors import *

Wyświetl plik

@ -2,7 +2,6 @@
# Released under the MIT License (MIT). See LICENSE. # Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch # Copyright (c) 2021 Peter Hinch
from micropython import const
from gui.core.ugui import Widget, display from gui.core.ugui import Widget, display
from gui.core.colors import * from gui.core.colors import *
@ -11,10 +10,11 @@ dolittle = lambda *_ : None
# Behaviour has issues compared to touch displays because movement between # Behaviour has issues compared to touch displays because movement between
# entries is sequential. This can affect the choice in when the callback runs. # entries is sequential. This can affect the choice in when the callback runs.
# It always runs when select is pressed. See 'also' ctor arg. # It always runs when select is pressed. See 'also' ctor arg.
ON_MOVE = const(1) # Also run whenever the currency moves.
ON_LEAVE = const(2) # Also run on exit from the control.
class Listbox(Widget): class Listbox(Widget):
ON_MOVE = 1 # Also run whenever the currency moves.
ON_LEAVE = 2 # Also run on exit from the control.
@staticmethod @staticmethod
def dimensions(writer, elements): def dimensions(writer, elements):
entry_height = writer.height + 2 # Allow a pixel above and below text entry_height = writer.height + 2 # Allow a pixel above and below text
@ -81,13 +81,13 @@ class Listbox(Widget):
def do_up(self, _): def do_up(self, _):
if v := self._value: if v := self._value:
self.value(v - 1) self.value(v - 1)
if (self.also & ON_MOVE): # Treat as if select pressed if (self.also & Listbox.ON_MOVE): # Treat as if select pressed
self.do_sel() self.do_sel()
def do_down(self, _): def do_down(self, _):
if (v := self._value) < len(self.elements) - 1: if (v := self._value) < len(self.elements) - 1:
self.value(v + 1) self.value(v + 1)
if (self.also & ON_MOVE): if (self.also & Listbox.ON_MOVE):
self.do_sel() self.do_sel()
# Callback runs if select is pressed. Also (if ON_LEAVE) if user changes # Callback runs if select is pressed. Also (if ON_LEAVE) if user changes
@ -102,5 +102,5 @@ class Listbox(Widget):
self.ev = self._value # Value change detection self.ev = self._value # Value change detection
def leave(self): def leave(self):
if (self.also & ON_LEAVE) and self._value != self.ev: if (self.also & Listbox.ON_LEAVE) and self._value != self.ev:
self.do_sel() self.do_sel()

Wyświetl plik

@ -16,7 +16,8 @@ import uasyncio as asyncio
# Reason for no tab support in nano-gui/private/reason_for_no_tabs # Reason for no tab support in nano-gui/private/reason_for_no_tabs
class Textbox(LinearIO): class Textbox(LinearIO):
def __init__(self, writer, row, col, width, nlines, *, bdcolor=None, fgcolor=None, def __init__(self, writer, row, col, width, nlines, *,
bdcolor=None, fgcolor=None,
bgcolor=None, clip=True, active=False): bgcolor=None, clip=True, active=False):
height = nlines * writer.height height = nlines * writer.height
devht = writer.device.height devht = writer.device.height

Wyświetl plik

@ -43,7 +43,7 @@ spi = SPI(0, baudrate=30_000_000)
gc.collect() # Precaution before instantiating framebuf gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, pcs, pdc, prst, usd=True) ssd = SSD(spi, pcs, pdc, prst, usd=True)
from gui.core.ugui import Display, setup from gui.core.ugui import Display
# Create and export a Display instance # Create and export a Display instance
# Define control buttons # Define control buttons
nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control
@ -52,4 +52,3 @@ 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)
setup(display)

Wyświetl plik

@ -43,7 +43,7 @@ spi = SPI(0, baudrate=30_000_000)
gc.collect() # Precaution before instantiating framebuf gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, pcs, pdc, prst, usd=True) ssd = SSD(spi, pcs, pdc, prst, usd=True)
from gui.core.ugui import Display, setup from gui.core.ugui import Display
# Create and export a Display instance # Create and export a Display instance
# Define control buttons # Define control buttons
nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control
@ -52,4 +52,3 @@ 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)
setup(display)

Wyświetl plik

@ -95,7 +95,7 @@ ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSC
# Normal portrait display: consistent with TTGO logo at top # Normal portrait display: consistent with TTGO logo at top
# ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT, display=TDISPLAY) # ssd = SSD(spi, height=240, width=135, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT, display=TDISPLAY)
from gui.core.ugui import Display, setup from gui.core.ugui import Display
# Create and export a Display instance # Create and export a Display instance
# Define control buttons # Define control buttons
nxt = Pin(36, Pin.IN, Pin.PULL_UP) # Move to next control nxt = Pin(36, Pin.IN, Pin.PULL_UP) # Move to next control
@ -104,7 +104,6 @@ prev = Pin(38, Pin.IN, Pin.PULL_UP) # Move to previous control
increase = Pin(39, Pin.IN, Pin.PULL_UP) # Increase control's value increase = Pin(39, Pin.IN, Pin.PULL_UP) # Increase control's value
decrease = Pin(32, Pin.IN, Pin.PULL_UP) # Decrease control's value decrease = Pin(32, 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)
setup(display)
# optional # optional
# b1 = Pin(BUTTON1, Pin.IN) # b1 = Pin(BUTTON1, Pin.IN)