kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
Initial commit.
rodzic
7828c0513c
commit
64d75fe273
470
README.md
470
README.md
|
@ -1,8 +1,470 @@
|
|||
# micropython-micro-gui
|
||||
Under development: will be released soon after further testing.
|
||||
|
||||
A lightweight MicroPython GUI library for display drivers based on framebuf, allows input via pushbuttons or via a switch joystick.
|
||||
This is a lightweight, portable, MicroPython GUI library for displays with
|
||||
drivers subclassed from `framebuf`. It allows input via pushbuttons or via a
|
||||
switch joystick.
|
||||
|
||||
It is larger and more complex than nano-gui owing to the support for input. It enables switching between screens and launching modal windows. In addition to nano-gui widgets it supports listboxes, dropdown lists, various means of entering or displaying floating point values, and other widgets.
|
||||
It is larger and more complex than `nano-gui` owing to the support for input.
|
||||
It enables switching between screens and launching modal windows. In addition
|
||||
to `nano-gui` widgets it supports listboxes, dropdown lists, various means of
|
||||
entering or displaying floating point values, and other widgets.
|
||||
|
||||
It uses display drivers for [nano-gui](https://github.com/peterhinch/micropython-nano-gui) providing portability to a wide range of displays. It is also portable between hosts. Currently running on RP2, but I intend to test on Pyboard and ESP32/TTGo TDisplay.
|
||||
It is compatible with all display drivers for
|
||||
[nano-gui](https://github.com/peterhinch/micropython-nano-gui) so is portable
|
||||
to a wide range of displays. It is also portable between hosts.
|
||||
|
||||
## This document is seriously incomplete.
|
||||
## It may be several weeks before it is usable.
|
||||
## Code is in a better state.
|
||||
|
||||
# 0. Contents
|
||||
|
||||
**TODO**
|
||||
|
||||
# 1. Basic concepts
|
||||
|
||||
Internally `micro-gui` uses `uasyncio`. It presents a conventional callback
|
||||
based interface; knowledge of `uasyncio` is not required for its use. Display
|
||||
refresh is handled automatically. As in nano-gui, widgets are drawn using
|
||||
graphics primitives rather than icons. This makes them efficiently scalable and
|
||||
minimises RAM usage compared to icon-based graphics. It also facilitates the
|
||||
provision of extra visual information. For example the color of all or part of
|
||||
a widget may be changed programmatically, for example to highlight an overrange
|
||||
condition.
|
||||
|
||||
## 1.1 Coordinates
|
||||
|
||||
These are defined as `row` and `col` values where `row==0` and `col==0`
|
||||
corresponds to the top left most pixel. Rows increase downwards and columns
|
||||
increase to the right. The graph plotting widget uses normal mathematical
|
||||
conventions within graphs.
|
||||
|
||||
## 1.2 Screen, Window and Widget objects
|
||||
|
||||
A `Screen` is a window which occupies the entire display. A `Screen` can
|
||||
overlay another, replacing all its contents. When closed, the `Screen` below is
|
||||
re-displayed.
|
||||
|
||||
A `Window` is a subclass of `Screen` but is smaller, with size and location
|
||||
attributes. It can overlay part of an underlying `Screen` and is typically used
|
||||
for modal dialog boxes.
|
||||
|
||||
A `Widget` is an object capable of displaying data. Some are also capable of
|
||||
data input. The latter can be capable of accepting focus, see
|
||||
[navigation](./README.md#13-navigation). `Widget` objects have dimensions
|
||||
defined as `height` and `width`. The space requred by them exceeds these by two
|
||||
pixels all round, as a white border is drawn to show which object currently has
|
||||
focus. Thus to place a `Widget` at the extreme top left, `row` and `col` values
|
||||
should be 2.
|
||||
|
||||
## 1.3 Fonts
|
||||
|
||||
Python font files are in the `gui/fonts` directory. The easiest way to conserve
|
||||
RAM is to freeze them which is highly recommended. In doing so the directory
|
||||
structure must be maintained.
|
||||
|
||||
To create alternatives, Python fonts may be generated from industry standard
|
||||
font files with
|
||||
[font_to_py.py](https://github.com/peterhinch/micropython-font-to-py.git). The
|
||||
`-x` option for horizontal mapping must be specified. If fixed pitch rendering
|
||||
is required `-f` is also required. Supplied examples are:
|
||||
|
||||
* `arial10.py` Variable pitch Arial. 10 pixels high.
|
||||
* `arial35.py` Arial 35 high.
|
||||
* `arial_50.py` Arial 50 high.
|
||||
* `courier20.py` Fixed pitch Courier, 20 high.
|
||||
* `font6.py` FreeSans 14 high.
|
||||
* `font10.py` FreeSans 17 high.
|
||||
* `freesans20.py` FreeSans 20 high.
|
||||
|
||||
## 1.4 Navigation
|
||||
|
||||
The GUI requires from 2 to 5 pushbuttons for control. These are:
|
||||
1. `Next` Move to the next widget.
|
||||
2. `Select` Operate the currently selected widget.
|
||||
3. `Prev` Move to the previous widget.
|
||||
4. `Increase` Move within the widget.
|
||||
5. `Decrease` Move within the widget.
|
||||
|
||||
Many widgets such as `Pushbutton` or `Checkbox` objects require only the
|
||||
`Select` button to operate: it is possible to design an interface using only
|
||||
the first two buttons.
|
||||
|
||||
Widgets such as `Listbox` objects, dropdown lists (`Dropdown`), and those for
|
||||
floating point data entry require the `Increase` and `Decrease` buttons to move
|
||||
within the widget or to adjust the linear value.
|
||||
|
||||
A `LinearIO` is a `Widget` that responds to the `increase` and `decrease`
|
||||
buttons by running an `asyncio` task. These typically output floating point
|
||||
values using an accelerating algorithm responding to the duration of the button
|
||||
press. This enables floats with a wide dynamic range to be adjusted with
|
||||
precision.
|
||||
|
||||
The currently selected `Widget` is identified by a white border: the focus
|
||||
moves between widgets via `Next` and `Prev`. Only `Widget` instances that can
|
||||
accept input can receive the focus; such widgets are defined as `active`. Some
|
||||
widgets can be declared as `active` or not in the constructor. An `active`
|
||||
widget can be disabled and re-enabled at runtime. While disabled a widget is
|
||||
shown "greyed-out" and cannot accept the focus.
|
||||
|
||||
## 1.5 Hardware definition
|
||||
|
||||
A file `hardware_setup.py` must exist in the GUI root directory. This defines
|
||||
the connections to the display, the display driver, and pins used for the
|
||||
pushbuttons. Example files may be found in the `setup_examples` directory.
|
||||
|
||||
Display drivers are documented
|
||||
[here](https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md).
|
||||
|
||||
## 1.6 Installation
|
||||
|
||||
The easy way to start is to use `mpremote` which allows a directory on your PC
|
||||
to be mounted on the host. In this way the filesystem on the host is left
|
||||
unchanged. This is at some cost in loading speed, especially on ESP32. If
|
||||
adopting this approach, you will need to ensure the `hardware_setup.py` file on
|
||||
the PC matches your hardware. Install `mpremote` with
|
||||
```bash
|
||||
$ pip3 install mpremote
|
||||
```
|
||||
Clone the repo to your PC with
|
||||
```bash
|
||||
$ git clone https://github.com/peterhinch/micropython-micro-gui
|
||||
$ cd micropython-micro-gui
|
||||
```
|
||||
Edit `hardware_setup.py` then run:
|
||||
```bash
|
||||
$ mpremote mount .
|
||||
```
|
||||
This should provide a REPL. Run the minimal demo:
|
||||
```python
|
||||
>>> import gui.demos.simple
|
||||
```
|
||||
If installing to the device's filesystem it is necessary to maintain the
|
||||
directory structure. The `drivers` and `gui` directories (with subdirectories
|
||||
and contents) should be copied, along with `hardware_setup.py`. Filesystem
|
||||
space may be conserved by copying only the display driver in use. Unused
|
||||
widgets, fonts and demos can also be trimmed, but directory structure must be
|
||||
kept.
|
||||
|
||||
There is scope for speeding loading and saving RAM by using frozen bytecode.
|
||||
Once again, directory structure must be maintained.
|
||||
|
||||
## 1.7 Quick hardware check
|
||||
|
||||
The following may be pasted at the REPL to verify correct connection to the
|
||||
display. It also confirms that `hardware_setup.py` is specifying a suitable
|
||||
display driver.
|
||||
```python
|
||||
from hardware_setup import ssd # Create a display instance
|
||||
from gui.core.colors import *
|
||||
ssd.fill(0)
|
||||
ssd.line(0, 0, ssd.width - 1, ssd.height - 1, GREEN) # Green diagonal corner-to-corner
|
||||
ssd.rect(0, 0, 15, 15, RED) # Red square at top left
|
||||
ssd.rect(ssd.width -15, ssd.height -15, 15, 15, BLUE) # Blue square at bottom right
|
||||
ssd.show()
|
||||
```
|
||||
|
||||
## 1.8 Performance and hardware notes
|
||||
|
||||
The largest supported display is a 320x240 ILI9341 unit. On a Pi Pico with no
|
||||
use of frozen bytecode the demos run with over 74K of free RAM. Substantial
|
||||
improvements could be achieved using frozen bytecode.
|
||||
|
||||
Snappy navigation benefits from several approaches:
|
||||
1. Clocking the SPI bus as fast as possible.
|
||||
2. Clocking the host fast (`machine.freq`).
|
||||
3. Device driver support for `uasyncio`. Currently this exists on ILI9341 and
|
||||
ST7789 (e.g. TTGO T-Display). I intend to extend this to other drivers.
|
||||
|
||||
On ESP32 I found it necessary to use physical pullup resistors on the
|
||||
pushbutton GPIO lines.
|
||||
|
||||
## 1.9 Firmware and dependencies
|
||||
|
||||
Firmware should be V1.15 or later.
|
||||
|
||||
The source tree includes all dependencies. These are listed to enable users to
|
||||
check for newer versions:
|
||||
|
||||
* [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py)
|
||||
Provides text rendering of Python font files.
|
||||
|
||||
A copy of the official driver for OLED displays using the SSD1306 chip is
|
||||
provided. The official file is here:
|
||||
* [SSD1306 driver](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py).
|
||||
|
||||
Displays based on the Nokia 5110 (PCD8544 chip) require this driver. It is not
|
||||
in this repo but may be found here:
|
||||
* [PCD8544/Nokia 5110](https://github.com/mcauser/micropython-pcd8544.git)
|
||||
|
||||
Synchronisation primitives for `uasyncio` may be found here:
|
||||
* [My async repo](https://github.com/peterhinch/micropython-async/tree/master/v3/primitives).
|
||||
|
||||
## 1.10 Supported hosts and displays
|
||||
|
||||
Development was done using a Raspberry Pi Pico connected to a cheap ILI9341
|
||||
320x240 display. I have also tested a TTGO T-Display (an ESP32 host) and a
|
||||
Pyboard. Code is written with portability as an aim, but MicroPython configs
|
||||
vary between platforms and I can't guarantee that every widget will work on
|
||||
every platform. For example, some use the `cmath` module which may be absent on
|
||||
some builds.
|
||||
|
||||
Supported displays are as per
|
||||
[the nano-gui list](https://github.com/peterhinch/micropython-nano-gui/blob/master/README.md#12-description).
|
||||
In practice usage with ePaper displays is questionable because of their slow
|
||||
refresh times. I haven't tested these, or the Sharp displays.
|
||||
|
||||
Display drivers are documented [here](https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md).
|
||||
|
||||
## 1.11 Files
|
||||
|
||||
Display drivers may be found in the `drivers` directory. These are copies of
|
||||
those in `nano-gui`, included for convenience.
|
||||
|
||||
The system is organised as a Python package with the root being `gui`. Core
|
||||
files in `gui/core` are:
|
||||
* `colors.py` Constants including colors and shapes.
|
||||
* `ugui.py` The main GUI code.
|
||||
* `writer.py` Supports the `Writer` and `CWriter` classes.
|
||||
|
||||
The `gui/primitives` directory contains the following files:
|
||||
* `switch.py` Interface to physical pushbuttons.
|
||||
* `delay_ms.py` A software triggerable timer.
|
||||
|
||||
The `gui/demos` directory contains a variety of demos and tests, some of which
|
||||
require a large (320x240) display. Demos are run by issuing (fo example):
|
||||
```python
|
||||
>>> import gui.demos.simple
|
||||
```
|
||||
* `simple.py` Minimal demo discussed below.
|
||||
* `active.py` Demonstrates `active` controls providing floating point input.
|
||||
* `plot.py` Graph plotting.
|
||||
* `screens.py` Listbox, dropdown and dialog boxes.
|
||||
* `tbox.py` Text boxes and user-controlled scrolling.
|
||||
* `various.py` Assorted widgets including the different types of pushbutton.
|
||||
* `vtest.py` Clock and compass styles of vector display.
|
||||
|
||||
# 2. Usage
|
||||
|
||||
## 2.1 Program structure and operation
|
||||
|
||||
The following is a minimal script (found in `gui.demos.simple.py`) which will
|
||||
run on a minimal system with a small display and two pushbuttons. It provides
|
||||
two `Button` widgets with "Yes" and "No" legends.
|
||||
|
||||
It may be run by issuing
|
||||
```python
|
||||
>>> import gui.demos.simple
|
||||
```
|
||||
at the REPL.
|
||||
|
||||
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
|
||||
of contiguous RAM.
|
||||
```python
|
||||
from hardware_setup import ssd # Create a display instance
|
||||
from gui.core.ugui import Screen
|
||||
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
from gui.core.writer import CWriter
|
||||
|
||||
# Font for CWriter
|
||||
import gui.fonts.arial10 as arial10
|
||||
from gui.core.colors import *
|
||||
|
||||
|
||||
class BaseScreen(Screen):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
def my_callback(button, arg):
|
||||
print('Button pressed', arg)
|
||||
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
|
||||
col = 2
|
||||
row = 2
|
||||
Label(wri, row, col, 'Simple Demo')
|
||||
row = 20
|
||||
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
|
||||
col += 60
|
||||
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
|
||||
CloseButton(wri) # Quit the application
|
||||
|
||||
def test():
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(BaseScreen)
|
||||
|
||||
test()
|
||||
```
|
||||
Note how the `Next` pushbutton moves the focus between the two buttons and the
|
||||
"X" close button. The focus does not move to the "Simple Demo" widget because
|
||||
it is not `active`: a `Label` cannot accept user input. Pushing the `Select`
|
||||
pushbutton while the focus is on a `Pushbutton` causes the callback to run.
|
||||
|
||||
Applications start by performing `Screen.change()` to a user-defined Screen
|
||||
object. This must be subclassed from the GUI's `Screen` class. Note that
|
||||
`Screen.change` accepts a class name, not a class instance.
|
||||
|
||||
The user defined `BaseScreen` class constructor instantiates all widgets to be
|
||||
displayed and typically associates them with callback functions - which may be
|
||||
bound methods. Screens typically have a `CloseButton` widget. This is a special
|
||||
`Pushbutton` subclass which displays as an "X" at the top right corner of the
|
||||
physical display and closes the current screen, showing the one below. If used
|
||||
on the bottom level `Screen` (as above) it closes the application.
|
||||
|
||||
The `wri` `CWriter` instance associates a widget with a font. All widgets use
|
||||
a `CWriter` instance followed by `row` and `col` as positional constructor args
|
||||
followed typically by a number of optional keyword args. These have (hopefully)
|
||||
sensible defaults enabling you to get started easily.
|
||||
|
||||
## 2.2 Callbacks
|
||||
|
||||
The interface is event driven. Widgets may have optional callbacks which will
|
||||
be executed when a given event occurs. A callback function receives positional
|
||||
arguments. The first is a reference to the object raising the callback.
|
||||
Subsequent arguments are user defined, and are specified as a tuple or list of
|
||||
items. Callbacks are optional, as are the argument lists - a default null
|
||||
function and empty list are provided. Callbacks may optionally be written as
|
||||
bound methods - see Screens below for a reason why this can be useful.
|
||||
|
||||
When writing callbacks take care to ensure that the number of arguments passed
|
||||
is correct, bearing in mind the first arg listed above. Failure to do this will
|
||||
result in tracebacks which implicate the GUI code rather than the buggy user
|
||||
code: this is because the GUI runs the callbacks.
|
||||
|
||||
## 2.3 Colors
|
||||
|
||||
The file `gui/core/colors.py` defines standard color constants which may be
|
||||
used with any display driver. This section describes how to change these or
|
||||
to create additional colors.
|
||||
|
||||
Most of the color display drivers define colors as 8-bit or larger values.
|
||||
In such cases colors may be created and assigned to variables as follows:
|
||||
```python
|
||||
from hardware_setup import ssd
|
||||
PALE_YELLOW = ssd.rgb(150, 150, 0)
|
||||
```
|
||||
The GUI also provides drivers with 4-bit color to minimise RAM use. Colors are
|
||||
assigned to a lookup table having 16 entries. The frame buffer stores 4-bit
|
||||
color values, which are converted to the correct color depth for the hardware
|
||||
when the display is refreshed.
|
||||
|
||||
Of the possible 16 colors 13 are assigned in `gui/core/colors.py`, leaving
|
||||
color numbers 12, 13 and 14 free. Any color can be assigned as follows:
|
||||
```python
|
||||
from gui.core.colors import * # Imports the create_color function
|
||||
PALE_YELLOW = create_color(12, 150, 150, 0)
|
||||
```
|
||||
This creates a color `rgb(150, 150, 0)` assigns it to "spare" color number 12
|
||||
then sets `PALE_YELLOW` to 12. Any color number in range `0 <= n <= 15` may be
|
||||
used (implying that predefined colors may be reassigned). It is recommended
|
||||
that `BLACK` (0) and `WHITE` (15) are not changed. If code is to be ported
|
||||
between 4-bit and other drivers, use `create_color()` for all custom colors:
|
||||
it will produce appropriate behaviour. For an example see the `nano-gui` demo
|
||||
`color15.py` - in particular the `vari_fields` function.
|
||||
|
||||
### 2.3.1 Monochrome displays
|
||||
|
||||
Most widgets work on monochrome displays if color settings are left at default
|
||||
values. If a color is specified, drivers in this repo will convert it to black
|
||||
or white depending on its level of saturation. A low level will produce the
|
||||
background color, a high level the foreground.
|
||||
|
||||
At the bit level `1` represents the foreground. This is white on an emitting
|
||||
display such as an OLED. On a Sharp display it indicates reflection.
|
||||
|
||||
There is an issue regarding ePaper displays discussed
|
||||
[here](https://github.com/peterhinch/micropython-nano-gui/blob/master/README.md#312-monochrome-displays).
|
||||
I don't consider ePaper displays as suitable for I/O because of their slow
|
||||
refresh time.
|
||||
|
||||
# 3. Class details
|
||||
|
||||
# 4. Screen class
|
||||
|
||||
The `Screen` class presents a full-screen canvas onto which displayable
|
||||
objects are rendered. Before instantiating widgets a `Screen` instance must be
|
||||
created. This will be current until another is instantiated. When a widget is
|
||||
instantiated it is associated with the current screen.
|
||||
|
||||
All applications require the creation of at least one user screen. This is done
|
||||
by subclassing the `Screen` class. Widgets are instantiated in the constructor.
|
||||
Widgets may be assigned to bound variable: this facilitates communication
|
||||
between them.
|
||||
|
||||
## 4.1 Class methods
|
||||
|
||||
In normal use the following methods only are required:
|
||||
* `change` Change screen, refreshing the display. Mandatory positional
|
||||
argument: the new screen class name. This must be a class subclassed from
|
||||
`Screen`. The class will be instantiated and displayed. Optional keyword
|
||||
arguments: `args`, `kwargs`. These enable passing positional and keyword
|
||||
arguments to the constructor of the new screen.
|
||||
* `back` Restore previous screen.
|
||||
|
||||
These are uncommon:__
|
||||
* `shutdown` Clear the screen and shut down the GUI. Normally done by a
|
||||
`CloseButton` instance.
|
||||
* `show(cls, force)`. This causes the screen to be redrawn. If `force` is
|
||||
`False` unchanged widgets are not refreshed. If `True`, all visible widgets
|
||||
are re-drawn. Explicit calls to this should never be needed.
|
||||
|
||||
See `demos/plot.py` for an example of multi-screen design.
|
||||
|
||||
## 4.2 Constructor
|
||||
|
||||
This takes no arguments.
|
||||
|
||||
## 4.3 Callback methods
|
||||
|
||||
These are null functions which may be redefined in user subclasses.
|
||||
|
||||
* `on_open` Called when a screen is instantiated but prior to display.
|
||||
* `after_open` Called after a screen has been displayed.
|
||||
* `on_hide` Called when a screen ceases to be current.
|
||||
|
||||
See `demos/plot.py` for examples of usage of `after_open`.
|
||||
|
||||
## 4.4 Method
|
||||
|
||||
* `reg_task` args `task`, `on_change=False`. The first arg may be a `Task`
|
||||
instance or a coroutine. It is a convenience method which provides for the
|
||||
automatic cancellation of tasks. If a screen runs independent coros it can opt
|
||||
to register these. On shudown, any registered tasks of the base screen are
|
||||
cancelled. On screen change, registered tasks with `on_change` `True` are
|
||||
cancelled. For finer control applications can ignore this method and handle
|
||||
cancellation explicitly in code.
|
||||
|
||||
# 5. Window class
|
||||
|
||||
This is a `Screen` subclass providing for modal windows. As such it has
|
||||
positional and dimension information. Usage consists of writing a user class
|
||||
subclassed from `Window`. Example code is in `demos/screens.py`.
|
||||
|
||||
## 5.2 Constructor
|
||||
|
||||
This takes the following positional args:
|
||||
* `row`
|
||||
* `col`
|
||||
* `height`
|
||||
* `width`
|
||||
|
||||
Followed by keyword-only args
|
||||
* `draw_border=True`
|
||||
* `bgcolor=None` Background color, default black.
|
||||
* `fgcolor=None` Foreground color, default white.
|
||||
|
||||
## 5.3 Class method
|
||||
|
||||
* `value` This accepts a single arg which cane be any Python type. It allows
|
||||
widgets on a `Window` to store information in a way which can be accessed from
|
||||
the calling screen. This typically occurs after the window has closed and no
|
||||
longer exists as an instance.
|
||||
|
||||
Another approach, demonstrated in `demos/screens.py`, is to pass one or more
|
||||
callbacks to the user window constructor args. These may be called by widgets
|
||||
to send data to the calling screen. Note that widgets on the screen below will
|
||||
not be updated until the window has closed.
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
# epaper2in7_fb.py nanogui driver for ePpaper 2.7" display
|
||||
# Tested with Pyboard linked to Raspberry Pi 2.7" E-Ink Display HAT
|
||||
# EPD is subclassed from framebuf.FrameBuffer for use with Writer class and nanogui.
|
||||
# Optimisations to reduce allocations and RAM use.
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Based on the following sources:
|
||||
# https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT
|
||||
# MicroPython Waveshare 2.7" Black/White GDEW027W3 e-paper display driver
|
||||
# https://github.com/mcauser/micropython-waveshare-epaper referred to as "mcauser"
|
||||
# https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in7.py ("official")
|
||||
|
||||
import framebuf
|
||||
import uasyncio as asyncio
|
||||
from time import sleep_ms, ticks_ms, ticks_us, ticks_diff
|
||||
|
||||
class EPD(framebuf.FrameBuffer):
|
||||
# A monochrome approach should be used for coding this. The rgb method ensures
|
||||
# nothing breaks if users specify colors.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, spi, cs, dc, rst, busy, landscape=False, asyn=False):
|
||||
self._spi = spi
|
||||
self._cs = cs # Pins
|
||||
self._dc = dc
|
||||
self._rst = rst
|
||||
self._busy = busy
|
||||
self._lsc = landscape
|
||||
self._asyn = asyn
|
||||
self._as_busy = False # Set immediately on start of task. Cleared when busy pin is logically false (physically 1).
|
||||
self._updated = asyncio.Event()
|
||||
# Dimensions in pixels. Waveshare code is portrait mode.
|
||||
# Public bound variables required by nanogui.
|
||||
self.width = 264 if landscape else 176
|
||||
self.height = 176 if landscape else 264
|
||||
self.demo_mode = False # Special mode enables demos to run
|
||||
self._buffer = bytearray(self.height * self.width // 8)
|
||||
self._mvb = memoryview(self._buffer)
|
||||
mode = framebuf.MONO_VLSB if landscape else framebuf.MONO_HLSB
|
||||
super().__init__(self._buffer, self.width, self.height, mode)
|
||||
self.init()
|
||||
|
||||
def _command(self, command, data=None):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(command)
|
||||
self._cs(1)
|
||||
if data is not None:
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(data)
|
||||
self._cs(1)
|
||||
|
||||
def init(self):
|
||||
# Hardware reset
|
||||
self._rst(1)
|
||||
sleep_ms(200)
|
||||
self._rst(0)
|
||||
sleep_ms(200) # 5ms in Waveshare code
|
||||
self._rst(1)
|
||||
sleep_ms(200)
|
||||
# Initialisation
|
||||
cmd = self._command
|
||||
cmd(b'\x01', b'\x03\x00\x2B\x2B\x09') # POWER_SETTING: VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR
|
||||
cmd(b'\x06', b'\x07\x07\x17') # BOOSTER_SOFT_START
|
||||
cmd(b'\xf8', b'\x60\xA5') # POWER_OPTIMIZATION
|
||||
cmd(b'\xf8', b'\x89\xA5')
|
||||
cmd(b'\xf8', b'\x90\x00')
|
||||
cmd(b'\xf8', b'\x93\x2A')
|
||||
cmd(b'\xf8', b'\xA0\xA5')
|
||||
cmd(b'\xf8', b'\xA1\x00')
|
||||
cmd(b'\xf8', b'\x73\x41')
|
||||
cmd(b'\x16', b'\x00') # PARTIAL_DISPLAY_REFRESH
|
||||
cmd(b'\x04') # POWER_ON
|
||||
self.wait_until_ready()
|
||||
cmd(b'\x00', b'\xAF') # PANEL_SETTING: KW-BF, KWR-AF, BWROTP 0f
|
||||
cmd(b'\x30', b'\x3A') # PLL_CONTROL: 3A 100HZ, 29 150Hz, 39 200HZ 31 171HZ
|
||||
cmd(b'\x50', b'\x57') # Vcom and data interval setting (PGH)
|
||||
cmd(b'\x82', b'\x12') # VCM_DC_SETTING_REGISTER
|
||||
sleep_ms(2) # No delay in official code
|
||||
# Set LUT. Local bytes objects reduce RAM usage.
|
||||
|
||||
# Values used by mcauser
|
||||
#lut_vcom_dc =\
|
||||
#b'\x00\x00\x00\x0F\x0F\x00\x00\x05\x00\x32\x32\x00\x00\x02\x00'\
|
||||
#b'\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
#b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
#lut_ww =\
|
||||
#b'\x50\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\xA0\x0F\x0F'\
|
||||
#b'\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
#b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # R21H
|
||||
#lut_bb =\
|
||||
#b'\xA0\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\x50\x0F\x0F'\
|
||||
#b'\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
#b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # R24H b
|
||||
|
||||
# Values from official code:
|
||||
lut_vcom_dc =\
|
||||
b'\x00\x00\x00\x08\x00\x00\x00\x02\x60\x28\x28\x00\x00\x01\x00'\
|
||||
b'\x14\x00\x00\x00\x01\x00\x12\x12\x00\x00\x01\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
lut_ww =\
|
||||
b'\x40\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x40\x14\x00'\
|
||||
b'\x00\x00\x01\xA0\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
lut_bb =\
|
||||
b'\x80\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x80\x14\x00'\
|
||||
b'\x00\x00\x01\x50\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
# Both agree on this:
|
||||
lut_bw = lut_ww # R22H r
|
||||
lut_wb = lut_bb # R23H w
|
||||
cmd(b'\x20', lut_vcom_dc) # LUT_FOR_VCOM vcom
|
||||
cmd(b'\x21', lut_ww) # LUT_WHITE_TO_WHITE ww --
|
||||
cmd(b'\x22', lut_bw) # LUT_BLACK_TO_WHITE bw r
|
||||
cmd(b'\x23', lut_bb) # LUT_WHITE_TO_BLACK wb w
|
||||
cmd(b'\x24', lut_wb) # LUT_BLACK_TO_BLACK bb b
|
||||
print('Init Done.')
|
||||
|
||||
def wait_until_ready(self):
|
||||
sleep_ms(50)
|
||||
t = ticks_ms()
|
||||
while not self.ready():
|
||||
sleep_ms(100)
|
||||
dt = ticks_diff(ticks_ms(), t)
|
||||
print('wait_until_ready {}ms {:5.1f}mins'.format(dt, dt/60_000))
|
||||
|
||||
async def wait(self):
|
||||
await asyncio.sleep_ms(0) # Ensure tasks run that might make it unready
|
||||
while not self.ready():
|
||||
await asyncio.sleep_ms(100)
|
||||
|
||||
# Pause until framebuf has been copied to device.
|
||||
async def updated(self):
|
||||
await self._updated.wait()
|
||||
|
||||
# For polling in asynchronous code. Just checks pin state.
|
||||
# 0 == busy. Comment in official code is wrong. Code is correct.
|
||||
def ready(self):
|
||||
return not(self._as_busy or (self._busy() == 0)) # 0 == busy
|
||||
|
||||
async def _as_show(self, buf1=bytearray(1)):
|
||||
mvb = self._mvb
|
||||
send = self._spi.write
|
||||
cmd = self._command
|
||||
cmd(b'\x10') # DATA_START_TRANSMISSION_1
|
||||
self._dc(1) # For some reason don't need to deassert CS here
|
||||
buf1[0] = 0xff
|
||||
t = ticks_ms()
|
||||
for i in range(len(mvb)):
|
||||
self._cs(0) # but do when copying the framebuf
|
||||
send(buf1)
|
||||
if not(i & 0x1f) and (ticks_diff(ticks_ms(), t) > 20):
|
||||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
self._cs(1)
|
||||
cmd(b'\x13') # DATA_START_TRANSMISSION_2 not in datasheet
|
||||
|
||||
self._dc(1)
|
||||
# Necessary to deassert CS after each byte otherwise display does not
|
||||
# clear down correctly
|
||||
t = ticks_ms()
|
||||
if self._lsc: # Landscape mode
|
||||
wid = self.width
|
||||
tbc = self.height // 8 # Vertical bytes per column
|
||||
iidx = wid * (tbc - 1) # Initial index
|
||||
idx = iidx # Index into framebuf
|
||||
vbc = 0 # Current vertical byte count
|
||||
hpc = 0 # Horizontal pixel count
|
||||
for i in range(len(mvb)):
|
||||
self._cs(0)
|
||||
buf1[0] = mvb[idx] # INVERSION HACK ~data
|
||||
send(buf1)
|
||||
self._cs(1)
|
||||
idx -= self.width
|
||||
vbc += 1
|
||||
vbc %= tbc
|
||||
if not vbc:
|
||||
hpc += 1
|
||||
idx = iidx + hpc
|
||||
if not(i & 0x1f) and (ticks_diff(ticks_ms(), t) > 20):
|
||||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
else:
|
||||
for i, b in enumerate(mvb):
|
||||
self._cs(0)
|
||||
buf1[0] = b # INVERSION HACK ~data
|
||||
send(buf1)
|
||||
self._cs(1)
|
||||
if not(i & 0x1f) and (ticks_diff(ticks_ms(), t) > 20):
|
||||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
|
||||
self._updated.set() # framebuf has now been copied to the device
|
||||
self._updated.clear()
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
await asyncio.sleep(1)
|
||||
while self._busy() == 0:
|
||||
await asyncio.sleep_ms(200) # Don't release lock until update is complete
|
||||
self._as_busy = False
|
||||
|
||||
# draw the current frame memory. Blocking time ~180ms
|
||||
def show(self, buf1=bytearray(1)):
|
||||
if self._asyn:
|
||||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True
|
||||
asyncio.create_task(self._as_show())
|
||||
return
|
||||
t = ticks_us()
|
||||
mvb = self._mvb
|
||||
send = self._spi.write
|
||||
cmd = self._command
|
||||
cmd(b'\x10') # DATA_START_TRANSMISSION_1
|
||||
self._dc(1) # For some reason don't need to deassert CS here
|
||||
buf1[0] = 0xff
|
||||
for i in range(len(mvb)):
|
||||
self._cs(0) # but do when copying the framebuf
|
||||
send(buf1)
|
||||
self._cs(1)
|
||||
cmd(b'\x13') # DATA_START_TRANSMISSION_2 not in datasheet
|
||||
|
||||
self._dc(1)
|
||||
# Necessary to deassert CS after each byte otherwise display does not
|
||||
# clear down correctly
|
||||
if self._lsc: # Landscape mode
|
||||
wid = self.width
|
||||
tbc = self.height // 8 # Vertical bytes per column
|
||||
iidx = wid * (tbc - 1) # Initial index
|
||||
idx = iidx # Index into framebuf
|
||||
vbc = 0 # Current vertical byte count
|
||||
hpc = 0 # Horizontal pixel count
|
||||
for _ in range(len(mvb)):
|
||||
self._cs(0)
|
||||
buf1[0] = mvb[idx] # INVERSION HACK ~data
|
||||
send(buf1)
|
||||
self._cs(1)
|
||||
idx -= self.width
|
||||
vbc += 1
|
||||
vbc %= tbc
|
||||
if not vbc:
|
||||
hpc += 1
|
||||
idx = iidx + hpc
|
||||
else:
|
||||
for b in mvb:
|
||||
self._cs(0)
|
||||
buf1[0] = b # INVERSION HACK ~data
|
||||
send(buf1)
|
||||
self._cs(1)
|
||||
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
te = ticks_us()
|
||||
print('show time', ticks_diff(te, t)//1000, 'ms')
|
||||
if not self.demo_mode:
|
||||
# Immediate return to avoid blocking the whole application.
|
||||
# User should wait for ready before calling refresh()
|
||||
return
|
||||
self.wait_until_ready()
|
||||
sleep_ms(2000) # Give time for user to see result
|
||||
|
||||
|
||||
# to wake call init()
|
||||
def sleep(self):
|
||||
self._as_busy = False
|
||||
self.wait_until_ready()
|
||||
cmd = self._command
|
||||
cmd(b'\x50', b'\xf7') # From Waveshare code
|
||||
cmd(b'\x02') # POWER_OFF
|
||||
cmd(b'\x07', b'\xA5') # DEEP_SLEEP (Waveshare and mcauser)
|
||||
self._rst(0) # According to schematic this turns off the power
|
||||
|
||||
# Testing connections by toggling pins connected to 40-way connector and checking volts on small connector
|
||||
# All OK except rst: a 1 level produced only about 1.6V as against 3.3V for all other I/O.
|
||||
# Further the level on the 40-way connector read 2.9V as agains 3.3V for others. Suspect hardware problem,
|
||||
# ordered a second unit from Amazon.
|
||||
#import machine
|
||||
#import gc
|
||||
|
||||
#pdc = machine.Pin('Y1', machine.Pin.OUT_PP, value=0)
|
||||
#pcs = machine.Pin('Y2', machine.Pin.OUT_PP, value=1)
|
||||
#prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
|
||||
#pbusy = machine.Pin('Y4', machine.Pin.IN)
|
||||
## baudrate
|
||||
## From https://github.com/mcauser/micropython-waveshare-epaper/blob/master/examples/2in9-hello-world/test.py 2MHz
|
||||
## From https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in7.py 4MHz
|
||||
#spi = machine.SPI(2, baudrate=2_000_000)
|
||||
#gc.collect() # Precaution before instantiating framebuf
|
||||
#epd = EPD(spi, pcs, pdc, prst, pbusy) # Create a display instance
|
||||
#sleep_ms(100)
|
||||
#epd.init()
|
||||
#print('Initialised')
|
||||
#epd.fill(1) # 1 seems to be white
|
||||
#epd.show()
|
||||
#sleep_ms(1000)
|
||||
#epd.fill(0)
|
||||
#epd.show()
|
||||
#epd._rst(0)
|
||||
#epd._dc(0) # Turn off power according to RPI code
|
|
@ -0,0 +1,234 @@
|
|||
# epd29.py nanogui driver for Adafruit Flexible 2.9" Black and White ePaper display.
|
||||
# [Interface breakout](https://www.adafruit.com/product/4224)
|
||||
# [Display](https://www.adafruit.com/product/4262)
|
||||
|
||||
# EPD is subclassed from framebuf.FrameBuffer for use with Writer class and nanogui.
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Based on the following sources:
|
||||
# [CircuitPython code](https://github.com/adafruit/Adafruit_CircuitPython_IL0373) Author: Scott Shawcroft
|
||||
# [Adafruit setup guide](https://learn.adafruit.com/adafruit-eink-display-breakouts/circuitpython-code-2)
|
||||
# [IL0373 datasheet](https://www.smart-prototyping.com/image/data/9_Modules/EinkDisplay/GDEW0154T8/IL0373.pdf)
|
||||
# [Adafruit demo](https://github.com/adafruit/Adafruit_CircuitPython_IL0373/blob/3f4f52eb3a65173165da1908f93a95383b45a726/examples/il0373_flexible_2.9_monochrome.py)
|
||||
# [eInk breakout schematic](https://learn.adafruit.com/assets/57645)
|
||||
|
||||
# Physical pixels are 296w 128h. However the driver views the display as 128w * 296h with the
|
||||
# Adfruit code transposing the axes.
|
||||
|
||||
import framebuf
|
||||
import uasyncio as asyncio
|
||||
from micropython import const
|
||||
from time import sleep_ms, sleep_us, ticks_ms, ticks_us, ticks_diff
|
||||
|
||||
_MAX_BLOCK = const(20) # Maximum blocking time (ms) for asynchronous show.
|
||||
|
||||
class EPD(framebuf.FrameBuffer):
|
||||
# A monochrome approach should be used for coding this. The rgb method ensures
|
||||
# nothing breaks if users specify colors.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, spi, cs, dc, rst, busy, landscape=True, asyn=False):
|
||||
self._spi = spi
|
||||
self._cs = cs # Pins
|
||||
self._dc = dc
|
||||
self._rst = rst # Active low.
|
||||
self._busy = busy # Active low on IL0373
|
||||
self._lsc = landscape
|
||||
self._asyn = asyn
|
||||
# ._as_busy is set immediately on start of task. Cleared
|
||||
# when busy pin is logically false (physically 1).
|
||||
self._as_busy = False
|
||||
self._updated = asyncio.Event()
|
||||
# Public bound variables required by nanogui.
|
||||
# Dimensions in pixels as seen by nanogui (landscape mode).
|
||||
self.width = 296 if landscape else 128
|
||||
self.height = 128 if landscape else 296
|
||||
# Other public bound variable.
|
||||
# Special mode enables demos written for generic displays to run.
|
||||
self.demo_mode = False
|
||||
|
||||
self._buffer = bytearray(self.height * self.width // 8)
|
||||
self._mvb = memoryview(self._buffer)
|
||||
mode = framebuf.MONO_VLSB if landscape else framebuf.MONO_HLSB
|
||||
super().__init__(self._buffer, self.width, self.height, mode)
|
||||
self.init()
|
||||
|
||||
def _command(self, command, data=None):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(command)
|
||||
self._cs(1)
|
||||
if data is not None:
|
||||
self._data(data)
|
||||
|
||||
# Datasheet P26 seems to mandate CS False after each byte. Ugh.
|
||||
def _data(self, data, buf1=bytearray(1)):
|
||||
self._dc(1)
|
||||
for b in data:
|
||||
self._cs(0)
|
||||
buf1[0] = b
|
||||
self._spi.write(buf1)
|
||||
self._cs(1)
|
||||
|
||||
def init(self):
|
||||
# Hardware reset
|
||||
self._rst(1)
|
||||
sleep_ms(200)
|
||||
self._rst(0)
|
||||
sleep_ms(200)
|
||||
self._rst(1)
|
||||
sleep_ms(200)
|
||||
# Initialisation
|
||||
cmd = self._command
|
||||
# Power setting. Data from Adafruit.
|
||||
# Datasheet default \x03\x00\x26\x26\x03 - slightly different voltages.
|
||||
cmd(b'\x01', b'\x03\x00\x2b\x2b\x09')
|
||||
# Booster soft start. Matches datasheet.
|
||||
cmd(b'\x06', b'\x17\x17\x17')
|
||||
cmd(b'\x04') # Power on
|
||||
sleep_ms(200)
|
||||
# Iss https://github.com/adafruit/Adafruit_CircuitPython_IL0373/issues/16
|
||||
cmd(b'\x00', b'\x9f')
|
||||
# CDI: As used by Adafruit. Datasheet is confusing on this.
|
||||
# See https://github.com/adafruit/Adafruit_CircuitPython_IL0373/issues/11
|
||||
# With 0x37 got white border on flexible display, black on FeatherWing
|
||||
# 0xf7 still produced black border on FeatherWing
|
||||
cmd(b'\x50', b'\x37')
|
||||
# PLL: correct for 150Hz as specified in Adafruit code
|
||||
cmd(b'\x30', b'\x29')
|
||||
# Resolution 128w * 296h as required by IL0373
|
||||
cmd(b'\x61', b'\x80\x01\x28') # Note hex(296) == 0x128
|
||||
# Set VCM_DC. Now clarified with Adafruit.
|
||||
# https://github.com/adafruit/Adafruit_CircuitPython_IL0373/issues/17
|
||||
cmd(b'\x82', b'\x12') # Set Vcom to -1.0V
|
||||
sleep_ms(50)
|
||||
print('Init Done.')
|
||||
|
||||
# For use in synchronous code: blocking wait on ready state.
|
||||
def wait_until_ready(self):
|
||||
sleep_ms(50)
|
||||
while not self.ready():
|
||||
sleep_ms(100)
|
||||
|
||||
# Asynchronous wait on ready state. Pause (4.9s) for physical refresh.
|
||||
async def wait(self):
|
||||
await asyncio.sleep_ms(0) # Ensure tasks run that might make it unready
|
||||
while not self.ready():
|
||||
await asyncio.sleep_ms(100)
|
||||
|
||||
# Pause until framebuf has been copied to device.
|
||||
async def updated(self):
|
||||
await self._updated.wait()
|
||||
|
||||
# Return immediate status. Pin state: 0 == busy.
|
||||
def ready(self):
|
||||
return not(self._as_busy or (self._busy() == 0))
|
||||
|
||||
async def _as_show(self, buf1=bytearray(1)):
|
||||
mvb = self._mvb
|
||||
cmd = self._command
|
||||
dat = self._data
|
||||
cmd(b'\x13')
|
||||
t = ticks_ms()
|
||||
if self._lsc: # Landscape mode
|
||||
wid = self.width
|
||||
tbc = self.height // 8 # Vertical bytes per column
|
||||
iidx = wid * (tbc - 1) # Initial index
|
||||
idx = iidx # Index into framebuf
|
||||
vbc = 0 # Current vertical byte count
|
||||
hpc = 0 # Horizontal pixel count
|
||||
for i in range(len(mvb)):
|
||||
buf1[0] = ~mvb[idx]
|
||||
dat(buf1)
|
||||
idx -= wid
|
||||
vbc += 1
|
||||
vbc %= tbc
|
||||
if not vbc:
|
||||
hpc += 1
|
||||
idx = iidx + hpc
|
||||
if not(i & 0x0f) and (ticks_diff(ticks_ms(), t) > _MAX_BLOCK):
|
||||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
else:
|
||||
for i, b in enumerate(mvb):
|
||||
buf1[0] = ~b
|
||||
dat(buf1)
|
||||
if not(i & 0x0f) and (ticks_diff(ticks_ms(), t) > _MAX_BLOCK):
|
||||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
|
||||
cmd(b'\x11') # Data stop
|
||||
self._updated.set()
|
||||
self._updated.clear()
|
||||
sleep_us(20) # Allow for data coming back: currently ignore this
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
# busy goes low now, for ~4.9 seconds.
|
||||
await asyncio.sleep(1)
|
||||
while self._busy() == 0:
|
||||
await asyncio.sleep_ms(200)
|
||||
self._as_busy = False
|
||||
|
||||
# draw the current frame memory.
|
||||
def show(self, buf1=bytearray(1)):
|
||||
if self._asyn:
|
||||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True # Immediate busy flag. Pin goes low much later.
|
||||
asyncio.create_task(self._as_show())
|
||||
return
|
||||
|
||||
mvb = self._mvb
|
||||
cmd = self._command
|
||||
dat = self._data
|
||||
# DATA_START_TRANSMISSION_2 Datasheet P31 indicates this sets
|
||||
# busy pin low (True) and that it stays logically True until
|
||||
# refresh is complete. In my testing this doesn't happen.
|
||||
cmd(b'\x13')
|
||||
if self._lsc: # Landscape mode
|
||||
wid = self.width
|
||||
tbc = self.height // 8 # Vertical bytes per column
|
||||
iidx = wid * (tbc - 1) # Initial index
|
||||
idx = iidx # Index into framebuf
|
||||
vbc = 0 # Current vertical byte count
|
||||
hpc = 0 # Horizontal pixel count
|
||||
for _ in range(len(mvb)):
|
||||
buf1[0] = ~mvb[idx]
|
||||
dat(buf1)
|
||||
idx -= wid
|
||||
vbc += 1
|
||||
vbc %= tbc
|
||||
if not vbc:
|
||||
hpc += 1
|
||||
idx = iidx + hpc
|
||||
else:
|
||||
for b in mvb:
|
||||
buf1[0] = ~b
|
||||
dat(buf1)
|
||||
|
||||
cmd(b'\x11') # Data stop
|
||||
sleep_us(20) # Allow for data coming back: currently ignore this
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
# 258ms to get here on Pyboard D
|
||||
# Checking with scope, busy goes low now. For 4.9s.
|
||||
if not self.demo_mode:
|
||||
# Immediate return to avoid blocking the whole application.
|
||||
# User should wait for ready before calling refresh()
|
||||
return
|
||||
self.wait_until_ready()
|
||||
sleep_ms(2000) # Give time for user to see result
|
||||
|
||||
# to wake call init()
|
||||
def sleep(self):
|
||||
self._as_busy = False
|
||||
self.wait_until_ready()
|
||||
cmd = self._command
|
||||
# CDI: not sure about value or why we set this here. Copying Adafruit.
|
||||
cmd(b'\x50', b'\x17')
|
||||
# Set VCM_DC. 0 is datasheet default.
|
||||
cmd(b'\x82', b'\x00')
|
||||
# POWER_OFF. User code should pull ENA low to power down the display.
|
||||
cmd(b'\x02')
|
|
@ -0,0 +1,166 @@
|
|||
# ILI9341 nano-gui driver for ili9341 displays
|
||||
# As with all nano-gui displays, touch is not supported.
|
||||
|
||||
# Copyright (c) Peter Hinch 2020-2021
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# This work is based on the following sources.
|
||||
# https://github.com/rdagger/micropython-ili9341
|
||||
# Also this forum thread with ideas from @minyiky:
|
||||
# https://forum.micropython.org/viewtopic.php?f=18&t=9368
|
||||
|
||||
from time import sleep_ms
|
||||
import gc
|
||||
import framebuf
|
||||
import uasyncio as asyncio
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr16, source:ptr8, lut:ptr16, length:int):
|
||||
# rgb565 - 16bit/pixel
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
dest[n] = lut[c >> 4] # current pixel
|
||||
n += 1
|
||||
dest[n] = lut[c & 0x0f] # next pixel
|
||||
n += 1
|
||||
|
||||
|
||||
class ILI9341(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(32)
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
# ILI9341 expects RGB order
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xf8) | (g & 0xe0) >> 5 | (g & 0x1c) << 11 | (b & 0xf8) << 5
|
||||
|
||||
# Transpose width & height for landscape mode
|
||||
def __init__(self, spi, cs, dc, rst, height=240, width=320,
|
||||
usd=False, init_spi=False):
|
||||
self._spi = spi
|
||||
self._cs = cs
|
||||
self._dc = dc
|
||||
self._rst = rst
|
||||
self.height = height
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS4_HMSB
|
||||
gc.collect()
|
||||
buf = bytearray(self.height * self.width // 2)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, self.width, self.height, mode)
|
||||
self._linebuf = bytearray(self.width * 2)
|
||||
# Hardware reset
|
||||
self._rst(0)
|
||||
sleep_ms(50)
|
||||
self._rst(1)
|
||||
sleep_ms(50)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(spi) # Bus may be shared
|
||||
self._lock = asyncio.Lock()
|
||||
# Send initialization commands
|
||||
self._wcmd(b'\x01') # SWRESET Software reset
|
||||
sleep_ms(100)
|
||||
self._wcd(b'\xcf', b'\x00\xC1\x30') # PWCTRB Pwr ctrl B
|
||||
self._wcd(b'\xed', b'\x64\x03\x12\x81') # POSC Pwr on seq. ctrl
|
||||
self._wcd(b'\xe8', b'\x85\x00\x78') # DTCA Driver timing ctrl A
|
||||
self._wcd(b'\xcb', b'\x39\x2C\x00\x34\x02') # PWCTRA Pwr ctrl A
|
||||
self._wcd(b'\xf7', b'\x20') # PUMPRC Pump ratio control
|
||||
self._wcd(b'\xea', b'\x00\x00') # DTCB Driver timing ctrl B
|
||||
self._wcd(b'\xc0', b'\x23') # PWCTR1 Pwr ctrl 1
|
||||
self._wcd(b'\xc1', b'\x10') # PWCTR2 Pwr ctrl 2
|
||||
self._wcd(b'\xc5', b'\x3E\x28') # VMCTR1 VCOM ctrl 1
|
||||
self._wcd(b'\xc7', b'\x86') # VMCTR2 VCOM ctrl 2
|
||||
# (b'\x88', b'\xe8', b'\x48', b'\x28')[rotation // 90]
|
||||
if self.height > self.width:
|
||||
self._wcd(b'\x36', b'\x48' if usd else b'\x88') # MADCTL: RGB portrait mode
|
||||
else:
|
||||
self._wcd(b'\x36', b'\x28' if usd else b'\xe8') # MADCTL: RGB landscape mode
|
||||
self._wcd(b'\x37', b'\x00') # VSCRSADD Vertical scrolling start address
|
||||
self._wcd(b'\x3a', b'\x55') # PIXFMT COLMOD: Pixel format 16 bits (MCU & interface)
|
||||
self._wcd(b'\xb1', b'\x00\x18') # FRMCTR1 Frame rate ctrl
|
||||
self._wcd(b'\xb6', b'\x08\x82\x27') # DFUNCTR
|
||||
self._wcd(b'\xf2', b'\x00') # ENABLE3G Enable 3 gamma ctrl
|
||||
self._wcd(b'\x26', b'\x01') # GAMMASET Gamma curve selected
|
||||
self._wcd(b'\xe0', b'\x0F\x31\x2B\x0C\x0E\x08\x4E\xF1\x37\x07\x10\x03\x0E\x09\x00') # GMCTRP1
|
||||
self._wcd(b'\xe1', b'\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F') # GMCTRN1
|
||||
self._wcmd(b'\x11') # SLPOUT Exit sleep
|
||||
sleep_ms(100)
|
||||
self._wcmd(b'\x29') # DISPLAY_ON
|
||||
sleep_ms(100)
|
||||
|
||||
# Write a command.
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, command, data):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(command)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(data)
|
||||
self._cs(1)
|
||||
|
||||
# Time (ESP32 stock freq) 196ms portrait, 185ms landscape.
|
||||
# mem free on ESP32 43472 bytes (vs 110192)
|
||||
@micropython.native
|
||||
def show(self):
|
||||
clut = ILI9341.lut
|
||||
wd = self.width // 2
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
# Commands needed to start data write
|
||||
self._wcd(b'\x2a', int.to_bytes(self.width, 4, 'big')) # SET_COLUMN
|
||||
self._wcd(b'\x2b', int.to_bytes(ht, 4, 'big')) # SET_PAGE
|
||||
self._wcmd(b'\x2c') # WRITE_RAM
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
for start in range(0, wd*ht, wd): # For each line
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
||||
|
||||
def busy(self):
|
||||
return self._lock.locked()
|
||||
|
||||
async def do_refresh(self, split=4):
|
||||
if self.busy():
|
||||
print('Warning: refresh paused until prior refresh completed.')
|
||||
async with self._lock:
|
||||
lines, mod = divmod(self.height, split) # Lines per segment
|
||||
if mod:
|
||||
raise ValueError('Invalid do_refresh arg.')
|
||||
clut = ILI9341.lut
|
||||
wd = self.width // 2
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
# Commands needed to start data write
|
||||
self._wcd(b'\x2a', int.to_bytes(self.width, 4, 'big')) # SET_COLUMN
|
||||
self._wcd(b'\x2b', int.to_bytes(ht, 4, 'big')) # SET_PAGE
|
||||
self._wcmd(b'\x2c') # WRITE_RAM
|
||||
self._dc(1)
|
||||
line = 0
|
||||
for _ in range(split): # For each segment
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._cs(0)
|
||||
for start in range(wd * line, wd * (line + lines), wd): # For each line
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
line += lines
|
||||
self._cs(1) # Allow other tasks to use bus
|
||||
await asyncio.sleep_ms(0)
|
|
@ -0,0 +1,70 @@
|
|||
# sharp.py Device driver for monochrome sharp displays
|
||||
|
||||
# Tested on
|
||||
# https://www.adafruit.com/product/4694 2.7 inch 400x240 Monochrome
|
||||
# Should also work on
|
||||
# https://www.adafruit.com/product/3502 1.3 inch 144x168
|
||||
# https://www.adafruit.com/product/1393 1.3 inch 96x96 Monochrome
|
||||
|
||||
# Copyright (c) Peter Hinch 2020-2021
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Code checked against https://github.com/adafruit/Adafruit_CircuitPython_SharpMemoryDisplay
|
||||
# Current draw on 2.7" Adafruit display ~90uA.
|
||||
# 2.7" schematic https://learn.adafruit.com/assets/94077
|
||||
# Datasheet 2.7" https://cdn-learn.adafruit.com/assets/assets/000/094/215/original/LS027B7DH01_Rev_Jun_2010.pdf?1597872422
|
||||
# Datasheet 1.3" http://www.adafruit.com/datasheets/LS013B4DN04-3V_FPC-204284.pdf
|
||||
import framebuf
|
||||
import machine
|
||||
from micropython import const
|
||||
|
||||
_WRITECMD = const(1) # Command bits
|
||||
_VCOM = const(2)
|
||||
|
||||
|
||||
class SHARP(framebuf.FrameBuffer):
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, spi, pincs, height=240, width=400, vcom=False):
|
||||
spi.init(baudrate=2_000_000, firstbit=machine.SPI.LSB) # Data sheet: should support 2MHz
|
||||
self._spi = spi
|
||||
self._pincs = pincs
|
||||
self.height = height # Required by Writer class and nanogui
|
||||
self.width = width
|
||||
self._buffer = bytearray(self.height * self.width // 8)
|
||||
self._mvb = memoryview(self._buffer)
|
||||
super().__init__(self._buffer, self.width, self.height, framebuf.MONO_HMSB)
|
||||
self._cmd = bytearray(1) # Buffer for command. Holds current VCOM bit
|
||||
self._cmd[0] = _WRITECMD | _VCOM if vcom else _WRITECMD
|
||||
self._lno = bytearray(1) # Line no.
|
||||
self._dummy = bytearray(1) # Dummy (0)
|
||||
|
||||
# .show should be called periodically to avoid frame inversion flag
|
||||
# (VCOM) retaining the same value for long periods
|
||||
def show(self):
|
||||
spi = self._spi
|
||||
bpl = self.width // 8 # Bytes per line
|
||||
self._pincs(1) # CS is active high
|
||||
spi.write(self._cmd)
|
||||
start = 0
|
||||
lno = self._lno
|
||||
lno[0] = 1 # Gate line address (starts at 1)
|
||||
for _ in range(self.height):
|
||||
spi.write(lno)
|
||||
spi.write(self._mvb[start : start + bpl])
|
||||
spi.write(self._dummy)
|
||||
start += bpl
|
||||
lno[0] += 1 # Gate line address
|
||||
spi.write(self._dummy)
|
||||
self._pincs(0)
|
||||
self._cmd[0] ^= _VCOM # Toggle frame inversion flag
|
||||
|
||||
# Toggle the VCOM bit without changing the display. Power saving method.
|
||||
def update(self):
|
||||
self._pincs(1)
|
||||
self._lno[0] = self._cmd[0] & _VCOM
|
||||
self._spi.write(self._lno)
|
||||
self._cmd[0] ^= _VCOM # Toggle frame inversion flag
|
||||
self._pincs(0)
|
|
@ -0,0 +1,159 @@
|
|||
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
|
||||
|
||||
from micropython import const
|
||||
import framebuf
|
||||
|
||||
|
||||
# register definitions
|
||||
SET_CONTRAST = const(0x81)
|
||||
SET_ENTIRE_ON = const(0xA4)
|
||||
SET_NORM_INV = const(0xA6)
|
||||
SET_DISP = const(0xAE)
|
||||
SET_MEM_ADDR = const(0x20)
|
||||
SET_COL_ADDR = const(0x21)
|
||||
SET_PAGE_ADDR = const(0x22)
|
||||
SET_DISP_START_LINE = const(0x40)
|
||||
SET_SEG_REMAP = const(0xA0)
|
||||
SET_MUX_RATIO = const(0xA8)
|
||||
SET_COM_OUT_DIR = const(0xC0)
|
||||
SET_DISP_OFFSET = const(0xD3)
|
||||
SET_COM_PIN_CFG = const(0xDA)
|
||||
SET_DISP_CLK_DIV = const(0xD5)
|
||||
SET_PRECHARGE = const(0xD9)
|
||||
SET_VCOM_DESEL = const(0xDB)
|
||||
SET_CHARGE_PUMP = const(0x8D)
|
||||
|
||||
# Subclassing FrameBuffer provides support for graphics primitives
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
class SSD1306(framebuf.FrameBuffer):
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, width, height, external_vcc):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.external_vcc = external_vcc
|
||||
self.pages = self.height // 8
|
||||
self.buffer = bytearray(self.pages * self.width)
|
||||
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
|
||||
self.init_display()
|
||||
|
||||
def init_display(self):
|
||||
for cmd in (
|
||||
SET_DISP | 0x00, # off
|
||||
# address setting
|
||||
SET_MEM_ADDR,
|
||||
0x00, # horizontal
|
||||
# resolution and layout
|
||||
SET_DISP_START_LINE | 0x00,
|
||||
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
||||
SET_MUX_RATIO,
|
||||
self.height - 1,
|
||||
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
|
||||
SET_DISP_OFFSET,
|
||||
0x00,
|
||||
SET_COM_PIN_CFG,
|
||||
0x02 if self.width > 2 * self.height else 0x12,
|
||||
# timing and driving scheme
|
||||
SET_DISP_CLK_DIV,
|
||||
0x80,
|
||||
SET_PRECHARGE,
|
||||
0x22 if self.external_vcc else 0xF1,
|
||||
SET_VCOM_DESEL,
|
||||
0x30, # 0.83*Vcc
|
||||
# display
|
||||
SET_CONTRAST,
|
||||
0xFF, # maximum
|
||||
SET_ENTIRE_ON, # output follows RAM contents
|
||||
SET_NORM_INV, # not inverted
|
||||
# charge pump
|
||||
SET_CHARGE_PUMP,
|
||||
0x10 if self.external_vcc else 0x14,
|
||||
SET_DISP | 0x01,
|
||||
): # on
|
||||
self.write_cmd(cmd)
|
||||
self.fill(0)
|
||||
self.show()
|
||||
|
||||
def poweroff(self):
|
||||
self.write_cmd(SET_DISP | 0x00)
|
||||
|
||||
def poweron(self):
|
||||
self.write_cmd(SET_DISP | 0x01)
|
||||
|
||||
def contrast(self, contrast):
|
||||
self.write_cmd(SET_CONTRAST)
|
||||
self.write_cmd(contrast)
|
||||
|
||||
def invert(self, invert):
|
||||
self.write_cmd(SET_NORM_INV | (invert & 1))
|
||||
|
||||
def show(self):
|
||||
x0 = 0
|
||||
x1 = self.width - 1
|
||||
if self.width == 64:
|
||||
# displays with width of 64 pixels are shifted by 32
|
||||
x0 += 32
|
||||
x1 += 32
|
||||
self.write_cmd(SET_COL_ADDR)
|
||||
self.write_cmd(x0)
|
||||
self.write_cmd(x1)
|
||||
self.write_cmd(SET_PAGE_ADDR)
|
||||
self.write_cmd(0)
|
||||
self.write_cmd(self.pages - 1)
|
||||
self.write_data(self.buffer)
|
||||
|
||||
|
||||
class SSD1306_I2C(SSD1306):
|
||||
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
|
||||
self.i2c = i2c
|
||||
self.addr = addr
|
||||
self.temp = bytearray(2)
|
||||
self.write_list = [b"\x40", None] # Co=0, D/C#=1
|
||||
super().__init__(width, height, external_vcc)
|
||||
|
||||
def write_cmd(self, cmd):
|
||||
self.temp[0] = 0x80 # Co=1, D/C#=0
|
||||
self.temp[1] = cmd
|
||||
self.i2c.writeto(self.addr, self.temp)
|
||||
|
||||
def write_data(self, buf):
|
||||
self.write_list[1] = buf
|
||||
self.i2c.writevto(self.addr, self.write_list)
|
||||
|
||||
|
||||
class SSD1306_SPI(SSD1306):
|
||||
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
|
||||
self.rate = 10 * 1024 * 1024
|
||||
dc.init(dc.OUT, value=0)
|
||||
res.init(res.OUT, value=0)
|
||||
cs.init(cs.OUT, value=1)
|
||||
self.spi = spi
|
||||
self.dc = dc
|
||||
self.res = res
|
||||
self.cs = cs
|
||||
import time
|
||||
|
||||
self.res(1)
|
||||
time.sleep_ms(1)
|
||||
self.res(0)
|
||||
time.sleep_ms(10)
|
||||
self.res(1)
|
||||
super().__init__(width, height, external_vcc)
|
||||
|
||||
def write_cmd(self, cmd):
|
||||
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
|
||||
self.cs(1)
|
||||
self.dc(0)
|
||||
self.cs(0)
|
||||
self.spi.write(bytearray([cmd]))
|
||||
self.cs(1)
|
||||
|
||||
def write_data(self, buf):
|
||||
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
|
||||
self.cs(1)
|
||||
self.dc(1)
|
||||
self.cs(0)
|
||||
self.spi.write(buf)
|
||||
self.cs(1)
|
|
@ -0,0 +1,81 @@
|
|||
# SSD1331.py MicroPython driver for Adafruit 0.96" OLED display
|
||||
# https://www.adafruit.com/product/684
|
||||
|
||||
# The MIT License (MIT)
|
||||
|
||||
# Copyright (c) Peter Hinch 2018-2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Show command
|
||||
# 0x15, 0, 0x5f, 0x75, 0, 0x3f Col 0-95 row 0-63
|
||||
|
||||
# Initialisation command
|
||||
# 0xae display off (sleep mode)
|
||||
# 0xa0, 0x32 256 color RGB, horizontal RAM increment
|
||||
# 0xa1, 0x00 Startline row 0
|
||||
# 0xa2, 0x00 Vertical offset 0
|
||||
# 0xa4 Normal display
|
||||
# 0xa8, 0x3f Set multiplex ratio
|
||||
# 0xad, 0x8e Ext supply
|
||||
# 0xb0, 0x0b Disable power save mode
|
||||
# 0xb1, 0x31 Phase period
|
||||
# 0xb3, 0xf0 Oscillator frequency
|
||||
# 0x8a, 0x64, 0x8b, 0x78, 0x8c, 0x64, # Precharge
|
||||
# 0xbb, 0x3a Precharge voltge
|
||||
# 0xbe, 0x3e COM deselect level
|
||||
# 0x87, 0x06 master current attenuation factor
|
||||
# 0x81, 0x91 contrast for all color "A" segment
|
||||
# 0x82, 0x50 contrast for all color "B" segment
|
||||
# 0x83, 0x7d contrast for all color "C" segment
|
||||
# 0xaf Display on
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
import sys
|
||||
# https://github.com/peterhinch/micropython-nano-gui/issues/2
|
||||
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
|
||||
# Mode 0, 0 works on ESP and STM
|
||||
|
||||
# Data sheet SPI spec: 150ns min clock period 6.66MHz
|
||||
|
||||
class SSD1331(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to an 8 bit colour value
|
||||
# acceptable to hardware: rrrgggbb
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=64, width=96, init_spi=False):
|
||||
self._spi = spi
|
||||
self._pincs = pincs
|
||||
self._pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
self._write(b'\xae\xa0\x32\xa1\x00\xa2\x00\xa4\xa8\x3f\xad\x8e\xb0'\
|
||||
b'\x0b\xb1\x31\xb3\xf0\x8a\x64\x8b\x78\x8c\x64\xbb\x3a\xbe\x3e\x87'\
|
||||
b'\x06\x81\x91\x82\x50\x83\x7d\xaf', 0)
|
||||
gc.collect()
|
||||
self.show()
|
||||
|
||||
def _write(self, buf, dc):
|
||||
self._pincs(1)
|
||||
self._pindc(dc)
|
||||
self._pincs(0)
|
||||
self._spi.write(buf)
|
||||
self._pincs(1)
|
||||
|
||||
def show(self, _cmd=b'\x15\x00\x5f\x75\x00\x3f'): # Pre-allocate
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(spi) # Bus may be shared
|
||||
self._write(_cmd, 0)
|
||||
self._write(self.buffer, 1)
|
|
@ -0,0 +1,81 @@
|
|||
# SSD1331.py MicroPython driver for Adafruit 0.96" OLED display
|
||||
# https://www.adafruit.com/product/684
|
||||
|
||||
# Copyright (c) Peter Hinch 2019-2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Show command
|
||||
# 0x15, 0, 0x5f, 0x75, 0, 0x3f Col 0-95 row 0-63
|
||||
|
||||
# Initialisation command
|
||||
# 0xae display off (sleep mode)
|
||||
# 0xa0, 0x72 16 bit RGB, horizontal RAM increment
|
||||
# 0xa1, 0x00 Startline row 0
|
||||
# 0xa2, 0x00 Vertical offset 0
|
||||
# 0xa4 Normal display
|
||||
# 0xa8, 0x3f Set multiplex ratio
|
||||
# 0xad, 0x8e Ext supply
|
||||
# 0xb0, 0x0b Disable power save mode
|
||||
# 0xb1, 0x31 Phase period
|
||||
# 0xb3, 0xf0 Oscillator frequency
|
||||
# 0x8a, 0x64, 0x8b, 0x78, 0x8c, 0x64, # Precharge
|
||||
# 0xbb, 0x3a Precharge voltge
|
||||
# 0xbe, 0x3e COM deselect level
|
||||
# 0x87, 0x06 master current attenuation factor
|
||||
# 0x81, 0x91 contrast for all color "A" segment
|
||||
# 0x82, 0x50 contrast for all color "B" segment
|
||||
# 0x83, 0x7d contrast for all color "C" segment
|
||||
# 0xaf Display on
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
|
||||
# https://github.com/peterhinch/micropython-nano-gui/issues/2
|
||||
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
|
||||
# Mode 0, 0 works on ESP and STM
|
||||
|
||||
# Data sheet SPI spec: 150ns min clock period 6.66MHz
|
||||
class SSD1331(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value RGB565
|
||||
# acceptable to hardware: rrrrrggggggbbbbb
|
||||
# LS byte of 16 bit result is shifted out 1st
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return ((b & 0xf8) << 5) | ((g & 0x1c) << 11) | (r & 0xf8) | ((g & 0xe0) >> 5)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=64, width=96, init_spi=False):
|
||||
self._spi = spi
|
||||
self._pincs = pincs
|
||||
self._pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.RGB565
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width * 2)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(spi) # Bus may be shared
|
||||
self._write(b'\xae\xa0\x72\xa1\x00\xa2\x00\xa4\xa8\x3f\xad\x8e\xb0'\
|
||||
b'\x0b\xb1\x31\xb3\xf0\x8a\x64\x8b\x78\x8c\x64\xbb\x3a\xbe\x3e\x87'\
|
||||
b'\x06\x81\x91\x82\x50\x83\x7d\xaf', 0)
|
||||
gc.collect()
|
||||
self.show()
|
||||
|
||||
def _write(self, buf, dc):
|
||||
self._pincs(1)
|
||||
self._pindc(dc)
|
||||
self._pincs(0)
|
||||
self._spi.write(buf)
|
||||
self._pincs(1)
|
||||
|
||||
def show(self, _cmd=b'\x15\x00\x5f\x75\x00\x3f'): # Pre-allocate
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(spi) # Bus may be shared
|
||||
self._write(_cmd, 0)
|
||||
self._write(self.buffer, 1)
|
|
@ -0,0 +1,31 @@
|
|||
# test_colors.py Test color rendition on SSD1331 (Adafruit 0.96" OLED).
|
||||
# Author Peter Hinch
|
||||
# Released under the MIT licence.
|
||||
|
||||
import machine
|
||||
# Can test either driver
|
||||
# from ssd1331 import SSD1331 as SSD
|
||||
from ssd1331_16bit import SSD1331 as SSD
|
||||
|
||||
# Initialise hardware
|
||||
def setup():
|
||||
pdc = machine.Pin('X1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('X2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('X3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(1)
|
||||
ssd = SSD(spi, pcs, pdc, prst) # Create a display instance
|
||||
return ssd
|
||||
|
||||
ssd = setup()
|
||||
ssd.fill(0)
|
||||
# Operate in landscape mode
|
||||
x = 0
|
||||
for y in range(96):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(round(255*y/96), 0, 0))
|
||||
x += 20
|
||||
for y in range(96):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(0, round(255*y/96), 0))
|
||||
x += 20
|
||||
for y in range(96):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(0, 0, round(255*y/96)))
|
||||
ssd.show()
|
|
@ -0,0 +1,143 @@
|
|||
# SSD1351.py MicroPython driver for Adafruit color OLED displays.
|
||||
# STM (Pyboard etc) version. Display refresh takes 41ms on Pyboard V1.0
|
||||
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
||||
# This driver is based on the Adafruit C++ library for Arduino
|
||||
# https://github.com/adafruit/Adafruit-SSD1351-library.git
|
||||
|
||||
# Copyright (c) Peter Hinch 2018-2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
import micropython
|
||||
from uctypes import addressof
|
||||
|
||||
# Timings with standard emitter
|
||||
# 1.86ms * 128 lines = 240ms. copy dominates: show() took 272ms
|
||||
# Buffer transfer time = 272-240 = 32ms which accords with expected:
|
||||
# 128*128*2/10500000 = 31.2ms (2 bytes/pixel, baudrate = 10.5MHz)
|
||||
# With assembler .show() takes 41ms
|
||||
|
||||
# Copy a buffer with 8 bit rrrgggbb pixels to a buffer of 16 bit pixels.
|
||||
@micropython.asm_thumb
|
||||
def _lcopy(r0, r1, r2): # r0 dest, r1 source, r2 no. of bytes
|
||||
label(LOOP)
|
||||
ldrb(r3, [r1, 0]) # Get source byte to r3, r5, r6
|
||||
mov(r5, r3)
|
||||
mov(r6, r3)
|
||||
mov(r4, 3)
|
||||
and_(r3, r4)
|
||||
mov(r4, 6)
|
||||
lsl(r3, r4)
|
||||
mov(r4, 0x1c)
|
||||
and_(r5, r4)
|
||||
mov(r4, 2)
|
||||
lsr(r5, r4)
|
||||
orr(r3, r5)
|
||||
strb(r3, [r0, 0])
|
||||
mov(r4, 0xe0)
|
||||
and_(r6, r4)
|
||||
mov(r4, 3)
|
||||
lsr(r6, r4)
|
||||
strb(r6, [r0, 1])
|
||||
add(r0, 2)
|
||||
add(r1, 1)
|
||||
sub(r2, 1)
|
||||
bne(LOOP)
|
||||
|
||||
# Initialisation commands in cmd_init:
|
||||
# 0xfd, 0x12, 0xfd, 0xb1, # Unlock command mode
|
||||
# 0xae, # display off (sleep mode)
|
||||
# 0xb3, 0xf1, # clock div
|
||||
# 0xca, 0x7f, # mux ratio
|
||||
# 0xa0, 0x74, # setremap 0x74
|
||||
# 0x15, 0, 0x7f, # setcolumn
|
||||
# 0x75, 0, 0x7f, # setrow
|
||||
# 0xa1, 0, # set display start line
|
||||
# 0xa2, 0, # displayoffset
|
||||
# 0xb5, 0, # setgpio
|
||||
# 0xab, 1, # functionselect: serial interface, internal Vdd regulator
|
||||
# 0xb1, 0x32, # Precharge
|
||||
# 0xbe, 0x05, # vcommh
|
||||
# 0xa6, # normaldisplay
|
||||
# 0xc1, 0xc8, 0x80, 0xc8, # contrast abc
|
||||
# 0xc7, 0x0f, # Master contrast
|
||||
# 0xb4, 0xa0, 0xb5, 0x55, # set vsl (see datasheet re ext circuit)
|
||||
# 0xb6, 1, # Precharge 2
|
||||
# 0xaf, # Display on
|
||||
|
||||
# SPI baudrate: Pyboard can produce 10.5MHz or 21MHz. Datasheet gives max of 20MHz.
|
||||
# Attempt to use 21MHz failed but might work on a PCB or with very short leads.
|
||||
class SSD1351(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to an 8 bit colour value
|
||||
# acceptable to hardware: rrrgggbb
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=128, width=128, init_spi=False):
|
||||
if height not in (96, 128):
|
||||
raise ValueError('Unsupported height {}'.format(height))
|
||||
self.spi = spi
|
||||
self.spi_init = init_spi
|
||||
self.pincs = pincs
|
||||
self.pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
self.linebuf = bytearray(self.width * 2)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(spi) # Bus may be shared
|
||||
# See above comment to explain this allocation-saving gibberish.
|
||||
self._write(b'\xfd\x12\xfd\xb1\xae\xb3\xf1\xca\x7f\xa0\x74'\
|
||||
b'\x15\x00\x7f\x75\x00\x7f\xa1\x00\xa2\x00\xb5\x00\xab\x01'\
|
||||
b'\xb1\x32\xbe\x05\xa6\xc1\xc8\x80\xc8\xc7\x0f'\
|
||||
b'\xb4\xa0\xb5\x55\xb6\x01\xaf', 0)
|
||||
self.show()
|
||||
gc.collect()
|
||||
|
||||
def _write(self, buf, dc):
|
||||
self.pincs(1)
|
||||
self.pindc(dc)
|
||||
self.pincs(0)
|
||||
self.spi.write(buf)
|
||||
self.pincs(1)
|
||||
|
||||
# Write lines from the framebuf out of order to match the mapping of the
|
||||
# SSD1351 RAM to the OLED device.
|
||||
def show(self):
|
||||
lb = self.linebuf
|
||||
buf = self.buffer
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(self.spi) # Bus may be shared
|
||||
self._write(b'\x5c', 0) # Enable data write
|
||||
if self.height == 128:
|
||||
for l in range(128):
|
||||
l0 = (95 - l) % 128 # 95 94 .. 1 0 127 126 .. 96
|
||||
start = l0 * self.width
|
||||
_lcopy(lb, addressof(buf) + start, self.width)
|
||||
self._write(lb, 1) # Send a line
|
||||
else:
|
||||
for l in range(128):
|
||||
if l < 64:
|
||||
start = (63 -l) * self.width # 63 62 .. 1 0
|
||||
_lcopy(lb, addressof(buf) + start, self.width)
|
||||
self._write(lb, 1) # Send a line
|
||||
elif l < 96: # This is daft but I can't get setrow to work
|
||||
self._write(lb, 1) # Let RAM counter increase
|
||||
else:
|
||||
start = (191 - l) * self.width # 127 126 .. 95
|
||||
_lcopy(lb, addressof(buf) + start, self.width)
|
||||
self._write(lb, 1) # Send a line
|
|
@ -0,0 +1,108 @@
|
|||
# SSD1351_16bit.py MicroPython driver for Adafruit color OLED displays.
|
||||
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
||||
# This driver is based on the Adafruit C++ library for Arduino
|
||||
# https://github.com/adafruit/Adafruit-SSD1351-library.git
|
||||
|
||||
# Copyright (c) Peter Hinch 2019-2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
import micropython
|
||||
from uctypes import addressof
|
||||
|
||||
# https://github.com/peterhinch/micropython-nano-gui/issues/2
|
||||
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
|
||||
# Now using 0,0 on STM and ESP32
|
||||
|
||||
# Initialisation commands in cmd_init:
|
||||
# 0xfd, 0x12, 0xfd, 0xb1, # Unlock command mode
|
||||
# 0xae, # display off (sleep mode)
|
||||
# 0xb3, 0xf1, # clock div
|
||||
# 0xca, 0x7f, # mux ratio
|
||||
# 0xa0, 0x74, # setremap 0x74
|
||||
# 0x15, 0, 0x7f, # setcolumn
|
||||
# 0x75, 0, 0x7f, # setrow
|
||||
# 0xa1, 0, # set display start line
|
||||
# 0xa2, 0, # displayoffset
|
||||
# 0xb5, 0, # setgpio
|
||||
# 0xab, 1, # functionselect: serial interface, internal Vdd regulator
|
||||
# 0xb1, 0x32, # Precharge
|
||||
# 0xbe, 0x05, # vcommh
|
||||
# 0xa6, # normaldisplay
|
||||
# 0xc1, 0xc8, 0x80, 0xc8, # contrast abc
|
||||
# 0xc7, 0x0f, # Master contrast
|
||||
# 0xb4, 0xa0, 0xb5, 0x55, # set vsl (see datasheet re ext circuit)
|
||||
# 0xb6, 1, # Precharge 2
|
||||
# 0xaf, # Display on
|
||||
|
||||
|
||||
class SSD1351(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value RGB565
|
||||
# acceptable to hardware: rrrrrggggggbbbbb
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return ((r & 0xf8) << 5) | ((g & 0x1c) << 11) | (b & 0xf8) | ((g & 0xe0) >> 5)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=128, width=128, init_spi=False):
|
||||
if height not in (96, 128):
|
||||
raise ValueError('Unsupported height {}'.format(height))
|
||||
self.spi = spi
|
||||
self.spi_init = init_spi
|
||||
self.pincs = pincs
|
||||
self.pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
mode = framebuf.RGB565
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width * 2)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
self.mvb = memoryview(self.buffer)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(spi) # Bus may be shared
|
||||
# See above comment to explain this allocation-saving gibberish.
|
||||
self._write(b'\xfd\x12\xfd\xb1\xae\xb3\xf1\xca\x7f\xa0\x74'\
|
||||
b'\x15\x00\x7f\x75\x00\x7f\xa1\x00\xa2\x00\xb5\x00\xab\x01'\
|
||||
b'\xb1\x32\xbe\x05\xa6\xc1\xc8\x80\xc8\xc7\x0f'\
|
||||
b'\xb4\xa0\xb5\x55\xb6\x01\xaf', 0)
|
||||
self.show()
|
||||
gc.collect()
|
||||
|
||||
def _write(self, mv, dc):
|
||||
self.pincs(1)
|
||||
self.pindc(dc)
|
||||
self.pincs(0)
|
||||
self.spi.write(bytes(mv))
|
||||
self.pincs(1)
|
||||
|
||||
# Write lines from the framebuf out of order to match the mapping of the
|
||||
# SSD1351 RAM to the OLED device.
|
||||
def show(self):
|
||||
mvb = self.mvb
|
||||
bw = self.width * 2 # Width in bytes
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(self.spi) # Bus may be shared
|
||||
self._write(b'\x5c', 0) # Enable data write
|
||||
if self.height == 128:
|
||||
for l in range(128):
|
||||
l0 = (95 - l) % 128 # 95 94 .. 1 0 127 126 .. 96
|
||||
start = l0 * self.width * 2
|
||||
self._write(mvb[start : start + bw], 1) # Send a line
|
||||
else:
|
||||
for l in range(128):
|
||||
if l < 64:
|
||||
start = (63 -l) * self.width * 2 # 63 62 .. 1 0
|
||||
elif l < 96:
|
||||
start = 0
|
||||
else:
|
||||
start = (191 - l) * self.width * 2 # 127 126 .. 95
|
||||
self._write(mvb[start : start + bw], 1) # Send a line
|
|
@ -0,0 +1,142 @@
|
|||
# SSD1351_4bit.py MicroPython driver for Adafruit color OLED displays.
|
||||
# This is cross-platform and uses 4 bit color for minimum RAM usage.
|
||||
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
||||
# This driver is based on the Adafruit C++ library for Arduino
|
||||
# https://github.com/adafruit/Adafruit-SSD1351-library.git
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
import micropython
|
||||
from uctypes import addressof
|
||||
|
||||
# https://github.com/peterhinch/micropython-nano-gui/issues/2
|
||||
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
|
||||
# Now using 0,0 on STM and ESP32
|
||||
|
||||
# ESP32 produces 20MHz, Pyboard D SF2W: 15MHz, SF6W: 18MHz, Pyboard 1.1: 10.5MHz
|
||||
# OLED datasheet: should support 20MHz
|
||||
def spi_init(spi):
|
||||
spi.init(baudrate=20_000_000) # Data sheet: should support 20MHz
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, lut:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
d = (c & 0xf0) >> 3 # 2* LUT indices (LUT is 16 bit color)
|
||||
e = (c & 0x0f) << 1
|
||||
dest[n] = lut[d]
|
||||
n += 1
|
||||
dest[n] = lut[d + 1]
|
||||
n += 1
|
||||
dest[n] = lut[e]
|
||||
n += 1
|
||||
dest[n] = lut[e + 1]
|
||||
n += 1
|
||||
|
||||
|
||||
# Initialisation commands in cmd_init:
|
||||
# 0xfd, 0x12, 0xfd, 0xb1, # Unlock command mode
|
||||
# 0xae, # display off (sleep mode)
|
||||
# 0xb3, 0xf1, # clock div
|
||||
# 0xca, 0x7f, # mux ratio
|
||||
# 0xa0, 0x74, # setremap 0x74
|
||||
# 0x15, 0, 0x7f, # setcolumn
|
||||
# 0x75, 0, 0x7f, # setrow
|
||||
# 0xa1, 0, # set display start line
|
||||
# 0xa2, 0, # displayoffset
|
||||
# 0xb5, 0, # setgpio
|
||||
# 0xab, 1, # functionselect: serial interface, internal Vdd regulator
|
||||
# 0xb1, 0x32, # Precharge
|
||||
# 0xbe, 0x05, # vcommh
|
||||
# 0xa6, # normaldisplay
|
||||
# 0xc1, 0xc8, 0x80, 0xc8, # contrast abc
|
||||
# 0xc7, 0x0f, # Master contrast
|
||||
# 0xb4, 0xa0, 0xb5, 0x55, # set vsl (see datasheet re ext circuit)
|
||||
# 0xb6, 1, # Precharge 2
|
||||
# 0xaf, # Display on
|
||||
|
||||
|
||||
class SSD1351(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(32)
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
# Note pretty colors in datasheet don't match actual colors. See doc.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (b & 0xf8)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=128, width=128, init_spi=False):
|
||||
if height not in (96, 128):
|
||||
raise ValueError('Unsupported height {}'.format(height))
|
||||
self.spi = spi
|
||||
self.pincs = pincs
|
||||
self.pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self.spi_init = init_spi
|
||||
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width // 2)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
self.linebuf = bytearray(self.width * 2)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(spi) # Bus may be shared
|
||||
# See above comment to explain this allocation-saving gibberish.
|
||||
self._write(b'\xfd\x12\xfd\xb1\xae\xb3\xf1\xca\x7f\xa0\x74'\
|
||||
b'\x15\x00\x7f\x75\x00\x7f\xa1\x00\xa2\x00\xb5\x00\xab\x01'\
|
||||
b'\xb1\x32\xbe\x05\xa6\xc1\xc8\x80\xc8\xc7\x0f'\
|
||||
b'\xb4\xa0\xb5\x55\xb6\x01\xaf', 0)
|
||||
gc.collect()
|
||||
self.show()
|
||||
|
||||
def _write(self, buf, dc):
|
||||
self.pincs(1)
|
||||
self.pindc(dc)
|
||||
self.pincs(0)
|
||||
self.spi.write(buf)
|
||||
self.pincs(1)
|
||||
|
||||
# Write lines from the framebuf out of order to match the mapping of the
|
||||
# SSD1351 RAM to the OLED device.
|
||||
def show(self): # 44ms on Pyboard 1.x
|
||||
clut = SSD1351.lut
|
||||
lb = self.linebuf
|
||||
wd = self.width // 2
|
||||
buf = memoryview(self.buffer)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(self.spi) # Bus may be shared
|
||||
self._write(b'\x5c', 0) # Enable data write
|
||||
if self.height == 128:
|
||||
for l in range(128):
|
||||
l0 = (95 - l) % 128 # 95 94 .. 1 0 127 126...
|
||||
start = l0 * wd
|
||||
_lcopy(lb, buf[start : start + wd], clut, wd)
|
||||
self._write(lb, 1) # Send a line
|
||||
else:
|
||||
for l in range(128):
|
||||
if l < 64:
|
||||
start = (63 -l) * wd
|
||||
_lcopy(lb, buf[start : start + wd], clut, wd)
|
||||
elif l < 96: # This is daft but I can't get setrow to work
|
||||
pass # Let RAM counter increase
|
||||
else:
|
||||
start = (191 - l) * wd
|
||||
_lcopy(lb, buf[start : start + wd], clut, wd)
|
||||
self._write(lb, 1) # Send a line
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# SSD1351_generic.py MicroPython driver for Adafruit color OLED displays.
|
||||
# This is cross-platform. It lacks STM optimisations and is slower than the
|
||||
# standard version.
|
||||
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
||||
# This driver is based on the Adafruit C++ library for Arduino
|
||||
# https://github.com/adafruit/Adafruit-SSD1351-library.git
|
||||
|
||||
# Copyright (c) Peter Hinch 2018-2020
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
import framebuf
|
||||
import utime
|
||||
import gc
|
||||
import micropython
|
||||
from uctypes import addressof
|
||||
|
||||
import sys
|
||||
# https://github.com/peterhinch/micropython-nano-gui/issues/2
|
||||
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
|
||||
# Now using 0,0 on STM and ESP32
|
||||
|
||||
# Timings with standard emitter
|
||||
# 1.86ms * 128 lines = 240ms. copy dominates: show() took 272ms
|
||||
# Buffer transfer time = 272-240 = 32ms which accords with expected:
|
||||
# 128*128*2/10500000 = 31.2ms (2 bytes/pixel, baudrate = 10.5MHz)
|
||||
# With viper emitter show() takes 47ms vs 41ms for assembler.
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
dest[n] = ((c & 3) << 6) | ((c & 0x1c) >> 2) # Blue green
|
||||
n += 1
|
||||
dest[n] = (c & 0xe0) >> 3 # Red
|
||||
n += 1
|
||||
|
||||
# Initialisation commands in cmd_init:
|
||||
# 0xfd, 0x12, 0xfd, 0xb1, # Unlock command mode
|
||||
# 0xae, # display off (sleep mode)
|
||||
# 0xb3, 0xf1, # clock div
|
||||
# 0xca, 0x7f, # mux ratio
|
||||
# 0xa0, 0x74, # setremap 0x74
|
||||
# 0x15, 0, 0x7f, # setcolumn
|
||||
# 0x75, 0, 0x7f, # setrow
|
||||
# 0xa1, 0, # set display start line
|
||||
# 0xa2, 0, # displayoffset
|
||||
# 0xb5, 0, # setgpio
|
||||
# 0xab, 1, # functionselect: serial interface, internal Vdd regulator
|
||||
# 0xb1, 0x32, # Precharge
|
||||
# 0xbe, 0x05, # vcommh
|
||||
# 0xa6, # normaldisplay
|
||||
# 0xc1, 0xc8, 0x80, 0xc8, # contrast abc
|
||||
# 0xc7, 0x0f, # Master contrast
|
||||
# 0xb4, 0xa0, 0xb5, 0x55, # set vsl (see datasheet re ext circuit)
|
||||
# 0xb6, 1, # Precharge 2
|
||||
# 0xaf, # Display on
|
||||
|
||||
class SSD1351(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to an 8 bit colour value
|
||||
# acceptable to hardware: rrrgggbb
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
|
||||
|
||||
def __init__(self, spi, pincs, pindc, pinrs, height=128, width=128, init_spi=False):
|
||||
if height not in (96, 128):
|
||||
raise ValueError('Unsupported height {}'.format(height))
|
||||
self.spi = spi
|
||||
self.spi_init = init_spi
|
||||
self.pincs = pincs
|
||||
self.pindc = pindc # 1 = data 0 = cmd
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
|
||||
gc.collect()
|
||||
self.buffer = bytearray(self.height * self.width)
|
||||
super().__init__(self.buffer, self.width, self.height, mode)
|
||||
self.linebuf = bytearray(self.width * 2)
|
||||
pinrs(0) # Pulse the reset line
|
||||
utime.sleep_ms(1)
|
||||
pinrs(1)
|
||||
utime.sleep_ms(1)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(spi) # Bus may be shared
|
||||
# See above comment to explain this allocation-saving gibberish.
|
||||
self._write(b'\xfd\x12\xfd\xb1\xae\xb3\xf1\xca\x7f\xa0\x74'\
|
||||
b'\x15\x00\x7f\x75\x00\x7f\xa1\x00\xa2\x00\xb5\x00\xab\x01'\
|
||||
b'\xb1\x32\xbe\x05\xa6\xc1\xc8\x80\xc8\xc7\x0f'\
|
||||
b'\xb4\xa0\xb5\x55\xb6\x01\xaf', 0)
|
||||
gc.collect()
|
||||
self.show()
|
||||
|
||||
def _write(self, buf, dc):
|
||||
self.pincs(1)
|
||||
self.pindc(dc)
|
||||
self.pincs(0)
|
||||
self.spi.write(buf)
|
||||
self.pincs(1)
|
||||
|
||||
# Write lines from the framebuf out of order to match the mapping of the
|
||||
# SSD1351 RAM to the OLED device.
|
||||
def show(self):
|
||||
lb = self.linebuf
|
||||
buf = memoryview(self.buffer)
|
||||
if self.spi_init: # A callback was passed
|
||||
self.spi_init(self.spi) # Bus may be shared
|
||||
self._write(b'\x5c', 0) # Enable data write
|
||||
if self.height == 128:
|
||||
for l in range(128):
|
||||
l0 = (95 - l) % 128 # 95 94 .. 1 0 127 126...
|
||||
start = l0 * self.width
|
||||
_lcopy(lb, buf[start : start + self.width], self.width)
|
||||
self._write(lb, 1) # Send a line
|
||||
else:
|
||||
for l in range(128):
|
||||
if l < 64:
|
||||
start = (63 -l) * self.width
|
||||
_lcopy(lb, buf[start : start + self.width], self.width)
|
||||
self._write(lb, 1) # Send a line
|
||||
elif l < 96: # This is daft but I can't get setrow to work
|
||||
self._write(lb, 1) # Let RAM counter increase
|
||||
else:
|
||||
start = (191 - l) * self.width
|
||||
_lcopy(lb, buf[start : start + self.width], self.width)
|
||||
self._write(lb, 1) # Send a line
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# test128_row.py Test for device driver on 96 row display
|
||||
import machine
|
||||
from ssd1351 import SSD1351 as SSD
|
||||
|
||||
# Initialise hardware
|
||||
def setup():
|
||||
pdc = machine.Pin('X1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('X2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('X3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(1)
|
||||
ssd = SSD(spi, pcs, pdc, prst) # Create a display instance
|
||||
return ssd
|
||||
|
||||
ssd = setup()
|
||||
ssd.fill(0)
|
||||
ssd.line(0, 0, 127, 127, ssd.rgb(0, 255, 0))
|
||||
ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0))
|
||||
ssd.show()
|
|
@ -0,0 +1,18 @@
|
|||
# test96.py Test for device driver on 96 row display
|
||||
import machine
|
||||
from ssd1351 import SSD1351 as SSD
|
||||
|
||||
# Initialise hardware
|
||||
def setup():
|
||||
pdc = machine.Pin('X1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('X2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('X3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(1)
|
||||
ssd = SSD(spi, pcs, pdc, prst, height=96) # Create a display instance
|
||||
return ssd
|
||||
|
||||
ssd = setup()
|
||||
ssd.fill(0)
|
||||
ssd.line(0, 0, 127, 95, ssd.rgb(0, 255, 0))
|
||||
ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0))
|
||||
ssd.show()
|
|
@ -0,0 +1,27 @@
|
|||
# test_colors_96.py
|
||||
# Check color mapping. Runs on 96 row display (change height for 128 row)
|
||||
|
||||
import machine
|
||||
from ssd1351_16bit import SSD1351 as SSD
|
||||
|
||||
# Initialise hardware
|
||||
def setup():
|
||||
pdc = machine.Pin('X1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('X2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('X3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(1)
|
||||
ssd = SSD(spi, pcs, pdc, prst, height=96) # Create a display instance
|
||||
return ssd
|
||||
|
||||
ssd = setup()
|
||||
ssd.fill(0)
|
||||
x = 0
|
||||
for y in range(128):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(round(255*y/128), 0, 0))
|
||||
x += 20
|
||||
for y in range(128):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(0, round(255*y/128), 0))
|
||||
x += 20
|
||||
for y in range(128):
|
||||
ssd.line(y, x, y, x+20, ssd.rgb(0, 0, round(255*y/128)))
|
||||
ssd.show()
|
|
@ -0,0 +1,53 @@
|
|||
https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket/python-usage
|
||||
|
||||
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
|
||||
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
|
||||
|
||||
|
||||
# disp = st7735.ST7735R(spi, rotation=90, bgr=True, # 0.96" MiniTFT ST7735R
|
||||
# disp = ssd1351.SSD1351(spi, rotation=180,
|
||||
|
||||
|
||||
|
||||
import machine
|
||||
import gc
|
||||
from time import sleep_ms
|
||||
from drivers.st7735r.st7735r144 import ST7735R as SSD
|
||||
height = 128
|
||||
width = 128 # 160
|
||||
|
||||
pdc = machine.Pin('Y1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('Y2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(2, baudrate=12_000_000)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, height, width) # Create a display instance
|
||||
ssd.fill(0)
|
||||
ssd.show()
|
||||
sleep_ms(1000)
|
||||
ssd.line(0, 0, width - 1, height - 1, ssd.rgb(0, 255, 0)) # Green diagonal corner-to-corner
|
||||
ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0)) # Red square at top left
|
||||
ssd.show()
|
||||
sleep_ms(2000)
|
||||
ssd.fill(0)
|
||||
ssd.show()
|
||||
ssd.line(0, 0, width - 1, height - 1, ssd.rgb(0, 255, 255))
|
||||
ssd.rect(0, 0, 40, 40, ssd.rgb(0, 0, 255))
|
||||
ssd.rect(width - 41, height - 41, 40, 40, ssd.rgb(0, 0, 255))
|
||||
ssd.show()
|
||||
|
||||
Attempt to rotate 1.44" unit fell foul of x and y offsets with 1-2 pixel errors.
|
||||
Rotation passed to ctor
|
||||
def __init__(self, spi, cs, dc, rst, height=128, width=128, init_spi=False, rotation=0):
|
||||
...
|
||||
quad, mod = divmod(rotation, 90) # Get quadrant
|
||||
if mod:
|
||||
raise ValueError('Rotation should be divisible by 90')
|
||||
...
|
||||
|
||||
self._init(quad)
|
||||
|
||||
def _init(self, quad):
|
||||
...
|
||||
rval = (b'\x20', b'\x40', b'\xe0', b'\x80')[quad]
|
||||
wcd(b'\x36', rval)
|
|
@ -0,0 +1,154 @@
|
|||
# st7735r.py Driver for 1.8" 128*160 ST7735R LCD displays for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# Supported display
|
||||
# Adfruit 1.8' Color TFT LCD display with MicroSD Card Breakout:
|
||||
# https://www.adafruit.com/product/358
|
||||
|
||||
# Based on
|
||||
# https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/master/adafruit_st7735r.py
|
||||
# https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py
|
||||
# https://github.com/boochow/MicroPython-ST7735
|
||||
|
||||
# https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket/python-usage
|
||||
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
|
||||
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
|
||||
|
||||
from time import sleep_ms
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
|
||||
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
|
||||
|
||||
# _lcopy: copy a line in 8 bit format to one in 12 bit RGB444. para 9.8.20.
|
||||
# 2 bytes become 3 in destination. Source format:
|
||||
# < D7 D6 D5 D4 D3 D2 D1 D0>
|
||||
# <R02 R01 R00 G02 G01 G00 B01 B00> <R12 R11 R10 G12 G11 G10 B11 B10>
|
||||
# dest:
|
||||
# <R02 R01 R00 0 G02 G01 G00 0> <B01 B00 0 0 R12 R11 R10 0> <G12 G11 G10 0 B11 B10 0 0>
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(0, length, 2):
|
||||
c = source[x]
|
||||
d = source[x + 1]
|
||||
dest[n] = (c & 0xe0) | ((c & 0x1c) >> 1) # R0 G0
|
||||
n += 1
|
||||
dest[n] = ((c & 3) << 6) | ((d & 0xe0) >> 4) # B0 R1
|
||||
n += 1
|
||||
dest[n] = ((d & 0x1c) << 3) | ((d & 3) << 2) # G1 B1
|
||||
n += 1
|
||||
|
||||
class ST7735R(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to an 8 bit colour value
|
||||
# rrrgggbb. Converted to 12 bit on the fly.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=128, width=160, usd=False, init_spi=False):
|
||||
self._spi = spi
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
|
||||
gc.collect()
|
||||
buf = bytearray(height * width)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, width, height, mode)
|
||||
self._linebuf = bytearray(int(width * 3 // 2)) # 12 bit color out
|
||||
self._init(usd)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 500ms.
|
||||
def _init(self, usd):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies > 120ms
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT
|
||||
sleep_ms(256) # Adafruit delay (datsheet 120ms)
|
||||
wcd(b'\xb1', b'\x01\x2C\x2D') # FRMCTRL1
|
||||
wcd(b'\xb2', b'\x01\x2C\x2D') # FRMCTRL2
|
||||
wcd(b'\xb3', b'\x01\x2C\x2D\x01\x2C\x2D') # FRMCTRL3
|
||||
wcd(b'\xb4', b'\x07') # INVCTR line inversion
|
||||
|
||||
wcd(b'\xc0', b'\xa2\x02\x84') # PWCTR1 GVDD = 4.7V, 1.0uA
|
||||
wcd(b'\xc1', b'\xc5') # PWCTR2 VGH=14.7V, VGL=-7.35V
|
||||
wcd(b'\xc2', b'\x0a\x00') # PWCTR3 Opamp current small, Boost frequency
|
||||
wcd(b'\xc3', b'\x8a\x2a') # PWCTR4
|
||||
wcd(b'\xc4', b'\x8a\xee') # PWCTR5
|
||||
wcd(b'\xc5', b'\x0e') # VMCTR1 VCOMH = 4V, VOML = -1.1V NOTE I make VCOM == -0.775V
|
||||
|
||||
cmd(b'\x20') # INVOFF
|
||||
# d7..d5 of MADCTL determine rotation/orientation
|
||||
if self.height > self.width:
|
||||
wcd(b'\x36', b'\x80' if usd else b'\x40') # MADCTL: RGB portrait mode
|
||||
else:
|
||||
wcd(b'\x36', b'\xe0' if usd else b'\x20') # MADCTL: RGB landscape mode
|
||||
wcd(b'\x3a', b'\x03') # COLMOD 12 bit
|
||||
wcd(b'\xe0', b'\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10') # GMCTRP1 Gamma
|
||||
wcd(b'\xe1', b'\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10') # GMCTRN1
|
||||
|
||||
wcd(b'\x2a', int.to_bytes(self.width, 4, 'big')) # CASET column address 0 start, 160 end
|
||||
wcd(b'\x2b', int.to_bytes(self.height, 4, 'big')) # RASET
|
||||
|
||||
cmd(b'\x13') # NORON
|
||||
sleep_ms(10)
|
||||
cmd(b'\x29') # DISPON
|
||||
sleep_ms(100)
|
||||
|
||||
def show(self): # Blocks 36ms on Pyboard D at stock frequency (160*128)
|
||||
wd = self.width
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(wd * (ht - 1), -1, - wd): # For each line
|
||||
_lcopy(lb, buf[start :], wd) # Copy and map colors (68us)
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
|
@ -0,0 +1,158 @@
|
|||
# st7735r144.py Driver for ST7735R 1.44" LCD display for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# Supported display
|
||||
# Adafruit 1.44' Color TFT LCD Display with MicroSD Card breakout:
|
||||
# https://www.adafruit.com/product/2088
|
||||
|
||||
# Based on
|
||||
# https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/master/adafruit_st7735r.py
|
||||
# https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py
|
||||
# https://github.com/boochow/MicroPython-ST7735
|
||||
|
||||
# https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket/python-usage
|
||||
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
|
||||
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
|
||||
|
||||
from time import sleep_ms
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
|
||||
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
|
||||
|
||||
# _lcopy: copy a line in 8 bit format to one in 16 bit RGB565.
|
||||
# 1 bytes becomes 2 in destination. Source format:
|
||||
# < D7 D6 D5 D4 D3 D2 D1 D0>
|
||||
# <R02 R01 R00 G02 G01 G00 B01 B00> <R12 R11 R10 G12 G11 G10 B11 B10>
|
||||
# dest:
|
||||
# <B01 B00 0 0 0 G02 G01 G00> <0 0 0 R02 R01 R00 0 0>
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
dest[n] = ((c & 3) << 6) | ((c & 0x1c) >> 2) # Blue green
|
||||
n += 1
|
||||
dest[n] = (c & 0xe0) >> 3 # Red
|
||||
n += 1
|
||||
|
||||
|
||||
class ST7735R(framebuf.FrameBuffer):
|
||||
# Convert r, g, b in range 0-255 to an 8 bit colour value
|
||||
# rrrgggbb. Converted to 16 bit on the fly.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=128, width=128, rotation=0, init_spi=False):
|
||||
self._spi = spi
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
|
||||
gc.collect()
|
||||
buf = bytearray(self.height * self.width)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, self.width, self.height, mode)
|
||||
self._linebuf = bytearray(self.width * 2) # 16 bit color out
|
||||
quad, mod = divmod(rotation, 90) # Get quadrant
|
||||
if mod or quad > 3:
|
||||
quad %= 4
|
||||
print('Warning: rotation adjusted to', quad * 90)
|
||||
self._init(quad)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 500ms.
|
||||
def _init(self, quad):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies > 120ms
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT
|
||||
sleep_ms(256) # Adafruit delay (datsheet 120ms)
|
||||
wcd(b'\xb1', b'\x01\x2C\x2D') # FRMCTRL1
|
||||
wcd(b'\xb2', b'\x01\x2C\x2D') # FRMCTRL2
|
||||
wcd(b'\xb3', b'\x01\x2C\x2D\x01\x2C\x2D') # FRMCTRL3
|
||||
wcd(b'\xb4', b'\x07') # INVCTR line inversion
|
||||
|
||||
wcd(b'\xc0', b'\xa2\x02\x84') # PWCTR1 GVDD = 4.7V, 1.0uA
|
||||
wcd(b'\xc1', b'\xc5') # PWCTR2 VGH=14.7V, VGL=-7.35V
|
||||
wcd(b'\xc2', b'\x0a\x00') # PWCTR3 Opamp current small, Boost frequency
|
||||
wcd(b'\xc3', b'\x8a\x2a') # PWCTR4
|
||||
wcd(b'\xc4', b'\x8a\xee') # PWCTR5
|
||||
wcd(b'\xc5', b'\x0e') # VMCTR1 VCOMH = 4V, VOML = -1.1V NOTE I make VCOM == -0.775V
|
||||
|
||||
cmd(b'\x20') # INVOFF
|
||||
# d7..d5 of MADCTL determine rotation/orientation
|
||||
# (MADCTL_DATA, ColumnOffset, RowOffset)
|
||||
rval, co, ro = ((b'\x20', 1, 2),
|
||||
(b'\x40', 2, 1),
|
||||
(b'\xe0', 3, 2),
|
||||
(b'\x80', 2, 3))[quad]
|
||||
wcd(b'\x36', rval) # MADCTL: rotation mode for 1.44" display
|
||||
wcd(b'\x3a', b'\x05') # COLMOD 16 bit
|
||||
wcd(b'\xe0', b'\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10') # GMCTRP1 Gamma
|
||||
wcd(b'\xe1', b'\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10') # GMCTRN1
|
||||
|
||||
wcd(b'\x2a', int.to_bytes((co << 16) + self.width + co - 1, 4, 'big')) # CASET
|
||||
wcd(b'\x2b', int.to_bytes((ro << 16) + self.height + ro - 1, 4, 'big')) # RASET
|
||||
|
||||
cmd(b'\x13') # NORON
|
||||
sleep_ms(10)
|
||||
cmd(b'\x29') # DISPON
|
||||
sleep_ms(100)
|
||||
|
||||
def show(self): # Blocks 38.6ms on Pyboard D at stock frequency
|
||||
wd = self.width
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(wd * (ht - 1), -1, - wd): # For each line
|
||||
_lcopy(lb, buf[start :], wd) # Copy and map colors (68us)
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
|
@ -0,0 +1,162 @@
|
|||
# st7735r144.py Driver for ST7735R 1.44" LCD display for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# Supported display
|
||||
# Adafruit 1.44' Color TFT LCD Display with MicroSD Card breakout:
|
||||
# https://www.adafruit.com/product/2088
|
||||
|
||||
# Based on
|
||||
# https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/master/adafruit_st7735r.py
|
||||
# https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py
|
||||
# https://github.com/boochow/MicroPython-ST7735
|
||||
|
||||
# https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket/python-usage
|
||||
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
|
||||
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
|
||||
|
||||
from time import sleep_ms
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
|
||||
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, lut:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
d = (c & 0xf0) >> 3 # 2* LUT indices (LUT is 16 bit color)
|
||||
e = (c & 0x0f) << 1
|
||||
dest[n] = lut[d]
|
||||
n += 1
|
||||
dest[n] = lut[d + 1]
|
||||
n += 1
|
||||
dest[n] = lut[e]
|
||||
n += 1
|
||||
dest[n] = lut[e + 1]
|
||||
n += 1
|
||||
|
||||
|
||||
class ST7735R(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(32)
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (r & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (b & 0xf8)
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=128, width=128, rotation=0, init_spi=False):
|
||||
self._spi = spi
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
|
||||
gc.collect()
|
||||
buf = bytearray(self.height * self.width // 2)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, self.width, self.height, mode)
|
||||
self._linebuf = bytearray(self.width * 2) # 16 bit color out
|
||||
quad, mod = divmod(rotation, 90) # Get quadrant
|
||||
if mod or quad > 3:
|
||||
quad %= 4
|
||||
print('Warning: rotation adjusted to', quad * 90)
|
||||
self._init(quad)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 500ms.
|
||||
def _init(self, quad):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies > 120ms
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT
|
||||
sleep_ms(256) # Adafruit delay (datsheet 120ms)
|
||||
wcd(b'\xb1', b'\x01\x2C\x2D') # FRMCTRL1
|
||||
wcd(b'\xb2', b'\x01\x2C\x2D') # FRMCTRL2
|
||||
wcd(b'\xb3', b'\x01\x2C\x2D\x01\x2C\x2D') # FRMCTRL3
|
||||
wcd(b'\xb4', b'\x07') # INVCTR line inversion
|
||||
|
||||
wcd(b'\xc0', b'\xa2\x02\x84') # PWCTR1 GVDD = 4.7V, 1.0uA
|
||||
wcd(b'\xc1', b'\xc5') # PWCTR2 VGH=14.7V, VGL=-7.35V
|
||||
wcd(b'\xc2', b'\x0a\x00') # PWCTR3 Opamp current small, Boost frequency
|
||||
wcd(b'\xc3', b'\x8a\x2a') # PWCTR4
|
||||
wcd(b'\xc4', b'\x8a\xee') # PWCTR5
|
||||
wcd(b'\xc5', b'\x0e') # VMCTR1 VCOMH = 4V, VOML = -1.1V NOTE I make VCOM == -0.775V
|
||||
|
||||
cmd(b'\x20') # INVOFF
|
||||
# d7..d5 of MADCTL determine rotation/orientation
|
||||
# (MADCTL_DATA, ColumnOffset, RowOffset)
|
||||
rval, co, ro = ((b'\x20', 1, 2),
|
||||
(b'\x40', 2, 1),
|
||||
(b'\xe0', 3, 2),
|
||||
(b'\x80', 2, 3))[quad]
|
||||
wcd(b'\x36', rval) # MADCTL: rotation mode for 1.44" display
|
||||
wcd(b'\x3a', b'\x05') # COLMOD 16 bit
|
||||
wcd(b'\xe0', b'\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10') # GMCTRP1 Gamma
|
||||
wcd(b'\xe1', b'\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10') # GMCTRN1
|
||||
|
||||
wcd(b'\x2a', int.to_bytes((co << 16) + self.width + co - 1, 4, 'big')) # CASET
|
||||
wcd(b'\x2b', int.to_bytes((ro << 16) + self.height + ro - 1, 4, 'big')) # RASET
|
||||
|
||||
cmd(b'\x13') # NORON
|
||||
sleep_ms(10)
|
||||
cmd(b'\x29') # DISPON
|
||||
sleep_ms(100)
|
||||
|
||||
def show(self): # Blocks 38.6ms on Pyboard D at stock frequency
|
||||
clut = ST7735R.lut
|
||||
wd = self.width // 2
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(wd * (ht - 1), -1, - wd): # For each line
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors (68us)
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
|
@ -0,0 +1,156 @@
|
|||
# st7735r.py Driver for 1.8" 128*160 ST7735R LCD displays for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# Supported display
|
||||
# Adfruit 1.8' Color TFT LCD display with MicroSD Card Breakout:
|
||||
# https://www.adafruit.com/product/358
|
||||
|
||||
# Based on
|
||||
# https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/master/adafruit_st7735r.py
|
||||
# https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py
|
||||
# https://github.com/boochow/MicroPython-ST7735
|
||||
|
||||
# https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket/python-usage
|
||||
# disp = st7735.ST7735R(spi, rotation=90, # 1.8" ST7735R
|
||||
# disp = st7735.ST7735R(spi, rotation=270, height=128, x_offset=2, y_offset=3, # 1.44" ST7735R
|
||||
|
||||
from time import sleep_ms
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
|
||||
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
|
||||
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, lut:ptr8, length:int):
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
d = (c & 0xf0) >> 3 # 2* LUT indices (LUT is 16 bit color)
|
||||
e = (c & 0x0f) << 1
|
||||
dest[n] = lut[d]
|
||||
n += 1
|
||||
dest[n] = lut[d + 1]
|
||||
n += 1
|
||||
dest[n] = lut[e]
|
||||
n += 1
|
||||
dest[n] = lut[e + 1]
|
||||
n += 1
|
||||
|
||||
class ST7735R(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(32)
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return (b & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (r & 0xf8)
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=128, width=160, usd=False, init_spi=False):
|
||||
self._spi = spi
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
|
||||
gc.collect()
|
||||
buf = bytearray(height * width // 2)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, width, height, mode)
|
||||
self._linebuf = bytearray(self.width * 2) # 16 bit color out
|
||||
self._init(usd)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 500ms.
|
||||
def _init(self, usd):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies > 120ms
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT
|
||||
sleep_ms(256) # Adafruit delay (datsheet 120ms)
|
||||
wcd(b'\xb1', b'\x01\x2C\x2D') # FRMCTRL1
|
||||
wcd(b'\xb2', b'\x01\x2C\x2D') # FRMCTRL2
|
||||
wcd(b'\xb3', b'\x01\x2C\x2D\x01\x2C\x2D') # FRMCTRL3
|
||||
wcd(b'\xb4', b'\x07') # INVCTR line inversion
|
||||
|
||||
wcd(b'\xc0', b'\xa2\x02\x84') # PWCTR1 GVDD = 4.7V, 1.0uA
|
||||
wcd(b'\xc1', b'\xc5') # PWCTR2 VGH=14.7V, VGL=-7.35V
|
||||
wcd(b'\xc2', b'\x0a\x00') # PWCTR3 Opamp current small, Boost frequency
|
||||
wcd(b'\xc3', b'\x8a\x2a') # PWCTR4
|
||||
wcd(b'\xc4', b'\x8a\xee') # PWCTR5
|
||||
wcd(b'\xc5', b'\x0e') # VMCTR1 VCOMH = 4V, VOML = -1.1V NOTE I make VCOM == -0.775V
|
||||
|
||||
cmd(b'\x20') # INVOFF
|
||||
# d7..d5 of MADCTL determine rotation/orientation
|
||||
if self.height > self.width:
|
||||
wcd(b'\x36', b'\x80' if usd else b'\x40') # MADCTL: RGB portrait mode
|
||||
else:
|
||||
wcd(b'\x36', b'\xe0' if usd else b'\x20') # MADCTL: RGB landscape mode
|
||||
wcd(b'\x3a', b'\x05') # COLMOD 16 bit
|
||||
wcd(b'\xe0', b'\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10') # GMCTRP1 Gamma
|
||||
wcd(b'\xe1', b'\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10') # GMCTRN1
|
||||
|
||||
wcd(b'\x2a', int.to_bytes(self.width, 4, 'big')) # CASET column address 0 start, 160 end
|
||||
wcd(b'\x2b', int.to_bytes(self.height, 4, 'big')) # RASET
|
||||
|
||||
cmd(b'\x13') # NORON
|
||||
sleep_ms(10)
|
||||
cmd(b'\x29') # DISPON
|
||||
sleep_ms(100)
|
||||
|
||||
def show(self): # Blocks 36ms on Pyboard D at stock frequency (160*128)
|
||||
clut = ST7735R.lut
|
||||
wd = self.width // 2
|
||||
ht = self.height
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(wd * (ht - 1), -1, - wd): # For each line
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
|
@ -0,0 +1,237 @@
|
|||
# st7789.py Driver for ST7789 LCD displays for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch, Ihor Nehrutsa
|
||||
|
||||
# Tested displays:
|
||||
# Adafruit 1.3" 240x240 Wide Angle TFT LCD Display with MicroSD - ST7789
|
||||
# https://www.adafruit.com/product/4313
|
||||
# TTGO T-Display
|
||||
# http://www.lilygo.cn/prod_view.aspx?TypeId=50044&Id=1126
|
||||
|
||||
# Based on
|
||||
# Adfruit https://github.com/adafruit/Adafruit_CircuitPython_ST7789/blob/master/adafruit_st7789.py
|
||||
# Also see st7735r_4bit.py for other source acknowledgements
|
||||
|
||||
# SPI bus: default mode. Driver performs no read cycles.
|
||||
# Datasheet table 6 p44 scl write cycle 16ns == 62.5MHz
|
||||
|
||||
from time import sleep_ms #, ticks_us, ticks_diff
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
import uasyncio as asyncio
|
||||
|
||||
# User orientation constants
|
||||
LANDSCAPE = 0 # Default
|
||||
REFLECT = 1
|
||||
USD = 2
|
||||
PORTRAIT = 4
|
||||
# Display types
|
||||
GENERIC = (0, 0, 0)
|
||||
TDISPLAY = (52, 40, 1)
|
||||
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr16, source:ptr8, lut:ptr16, length:int):
|
||||
# rgb565 - 16bit/pixel
|
||||
n = 0
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
dest[n] = lut[c >> 4] # current pixel
|
||||
n += 1
|
||||
dest[n] = lut[c & 0x0f] # next pixel
|
||||
n += 1
|
||||
|
||||
class ST7789(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(0xFF for _ in range(32)) # set all colors to BLACK
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value rgb565.
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
# For some reason color must be inverted on this controller.
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return ((b & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (r & 0xf8)) ^ 0xffff
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=240, width=240,
|
||||
disp_mode=LANDSCAPE, init_spi=False, display=GENERIC):
|
||||
if not 0 <= disp_mode <= 7:
|
||||
raise ValueError('Invalid display mode:', disp_mode)
|
||||
if not display in (GENERIC, TDISPLAY):
|
||||
raise ValueError('Invalid display type.')
|
||||
self._spi = spi # Clock cycle time for write 16ns 62.5MHz max (read is 150ns)
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._offset = display[:2] # display arg is (x, y, orientation)
|
||||
orientation = display[2] # where x, y is the RAM offset
|
||||
self._spi_init = init_spi # Possible user callback
|
||||
self._lock = asyncio.Lock()
|
||||
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
|
||||
gc.collect()
|
||||
buf = bytearray(height * -(-width // 2)) # Ceiling division for odd widths
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, width, height, mode)
|
||||
self._linebuf = bytearray(self.width * 2) # 16 bit color out
|
||||
self._init(disp_mode, orientation)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 163ms. Adafruit have various sleep delays
|
||||
# where I can find no requirement in the datasheet. I removed them with
|
||||
# other redundant code.
|
||||
def _init(self, user_mode, orientation):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies 120ms before SLPOUT
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT: exit sleep mode
|
||||
sleep_ms(10) # Adafruit delay 500ms (datsheet 5ms)
|
||||
wcd(b'\x3a', b'\x55') # _COLMOD 16 bit/pixel, 65Kbit color space
|
||||
cmd(b'\x20') # INVOFF Adafruit turn inversion on. This driver fixes .rgb
|
||||
cmd(b'\x13') # NORON Normal display mode
|
||||
|
||||
# Table maps user request onto hardware values. index values:
|
||||
# 0 Normal
|
||||
# 1 Reflect
|
||||
# 2 USD
|
||||
# 3 USD reflect
|
||||
# Followed by same for LANDSCAPE
|
||||
if not orientation:
|
||||
user_mode ^= PORTRAIT
|
||||
# Hardware mappings
|
||||
# d7..d5 of MADCTL determine rotation/orientation datasheet P124, P231
|
||||
# d5 = MV row/col exchange
|
||||
# d6 = MX col addr order
|
||||
# d7 = MY page addr order
|
||||
# LANDSCAPE = 0
|
||||
# PORTRAIT = 0x20
|
||||
# REFLECT = 0x40
|
||||
# USD = 0x80
|
||||
mode = (0x60, 0xe0, 0xa0, 0x20, 0, 0x40, 0xc0, 0x80)[user_mode]
|
||||
# Set display window depending on mode, .height and .width.
|
||||
self.set_window(mode)
|
||||
wcd(b'\x36', int.to_bytes(mode, 1, 'little'))
|
||||
cmd(b'\x29') # DISPON. Adafruit then delay 500ms.
|
||||
|
||||
# Define the mapping between RAM and the display.
|
||||
# Datasheet section 8.12 p124.
|
||||
def set_window(self, mode):
|
||||
portrait, reflect, usd = 0x20, 0x40, 0x80
|
||||
rht = 320
|
||||
rwd = 240 # RAM ht and width
|
||||
wht = self.height # Window (framebuf) dimensions.
|
||||
wwd = self.width # In portrait mode wht > wwd
|
||||
if mode & portrait:
|
||||
xoff = self._offset[1] # x and y transposed
|
||||
yoff = self._offset[0]
|
||||
xs = xoff
|
||||
xe = wwd + xoff - 1
|
||||
ys = yoff # y start
|
||||
ye = wht + yoff - 1 # y end
|
||||
if mode & reflect:
|
||||
ys = rwd - wht - yoff
|
||||
ye = rwd - yoff - 1
|
||||
if mode & usd:
|
||||
xs = rht - wwd - xoff
|
||||
xe = rht - xoff - 1
|
||||
else: # LANDSCAPE
|
||||
xoff = self._offset[0]
|
||||
yoff = self._offset[1]
|
||||
xs = xoff
|
||||
xe = wwd + xoff - 1
|
||||
ys = yoff # y start
|
||||
ye = wht + yoff - 1 # y end
|
||||
if mode & usd:
|
||||
ys = rht - wht - yoff
|
||||
ye = rht - yoff - 1
|
||||
if mode & reflect:
|
||||
xs = rwd - wwd - xoff
|
||||
xe = rwd - xoff - 1
|
||||
|
||||
# Col address set.
|
||||
self._wcd(b'\x2a', int.to_bytes((xs << 16) + xe, 4, 'big'))
|
||||
# Row address set
|
||||
self._wcd(b'\x2b', int.to_bytes((ys << 16) + ye, 4, 'big'))
|
||||
|
||||
#@micropython.native # Made virtually no difference to timing.
|
||||
def show(self): # Blocks for 83ms @60MHz SPI
|
||||
# Blocks for 60ms @30MHz SPI on TTGO in PORTRAIT mode
|
||||
# Blocks for 46ms @30MHz SPI on TTGO in LANDSCAPE mode
|
||||
#ts = ticks_us()
|
||||
clut = ST7789.lut
|
||||
wd = -(-self.width // 2) # Ceiling division for odd number widths
|
||||
end = self.height * wd
|
||||
lb = memoryview(self._linebuf)
|
||||
buf = self._mvb
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(0, end, wd):
|
||||
_lcopy(lb, buf[start:], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
||||
#print(ticks_diff(ticks_us(), ts))
|
||||
|
||||
# Asynchronous refresh with support for reducing blocking time.
|
||||
async def do_refresh(self, split=5):
|
||||
async with self._lock:
|
||||
lines, mod = divmod(self.height, split) # Lines per segment
|
||||
if mod:
|
||||
raise ValueError('Invalid do_refresh arg.')
|
||||
clut = ST7789.lut
|
||||
wd = -(-self.width // 2)
|
||||
lb = memoryview(self._linebuf)
|
||||
buf = self._mvb
|
||||
line = 0
|
||||
for n in range(split):
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(b'\x3c' if n else b'\x2c') # RAMWR/Write memory continue
|
||||
self._dc(1)
|
||||
for start in range(wd * line, wd * (line + lines), wd):
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
line += lines
|
||||
self._cs(1)
|
||||
await asyncio.sleep(0)
|
|
@ -0,0 +1,56 @@
|
|||
# colors.py Micropython GUI library for TFT displays: colors and shapes
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2019 Peter Hinch
|
||||
from hardware_setup import SSD
|
||||
|
||||
# Code can be portable between 4-bit and other drivers by calling create_color
|
||||
def create_color(idx, r, g, b):
|
||||
c = SSD.rgb(r, g, b)
|
||||
if not hasattr(SSD, 'lut'):
|
||||
return c
|
||||
if not 0 <= idx <= 15:
|
||||
raise ValueError('Color nos must be 0..15')
|
||||
x = idx << 1
|
||||
SSD.lut[x] = c & 0xff
|
||||
SSD.lut[x + 1] = c >> 8
|
||||
return idx
|
||||
|
||||
if hasattr(SSD, 'lut'): # Colors defined by LUT
|
||||
BLACK = create_color(0, 0, 0, 0)
|
||||
GREEN = create_color(1, 0, 255, 0)
|
||||
RED = create_color(2, 255, 0, 0)
|
||||
LIGHTRED = create_color(3, 140, 0, 0)
|
||||
BLUE = create_color(4, 0, 0, 255)
|
||||
YELLOW = create_color(5, 255, 255, 0)
|
||||
GREY = create_color(6, 100, 100, 100)
|
||||
MAGENTA = create_color(7, 255, 0, 255)
|
||||
CYAN = create_color(8, 0, 255, 255)
|
||||
LIGHTGREEN = create_color(9, 0, 100, 0)
|
||||
DARKGREEN = create_color(10, 0, 80, 0)
|
||||
DARKBLUE = create_color(11, 0, 0, 90)
|
||||
# 12, 13, 14 free for user definition
|
||||
WHITE = create_color(15, 255, 255, 255)
|
||||
else:
|
||||
BLACK = SSD.rgb(0, 0, 0)
|
||||
GREEN = SSD.rgb(0, 255, 0)
|
||||
RED = SSD.rgb(255, 0, 0)
|
||||
LIGHTRED = SSD.rgb(140, 0, 0)
|
||||
BLUE = SSD.rgb(0, 0, 255)
|
||||
YELLOW = SSD.rgb(255, 255, 0)
|
||||
GREY = SSD.rgb(100, 100, 100)
|
||||
MAGENTA = SSD.rgb(255, 0, 255)
|
||||
CYAN = SSD.rgb(0, 255, 255)
|
||||
LIGHTGREEN = SSD.rgb(0, 100, 0)
|
||||
DARKGREEN = SSD.rgb(0, 80, 0)
|
||||
DARKBLUE = SSD.rgb(0, 0, 90)
|
||||
WHITE = SSD.rgb(255, 255, 255)
|
||||
|
||||
# Color used when clearing the screen
|
||||
BGCOLOR = BLACK
|
||||
|
||||
# RA8875 defines colors as 3-tuples with greying-out operating on those.
|
||||
# Should we assign GREY to any color > 0?
|
||||
CIRCLE = 1
|
||||
RECTANGLE = 2
|
||||
CLIPPED_RECT = 3
|
|
@ -0,0 +1,687 @@
|
|||
# ugui.py Micropython GUI library
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2019-2021 Peter Hinch
|
||||
|
||||
# Requires uasyncio V3
|
||||
|
||||
import uasyncio as asyncio
|
||||
from uasyncio import Event
|
||||
from time import ticks_diff, ticks_ms
|
||||
import gc
|
||||
|
||||
from gui.core.colors import *
|
||||
from hardware_setup import ssd
|
||||
|
||||
from gui.primitives.delay_ms import Delay_ms
|
||||
from gui.primitives.switch import Switch
|
||||
|
||||
gc.collect()
|
||||
__version__ = (0, 1, 0)
|
||||
|
||||
# Null function
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
async def _g():
|
||||
pass
|
||||
type_coro = type(_g())
|
||||
|
||||
def setup(d):
|
||||
global display
|
||||
display = d
|
||||
|
||||
_FIRST = const(0)
|
||||
_NEXT = const(1)
|
||||
_PREV = const(2)
|
||||
_LAST = const(3)
|
||||
|
||||
# Wrapper for ssd providing buttons and framebuf compatible methods
|
||||
class Display:
|
||||
|
||||
def __init__(self, ssd, nxt, sel, prev=None, up=None, down=None):
|
||||
self._next = Switch(nxt)
|
||||
self._sel = Switch(sel)
|
||||
# Mandatory buttons
|
||||
self._next.close_func(Screen.next_ctrl) # Call current screen bound method
|
||||
self._sel.close_func(Screen.sel_ctrl)
|
||||
self._sel.open_func(Screen.unsel)
|
||||
|
||||
self.height = ssd.height
|
||||
self.width = ssd.width
|
||||
|
||||
# Optional buttons
|
||||
self._prev = None
|
||||
if prev is not None:
|
||||
self._prev = Switch(prev)
|
||||
self._prev.close_func(Screen.prev_ctrl)
|
||||
# Up and down methods get the button as an arg.
|
||||
self._up = None
|
||||
if up is not None:
|
||||
self._up = Switch(up)
|
||||
self._up.close_func(self.do_up)
|
||||
self._down = None
|
||||
if down is not None:
|
||||
self._down = Switch(down)
|
||||
self._down.close_func(self.do_down)
|
||||
self._is_grey = False # Not greyed-out
|
||||
|
||||
def print_centred(self, writer, x, y, text, fgcolor=None, bgcolor=None):
|
||||
sl = writer.stringlen(text)
|
||||
writer.set_textpos(ssd, y - writer.height // 2, x - sl // 2)
|
||||
writer.setcolor(fgcolor, bgcolor)
|
||||
writer.printstring(text)
|
||||
writer.setcolor() # Restore defaults
|
||||
|
||||
def print_left(self, writer, x, y, txt, fgcolor=None, bgcolor=None, invert=False):
|
||||
writer.set_textpos(ssd, y, x)
|
||||
writer.setcolor(fgcolor, bgcolor)
|
||||
writer.printstring(txt, invert)
|
||||
writer.setcolor() # Restore defaults
|
||||
|
||||
def do_up(self):
|
||||
if self._down is not None and self._down(): # Interlock. TODO More?
|
||||
Screen.up_ctrl(self._up)
|
||||
|
||||
def do_down(self):
|
||||
if self._up is not None and self._up():
|
||||
Screen.down_ctrl(self._down)
|
||||
|
||||
# Greying out has only one option given limitation of 4-bit display driver
|
||||
# It would be possible to do better with RGB565 but would need inverse transformation
|
||||
# to (r, g, b), scale and re-convert to integer.
|
||||
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
|
||||
|
||||
def usegrey(self, val): # display.usegrey(True) sets greyed-out
|
||||
self._is_grey = val
|
||||
return self
|
||||
|
||||
# Graphics primitives: despatch to device (i.e. framebuf) or
|
||||
# local function for methods not implemented by framebuf.
|
||||
# These methods support greying out color overrides.
|
||||
# Clear screen.
|
||||
def clr_scr(self):
|
||||
ssd.fill_rect(0, 0, self.width - 1, self.height - 1, BGCOLOR)
|
||||
|
||||
def rect(self, x1, y1, w, h, color):
|
||||
ssd.rect(x1, y1, w, h, self._getcolor(color))
|
||||
|
||||
def fill_rect(self, x1, y1, w, h, color):
|
||||
ssd.fill_rect(x1, y1, w, h, self._getcolor(color))
|
||||
|
||||
def vline(self, x, y, l, color):
|
||||
ssd.vline(x, y, l, self._getcolor(color))
|
||||
|
||||
def hline(self, x, y, l, color):
|
||||
ssd.hline(x, y, l, self._getcolor(color))
|
||||
|
||||
def line(self, x1, y1, x2, y2, color):
|
||||
ssd.line(x1, y1, x2, y2, self._getcolor(color))
|
||||
|
||||
# Private method uses physical color
|
||||
def _circle(self, x0, y0, r, color): # Single pixel circle
|
||||
x = -r
|
||||
y = 0
|
||||
err = 2 -2*r
|
||||
while x <= 0:
|
||||
ssd.pixel(x0 -x, y0 +y, color)
|
||||
ssd.pixel(x0 +x, y0 +y, color)
|
||||
ssd.pixel(x0 +x, y0 -y, color)
|
||||
ssd.pixel(x0 -x, y0 -y, color)
|
||||
e2 = err
|
||||
if (e2 <= y):
|
||||
y += 1
|
||||
err += y*2 +1
|
||||
if (-x == y and e2 <= x):
|
||||
e2 = 0
|
||||
if (e2 > x):
|
||||
x += 1
|
||||
err += x*2 +1
|
||||
|
||||
def circle(self, x0, y0, r, color, width =1): # Draw circle (maybe grey)
|
||||
color = self._getcolor(color)
|
||||
x0, y0, r = int(x0), int(y0), int(r)
|
||||
for r in range(r, r -width, -1):
|
||||
self._circle(x0, y0, r, color)
|
||||
|
||||
def fillcircle(self, x0, y0, r, color): # Draw filled circle
|
||||
color = self._getcolor(color)
|
||||
x0, y0, r = int(x0), int(y0), int(r)
|
||||
x = -r
|
||||
y = 0
|
||||
err = 2 -2*r
|
||||
while x <= 0:
|
||||
ssd.line(x0 -x, y0 -y, x0 -x, y0 +y, color)
|
||||
ssd.line(x0 +x, y0 -y, x0 +x, y0 +y, color)
|
||||
e2 = err
|
||||
if (e2 <= y):
|
||||
y +=1
|
||||
err += y*2 +1
|
||||
if (-x == y and e2 <= x):
|
||||
e2 = 0
|
||||
if (e2 > x):
|
||||
x += 1
|
||||
err += x*2 +1
|
||||
|
||||
def clip_rect(self, x, y, w, h, color):
|
||||
color = self._getcolor(color)
|
||||
c = 4
|
||||
ssd.hline(x + c, y, w - 2 * c, color)
|
||||
ssd.hline(x + c, y + h, w - 2 * c, color)
|
||||
ssd.vline(x, y + c, h - 2 * c, color)
|
||||
ssd.vline(x + w - 1, y + c, h - 2 * c, color)
|
||||
ssd.line(x + c, y, x, y + c, color)
|
||||
ssd.line(x + w - c - 1, y, x + w - 1, y + c, color)
|
||||
ssd.line(x, y + h - c - 1, x + c, y + h - 1, color)
|
||||
ssd.line(x + w - 1, y + h - c - 1, x + w - c - 1, y + h, color)
|
||||
|
||||
def fill_clip_rect(self, x, y, w, h, color):
|
||||
color = self._getcolor(color)
|
||||
c = 4
|
||||
ssd.fill_rect(x, y + c, w, h - 2 * c, color)
|
||||
for z in range(c):
|
||||
l = w - 2 * (c - z) # Line length
|
||||
ssd.hline(x + c - z, y + z, l, color)
|
||||
ssd.hline(x + c - z, y + h - z - 1, l, color)
|
||||
|
||||
|
||||
class Screen:
|
||||
current_screen = None
|
||||
is_shutdown = Event()
|
||||
|
||||
@classmethod
|
||||
def next_ctrl(cls):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.move(_NEXT)
|
||||
|
||||
@classmethod
|
||||
def prev_ctrl(cls):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.move(_PREV)
|
||||
|
||||
@classmethod
|
||||
def sel_ctrl(cls):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.do_sel()
|
||||
|
||||
|
||||
@classmethod
|
||||
def unsel(cls):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.unsel_i()
|
||||
|
||||
@classmethod
|
||||
def up_ctrl(cls, button):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.do_up(button)
|
||||
|
||||
@classmethod
|
||||
def down_ctrl(cls, button):
|
||||
if cls.current_screen is not None:
|
||||
cls.current_screen.do_down(button)
|
||||
|
||||
# Move currency to a specific widget (e.g. ButtonList)
|
||||
@classmethod
|
||||
def select(cls, obj):
|
||||
if cls.current_screen is not None:
|
||||
return cls.current_screen.move_to(obj)
|
||||
|
||||
@classmethod
|
||||
def show(cls, force):
|
||||
for obj in cls.current_screen.displaylist:
|
||||
if obj.visible: # In a buttonlist only show visible button
|
||||
# pend signals an obect with changed contents
|
||||
if force or obj.draw:
|
||||
obj.draw_border()
|
||||
obj.show()
|
||||
obj.draw = False
|
||||
|
||||
@classmethod
|
||||
def change(cls, cls_new_screen, *, forward=True, args=[], kwargs={}):
|
||||
cs_old = cls.current_screen
|
||||
if cs_old is not None: # Leaving an existing screen
|
||||
for entry in cls.current_screen.tasklist:
|
||||
if entry[1]: # To be cancelled on screen change
|
||||
entry[0].cancel()
|
||||
cs_old.on_hide() # Optional method in subclass
|
||||
if forward:
|
||||
if isinstance(cls_new_screen, type):
|
||||
# Instantiate new screen. __init__ must terminate
|
||||
new_screen = cls_new_screen(*args, **kwargs)
|
||||
else:
|
||||
raise ValueError('Must pass Screen class or subclass (not instance)')
|
||||
new_screen.parent = cs_old
|
||||
cs_new = new_screen
|
||||
else:
|
||||
cs_new = cls_new_screen # An object, not a class
|
||||
cls.current_screen = cs_new
|
||||
cs_new.on_open() # Optional subclass method
|
||||
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()
|
||||
|
||||
@classmethod
|
||||
async def monitor(cls):
|
||||
ar = asyncio.create_task(cls.auto_refresh())
|
||||
await cls.is_shutdown.wait()
|
||||
cls.is_shutdown.clear()
|
||||
# Task cancellation and shutdown
|
||||
ar.cancel() # Refresh task
|
||||
for entry in cls.current_screen.tasklist:
|
||||
entry[0].cancel()
|
||||
await asyncio.sleep_ms(0) # Allow subclass to cancel tasks
|
||||
display.clr_scr()
|
||||
ssd.show()
|
||||
cls.current_screen = None # Ensure another demo can run
|
||||
|
||||
@staticmethod
|
||||
async def auto_refresh():
|
||||
arfsh = hasattr(ssd, 'do_refresh') # Refresh can be asynchronous
|
||||
while True:
|
||||
Screen.show(False) # Update stale controls. No physical refresh.
|
||||
# Now perform physical refresh.
|
||||
if arfsh:
|
||||
await ssd.do_refresh()
|
||||
else:
|
||||
ssd.show() # Synchronous (blocking) refresh.
|
||||
await asyncio.sleep_ms(0)
|
||||
|
||||
@classmethod
|
||||
def back(cls):
|
||||
parent = cls.current_screen.parent
|
||||
if parent is None: # Closing base screen. Quit.
|
||||
cls.shutdown()
|
||||
else:
|
||||
cls.change(parent, forward = False)
|
||||
|
||||
@classmethod
|
||||
def addobject(cls, obj):
|
||||
cs = cls.current_screen
|
||||
if cs is None:
|
||||
raise OSError('You must create a Screen instance')
|
||||
# Populate list of active widgets (i.e. ones that can acquire focus).
|
||||
if obj.active:
|
||||
# Append to active list regrdless of disabled state which may
|
||||
# change at runtime.
|
||||
al = cs.lstactive
|
||||
empty = al == [] or all(o.greyed_out() for o in al)
|
||||
al.append(obj)
|
||||
if empty and not obj.greyed_out():
|
||||
cs.selected_obj = len(al) - 1 # Index into lstactive
|
||||
cs.displaylist.append(obj) # All displayable objects
|
||||
|
||||
@classmethod
|
||||
def shutdown(cls):
|
||||
cls.is_shutdown.set() # Tell monitor() to shutdown
|
||||
|
||||
def __init__(self):
|
||||
self.lstactive = [] # Controls which respond to Select button
|
||||
self.selected_obj = None # Index of currently selected object
|
||||
self.displaylist = [] # All displayable objects
|
||||
self.tasklist = [] # Allow instance to register tasks for shutdown
|
||||
self.modal = False
|
||||
self.height = ssd.height # Occupies entire display
|
||||
self.width = ssd.width
|
||||
self.row = 0
|
||||
self.col = 0
|
||||
if Screen.current_screen is None: # Initialising class and task
|
||||
# Here we create singleton tasks
|
||||
asyncio.create_task(self._garbage_collect())
|
||||
Screen.current_screen = self
|
||||
self.parent = None
|
||||
|
||||
def _do_open(self, old_screen): # Window overrides
|
||||
dev = display.usegrey(False)
|
||||
# If opening a Screen from an Window just blank and redraw covered area
|
||||
if old_screen is not None and old_screen.modal:
|
||||
x0, y0, x1, y1, w, h = old_screen._list_dims()
|
||||
dev.fill_rect(x0, y0, w, h, BGCOLOR) # Blank to screen BG
|
||||
for obj in [z for z in self.displaylist if z.overlaps(x0, y0, x1, y1)]:
|
||||
if obj.visible:
|
||||
obj.draw_border()
|
||||
obj.show()
|
||||
# Normally clear the screen and redraw everything
|
||||
else:
|
||||
dev.clr_scr() # Clear framebuf but don't update display
|
||||
Screen.show(True) # Force full redraw
|
||||
|
||||
# Return an active control or None
|
||||
# By default returns the selected control
|
||||
# else checks a given control by index into lstactive
|
||||
def get_obj(self, idx=None):
|
||||
so = self.selected_obj if idx is None else idx
|
||||
if so is not None:
|
||||
co = self.lstactive[so]
|
||||
if co.visible and not co.greyed_out():
|
||||
return co
|
||||
return None
|
||||
|
||||
# Move currency to next enabled control. Arg is direction of move.
|
||||
def move(self, to):
|
||||
if to == _FIRST:
|
||||
idx = -1
|
||||
up = 1
|
||||
elif to == _LAST:
|
||||
idx = len(self.lstactive)
|
||||
up = -1
|
||||
else:
|
||||
idx = self.selected_obj
|
||||
up = 1 if to == _NEXT else -1
|
||||
|
||||
lo = self.get_obj() # Old current object
|
||||
done = False
|
||||
while not done:
|
||||
idx += up
|
||||
idx %= len(self.lstactive)
|
||||
co = self.get_obj(idx)
|
||||
if co is not None:
|
||||
if co is not lo:
|
||||
self.selected_obj = idx
|
||||
if lo is not None:
|
||||
lo.leave() # Tell object it's losing currency.
|
||||
lo.show() # Re-display with new status
|
||||
co.enter() # Tell object it has currency
|
||||
co.show()
|
||||
elif isinstance(self, Window):
|
||||
# Special case of Window with one object: leave
|
||||
# without making changes (Dropdown in particular)
|
||||
Screen.back()
|
||||
done = True
|
||||
|
||||
# Move currency to a specific control.
|
||||
def move_to(self, obj):
|
||||
lo = self.get_obj() # Old current object
|
||||
for idx in range(len(self.lstactive)) :
|
||||
co = self.get_obj(idx)
|
||||
if co is obj:
|
||||
self.selected_obj = idx
|
||||
if lo is not None:
|
||||
lo.leave() # Tell object it's losing currency.
|
||||
lo.show() # Re-display with new status
|
||||
co.enter() # Tell object it has currency
|
||||
co.show()
|
||||
return True # Success
|
||||
return False
|
||||
|
||||
def do_sel(self): # Direct to current control
|
||||
co = self.get_obj()
|
||||
if co is not None:
|
||||
co.do_sel()
|
||||
|
||||
def unsel_i(self):
|
||||
co = self.get_obj()
|
||||
if co is not None:
|
||||
co.unsel()
|
||||
|
||||
def do_up(self, button):
|
||||
co = self.get_obj()
|
||||
if co is not None and hasattr(co, 'do_up'):
|
||||
co.do_up(button) # Widget handles up/down
|
||||
else:
|
||||
Screen.current_screen.move(_FIRST)
|
||||
|
||||
def do_down(self, button):
|
||||
co = self.get_obj()
|
||||
if co is not None and hasattr(co, 'do_down'):
|
||||
co.do_down(button)
|
||||
else:
|
||||
Screen.current_screen.move(_LAST)
|
||||
|
||||
# Methods optionally implemented in subclass
|
||||
def on_open(self):
|
||||
return
|
||||
|
||||
def after_open(self):
|
||||
return
|
||||
|
||||
def on_hide(self):
|
||||
return
|
||||
|
||||
def locn(self, row, col):
|
||||
return self.row + row, self.col + col
|
||||
|
||||
# Housekeeping methods
|
||||
def reg_task(self, task, on_change=False): # May be passed a coro or a Task
|
||||
if isinstance(task, type_coro):
|
||||
task = asyncio.create_task(task)
|
||||
self.tasklist.append([task, on_change])
|
||||
|
||||
async def _garbage_collect(self):
|
||||
while True:
|
||||
await asyncio.sleep_ms(500)
|
||||
gc.collect()
|
||||
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
|
||||
#print(gc.mem_free())
|
||||
|
||||
# Very basic window class. Cuts a rectangular hole in a screen on which content may be drawn
|
||||
class Window(Screen):
|
||||
_value = None
|
||||
def __init__(self, row, col, height, width, *, draw_border=True, bgcolor=None, fgcolor=None):
|
||||
Screen.__init__(self)
|
||||
self.row = row
|
||||
self.col = col
|
||||
self.height = height
|
||||
self.width = width
|
||||
self.draw_border = draw_border
|
||||
self.modal = True
|
||||
self.fgcolor = fgcolor if fgcolor is not None else WHITE
|
||||
self.bgcolor = bgcolor if bgcolor is not None else BGCOLOR
|
||||
|
||||
def _do_open(self, old_screen):
|
||||
dev = display.usegrey(False)
|
||||
x, y = self.col, self.row
|
||||
dev.fill_rect(x, y, self.width, self.height, self.bgcolor)
|
||||
if self.draw_border:
|
||||
dev.rect(x, y, self.width, self.height, self.fgcolor)
|
||||
Screen.show(True)
|
||||
|
||||
def _list_dims(self):
|
||||
w = self.width
|
||||
h = self.height
|
||||
x = self.col
|
||||
y = self.row
|
||||
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
|
||||
class Widget:
|
||||
|
||||
def __init__(self, writer, row, col, height, width,
|
||||
fgcolor, bgcolor, bdcolor,
|
||||
value=None, active=False):
|
||||
self.active = active
|
||||
self._greyed_out = False
|
||||
Screen.addobject(self)
|
||||
self.screen = Screen.current_screen
|
||||
writer.set_clip(True, True, False) # Disable scrolling text
|
||||
self.writer = writer
|
||||
# The following assumes that the widget is mal-positioned, not oversize.
|
||||
if row < 0:
|
||||
row = 0
|
||||
self.warning()
|
||||
elif row + height >= ssd.height:
|
||||
row = ssd.height - height - 1
|
||||
self.warning()
|
||||
if col < 0:
|
||||
col = 0
|
||||
self.warning()
|
||||
elif col + width >= ssd.width:
|
||||
col = ssd.width - width - 1
|
||||
self.warning()
|
||||
self.row = row
|
||||
self.col = col
|
||||
self.height = height
|
||||
self.width = width
|
||||
self.visible = True # Used by ButtonList class for invisible buttons
|
||||
self.draw = True # Signals that obect must be redrawn
|
||||
self._value = value
|
||||
|
||||
# Current colors
|
||||
if fgcolor is None:
|
||||
fgcolor = writer.fgcolor
|
||||
if bgcolor is None:
|
||||
bgcolor = BGCOLOR
|
||||
if bdcolor is None:
|
||||
bdcolor = fgcolor
|
||||
self.fgcolor = fgcolor
|
||||
self.bgcolor = bgcolor
|
||||
# bdcolor is False if no border is to be drawn
|
||||
self.bdcolor = bdcolor
|
||||
# Default colors allow restoration after dynamic change
|
||||
self.def_fgcolor = fgcolor
|
||||
self.def_bgcolor = bgcolor
|
||||
self.def_bdcolor = bdcolor
|
||||
# has_border is True if a border was drawn
|
||||
self.has_border = False
|
||||
self.callback = dolittle # Value change callback
|
||||
self.args = []
|
||||
|
||||
def warning(self):
|
||||
print('Warning: attempt to create {} outside screen dimensions.'.format(self.__class__.__name__))
|
||||
|
||||
def greyed_out(self):
|
||||
return self._greyed_out # Subclass may be greyed out
|
||||
|
||||
def value(self, val=None): # User method to get or set value
|
||||
if val is not None:
|
||||
if type(val) is float:
|
||||
val = min(max(val, 0.0), 1.0)
|
||||
if val != self._value:
|
||||
self._value = val
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
self.callback(self, *self.args)
|
||||
return self._value
|
||||
|
||||
# Some widgets (e.g. Dial) have an associated Label
|
||||
def text(self, text=None, invert=False, fgcolor=None, bgcolor=None, bdcolor=None):
|
||||
if hasattr(self, 'label'):
|
||||
self.label.value(text, invert, fgcolor, bgcolor, bdcolor)
|
||||
else:
|
||||
raise ValueError('Method {}.text does not exist.'.format(self.__class__.__name__))
|
||||
|
||||
# Called from subclass prior to populating framebuf with control
|
||||
def show(self, black=True):
|
||||
if self.screen != Screen.current_screen:
|
||||
# Can occur if a control's action is to change screen.
|
||||
return False # Subclass abandons
|
||||
|
||||
self.draw = False
|
||||
self.draw_border()
|
||||
# Blank controls' space
|
||||
if self.visible:
|
||||
dev = display.usegrey(self._greyed_out)
|
||||
x = self.col
|
||||
y = self.row
|
||||
dev.fill_rect(x, y, self.width, self.height, BGCOLOR if black else self.bgcolor)
|
||||
return True
|
||||
|
||||
# Called by Screen.show(). Draw background and bounding box if required.
|
||||
# Border is always 2 pixels wide, outside control's bounding box
|
||||
def draw_border(self):
|
||||
if self.screen is Screen.current_screen:
|
||||
dev = display.usegrey(self._greyed_out)
|
||||
x = self.col - 2
|
||||
y = self.row - 2
|
||||
w = self.width + 4
|
||||
h = self.height + 4
|
||||
if self.has_focus():
|
||||
dev.rect(x, y, w, h, WHITE)
|
||||
self.has_border = True
|
||||
else:
|
||||
if isinstance(self.bdcolor, bool): # No border
|
||||
if self.has_border: # Border exists: erase it
|
||||
dev.rect(x, y, w, h, BGCOLOR)
|
||||
self.has_border = False
|
||||
elif self.bdcolor: # Border is required
|
||||
dev.rect(x, y, w, h, self.bdcolor)
|
||||
self.has_border = True
|
||||
|
||||
def overlaps(self, xa, ya, xb, yb): # Args must be sorted: xb > xa and yb > ya
|
||||
x0 = self.col
|
||||
y0 = self.row
|
||||
x1 = x0 + self.width
|
||||
y1 = y0 + self.height
|
||||
if (ya <= y1 and yb >= y0) and (xa <= x1 and xb >= x0):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _set_callbacks(self, cb, args): # Runs when value changes.
|
||||
self.callback = cb
|
||||
self.args = args
|
||||
|
||||
def has_focus(self):
|
||||
if self.active:
|
||||
cs = Screen.current_screen
|
||||
if (cso := cs.selected_obj) is not None:
|
||||
return cs.lstactive[cso] is self
|
||||
return False
|
||||
|
||||
def greyed_out(self, val=None):
|
||||
if val is not None and self.active and self._greyed_out != val:
|
||||
self._greyed_out = val
|
||||
if self.screen is Screen.current_screen:
|
||||
display.usegrey(val)
|
||||
self.draw_border()
|
||||
self.show()
|
||||
return self._greyed_out
|
||||
|
||||
# Button press methods. Called from Screen if object not greyed out.
|
||||
# For subclassing if specific behaviour is required.
|
||||
def do_sel(self): # Select button was pushed
|
||||
pass
|
||||
|
||||
def unsel(self): # Select button was released
|
||||
pass
|
||||
|
||||
def enter(self): # Control has acquired focus
|
||||
pass
|
||||
|
||||
def leave(self): # Control has lost focus
|
||||
pass
|
||||
|
||||
# Optional methods. Implement for controls which respond to up and down.
|
||||
# No dummy methods as these would prevent "first" and "last" focus movement
|
||||
# when current control has focus but is inactive.
|
||||
# def do_up(self, button)
|
||||
# def do_down(self, button)
|
||||
|
||||
# A LinearIO widget uses the up and down buttons to vary a float. Such widgets
|
||||
# have do_up and do_down methods which adjust the control's value in a
|
||||
# time-dependent manner.
|
||||
class LinearIO(Widget):
|
||||
def __init__(self, writer, row, col, height, width,
|
||||
fgcolor, bgcolor, bdcolor,
|
||||
value=None, active=True,
|
||||
min_delta=0.01, max_delta=0.1):
|
||||
self.min_delta = min_delta
|
||||
self.max_delta = max_delta
|
||||
super().__init__(writer, row, col, height, width,
|
||||
fgcolor, bgcolor, bdcolor,
|
||||
value, active)
|
||||
|
||||
def do_up(self, button):
|
||||
asyncio.create_task(self.btnhan(button, 1))
|
||||
|
||||
def do_down(self, button):
|
||||
asyncio.create_task(self.btnhan(button, -1))
|
||||
|
||||
async def btnhan(self, button, up): # Note: textbox.py, scale_log.py overrides
|
||||
d = self.min_delta
|
||||
self.value(self.value() + up * d)
|
||||
t = ticks_ms()
|
||||
while not button():
|
||||
await asyncio.sleep_ms(0) # Quit fast on button release
|
||||
if ticks_diff(ticks_ms(), t) > 500: # Button was held down
|
||||
d = min(self.max_delta, d * 2)
|
||||
self.value(self.value() + up * d)
|
||||
t = ticks_ms()
|
|
@ -0,0 +1,336 @@
|
|||
# writer.py Implements the Writer class.
|
||||
# Handles colour, word wrap and tab stops
|
||||
|
||||
# V0.40 Jan 2021 Improved handling of word wrap and line clip. Upside-down
|
||||
# rendering no longer supported: delegate to device driver.
|
||||
# V0.35 Sept 2020 Fast rendering option for color displays
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2019-2021 Peter Hinch
|
||||
|
||||
# A Writer supports rendering text to a Display instance in a given font.
|
||||
# Multiple Writer instances may be created, each rendering a font to the
|
||||
# same Display object.
|
||||
|
||||
# Timings based on a 20 pixel high proportional font, run on a pyboard V1.0.
|
||||
# Using CWriter's slow rendering: _printchar 9.5ms typ, 13.5ms max.
|
||||
# Using Writer's fast rendering: _printchar 115μs min 480μs typ 950μs max.
|
||||
|
||||
# CWriter on Pyboard D SF2W at standard clock rate
|
||||
# Fast method 500-600μs typical, up to 1.07ms on larger fonts
|
||||
# Revised fast method 691μs avg, up to 2.14ms on larger fonts
|
||||
# Slow method 2700μs typical, up to 11ms on larger fonts
|
||||
|
||||
import framebuf
|
||||
from uctypes import bytearray_at, addressof
|
||||
from sys import platform
|
||||
|
||||
__version__ = (0, 4, 2)
|
||||
|
||||
fast_mode = platform == 'pyboard'
|
||||
if fast_mode:
|
||||
try:
|
||||
try:
|
||||
from framebuf_utils import render
|
||||
except ImportError: # May be running in GUI. Try relative import.
|
||||
try:
|
||||
from .framebuf_utils import render
|
||||
except ImportError:
|
||||
fast_mode = False
|
||||
except ValueError:
|
||||
fast_mode = False
|
||||
if not fast_mode:
|
||||
print('Ignoring missing or invalid framebuf_utils.mpy.')
|
||||
|
||||
|
||||
class DisplayState():
|
||||
def __init__(self):
|
||||
self.text_row = 0
|
||||
self.text_col = 0
|
||||
|
||||
def _get_id(device):
|
||||
if not isinstance(device, framebuf.FrameBuffer):
|
||||
raise ValueError('Device must be derived from FrameBuffer.')
|
||||
return id(device)
|
||||
|
||||
# Basic Writer class for monochrome displays
|
||||
class Writer():
|
||||
|
||||
state = {} # Holds a display state for each device
|
||||
|
||||
@staticmethod
|
||||
def set_textpos(device, row=None, col=None):
|
||||
devid = _get_id(device)
|
||||
if devid not in Writer.state:
|
||||
Writer.state[devid] = DisplayState()
|
||||
s = Writer.state[devid] # Current state
|
||||
if row is not None:
|
||||
if row < 0 or row >= device.height:
|
||||
raise ValueError('row is out of range')
|
||||
s.text_row = row
|
||||
if col is not None:
|
||||
if col < 0 or col >= device.width:
|
||||
raise ValueError('col is out of range')
|
||||
s.text_col = col
|
||||
return s.text_row, s.text_col
|
||||
|
||||
def __init__(self, device, font, verbose=True):
|
||||
self.devid = _get_id(device)
|
||||
self.device = device
|
||||
if self.devid not in Writer.state:
|
||||
Writer.state[self.devid] = DisplayState()
|
||||
self.font = font
|
||||
if font.height() >= device.height or font.max_width() >= device.width:
|
||||
raise ValueError('Font too large for screen')
|
||||
# Allow to work with reverse or normal font mapping
|
||||
if font.hmap():
|
||||
self.map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
|
||||
else:
|
||||
raise ValueError('Font must be horizontally mapped.')
|
||||
if verbose:
|
||||
fstr = 'Orientation: Horizontal. Reversal: {}. Width: {}. Height: {}.'
|
||||
print(fstr.format(font.reverse(), device.width, device.height))
|
||||
print('Start row = {} col = {}'.format(self._getstate().text_row, self._getstate().text_col))
|
||||
self.screenwidth = device.width # In pixels
|
||||
self.screenheight = device.height
|
||||
self.bgcolor = 0 # Monochrome background and foreground colors
|
||||
self.fgcolor = 1
|
||||
self.row_clip = False # Clip or scroll when screen fullt
|
||||
self.col_clip = False # Clip or new line when row is full
|
||||
self.wrap = True # Word wrap
|
||||
self.cpos = 0
|
||||
self.tab = 4
|
||||
|
||||
self.glyph = None # Current char
|
||||
self.char_height = 0
|
||||
self.char_width = 0
|
||||
self.clip_width = 0
|
||||
|
||||
def _getstate(self):
|
||||
return Writer.state[self.devid]
|
||||
|
||||
def _newline(self):
|
||||
s = self._getstate()
|
||||
height = self.font.height()
|
||||
s.text_row += height
|
||||
s.text_col = 0
|
||||
margin = self.screenheight - (s.text_row + height)
|
||||
y = self.screenheight + margin
|
||||
if margin < 0:
|
||||
if not self.row_clip:
|
||||
self.device.scroll(0, margin)
|
||||
self.device.fill_rect(0, y, self.screenwidth, abs(margin), self.bgcolor)
|
||||
s.text_row += margin
|
||||
|
||||
def set_clip(self, row_clip=None, col_clip=None, wrap=None):
|
||||
if row_clip is not None:
|
||||
self.row_clip = row_clip
|
||||
if col_clip is not None:
|
||||
self.col_clip = col_clip
|
||||
if wrap is not None:
|
||||
self.wrap = wrap
|
||||
return self.row_clip, self.col_clip, self.wrap
|
||||
|
||||
@property
|
||||
def height(self): # Property for consistency with device
|
||||
return self.font.height()
|
||||
|
||||
def printstring(self, string, invert=False):
|
||||
# word wrapping. Assumes words separated by single space.
|
||||
q = string.split('\n')
|
||||
last = len(q) - 1
|
||||
for n, s in enumerate(q):
|
||||
if s:
|
||||
self._printline(s, invert)
|
||||
if n != last:
|
||||
self._printchar('\n')
|
||||
|
||||
def _printline(self, string, invert):
|
||||
rstr = None
|
||||
if self.wrap and self.stringlen(string, True): # Length > self.screenwidth
|
||||
pos = 0
|
||||
lstr = string[:]
|
||||
while self.stringlen(lstr, True): # Length > self.screenwidth
|
||||
pos = lstr.rfind(' ')
|
||||
lstr = lstr[:pos].rstrip()
|
||||
if pos > 0:
|
||||
rstr = string[pos + 1:]
|
||||
string = lstr
|
||||
|
||||
for char in string:
|
||||
self._printchar(char, invert)
|
||||
if rstr is not None:
|
||||
self._printchar('\n')
|
||||
self._printline(rstr, invert) # Recurse
|
||||
|
||||
def stringlen(self, string, oh=False):
|
||||
sc = self._getstate().text_col # Start column
|
||||
wd = self.screenwidth
|
||||
l = 0
|
||||
for char in string[:-1]:
|
||||
_, _, char_width = self.font.get_ch(char)
|
||||
l += char_width
|
||||
if oh and l + sc > wd:
|
||||
return True # All done. Save time.
|
||||
char = string[-1]
|
||||
_, _, char_width = self.font.get_ch(char)
|
||||
if oh and l + sc + char_width > wd:
|
||||
l += self._truelen(char) # Last char might have blank cols on RHS
|
||||
else:
|
||||
l += char_width # Public method. Return same value as old code.
|
||||
return l + sc > wd if oh else l
|
||||
|
||||
# Return the printable width of a glyph less any blank columns on RHS
|
||||
def _truelen(self, char):
|
||||
glyph, ht, wd = self.font.get_ch(char)
|
||||
div, mod = divmod(wd, 8)
|
||||
gbytes = div + 1 if mod else div # No. of bytes per row of glyph
|
||||
mc = 0 # Max non-blank column
|
||||
data = glyph[(wd - 1) // 8] # Last byte of row 0
|
||||
for row in range(ht): # Glyph row
|
||||
for col in range(wd -1, -1, -1): # Glyph column
|
||||
gbyte, gbit = divmod(col, 8)
|
||||
if gbit == 0: # Next glyph byte
|
||||
data = glyph[row * gbytes + gbyte]
|
||||
if col <= mc:
|
||||
break
|
||||
if data & (1 << (7 - gbit)): # Pixel is lit (1)
|
||||
mc = col # Eventually gives rightmost lit pixel
|
||||
break
|
||||
if mc + 1 == wd:
|
||||
break # All done: no trailing space
|
||||
print('Truelen', char, wd, mc + 1) # TEST
|
||||
return mc + 1
|
||||
|
||||
def _get_char(self, char, recurse):
|
||||
if not recurse: # Handle tabs
|
||||
if char == '\n':
|
||||
self.cpos = 0
|
||||
elif char == '\t':
|
||||
nspaces = self.tab - (self.cpos % self.tab)
|
||||
if nspaces == 0:
|
||||
nspaces = self.tab
|
||||
while nspaces:
|
||||
nspaces -= 1
|
||||
self._printchar(' ', recurse=True)
|
||||
self.glyph = None # All done
|
||||
return
|
||||
|
||||
self.glyph = None # Assume all done
|
||||
if char == '\n':
|
||||
self._newline()
|
||||
return
|
||||
glyph, char_height, char_width = self.font.get_ch(char)
|
||||
s = self._getstate()
|
||||
np = None # Allow restriction on printable columns
|
||||
if s.text_row + char_height > self.screenheight:
|
||||
if self.row_clip:
|
||||
return
|
||||
self._newline()
|
||||
oh = s.text_col + char_width - self.screenwidth # Overhang (+ve)
|
||||
if oh > 0:
|
||||
if self.col_clip or self.wrap:
|
||||
np = char_width - oh # No. of printable columns
|
||||
if np <= 0:
|
||||
return
|
||||
else:
|
||||
self._newline()
|
||||
self.glyph = glyph
|
||||
self.char_height = char_height
|
||||
self.char_width = char_width
|
||||
self.clip_width = char_width if np is None else np
|
||||
|
||||
# Method using blitting. Efficient rendering for monochrome displays.
|
||||
# Tested on SSD1306. Invert is for black-on-white rendering.
|
||||
def _printchar(self, char, invert=False, recurse=False):
|
||||
s = self._getstate()
|
||||
self._get_char(char, recurse)
|
||||
if self.glyph is None:
|
||||
return # All done
|
||||
buf = bytearray(self.glyph)
|
||||
if invert:
|
||||
for i, v in enumerate(buf):
|
||||
buf[i] = 0xFF & ~ v
|
||||
fbc = framebuf.FrameBuffer(buf, self.clip_width, self.char_height, self.map)
|
||||
self.device.blit(fbc, s.text_col, s.text_row)
|
||||
s.text_col += self.char_width
|
||||
self.cpos += 1
|
||||
|
||||
def tabsize(self, value=None):
|
||||
if value is not None:
|
||||
self.tab = value
|
||||
return self.tab
|
||||
|
||||
def setcolor(self, *_):
|
||||
return self.fgcolor, self.bgcolor
|
||||
|
||||
# Writer for colour displays or upside down rendering
|
||||
class CWriter(Writer):
|
||||
|
||||
|
||||
def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True):
|
||||
super().__init__(device, font, verbose)
|
||||
if bgcolor is not None: # Assume monochrome.
|
||||
self.bgcolor = bgcolor
|
||||
if fgcolor is not None:
|
||||
self.fgcolor = fgcolor
|
||||
self.def_bgcolor = self.bgcolor
|
||||
self.def_fgcolor = self.fgcolor
|
||||
self._printchar = self._pchfast if fast_mode else self._pchslow
|
||||
verbose and print('Render {} using fast mode'.format('is' if fast_mode else 'not'))
|
||||
|
||||
def _pchfast(self, char, invert=False, recurse=False):
|
||||
s = self._getstate()
|
||||
self._get_char(char, recurse)
|
||||
if self.glyph is None:
|
||||
return # All done
|
||||
buf = bytearray_at(addressof(self.glyph), len(self.glyph))
|
||||
fbc = framebuf.FrameBuffer(buf, self.char_width, self.char_height, self.map)
|
||||
fgcolor = self.bgcolor if invert else self.fgcolor
|
||||
bgcolor = self.fgcolor if invert else self.bgcolor
|
||||
# render clips a glyph if outside bounds of destination
|
||||
render(self.device, fbc, s.text_col, s.text_row, fgcolor, bgcolor)
|
||||
s.text_col += self.char_width
|
||||
self.cpos += 1
|
||||
|
||||
def _pchslow(self, char, invert=False, recurse=False):
|
||||
s = self._getstate()
|
||||
self._get_char(char, recurse)
|
||||
if self.glyph is None:
|
||||
return # All done
|
||||
char_height = self.char_height
|
||||
char_width = self.char_width
|
||||
clip_width = self.clip_width
|
||||
|
||||
div, mod = divmod(char_width, 8)
|
||||
gbytes = div + 1 if mod else div # No. of bytes per row of glyph
|
||||
device = self.device
|
||||
fgcolor = self.bgcolor if invert else self.fgcolor
|
||||
bgcolor = self.fgcolor if invert else self.bgcolor
|
||||
drow = s.text_row # Destination row
|
||||
wcol = s.text_col # Destination column of character start
|
||||
for srow in range(char_height): # Source row
|
||||
for scol in range(clip_width): # Source column
|
||||
# Destination column: add writer column
|
||||
dcol = wcol + scol
|
||||
gbyte, gbit = divmod(scol, 8)
|
||||
if gbit == 0: # Next glyph byte
|
||||
data = self.glyph[srow * gbytes + gbyte]
|
||||
pixel = fgcolor if data & (1 << (7 - gbit)) else bgcolor
|
||||
device.pixel(dcol, drow, pixel)
|
||||
drow += 1
|
||||
if drow >= self.screenheight or drow < 0:
|
||||
break
|
||||
s.text_col += char_width
|
||||
self.cpos += 1
|
||||
|
||||
def setcolor(self, fgcolor=None, bgcolor=None):
|
||||
if fgcolor is None and bgcolor is None:
|
||||
self.fgcolor = self.def_fgcolor
|
||||
self.bgcolor = self.def_bgcolor
|
||||
else:
|
||||
if fgcolor is not None:
|
||||
self.fgcolor = fgcolor
|
||||
if bgcolor is not None:
|
||||
self.bgcolor = bgcolor
|
||||
return self.fgcolor, self.bgcolor
|
|
@ -0,0 +1,99 @@
|
|||
# active.py micro-gui demo of widgets that respond to user control
|
||||
|
||||
# Import SSD and Display instances. Must be done first because of RAM use.
|
||||
from hardware_setup import display, ssd # Create a display instance
|
||||
from gui.core.ugui import Screen
|
||||
from gui.core.writer import CWriter
|
||||
import gui.fonts.arial10 as arial10 # Font for CWriter
|
||||
from gui.core.colors import *
|
||||
# Widgets
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.scale import Scale
|
||||
from gui.widgets.scale_log import ScaleLog
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
from gui.widgets.sliders import Slider, HorizSlider
|
||||
from gui.widgets.knob import Knob
|
||||
from gui.widgets.checkbox import Checkbox
|
||||
|
||||
|
||||
class BaseScreen(Screen):
|
||||
def __init__(self):
|
||||
|
||||
def tickcb(f, c):
|
||||
if f > 0.8:
|
||||
return RED
|
||||
if f < -0.8:
|
||||
return BLUE
|
||||
return c
|
||||
|
||||
def tick_log_cb(f, c):
|
||||
if f > 20_000:
|
||||
return RED
|
||||
if f < 4:
|
||||
return BLUE
|
||||
return c
|
||||
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
col = 2
|
||||
row = 200
|
||||
Label(wri, row, col, 'Result')
|
||||
col = 42
|
||||
self.lbl = Label(wri, row, col, 70, bdcolor=RED)
|
||||
|
||||
self.vslider = Slider(wri, 2, 2, callback=self.slider_cb,
|
||||
bdcolor=RED, slotcolor=BLUE,
|
||||
legends=('0.0', '0.5', '1.0'), value=0.5)
|
||||
|
||||
col = 80
|
||||
row = 15
|
||||
self.hslider = HorizSlider(wri, row, col, callback=self.slider_cb,
|
||||
bdcolor=YELLOW, slotcolor=BLUE,
|
||||
legends=('0.0', '0.5', '1.0'), value=0.7)
|
||||
row += 30
|
||||
self.scale = Scale(wri, row, col, width = 150, tickcb = tickcb,
|
||||
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN,
|
||||
callback=self.cb, active=True)
|
||||
row += 40
|
||||
self.scale_log = ScaleLog(wri, row, col, width = 150, tickcb = tick_log_cb,
|
||||
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN,
|
||||
callback=self.cb, value=10, active=True)
|
||||
row = 120
|
||||
self.knob = Knob(wri, row, 2, callback = self.cb, bgcolor=DARKGREEN, color=LIGHTRED)
|
||||
col = 150
|
||||
row = 185
|
||||
Checkbox(wri, row, col, callback=self.cbcb)
|
||||
col += 35
|
||||
Label(wri, row, col, 'Enable/disable')
|
||||
CloseButton(wri)
|
||||
|
||||
|
||||
def cb(self, obj):
|
||||
self.lbl.value('{:4.2f}'.format(obj.value()))
|
||||
|
||||
def cbcb(self, cb):
|
||||
val = cb.value()
|
||||
self.vslider.greyed_out(val)
|
||||
self.hslider.greyed_out(val)
|
||||
self.scale.greyed_out(val)
|
||||
self.scale_log.greyed_out(val)
|
||||
self.knob.greyed_out(val)
|
||||
|
||||
def slider_cb(self, s):
|
||||
self.cb(s)
|
||||
v = s.value()
|
||||
if v < 0.2:
|
||||
s.color(BLUE)
|
||||
elif v > 0.8:
|
||||
s.color(RED)
|
||||
else:
|
||||
s.color(GREEN)
|
||||
|
||||
def test():
|
||||
if display.height < 240 or display.width < 320:
|
||||
print(' This test requires a display of at least 320x240 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(BaseScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,250 @@
|
|||
# plot.py Test/demo program for micro-gui plot. Cross-patform,
|
||||
# but requires a large enough display.
|
||||
# Tested on Adafruit ssd1351-based OLED displays:
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from hardware_setup import ssd, display # Create a display instance
|
||||
|
||||
import cmath
|
||||
import math
|
||||
import uasyncio as asyncio
|
||||
from collections import OrderedDict
|
||||
|
||||
from gui.core.writer import Writer, CWriter
|
||||
from gui.core.ugui import Screen
|
||||
from gui.widgets.graph import PolarGraph, PolarCurve, CartesianGraph, Curve, TSequence
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
from gui.widgets.listbox import Listbox
|
||||
|
||||
# Fonts & colors
|
||||
import gui.fonts.arial10 as arial10
|
||||
from gui.core.colors import *
|
||||
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
|
||||
def fwdbutton(writer, row, col, cls_screen, text, color, *args, **kwargs):
|
||||
def fwd(button):
|
||||
Screen.change(cls_screen, args = args, kwargs = kwargs)
|
||||
Button(writer, row, col, callback = fwd, bgcolor = color,
|
||||
text = text, textcolor = BLACK, height = 20, width = 60)
|
||||
|
||||
|
||||
class EmptyScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Label(wri, 2, 2, 'Test of overlay.')
|
||||
Label(wri, 20, 2, 'Check redraw of underlying screen.')
|
||||
CloseButton(wri)
|
||||
|
||||
class CartesianScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = CartesianGraph(wri, 2, 2, yorigin = 2, fgcolor=GREEN,
|
||||
gridcolor=LIGHTGREEN) # Asymmetric y axis
|
||||
Label(wri, 100, 2, 'Asymmetric axes.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
# At this point in time the Screen and graph have been constructed but
|
||||
# not rendered. If we drew the curves now they would be overwritten by
|
||||
# the graph
|
||||
|
||||
# Now the graph has been drawn and we can overlay it with graphics primitives.
|
||||
# This is not a uasyncio issue, but is the way Screen.change() is coded.
|
||||
def after_open(self):
|
||||
def populate_1(func):
|
||||
x = -1
|
||||
while x < 1.01:
|
||||
yield x, func(x) # x, y
|
||||
x += 0.1
|
||||
|
||||
def populate_2():
|
||||
x = -1
|
||||
while x < 1.01:
|
||||
yield x, x**2 # x, y
|
||||
x += 0.1
|
||||
|
||||
Curve(self.g, YELLOW, populate_1(lambda x : x**3 + x**2 -x,)) # args demo
|
||||
Curve(self.g, RED, populate_2())
|
||||
|
||||
class PolarScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = PolarGraph(wri, 2, 2, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
def populate():
|
||||
def f(theta):
|
||||
return cmath.rect(math.sin(3 * theta), theta) # complex
|
||||
nmax = 150
|
||||
for n in range(nmax + 1):
|
||||
yield f(2 * cmath.pi * n / nmax) # complex z
|
||||
|
||||
PolarCurve(self.g, YELLOW, populate())
|
||||
|
||||
class Lissajous(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = CartesianGraph(wri, 2, 2, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
Label(wri, 100, 2, 'Lissajous figure.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
def populate():
|
||||
t = -math.pi
|
||||
while t <= math.pi:
|
||||
yield math.sin(t), math.cos(3*t) # x, y
|
||||
t += 0.1
|
||||
|
||||
Curve(self.g, YELLOW, populate())
|
||||
|
||||
class Lemniscate(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = CartesianGraph(wri, 2, 2, height = 75, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
Label(wri, 82, 2, 'To infinity and beyond...')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
def populate():
|
||||
t = -math.pi
|
||||
while t <= math.pi + 0.1:
|
||||
x = 0.5*math.sqrt(2)*math.cos(t)/(math.sin(t)**2 + 1)
|
||||
y = math.sqrt(2)*math.cos(t)*math.sin(t)/(math.sin(t)**2 + 1)
|
||||
yield x, y
|
||||
t += 0.1
|
||||
|
||||
Curve(self.g, YELLOW, populate())
|
||||
|
||||
class PolarClip(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = PolarGraph(wri, 2, 2, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
Label(wri, 100, 2, 'Clipping of polar data.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
def populate(rot):
|
||||
f = lambda theta : cmath.rect(1.15 * math.sin(5 * theta), theta) * rot # complex
|
||||
nmax = 150
|
||||
for n in range(nmax + 1):
|
||||
yield f(2 * cmath.pi * n / nmax) # complex z
|
||||
|
||||
PolarCurve(self.g, YELLOW, populate(1))
|
||||
PolarCurve(self.g, RED, populate(cmath.rect(1, cmath.pi/5),))
|
||||
|
||||
class RTPolar(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = PolarGraph(wri, 2, 2, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
Label(wri, 100, 2, 'Realtime polar data.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
self.reg_task(self.run(self.g), True) # Cancel on screen change
|
||||
|
||||
async def run(self, g):
|
||||
await asyncio.sleep_ms(0)
|
||||
curvey = PolarCurve(g, YELLOW)
|
||||
curver = PolarCurve(g, RED)
|
||||
for x in range(100):
|
||||
curvey.point(cmath.rect(x/100, -x * cmath.pi/30))
|
||||
curver.point(cmath.rect((100 - x)/100, -x * cmath.pi/30))
|
||||
await asyncio.sleep_ms(60)
|
||||
|
||||
class RTRect(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = CartesianGraph(wri, 2, 2, fgcolor=GREEN, gridcolor=LIGHTGREEN)
|
||||
Label(wri, 100, 2, 'Realtime discontinuous data.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
self.reg_task(self.run(self.g), True) # Cancel on screen change
|
||||
|
||||
async def run(self, g):
|
||||
await asyncio.sleep_ms(0)
|
||||
curve = Curve(g, RED)
|
||||
x = -1
|
||||
for _ in range(40):
|
||||
y = 0.1/x if abs(x) > 0.05 else None # Discontinuity
|
||||
curve.point(x, y)
|
||||
await asyncio.sleep_ms(100)
|
||||
x += 0.05
|
||||
g.clear()
|
||||
curve = Curve(g, YELLOW)
|
||||
x = -1
|
||||
for _ in range(40):
|
||||
y = -0.1/x if abs(x) > 0.05 else None # Discontinuity
|
||||
curve.point(x, y)
|
||||
await asyncio.sleep_ms(100)
|
||||
x += 0.05
|
||||
|
||||
class TSeq(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.g = CartesianGraph(wri, 2, 2, xorigin = 10, fgcolor=GREEN,
|
||||
gridcolor=LIGHTGREEN, bdcolor=False)
|
||||
Label(wri, 100, 2, 'Time sequence.')
|
||||
fwdbutton(wri, 2, 130, EmptyScreen, 'Forward', GREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def after_open(self): # After graph has been drawn
|
||||
self.reg_task(self.run(self.g), True) # Cancel on screen change
|
||||
|
||||
async def run(self, g):
|
||||
await asyncio.sleep_ms(0)
|
||||
tsy = TSequence(g, YELLOW, 50)
|
||||
tsr = TSequence(g, RED, 50)
|
||||
t = 0
|
||||
while True:
|
||||
g.show() # Redraw the empty graph
|
||||
tsy.add(0.9*math.sin(t/10))
|
||||
tsr.add(0.4*math.cos(t/10)) # Plot the new curves
|
||||
await asyncio.sleep_ms(400)
|
||||
t += 1
|
||||
|
||||
|
||||
class BaseScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
d = OrderedDict()
|
||||
d['Cartesian'] = CartesianScreen
|
||||
d['Polar'] = PolarScreen
|
||||
d['Lissajous'] = Lissajous
|
||||
d['Lemniscate'] = Lemniscate
|
||||
d['Polar clipping'] = PolarClip
|
||||
d['Realtime polar'] = RTPolar
|
||||
d['Realtime rect'] = RTRect
|
||||
d['Time sequence'] = TSeq
|
||||
|
||||
row = 2
|
||||
col = 2
|
||||
Listbox(wri, row, col, callback=self.lbcb, args=(d,),
|
||||
elements = tuple(d.keys()),
|
||||
bdcolor = GREEN, bgcolor = DARKGREEN)
|
||||
CloseButton(wri)
|
||||
|
||||
def lbcb(self, lb, d):
|
||||
Screen.change(d[lb.textvalue()])
|
||||
|
||||
def test():
|
||||
if display.height < 240 or display.width < 320:
|
||||
print(' This test requires a display of at least 320x240 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(BaseScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,109 @@
|
|||
# screens.py micro-gui demo of multiple screens, dropdowns etc
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
# Import SSD and Display instances. Must be done first because of RAM use.
|
||||
from hardware_setup import display, ssd # Create a display instance
|
||||
from gui.core.ugui import Screen, Window
|
||||
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, RadioButtons, CloseButton
|
||||
from gui.widgets.listbox import Listbox, ON_LEAVE
|
||||
from gui.widgets.dropdown import Dropdown
|
||||
from gui.widgets.dialog import DialogBox
|
||||
from gui.core.writer import CWriter
|
||||
|
||||
# Font for CWriter
|
||||
import gui.fonts.arial10 as arial10
|
||||
from gui.core.colors import *
|
||||
|
||||
# Note that litcolor is defeated by design, because the callback's action
|
||||
# is to change the screen currency. This tests the bugfix.
|
||||
def fwdbutton(writer, row, col, cls_screen, text, color, *args, **kwargs):
|
||||
def fwd(button):
|
||||
Screen.change(cls_screen, args = args, kwargs = kwargs)
|
||||
Button(writer, row, col, callback = fwd, bgcolor = color, litcolor = YELLOW,
|
||||
text = text, textcolor = WHITE, shape = CLIPPED_RECT)
|
||||
|
||||
# Demo of creating a dialog manually
|
||||
class UserDialogBox(Window):
|
||||
def __init__(self, writer, callback, args):
|
||||
|
||||
def back(button, text):
|
||||
Window.value(text)
|
||||
callback(Window, *args)
|
||||
Screen.back()
|
||||
|
||||
def close_cb(button, text):
|
||||
Window.value(text)
|
||||
callback(Window, *args)
|
||||
|
||||
height = 80
|
||||
width = 150
|
||||
super().__init__(20, 20, height, width, bgcolor = DARKGREEN)
|
||||
row = self.height - 30
|
||||
# .locn converts Window relative row, col to absolute row, col
|
||||
Button(writer, *self.locn(row, 20), height = 20, width = 50, textcolor = BLACK, bgcolor = RED,
|
||||
text = 'Cat', callback = back, args = ('Cat',))
|
||||
Button(writer, *self.locn(row, 80), height = 20, width = 50, textcolor = BLACK, bgcolor = GREEN,
|
||||
text = 'Dog', callback = back, args = ('Dog',))
|
||||
CloseButton(writer, callback=close_cb, args = ('Close',))
|
||||
|
||||
# Minimal screen change example
|
||||
class Overlay(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
Label(wri, 20, 20, 'Screen overlays base')
|
||||
CloseButton(wri)
|
||||
|
||||
class BaseScreen(Screen):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
def lbcb(lb):
|
||||
print('Listbox', lb.textvalue())
|
||||
|
||||
def ddcb(dd):
|
||||
print('Dropdown', tv := dd.textvalue())
|
||||
if tv == 'new screen':
|
||||
Screen.change(Overlay)
|
||||
|
||||
def dbcb(window, label):
|
||||
label.value('Auto Dialog: {}'.format(window.value()))
|
||||
|
||||
def udbcb(window, label):
|
||||
label.value('User Dialog: {}'.format(window.value()))
|
||||
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
|
||||
col = 2
|
||||
row = 2
|
||||
Listbox(wri, row, col, callback=lbcb,
|
||||
elements = ('cat', 'dog', 'aardvark', 'goat', 'pig', 'mouse'),
|
||||
bdcolor = GREEN, bgcolor = DARKGREEN, also = ON_LEAVE)
|
||||
col = 70
|
||||
Dropdown(wri, row, col, callback=ddcb,
|
||||
elements = ('hydrogen', 'helium', 'neon', 'xenon', 'new screen'),
|
||||
bdcolor = GREEN, bgcolor = DARKGREEN)
|
||||
row += 30
|
||||
lbl = Label(wri, row, col, 'Result from dialog box.')
|
||||
row += 20
|
||||
dialog_elements = (('Yes', GREEN), ('No', RED), ('Foo', YELLOW))
|
||||
# 1st 6 args are for fwdbutton
|
||||
fwdbutton(wri, row, col, DialogBox, 'Dialog', RED,
|
||||
# Args for DialogBox constructor
|
||||
wri, elements = dialog_elements, label = 'Test dialog', callback = dbcb, args = (lbl,))
|
||||
col += 60
|
||||
fwdbutton(wri, row, col, UserDialogBox, 'User', BLUE,
|
||||
# Args for UserDialogBox constructor
|
||||
wri, udbcb, (lbl,))
|
||||
CloseButton(wri) # Quit the application
|
||||
|
||||
def test():
|
||||
if display.height < 128 or display.width < 240:
|
||||
print('This test requires a display of at least 240x128 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(BaseScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,39 @@
|
|||
# simple.py Minimal micro-gui demo.
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
# Import SSD and Display instances. Must be done first because of RAM use.
|
||||
from hardware_setup import ssd # Create a display instance
|
||||
from gui.core.ugui import Screen
|
||||
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
from gui.core.writer import CWriter
|
||||
|
||||
# Font for CWriter
|
||||
import gui.fonts.arial10 as arial10
|
||||
from gui.core.colors import *
|
||||
|
||||
|
||||
class BaseScreen(Screen):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
def my_callback(button, arg):
|
||||
print('Button pressed', arg)
|
||||
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
|
||||
col = 2
|
||||
row = 2
|
||||
Label(wri, row, col, 'Simple Demo')
|
||||
row = 20
|
||||
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
|
||||
col += 60
|
||||
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
|
||||
CloseButton(wri) # Quit the application
|
||||
|
||||
def test():
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(BaseScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,120 @@
|
|||
# tbox.py Test/demo of Textbox widget for micro-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# Usage:
|
||||
# import gui.demos.tbox
|
||||
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from hardware_setup import display, ssd # Create a display instance
|
||||
|
||||
from gui.core.ugui import Screen
|
||||
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
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
|
||||
wri = CWriter(ssd, arial10, verbose=False)
|
||||
|
||||
def fwdbutton(wri, row, col, cls_screen, width, text='Next'):
|
||||
def fwd(button):
|
||||
Screen.change(cls_screen)
|
||||
Button(wri, row, col, height = 20, width = width,
|
||||
callback = fwd, fgcolor = BLACK, bgcolor = GREEN,
|
||||
text = text, shape = RECTANGLE)
|
||||
return width
|
||||
|
||||
|
||||
async def wrap(tb):
|
||||
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.clear()
|
||||
tb.append(s, ntrim = 100, line = 0)
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
if not tb.scroll(1):
|
||||
break
|
||||
|
||||
async def clip(tb):
|
||||
ss = ('clip demo', 'short', 'longer line', 'much longer line with spaces',
|
||||
'antidisestablishmentarianism', 'line with\nline break', 'Done')
|
||||
tb.clear()
|
||||
for s in ss:
|
||||
tb.append(s, ntrim = 100) # Default line=None scrolls to show most recent
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Args for textboxes
|
||||
# Positional
|
||||
pargs = (2, 2, 124, 7) # Row, Col, Width, nlines
|
||||
|
||||
# Keyword
|
||||
tbargs = {'fgcolor' : YELLOW,
|
||||
'bdcolor' : RED,
|
||||
'bgcolor' : DARKGREEN,
|
||||
}
|
||||
|
||||
|
||||
class TBCScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tb = Textbox(wri, *pargs, clip=True, **tbargs)
|
||||
CloseButton(wri)
|
||||
asyncio.create_task(self.main())
|
||||
|
||||
async def main(self):
|
||||
await clip(self.tb)
|
||||
|
||||
class TBWScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tb = Textbox(wri, *pargs, clip=False, **tbargs)
|
||||
CloseButton(wri)
|
||||
asyncio.create_task(self.main())
|
||||
|
||||
async def main(self):
|
||||
await wrap(self.tb)
|
||||
|
||||
user_str = '''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.
|
||||
|
||||
Please use the increase and decrease buttons to scroll this text.
|
||||
'''
|
||||
|
||||
class TBUScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
tb = Textbox(wri, *pargs, clip=False, active=True, **tbargs)
|
||||
tb.append(user_str, ntrim=100)
|
||||
CloseButton(wri)
|
||||
|
||||
|
||||
class MainScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Label(wri, 2, 2, 'Select test to run')
|
||||
col = 2
|
||||
row = 60
|
||||
col += fwdbutton(wri, row, col, TBWScreen, 50, 'Wrap') + 10
|
||||
col += fwdbutton(wri, row, col, TBCScreen, 50, 'Clip') + 10
|
||||
fwdbutton(wri, row, col, TBUScreen, 50, 'Scroll')
|
||||
CloseButton(wri)
|
||||
|
||||
|
||||
def test():
|
||||
if display.height < 128 or display.width < 128:
|
||||
print(' This test requires a display of at least 128x128 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(MainScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,160 @@
|
|||
# various.py micro-gui demo of multiple controls on a large display
|
||||
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
# Import SSD and Display instances. Must be done first because of RAM use.
|
||||
from hardware_setup import display, ssd # Create a display instance
|
||||
from gui.core.ugui import Screen
|
||||
from gui.core.writer import CWriter
|
||||
import gui.fonts.arial10 as arial10 # Font for CWriter
|
||||
from gui.core.colors import *
|
||||
# Widgets
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
from gui.widgets.meter import Meter
|
||||
from gui.widgets.scale import Scale
|
||||
from gui.widgets.buttons import Button, ButtonList, RadioButtons, CloseButton
|
||||
from gui.widgets.checkbox import Checkbox
|
||||
from gui.widgets.led import LED
|
||||
|
||||
import cmath
|
||||
import uasyncio as asyncio
|
||||
import utime
|
||||
import gc
|
||||
|
||||
|
||||
class FooScreen(Screen):
|
||||
def __init__(self):
|
||||
buttons = []
|
||||
|
||||
# A ButtonList with two entries
|
||||
table_buttonset = (
|
||||
{'fgcolor' : RED, 'text' : 'Disable', 'args' : (buttons, True)},
|
||||
{'fgcolor' : GREEN, 'text' : 'Enable', 'args' : (buttons, False)},
|
||||
)
|
||||
|
||||
table_radiobuttons = (
|
||||
{'text' : '1', 'args' : ('1',)},
|
||||
{'text' : '2', 'args' : ('2',)},
|
||||
{'text' : '3', 'args' : ('3',)},
|
||||
{'text' : '4', 'args' : ('4',)},
|
||||
)
|
||||
|
||||
def tickcb(f, c):
|
||||
if f > 0.8:
|
||||
return RED
|
||||
if f < -0.8:
|
||||
return BLUE
|
||||
return c
|
||||
|
||||
def bcb(b):
|
||||
print('Button pressed', b)
|
||||
|
||||
super().__init__()
|
||||
self.rb0 = None
|
||||
self.bs0 = None
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
lbltim = Label(wri, 50, 85, 'this is a test', bdcolor=RED)
|
||||
|
||||
m0 = Meter(wri, 20, 240, divisions = 4, ptcolor=YELLOW,
|
||||
label='left', style=Meter.LINE, legends=('0.0', '0.5', '1.0'))
|
||||
# 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
|
||||
scale = Scale(wri, 2, 100, width = 124, tickcb = tickcb,
|
||||
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN)
|
||||
|
||||
# Four Button instances
|
||||
row = 120
|
||||
ht = 30
|
||||
for i, s in enumerate(('a', 'b', 'c', 'd')):
|
||||
col= 2 + i * (ht + 5)
|
||||
buttons.append(Button(wri, row, col, height=ht, callback=bcb, text=s, litcolor=RED, shape=CIRCLE, bgcolor=DARKGREEN))
|
||||
|
||||
# ButtonList
|
||||
self.bs = ButtonList(self.callback)
|
||||
self.bs0 = None
|
||||
col+= 50
|
||||
for t in table_buttonset: # Buttons overlay each other at same location
|
||||
button = self.bs.add_button(wri, 120, col, shape=RECTANGLE, textcolor=BLUE, height=30, **t)
|
||||
if self.bs0 is None: # Save for reset button callback
|
||||
self.bs0 = button
|
||||
|
||||
# Reset button
|
||||
col+= 60
|
||||
btn = Button(wri, row, col, height=30, callback=self.rstcb, text='reset', litcolor=RED, fgcolor=GREEN, bgcolor=DARKGREEN)
|
||||
|
||||
# Radio buttons
|
||||
col= 2
|
||||
self.rb = RadioButtons(BLUE, self.rbcb) # color of selected button
|
||||
self.rb0 = None
|
||||
for t in table_radiobuttons:
|
||||
button = self.rb.add_button(wri, 160, col, textcolor = WHITE,
|
||||
fgcolor = BLUE, bgcolor = DARKBLUE, shape=CIRCLE, height = 30, **t)
|
||||
if self.rb0 is None: # Save for reset button callback
|
||||
self.rb0 = button
|
||||
col+= 35
|
||||
# Checkbox
|
||||
col+= 35
|
||||
Checkbox(wri, 160, col, callback=self.cbcb)
|
||||
col+= 40
|
||||
self.led = LED(wri, 160, col, color=YELLOW, bdcolor=GREEN)
|
||||
CloseButton(wri)
|
||||
asyncio.create_task(run(dial, lbltim, m0, scale))
|
||||
|
||||
|
||||
def callback(self, button, buttons, val):
|
||||
buttons[2].greyed_out(val)
|
||||
|
||||
def rbcb(self, button, val):
|
||||
print('RadioButtons callback', val)
|
||||
|
||||
def rstcb(self, button):
|
||||
print('Reset button: init ButtonList and RadioButtons')
|
||||
self.bs.value(self.bs0) # BUG This is calling ButtonList.value which calls ._update -> Screen.select which changes currency
|
||||
self.rb.value(self.rb0)
|
||||
|
||||
def cbcb(self, cb):
|
||||
self.led.value(cb.value())
|
||||
gc.collect()
|
||||
print('Free RAM:', gc.mem_free())
|
||||
|
||||
async def run(dial, lbltim, m0, scale):
|
||||
days = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
|
||||
'Sunday')
|
||||
months = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',
|
||||
'Aug', 'Sept', 'Oct', 'Nov', 'Dec')
|
||||
uv = lambda phi : cmath.rect(1, phi) # Return a unit vector of phase phi
|
||||
pi = cmath.pi
|
||||
hrs = Pointer(dial)
|
||||
mins = Pointer(dial)
|
||||
secs = Pointer(dial)
|
||||
|
||||
hstart = 0 + 0.7j # Pointer lengths and position at top
|
||||
mstart = 0 + 0.92j
|
||||
sstart = 0 + 0.92j
|
||||
|
||||
cv = -1.0 # Scale
|
||||
dv = 0.005
|
||||
while True:
|
||||
t = utime.localtime()
|
||||
hrs.value(hstart * uv(-t[3]*pi/6 - t[4]*pi/360), YELLOW)
|
||||
mins.value(mstart * uv(-t[4] * pi/30), YELLOW)
|
||||
secs.value(sstart * uv(-t[5] * pi/30), RED)
|
||||
lbltim.value('{:02d}.{:02d}.{:02d}'.format(t[3], t[4], t[5]))
|
||||
dial.text('{} {} {} {}'.format(days[t[6]], t[2], months[t[1] - 1], t[0]))
|
||||
m0.value(t[5]/60)
|
||||
scale.value(cv)
|
||||
await asyncio.sleep_ms(200)
|
||||
cv += dv
|
||||
if abs(cv) > 1.0:
|
||||
dv = -dv
|
||||
cv += dv
|
||||
|
||||
|
||||
def test():
|
||||
if display.height < 240 or display.width < 320:
|
||||
print(' This test requires a display of at least 320x240 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(FooScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,113 @@
|
|||
# vtest.py Test/demo of VectorDial for micro-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from hardware_setup import display, ssd # Create a display instance
|
||||
|
||||
import urandom
|
||||
import time
|
||||
from cmath import rect, pi
|
||||
import uasyncio as asyncio
|
||||
|
||||
from gui.core.ugui import Screen
|
||||
from gui.core.writer import CWriter
|
||||
from gui.fonts import font10
|
||||
from gui.core.colors import *
|
||||
# Widgets
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
from gui.widgets.vectors import Pointer, VectorDial
|
||||
|
||||
|
||||
def fwdbutton(wri, row, col, cls_screen, text='Next'):
|
||||
def fwd(button):
|
||||
Screen.change(cls_screen)
|
||||
Button(wri, row, col, height = 30, callback = fwd, fgcolor = BLACK, bgcolor = GREEN,
|
||||
text = text, shape = RECTANGLE, width = 100)
|
||||
|
||||
|
||||
class BackScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
wri = CWriter(ssd, font10, GREEN, BLACK, verbose=False)
|
||||
Label(wri, 2, 2, 'Ensure back refreshes properly')
|
||||
CloseButton(wri)
|
||||
|
||||
# Create a random vector. Interpolate between current vector and the new one.
|
||||
# Change pointer color dependent on magnitude.
|
||||
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
|
||||
while True:
|
||||
v1 = grv() + 1j * grv() # Random vector
|
||||
dv = (v1 - v) / steps # Interpolation vector
|
||||
for _ in range(steps):
|
||||
v += dv
|
||||
mag = abs(v)
|
||||
if mag < 0.3:
|
||||
ptr.value(v, BLUE)
|
||||
elif mag < 0.7:
|
||||
ptr.value(v, GREEN)
|
||||
else:
|
||||
ptr.value(v, RED)
|
||||
await asyncio.sleep_ms(200)
|
||||
|
||||
# Analog clock demo. Note this could also be achieved using the Dial class.
|
||||
async def aclock(dial, lbldate, lbltim):
|
||||
uv = lambda phi : rect(1, phi) # Return a unit vector of phase phi
|
||||
days = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
|
||||
'Sunday')
|
||||
months = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
|
||||
'August', 'September', 'October', 'November', 'December')
|
||||
|
||||
hrs = Pointer(dial)
|
||||
mins = Pointer(dial)
|
||||
secs = Pointer(dial)
|
||||
|
||||
hstart = 0 + 0.7j # Pointer lengths. Position at top.
|
||||
mstart = 0 + 1j
|
||||
sstart = 0 + 1j
|
||||
|
||||
while True:
|
||||
t = time.localtime()
|
||||
hrs.value(hstart * uv(-t[3] * pi/6 - t[4] * pi / 360), CYAN)
|
||||
mins.value(mstart * uv(-t[4] * pi/30), CYAN)
|
||||
secs.value(sstart * uv(-t[5] * pi/30), RED)
|
||||
lbltim.value('{:02d}.{:02d}.{:02d}'.format(t[3], t[4], t[5]))
|
||||
lbldate.value('{} {} {} {}'.format(days[t[6]], t[2], months[t[1] - 1], t[0]))
|
||||
await asyncio.sleep(1)
|
||||
|
||||
class VScreen(Screen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
labels = {'bdcolor' : RED,
|
||||
'fgcolor' : WHITE,
|
||||
'bgcolor' : DARKGREEN,
|
||||
}
|
||||
|
||||
wri = CWriter(ssd, font10, GREEN, BLACK, verbose=False)
|
||||
|
||||
fwdbutton(wri, 200, 2, BackScreen, 'Forward')
|
||||
CloseButton(wri)
|
||||
# Set up random vector display with two pointers
|
||||
dial = VectorDial(wri, 2, 2, height = 100, ticks = 12, fgcolor = YELLOW, arrow = True)
|
||||
self.reg_task(ptr_test(dial))
|
||||
self.reg_task(ptr_test(dial))
|
||||
# Set up clock display: instantiate labels
|
||||
lbldate = Label(wri, 110, 2, 200, **labels)
|
||||
lbltim = Label(wri, 150, 2, 80, **labels)
|
||||
dial = VectorDial(wri, 2, 120, height = 100, ticks = 12, fgcolor = GREEN, pip = GREEN)
|
||||
self.reg_task(aclock(dial, lbldate, lbltim))
|
||||
|
||||
def test():
|
||||
if display.height < 240 or display.width < 320:
|
||||
print(' This test requires a display of at least 320x240 pixels.')
|
||||
else:
|
||||
print('Testing micro-gui...')
|
||||
Screen.change(VScreen)
|
||||
|
||||
test()
|
|
@ -0,0 +1,139 @@
|
|||
# Code generated by font-to-py.py.
|
||||
# Font: Arial.ttf
|
||||
version = '0.25'
|
||||
|
||||
def height():
|
||||
return 10
|
||||
|
||||
def max_width():
|
||||
return 11
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 126
|
||||
|
||||
_font =\
|
||||
b'\x06\x00\x70\x88\x08\x10\x20\x20\x00\x20\x00\x00\x03\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x80\x80\x80\x80\x80\x80'\
|
||||
b'\x00\x80\x00\x00\x04\x00\xa0\xa0\xa0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x06\x00\x28\x28\xf8\x50\x50\xf8\xa0\xa0\x00\x00\x06\x00\x70\xa8'\
|
||||
b'\xa0\x70\x28\x28\xa8\x70\x20\x00\x0a\x00\x62\x00\x94\x00\x94\x00'\
|
||||
b'\x68\x00\x0b\x00\x14\x80\x14\x80\x23\x00\x00\x00\x00\x00\x07\x00'\
|
||||
b'\x30\x48\x48\x30\x50\x8c\x88\x74\x00\x00\x02\x00\x80\x80\x80\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x04\x00\x20\x40\x80\x80\x80\x80\x80\x80'\
|
||||
b'\x40\x20\x04\x00\x80\x40\x20\x20\x20\x20\x20\x20\x40\x80\x04\x00'\
|
||||
b'\x40\xe0\x40\xa0\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x20\x20'\
|
||||
b'\xf8\x20\x20\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x80'\
|
||||
b'\x80\x80\x04\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x03\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x03\x00\x20\x20\x40\x40'\
|
||||
b'\x40\x40\x80\x80\x00\x00\x06\x00\x70\x88\x88\x88\x88\x88\x88\x70'\
|
||||
b'\x00\x00\x06\x00\x20\x60\xa0\x20\x20\x20\x20\x20\x00\x00\x06\x00'\
|
||||
b'\x70\x88\x08\x08\x10\x20\x40\xf8\x00\x00\x06\x00\x70\x88\x08\x30'\
|
||||
b'\x08\x08\x88\x70\x00\x00\x06\x00\x10\x30\x50\x50\x90\xf8\x10\x10'\
|
||||
b'\x00\x00\x06\x00\x78\x40\x80\xf0\x08\x08\x88\x70\x00\x00\x06\x00'\
|
||||
b'\x70\x88\x80\xf0\x88\x88\x88\x70\x00\x00\x06\x00\xf8\x10\x10\x20'\
|
||||
b'\x20\x40\x40\x40\x00\x00\x06\x00\x70\x88\x88\x70\x88\x88\x88\x70'\
|
||||
b'\x00\x00\x06\x00\x70\x88\x88\x88\x78\x08\x88\x70\x00\x00\x03\x00'\
|
||||
b'\x00\x00\x80\x00\x00\x00\x00\x80\x00\x00\x03\x00\x00\x00\x80\x00'\
|
||||
b'\x00\x00\x00\x80\x80\x80\x06\x00\x00\x00\x08\x70\x80\x70\x08\x00'\
|
||||
b'\x00\x00\x06\x00\x00\x00\x00\xf8\x00\xf8\x00\x00\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x80\x70\x08\x70\x80\x00\x00\x00\x06\x00\x70\x88\x08\x10'\
|
||||
b'\x20\x20\x00\x20\x00\x00\x0b\x00\x1f\x00\x60\x80\x4d\x40\x93\x40'\
|
||||
b'\xa2\x40\xa2\x40\xa6\x80\x9b\x00\x40\x40\x3f\x80\x08\x00\x10\x28'\
|
||||
b'\x28\x28\x44\x7c\x82\x82\x00\x00\x07\x00\xf8\x84\x84\xfc\x84\x84'\
|
||||
b'\x84\xf8\x00\x00\x07\x00\x38\x44\x80\x80\x80\x80\x44\x38\x00\x00'\
|
||||
b'\x07\x00\xf0\x88\x84\x84\x84\x84\x88\xf0\x00\x00\x06\x00\xf8\x80'\
|
||||
b'\x80\xf8\x80\x80\x80\xf8\x00\x00\x06\x00\xf8\x80\x80\xf0\x80\x80'\
|
||||
b'\x80\x80\x00\x00\x08\x00\x38\x44\x82\x80\x8e\x82\x44\x38\x00\x00'\
|
||||
b'\x07\x00\x84\x84\x84\xfc\x84\x84\x84\x84\x00\x00\x02\x00\x80\x80'\
|
||||
b'\x80\x80\x80\x80\x80\x80\x00\x00\x05\x00\x10\x10\x10\x10\x10\x90'\
|
||||
b'\x90\x60\x00\x00\x07\x00\x84\x88\x90\xb0\xd0\x88\x88\x84\x00\x00'\
|
||||
b'\x06\x00\x80\x80\x80\x80\x80\x80\x80\xf8\x00\x00\x08\x00\x82\xc6'\
|
||||
b'\xc6\xaa\xaa\xaa\x92\x92\x00\x00\x07\x00\x84\xc4\xa4\xa4\x94\x94'\
|
||||
b'\x8c\x84\x00\x00\x08\x00\x38\x44\x82\x82\x82\x82\x44\x38\x00\x00'\
|
||||
b'\x06\x00\xf0\x88\x88\x88\xf0\x80\x80\x80\x00\x00\x08\x00\x38\x44'\
|
||||
b'\x82\x82\x82\x9a\x44\x3e\x00\x00\x07\x00\xf8\x84\x84\xf8\x90\x88'\
|
||||
b'\x88\x84\x00\x00\x07\x00\x78\x84\x80\x60\x18\x04\x84\x78\x00\x00'\
|
||||
b'\x06\x00\xf8\x20\x20\x20\x20\x20\x20\x20\x00\x00\x07\x00\x84\x84'\
|
||||
b'\x84\x84\x84\x84\x84\x78\x00\x00\x08\x00\x82\x82\x44\x44\x28\x28'\
|
||||
b'\x10\x10\x00\x00\x0b\x00\x84\x20\x8a\x20\x4a\x40\x4a\x40\x51\x40'\
|
||||
b'\x51\x40\x20\x80\x20\x80\x00\x00\x00\x00\x07\x00\x84\x48\x48\x30'\
|
||||
b'\x30\x48\x48\x84\x00\x00\x08\x00\x82\x44\x44\x28\x10\x10\x10\x10'\
|
||||
b'\x00\x00\x07\x00\x7c\x08\x10\x10\x20\x20\x40\xfc\x00\x00\x03\x00'\
|
||||
b'\xc0\x80\x80\x80\x80\x80\x80\x80\x80\xc0\x03\x00\x80\x80\x40\x40'\
|
||||
b'\x40\x40\x20\x20\x00\x00\x03\x00\xc0\x40\x40\x40\x40\x40\x40\x40'\
|
||||
b'\x40\xc0\x05\x00\x20\x50\x50\x88\x00\x00\x00\x00\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x00\x04\x00\x80\x40\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x70\x88\x78\x88\x98\xe8'\
|
||||
b'\x00\x00\x06\x00\x80\x80\xb0\xc8\x88\x88\xc8\xb0\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x70\x88\x80\x80\x88\x70\x00\x00\x06\x00\x08\x08\x68\x98'\
|
||||
b'\x88\x88\x98\x68\x00\x00\x06\x00\x00\x00\x70\x88\xf8\x80\x88\x70'\
|
||||
b'\x00\x00\x04\x00\x20\x40\xe0\x40\x40\x40\x40\x40\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x68\x98\x88\x88\x98\x68\x08\xf0\x06\x00\x80\x80\xb0\xc8'\
|
||||
b'\x88\x88\x88\x88\x00\x00\x02\x00\x80\x00\x80\x80\x80\x80\x80\x80'\
|
||||
b'\x00\x00\x02\x00\x40\x00\x40\x40\x40\x40\x40\x40\x40\x80\x05\x00'\
|
||||
b'\x80\x80\x90\xa0\xc0\xe0\xa0\x90\x00\x00\x02\x00\x80\x80\x80\x80'\
|
||||
b'\x80\x80\x80\x80\x00\x00\x08\x00\x00\x00\xbc\xd2\x92\x92\x92\x92'\
|
||||
b'\x00\x00\x06\x00\x00\x00\xf0\x88\x88\x88\x88\x88\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x70\x88\x88\x88\x88\x70\x00\x00\x06\x00\x00\x00\xb0\xc8'\
|
||||
b'\x88\x88\xc8\xb0\x80\x80\x06\x00\x00\x00\x68\x98\x88\x88\x98\x68'\
|
||||
b'\x08\x08\x04\x00\x00\x00\xa0\xc0\x80\x80\x80\x80\x00\x00\x06\x00'\
|
||||
b'\x00\x00\x70\x88\x60\x10\x88\x70\x00\x00\x03\x00\x40\x40\xe0\x40'\
|
||||
b'\x40\x40\x40\x60\x00\x00\x06\x00\x00\x00\x88\x88\x88\x88\x98\x68'\
|
||||
b'\x00\x00\x06\x00\x00\x00\x88\x88\x50\x50\x20\x20\x00\x00\x0a\x00'\
|
||||
b'\x00\x00\x00\x00\x88\x80\x94\x80\x55\x00\x55\x00\x22\x00\x22\x00'\
|
||||
b'\x00\x00\x00\x00\x06\x00\x00\x00\x88\x50\x20\x20\x50\x88\x00\x00'\
|
||||
b'\x06\x00\x00\x00\x88\x88\x50\x50\x20\x20\x20\x40\x06\x00\x00\x00'\
|
||||
b'\xf8\x10\x20\x20\x40\xf8\x00\x00\x04\x00\x20\x40\x40\x40\x80\x40'\
|
||||
b'\x40\x40\x40\x20\x02\x00\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80'\
|
||||
b'\x04\x00\x80\x40\x40\x40\x20\x40\x40\x40\x40\x80\x06\x00\x00\x00'\
|
||||
b'\x00\xe8\xb0\x00\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x0c\x00\x0c\x00\x18\x00\x18\x00\x24\x00\x24\x00\x30\x00'\
|
||||
b'\x30\x00\x3c\x00\x3c\x00\x48\x00\x48\x00\x5e\x00\x5e\x00\x6a\x00'\
|
||||
b'\x6a\x00\x76\x00\x76\x00\x82\x00\x82\x00\x8e\x00\x8e\x00\x9a\x00'\
|
||||
b'\x9a\x00\xa6\x00\xa6\x00\xb2\x00\xb2\x00\xbe\x00\xbe\x00\xca\x00'\
|
||||
b'\xca\x00\xd6\x00\xd6\x00\xe2\x00\xe2\x00\xee\x00\xee\x00\xfa\x00'\
|
||||
b'\xfa\x00\x06\x01\x06\x01\x12\x01\x12\x01\x1e\x01\x1e\x01\x2a\x01'\
|
||||
b'\x2a\x01\x36\x01\x36\x01\x42\x01\x42\x01\x4e\x01\x4e\x01\x5a\x01'\
|
||||
b'\x5a\x01\x66\x01\x66\x01\x72\x01\x72\x01\x7e\x01\x7e\x01\x8a\x01'\
|
||||
b'\x8a\x01\x96\x01\x96\x01\xac\x01\xac\x01\xb8\x01\xb8\x01\xc4\x01'\
|
||||
b'\xc4\x01\xd0\x01\xd0\x01\xdc\x01\xdc\x01\xe8\x01\xe8\x01\xf4\x01'\
|
||||
b'\xf4\x01\x00\x02\x00\x02\x0c\x02\x0c\x02\x18\x02\x18\x02\x24\x02'\
|
||||
b'\x24\x02\x30\x02\x30\x02\x3c\x02\x3c\x02\x48\x02\x48\x02\x54\x02'\
|
||||
b'\x54\x02\x60\x02\x60\x02\x6c\x02\x6c\x02\x78\x02\x78\x02\x84\x02'\
|
||||
b'\x84\x02\x90\x02\x90\x02\x9c\x02\x9c\x02\xa8\x02\xa8\x02\xb4\x02'\
|
||||
b'\xb4\x02\xca\x02\xca\x02\xd6\x02\xd6\x02\xe2\x02\xe2\x02\xee\x02'\
|
||||
b'\xee\x02\xfa\x02\xfa\x02\x06\x03\x06\x03\x12\x03\x12\x03\x1e\x03'\
|
||||
b'\x1e\x03\x2a\x03\x2a\x03\x36\x03\x36\x03\x42\x03\x42\x03\x4e\x03'\
|
||||
b'\x4e\x03\x5a\x03\x5a\x03\x66\x03\x66\x03\x72\x03\x72\x03\x7e\x03'\
|
||||
b'\x7e\x03\x8a\x03\x8a\x03\x96\x03\x96\x03\xa2\x03\xa2\x03\xae\x03'\
|
||||
b'\xae\x03\xba\x03\xba\x03\xc6\x03\xc6\x03\xd2\x03\xd2\x03\xde\x03'\
|
||||
b'\xde\x03\xea\x03\xea\x03\xf6\x03\xf6\x03\x02\x04\x02\x04\x0e\x04'\
|
||||
b'\x0e\x04\x1a\x04\x1a\x04\x26\x04\x26\x04\x32\x04\x32\x04\x3e\x04'\
|
||||
b'\x3e\x04\x54\x04\x54\x04\x60\x04\x60\x04\x6c\x04\x6c\x04\x78\x04'\
|
||||
b'\x78\x04\x84\x04\x84\x04\x90\x04\x90\x04\x9c\x04\x9c\x04\xa8\x04'\
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
|
||||
def get_ch(ch):
|
||||
ordch = ord(ch)
|
||||
ordch = ordch + 1 if ordch >= 32 and ordch <= 126 else 32
|
||||
idx_offs = 4 * (ordch - 32)
|
||||
offset = int.from_bytes(_index[idx_offs : idx_offs + 2], 'little')
|
||||
next_offs = int.from_bytes(_index[idx_offs + 2 : idx_offs + 4], 'little')
|
||||
width = int.from_bytes(_font[offset:offset + 2], 'little')
|
||||
return _mvfont[offset + 2:next_offs], 10, width
|
||||
|
|
@ -0,0 +1,671 @@
|
|||
# Code generated by font_to_py.py.
|
||||
# Font: Arial.ttf
|
||||
# Cmd: ./font_to_py.py Arial.ttf 35 arial35.py -x
|
||||
version = '0.33'
|
||||
|
||||
def height():
|
||||
return 35
|
||||
|
||||
def baseline():
|
||||
return 27
|
||||
|
||||
def max_width():
|
||||
return 37
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 126
|
||||
|
||||
_font =\
|
||||
b'\x14\x00\x00\x00\x00\x01\xf8\x00\x07\xfe\x00\x0f\xff\x00\x1f\x0f'\
|
||||
b'\x80\x1c\x03\xc0\x38\x01\xc0\x38\x01\xc0\x00\x01\xc0\x00\x01\xc0'\
|
||||
b'\x00\x03\x80\x00\x07\x80\x00\x0f\x00\x00\x1e\x00\x00\x3c\x00\x00'\
|
||||
b'\x78\x00\x00\x70\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\xe0\x00'\
|
||||
b'\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x00\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e'\
|
||||
b'\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e'\
|
||||
b'\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0e\x00\x0e\x00\x0e\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x70'\
|
||||
b'\xe0\x70\xe0\x70\xe0\x70\xe0\x70\xe0\x70\xe0\x70\xe0\x70\xe0\x20'\
|
||||
b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x14\x00\x00\x00\x00\x01\xc1\xc0\x01\xc1\xc0\x01\xc3'\
|
||||
b'\xc0\x03\x83\x80\x03\x83\x80\x03\x83\x80\x03\x83\x80\xff\xff\xf0'\
|
||||
b'\xff\xff\xf0\xff\xff\xf0\x07\x07\x00\x07\x07\x00\x07\x07\x00\x0e'\
|
||||
b'\x0e\x00\x0e\x0e\x00\x0e\x0e\x00\xff\xff\xf0\xff\xff\xf0\xff\xff'\
|
||||
b'\xf0\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x3c\x38\x00'\
|
||||
b'\x38\x38\x00\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00'\
|
||||
b'\x00\x60\x00\x03\xf8\x00\x0f\xfe\x00\x1f\xff\x00\x1e\x67\x00\x3c'\
|
||||
b'\x63\x80\x38\x63\x80\x38\x60\x00\x38\x60\x00\x38\x60\x00\x1c\x60'\
|
||||
b'\x00\x1f\xe0\x00\x0f\xf8\x00\x03\xfe\x00\x00\xff\x00\x00\x6f\x80'\
|
||||
b'\x00\x63\x80\x00\x61\xc0\x00\x61\xc0\x70\x61\xc0\x70\x61\xc0\x78'\
|
||||
b'\x63\xc0\x3c\x63\x80\x3e\x67\x80\x1f\xff\x00\x0f\xfe\x00\x01\xf8'\
|
||||
b'\x00\x00\x60\x00\x00\x60\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x07'\
|
||||
b'\xc0\x03\x80\x0f\xe0\x07\x80\x1c\x70\x07\x00\x1c\x70\x0f\x00\x38'\
|
||||
b'\x38\x0e\x00\x38\x38\x1c\x00\x38\x38\x3c\x00\x38\x38\x38\x00\x38'\
|
||||
b'\x38\x78\x00\x38\x38\x70\x00\x18\x70\xf0\x00\x1c\x70\xe0\x00\x0f'\
|
||||
b'\xe1\xc3\xe0\x07\xc1\xc7\xf0\x00\x03\x8e\x38\x00\x07\x8e\x38\x00'\
|
||||
b'\x07\x1c\x1c\x00\x0f\x1c\x1c\x00\x0e\x1c\x1c\x00\x1e\x1c\x1c\x00'\
|
||||
b'\x1c\x1c\x1c\x00\x38\x1c\x1c\x00\x78\x0c\x38\x00\x70\x0e\x38\x00'\
|
||||
b'\xf0\x07\xf0\x00\xe0\x03\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x7c\x00\x01'\
|
||||
b'\xfe\x00\x03\xff\x00\x07\x87\x80\x07\x03\x80\x07\x03\x80\x07\x03'\
|
||||
b'\x80\x07\x83\x80\x03\x87\x00\x03\xde\x00\x01\xfc\x00\x01\xf8\x00'\
|
||||
b'\x03\xf0\x00\x0f\xb8\x00\x1e\x3c\x20\x1c\x1e\x38\x3c\x0f\x78\x38'\
|
||||
b'\x07\x70\x38\x03\xf0\x38\x03\xe0\x3c\x01\xe0\x1c\x03\xf0\x1f\x0f'\
|
||||
b'\xf8\x0f\xff\xbe\x07\xfe\x1c\x01\xf8\x08\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x07\x00\x00\x38\x38\x38\x38\x38\x38\x38\x38\x10\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\xc0\x01\x80\x03'\
|
||||
b'\x80\x03\x00\x07\x00\x06\x00\x0e\x00\x0c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38'\
|
||||
b'\x00\x38\x00\x38\x00\x18\x00\x1c\x00\x1c\x00\x1c\x00\x0c\x00\x0e'\
|
||||
b'\x00\x06\x00\x07\x00\x03\x00\x03\x80\x01\x80\x00\xc0\x00\x00\x0c'\
|
||||
b'\x00\x00\x00\x30\x00\x18\x00\x1c\x00\x0c\x00\x0e\x00\x06\x00\x07'\
|
||||
b'\x00\x03\x00\x03\x80\x03\x80\x03\x80\x01\x80\x01\xc0\x01\xc0\x01'\
|
||||
b'\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\x80\x03'\
|
||||
b'\x80\x03\x80\x03\x80\x07\x00\x07\x00\x06\x00\x0e\x00\x0c\x00\x1c'\
|
||||
b'\x00\x18\x00\x30\x00\x00\x00\x0e\x00\x00\x00\x03\x80\x03\x80\x03'\
|
||||
b'\x80\x3b\xb8\x7f\xfc\x1f\xf0\x07\xc0\x0e\xe0\x1e\xf0\x1c\x70\x08'\
|
||||
b'\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00'\
|
||||
b'\x70\x00\x00\x70\x00\x00\x70\x00\x3f\xff\xe0\x3f\xff\xe0\x3f\xff'\
|
||||
b'\xe0\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00'\
|
||||
b'\x00\x70\x00\x00\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00'\
|
||||
b'\x1c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x18\x00\x18\x00\x00\x00'\
|
||||
b'\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x7f\xe0\x7f\xe0\x7f\xe0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00'\
|
||||
b'\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0a\x00\x00\x00\x01\xc0\x01\xc0\x03\x80\x03\x80\x03\x80'\
|
||||
b'\x03\x80\x07\x00\x07\x00\x07\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00'\
|
||||
b'\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x38\x00\x38\x00\x38\x00\x78\x00'\
|
||||
b'\x70\x00\x70\x00\x70\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x01'\
|
||||
b'\xf8\x00\x07\xfe\x00\x0f\xff\x00\x0f\x0f\x00\x1e\x07\x80\x1c\x03'\
|
||||
b'\x80\x1c\x03\x80\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38'\
|
||||
b'\x01\xc0\x38\x01\xc0\x38\x01\xc0\x1c\x03\x80\x1c\x03\x80\x1e\x07'\
|
||||
b'\x80\x0f\x0f\x00\x0f\xff\x00\x07\xfe\x00\x01\xf8\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x18\x00\x00\x38\x00'\
|
||||
b'\x00\x78\x00\x00\xf8\x00\x01\xf8\x00\x03\xf8\x00\x0f\xb8\x00\x0f'\
|
||||
b'\x38\x00\x0c\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38'\
|
||||
b'\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00'\
|
||||
b'\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00'\
|
||||
b'\x38\x00\x00\x38\x00\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x14\x00\x00\x00\x00\x03\xf8\x00\x0f\xfe\x00\x1f\xff\x00\x3e\x0f'\
|
||||
b'\x80\x38\x03\x80\x70\x03\xc0\x70\x01\xc0\x00\x01\xc0\x00\x01\xc0'\
|
||||
b'\x00\x01\xc0\x00\x03\x80\x00\x07\x80\x00\x07\x00\x00\x0e\x00\x00'\
|
||||
b'\x1c\x00\x00\x38\x00\x00\xf0\x00\x01\xe0\x00\x03\xc0\x00\x07\x80'\
|
||||
b'\x00\x0f\x00\x00\x1c\x00\x00\x38\x00\x00\x3f\xff\xc0\x7f\xff\xc0'\
|
||||
b'\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00'\
|
||||
b'\x01\xf8\x00\x07\xfe\x00\x0f\xff\x00\x1e\x0f\x00\x1c\x07\x80\x38'\
|
||||
b'\x03\x80\x38\x03\x80\x00\x03\x80\x00\x07\x00\x00\x0f\x00\x00\xfe'\
|
||||
b'\x00\x00\xfe\x00\x00\xff\x00\x00\x07\x80\x00\x03\x80\x00\x01\xc0'\
|
||||
b'\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x38\x01\xc0\x38\x03\xc0\x1c'\
|
||||
b'\x03\x80\x1e\x0f\x80\x0f\xff\x00\x07\xfe\x00\x01\xf8\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x0e\x00\x00\x1e'\
|
||||
b'\x00\x00\x3e\x00\x00\x3e\x00\x00\x7e\x00\x00\xfe\x00\x00\xee\x00'\
|
||||
b'\x01\xee\x00\x03\xce\x00\x03\x8e\x00\x07\x8e\x00\x07\x0e\x00\x0e'\
|
||||
b'\x0e\x00\x1e\x0e\x00\x1c\x0e\x00\x38\x0e\x00\x78\x0e\x00\x7f\xff'\
|
||||
b'\xc0\x7f\xff\xc0\x7f\xff\xc0\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00'\
|
||||
b'\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x14\x00\x00\x00\x00\x07\xff\x80\x07\xff\x80\x0f\xff\x80\x0e'\
|
||||
b'\x00\x00\x0e\x00\x00\x0e\x00\x00\x1e\x00\x00\x1c\x00\x00\x1c\xf8'\
|
||||
b'\x00\x1f\xfe\x00\x1f\xff\x00\x3e\x0f\x80\x38\x03\x80\x00\x03\xc0'\
|
||||
b'\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x38'\
|
||||
b'\x01\xc0\x38\x03\x80\x1c\x03\x80\x1e\x0f\x00\x0f\xff\x00\x07\xfc'\
|
||||
b'\x00\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00'\
|
||||
b'\x00\x01\xf8\x00\x07\xfe\x00\x0f\xff\x00\x1f\x0f\x80\x1c\x03\x80'\
|
||||
b'\x3c\x03\xc0\x38\x01\xc0\x38\x00\x00\x70\x00\x00\x70\xf8\x00\x73'\
|
||||
b'\xfe\x00\x77\xff\x00\x7e\x0f\x80\x7c\x03\x80\x78\x03\xc0\x70\x01'\
|
||||
b'\xc0\x70\x01\xc0\x70\x01\xc0\x70\x01\xc0\x30\x01\xc0\x38\x03\x80'\
|
||||
b'\x3c\x03\x80\x1e\x0f\x80\x0f\xff\x00\x07\xfe\x00\x01\xf8\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x7f\xff\xc0\x7f'\
|
||||
b'\xff\xc0\x7f\xff\xc0\x00\x01\x80\x00\x03\x00\x00\x07\x00\x00\x0e'\
|
||||
b'\x00\x00\x1c\x00\x00\x1c\x00\x00\x38\x00\x00\x38\x00\x00\x70\x00'\
|
||||
b'\x00\x70\x00\x00\xe0\x00\x00\xe0\x00\x01\xc0\x00\x01\xc0\x00\x01'\
|
||||
b'\xc0\x00\x03\x80\x00\x03\x80\x00\x03\x80\x00\x03\x80\x00\x07\x00'\
|
||||
b'\x00\x07\x00\x00\x07\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x14\x00\x00\x00\x00\x01\xf8\x00\x07\xfe\x00\x0f\xff\x00'\
|
||||
b'\x0f\x0f\x00\x1e\x07\x80\x1c\x03\x80\x1c\x03\x80\x1c\x03\x80\x1e'\
|
||||
b'\x07\x80\x0f\x0f\x00\x07\xfe\x00\x03\xfc\x00\x0f\xff\x00\x1e\x07'\
|
||||
b'\x80\x1c\x03\x80\x38\x03\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x03\xc0\x1c\x03\x80\x1f\x07\x80\x0f\xff\x00\x07'\
|
||||
b'\xfe\x00\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00'\
|
||||
b'\x00\x00\x01\xf0\x00\x07\xfc\x00\x0f\xfe\x00\x1f\x07\x00\x1c\x03'\
|
||||
b'\x80\x3c\x03\x80\x38\x01\x80\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x3c\x03\xc0\x1c\x03\xc0\x1e\x0f\xc0\x0f\xfd\xc0\x07'\
|
||||
b'\xf9\xc0\x01\xf1\xc0\x00\x01\xc0\x00\x03\x80\x38\x03\x80\x38\x03'\
|
||||
b'\x80\x1c\x07\x00\x1e\x0f\x00\x0f\xfe\x00\x07\xfc\x00\x03\xf0\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00\x1c\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x1c\x00\x1c\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x1c\x00\x1c\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x1c\x00\x1c\x00\x1c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\x18\x00\x10\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00'\
|
||||
b'\x01\xe0\x00\x07\xe0\x00\x3f\xc0\x00\xfe\x00\x03\xf8\x00\x1f\xc0'\
|
||||
b'\x00\x3f\x00\x00\x38\x00\x00\x3f\x00\x00\x1f\xc0\x00\x03\xf8\x00'\
|
||||
b'\x00\xfe\x00\x00\x3f\xc0\x00\x07\xe0\x00\x01\xe0\x00\x00\x20\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3f\xff\xe0\x3f\xff\xe0\x3f\xff\xe0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x3f\xff\xe0\x3f\xff\xe0\x3f\xff'\
|
||||
b'\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x20\x00\x00\x3c\x00\x00\x3f\x00\x00\x1f\xe0\x00\x03\xf8'\
|
||||
b'\x00\x00\xfe\x00\x00\x1f\xc0\x00\x07\xe0\x00\x00\xe0\x00\x07\xe0'\
|
||||
b'\x00\x1f\xc0\x00\xfe\x00\x03\xf8\x00\x1f\xe0\x00\x3f\x00\x00\x3c'\
|
||||
b'\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x01\xf8'\
|
||||
b'\x00\x07\xfe\x00\x0f\xff\x00\x1f\x0f\x80\x1c\x03\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x03\x80\x00\x07\x80\x00'\
|
||||
b'\x0f\x00\x00\x1e\x00\x00\x3c\x00\x00\x78\x00\x00\x70\x00\x00\xe0'\
|
||||
b'\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00\x01\xff\x00\x00'\
|
||||
b'\x00\x0f\xff\xc0\x00\x00\x3f\xff\xf0\x00\x00\xfe\x01\xf8\x00\x01'\
|
||||
b'\xf8\x00\x7c\x00\x03\xe0\x00\x1e\x00\x03\xc0\x00\x0f\x00\x07\x80'\
|
||||
b'\xf8\xe7\x80\x0f\x03\xfc\xe3\x80\x0e\x07\xfe\xc3\x80\x1e\x0f\x07'\
|
||||
b'\xc3\xc0\x1c\x1e\x03\xc1\xc0\x1c\x1c\x01\xc1\xc0\x3c\x38\x01\xc1'\
|
||||
b'\xc0\x38\x38\x01\x81\xc0\x38\x70\x01\x81\xc0\x38\x70\x01\x81\xc0'\
|
||||
b'\x38\x70\x01\x83\x80\x38\x70\x03\x83\x80\x38\x70\x03\x07\x80\x38'\
|
||||
b'\x70\x07\x07\x00\x38\x38\x0f\x0e\x00\x1c\x3c\x3f\x3e\x00\x1c\x1f'\
|
||||
b'\xff\xfc\x00\x1e\x0f\xe7\xf8\x00\x0e\x07\xc3\xe0\x00\x0f\x00\x00'\
|
||||
b'\x00\xe0\x07\x80\x00\x01\xc0\x07\xc0\x00\x07\x80\x03\xf0\x00\x0f'\
|
||||
b'\x00\x00\xfe\x00\x7e\x00\x00\x7f\xff\xfc\x00\x00\x1f\xff\xf0\x00'\
|
||||
b'\x00\x01\xff\x80\x00\x17\x00\x00\x00\x00\x00\x7c\x00\x00\x7c\x00'\
|
||||
b'\x00\x7c\x00\x00\xee\x00\x00\xee\x00\x01\xef\x00\x01\xc7\x00\x01'\
|
||||
b'\xc7\x00\x03\x83\x80\x03\x83\x80\x03\x83\x80\x07\x01\xc0\x07\x01'\
|
||||
b'\xc0\x0f\x01\xe0\x0e\x00\xe0\x0f\xff\xe0\x1f\xff\xf0\x1f\xff\xf0'\
|
||||
b'\x1c\x00\x70\x38\x00\x38\x38\x00\x38\x78\x00\x3c\x70\x00\x1c\x70'\
|
||||
b'\x00\x1c\xf0\x00\x1e\xe0\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x18\x00\x00\x00\x00\x1f\xff\x00\x1f\xff\xc0\x1f\xff\xf0\x1c\x00'\
|
||||
b'\xf0\x1c\x00\x78\x1c\x00\x38\x1c\x00\x38\x1c\x00\x38\x1c\x00\x38'\
|
||||
b'\x1c\x00\x70\x1c\x00\xf0\x1f\xff\xe0\x1f\xff\xe0\x1f\xff\xf0\x1c'\
|
||||
b'\x00\xf8\x1c\x00\x38\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c\x00'\
|
||||
b'\x1c\x1c\x00\x1c\x1c\x00\x38\x1c\x00\xf8\x1f\xff\xf0\x1f\xff\xe0'\
|
||||
b'\x1f\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x3f\x80\x00\x00\xff\xe0\x00\x03\xff\xf0\x00\x07\xc0\xf8'\
|
||||
b'\x00\x0f\x00\x3c\x00\x0e\x00\x1c\x00\x1c\x00\x1e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x3c\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00'\
|
||||
b'\x00\x38\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00'\
|
||||
b'\x00\x38\x00\x00\x00\x1c\x00\x07\x00\x1c\x00\x0f\x00\x1e\x00\x0e'\
|
||||
b'\x00\x0e\x00\x1e\x00\x0f\x00\x3c\x00\x07\xc0\xfc\x00\x03\xff\xf8'\
|
||||
b'\x00\x01\xff\xe0\x00\x00\x3f\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x1f'\
|
||||
b'\xff\x80\x00\x1f\xff\xe0\x00\x1f\xff\xf0\x00\x1c\x00\xf8\x00\x1c'\
|
||||
b'\x00\x3c\x00\x1c\x00\x1c\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x0f\x00\x1c\x00\x07\x00\x1c\x00\x07\x00\x1c\x00\x07\x00\x1c'\
|
||||
b'\x00\x07\x00\x1c\x00\x07\x00\x1c\x00\x07\x00\x1c\x00\x07\x00\x1c'\
|
||||
b'\x00\x07\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x3c\x00\x1c\x00\xf8\x00\x1f\xff\xf0\x00\x1f'\
|
||||
b'\xff\xe0\x00\x1f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x1f\xff\xf8\x1f'\
|
||||
b'\xff\xf8\x1f\xff\xf8\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00'\
|
||||
b'\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1f\xff\xf0'\
|
||||
b'\x1f\xff\xf0\x1f\xff\xf0\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c'\
|
||||
b'\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00'\
|
||||
b'\x00\x1f\xff\xfc\x1f\xff\xfc\x1f\xff\xfc\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x16\x00\x00\x00\x00\x1f\xff\xf0\x1f\xff\xf0\x1f\xff\xf0'\
|
||||
b'\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c'\
|
||||
b'\x00\x00\x1c\x00\x00\x1c\x00\x00\x1f\xff\xc0\x1f\xff\xc0\x1f\xff'\
|
||||
b'\xc0\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00'\
|
||||
b'\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c'\
|
||||
b'\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x1f\xe0\x00\x00\xff\xf8\x00\x01\xff\xfe\x00\x03'\
|
||||
b'\xe0\x3f\x00\x07\x80\x0f\x00\x0f\x00\x07\x80\x1e\x00\x03\x80\x1c'\
|
||||
b'\x00\x01\xc0\x1c\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00\x00\x38'\
|
||||
b'\x00\x00\x00\x38\x00\x00\x00\x38\x01\xff\xc0\x38\x01\xff\xc0\x38'\
|
||||
b'\x01\xff\xc0\x38\x00\x01\xc0\x1c\x00\x01\xc0\x1c\x00\x01\xc0\x1e'\
|
||||
b'\x00\x01\xc0\x0f\x00\x01\xc0\x07\x80\x07\xc0\x03\xf0\x1f\xc0\x01'\
|
||||
b'\xff\xff\x00\x00\xff\xfc\x00\x00\x1f\xe0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1f\xff\xfe'\
|
||||
b'\x00\x1f\xff\xfe\x00\x1f\xff\xfe\x00\x1c\x00\x0e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x12\x00\x00\x00\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00'\
|
||||
b'\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e'\
|
||||
b'\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00'\
|
||||
b'\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x00\x0e\x00\x70\x0e\x00\x70'\
|
||||
b'\x0e\x00\x70\x0e\x00\x78\x1e\x00\x3c\x3c\x00\x3f\xfc\x00\x1f\xf8'\
|
||||
b'\x00\x07\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00'\
|
||||
b'\x00\x1c\x00\x1e\x1c\x00\x3c\x1c\x00\x78\x1c\x00\xf0\x1c\x01\xe0'\
|
||||
b'\x1c\x03\xc0\x1c\x07\x80\x1c\x0f\x00\x1c\x1e\x00\x1c\x3c\x00\x1c'\
|
||||
b'\x78\x00\x1c\xf8\x00\x1d\xfc\x00\x1f\xde\x00\x1f\x8e\x00\x1f\x07'\
|
||||
b'\x00\x1e\x07\x80\x1c\x03\xc0\x1c\x01\xc0\x1c\x00\xe0\x1c\x00\xf0'\
|
||||
b'\x1c\x00\x78\x1c\x00\x38\x1c\x00\x1c\x1c\x00\x1e\x1c\x00\x0f\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x1c\x00\x00\x1c'\
|
||||
b'\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00'\
|
||||
b'\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00'\
|
||||
b'\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c'\
|
||||
b'\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00'\
|
||||
b'\x00\x1f\xff\xe0\x1f\xff\xe0\x1f\xff\xe0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x1d\x00\x00\x00\x00\x00\x1f\x00\x07\xc0\x1f\x80\x0f\xc0'\
|
||||
b'\x1f\x80\x0f\xc0\x1f\x80\x0f\xc0\x1f\xc0\x0f\xc0\x1d\xc0\x1d\xc0'\
|
||||
b'\x1d\xc0\x1d\xc0\x1d\xc0\x1d\xc0\x1c\xe0\x39\xc0\x1c\xe0\x39\xc0'\
|
||||
b'\x1c\xe0\x39\xc0\x1c\xf0\x39\xc0\x1c\x70\x71\xc0\x1c\x70\x71\xc0'\
|
||||
b'\x1c\x70\x71\xc0\x1c\x38\xe1\xc0\x1c\x38\xe1\xc0\x1c\x38\xe1\xc0'\
|
||||
b'\x1c\x3d\xc1\xc0\x1c\x1d\xc1\xc0\x1c\x1d\xc1\xc0\x1c\x1d\xc1\xc0'\
|
||||
b'\x1c\x0f\x81\xc0\x1c\x0f\x81\xc0\x1c\x0f\x81\xc0\x1c\x0f\x01\xc0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x1a\x00\x00\x00\x00\x00\x1e\x00\x0e\x00\x1e\x00\x0e\x00\x1f\x00'\
|
||||
b'\x0e\x00\x1f\x80\x0e\x00\x1f\x80\x0e\x00\x1f\xc0\x0e\x00\x1d\xc0'\
|
||||
b'\x0e\x00\x1c\xe0\x0e\x00\x1c\xf0\x0e\x00\x1c\x70\x0e\x00\x1c\x38'\
|
||||
b'\x0e\x00\x1c\x3c\x0e\x00\x1c\x1c\x0e\x00\x1c\x0e\x0e\x00\x1c\x0f'\
|
||||
b'\x0e\x00\x1c\x07\x0e\x00\x1c\x03\x8e\x00\x1c\x03\xce\x00\x1c\x01'\
|
||||
b'\xce\x00\x1c\x00\xee\x00\x1c\x00\xfe\x00\x1c\x00\x7e\x00\x1c\x00'\
|
||||
b'\x7e\x00\x1c\x00\x3e\x00\x1c\x00\x1e\x00\x1c\x00\x1e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x3f\xc0\x00\x00\xff\xf0\x00\x03\xff\xf8\x00'\
|
||||
b'\x07\xe0\x7e\x00\x07\x80\x1e\x00\x0f\x00\x0f\x00\x1e\x00\x07\x80'\
|
||||
b'\x1c\x00\x03\x80\x1c\x00\x03\x80\x38\x00\x01\xc0\x38\x00\x01\xc0'\
|
||||
b'\x38\x00\x01\xc0\x38\x00\x01\xc0\x38\x00\x01\xc0\x38\x00\x01\xc0'\
|
||||
b'\x38\x00\x01\xc0\x38\x00\x01\xc0\x1c\x00\x03\x80\x1c\x00\x03\x80'\
|
||||
b'\x1e\x00\x07\x80\x0f\x00\x0f\x00\x07\x80\x1e\x00\x07\xe0\x7e\x00'\
|
||||
b'\x01\xff\xfc\x00\x00\xff\xf0\x00\x00\x3f\xc0\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00'\
|
||||
b'\x00\x1f\xff\x80\x1f\xff\xe0\x1f\xff\xf0\x1c\x00\x78\x1c\x00\x38'\
|
||||
b'\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c\x00\x1c\x1c'\
|
||||
b'\x00\x38\x1c\x00\xf8\x1f\xff\xf0\x1f\xff\xe0\x1f\xff\x80\x1c\x00'\
|
||||
b'\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00'\
|
||||
b'\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x3f\x80'\
|
||||
b'\x00\x00\xff\xe0\x00\x03\xff\xf8\x00\x07\xe0\xfc\x00\x0f\x80\x3e'\
|
||||
b'\x00\x0e\x00\x1e\x00\x1e\x00\x0f\x00\x1c\x00\x07\x00\x1c\x00\x07'\
|
||||
b'\x00\x38\x00\x03\x80\x38\x00\x03\x80\x38\x00\x03\x80\x38\x00\x03'\
|
||||
b'\x80\x38\x00\x03\x80\x38\x00\x03\x80\x38\x00\x03\x80\x38\x00\x03'\
|
||||
b'\x80\x1c\x00\x07\x00\x1c\x02\x07\x00\x1e\x03\x8f\x00\x0e\x03\xfe'\
|
||||
b'\x00\x0f\x81\xfe\x00\x07\xe0\xfc\x00\x03\xff\xfe\x00\x00\xff\xff'\
|
||||
b'\x80\x00\x3f\xcf\xc0\x00\x00\x03\x80\x00\x00\x00\x80\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x1f\xff\xc0\x00\x1f'\
|
||||
b'\xff\xf0\x00\x1f\xff\xf8\x00\x1c\x00\x7c\x00\x1c\x00\x1e\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x1e\x00\x1c\x00\x7c\x00\x1f\xff\xf8\x00\x1f\xff\xf0\x00\x1f'\
|
||||
b'\xff\xc0\x00\x1c\x0f\x00\x00\x1c\x07\xc0\x00\x1c\x03\xc0\x00\x1c'\
|
||||
b'\x01\xe0\x00\x1c\x00\xf0\x00\x1c\x00\xf0\x00\x1c\x00\x78\x00\x1c'\
|
||||
b'\x00\x3c\x00\x1c\x00\x3c\x00\x1c\x00\x1e\x00\x1c\x00\x1e\x00\x1c'\
|
||||
b'\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x18\x00\x00\x00\x00\x00\xfe\x00\x03\xff\xc0\x07\xff'\
|
||||
b'\xe0\x0f\x81\xf0\x1e\x00\xf0\x1c\x00\x78\x1c\x00\x38\x1c\x00\x38'\
|
||||
b'\x1e\x00\x00\x0f\x00\x00\x0f\xe0\x00\x07\xfe\x00\x01\xff\xc0\x00'\
|
||||
b'\x7f\xf0\x00\x07\xf8\x00\x00\xf8\x00\x00\x3c\x38\x00\x1c\x38\x00'\
|
||||
b'\x1c\x3c\x00\x1c\x1c\x00\x3c\x1e\x00\x38\x0f\x80\xf8\x07\xff\xf0'\
|
||||
b'\x03\xff\xe0\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00'\
|
||||
b'\x00\x00\x00\x7f\xff\xf0\x7f\xff\xf0\x7f\xff\xf0\x00\x70\x00\x00'\
|
||||
b'\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70'\
|
||||
b'\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00'\
|
||||
b'\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00'\
|
||||
b'\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1c'\
|
||||
b'\x00\x0e\x00\x1c\x00\x0e\x00\x1c\x00\x0e\x00\x1e\x00\x1e\x00\x0e'\
|
||||
b'\x00\x1c\x00\x0f\x00\x3c\x00\x07\xc0\xf8\x00\x07\xff\xf0\x00\x01'\
|
||||
b'\xff\xe0\x00\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x70\x00\x07\x78'\
|
||||
b'\x00\x0f\x38\x00\x0e\x38\x00\x0e\x3c\x00\x1e\x1c\x00\x1c\x1e\x00'\
|
||||
b'\x3c\x0e\x00\x38\x0e\x00\x38\x0f\x00\x78\x07\x00\x70\x07\x00\x70'\
|
||||
b'\x03\x80\xe0\x03\x80\xe0\x03\xc1\xe0\x01\xc1\xc0\x01\xc1\xc0\x01'\
|
||||
b'\xe3\xc0\x00\xe3\x80\x00\xe7\x80\x00\x77\x00\x00\x77\x00\x00\x7f'\
|
||||
b'\x00\x00\x3e\x00\x00\x3e\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x24\x00\x00\x00\x00\x00\x00\xe0\x01\xf0\x00\xe0\xe0\x01'\
|
||||
b'\xf0\x00\xe0\x70\x01\xf0\x01\xc0\x70\x03\xb8\x01\xc0\x70\x03\xb8'\
|
||||
b'\x01\xc0\x70\x03\xb8\x01\xc0\x38\x07\x1c\x03\x80\x38\x07\x1c\x03'\
|
||||
b'\x80\x38\x07\x1c\x03\x80\x38\x0f\x1e\x03\x80\x1c\x0e\x0e\x07\x00'\
|
||||
b'\x1c\x0e\x0e\x07\x00\x1c\x1e\x0e\x07\x00\x1c\x1c\x07\x07\x00\x0e'\
|
||||
b'\x1c\x07\x0e\x00\x0e\x1c\x07\x0e\x00\x0e\x38\x03\x8e\x00\x0e\x38'\
|
||||
b'\x03\x8e\x00\x0f\x38\x03\x9e\x00\x07\x78\x01\xdc\x00\x07\x70\x01'\
|
||||
b'\xdc\x00\x07\x70\x01\xdc\x00\x07\xf0\x01\xfc\x00\x03\xe0\x00\xf8'\
|
||||
b'\x00\x03\xe0\x00\xf8\x00\x03\xe0\x00\xf8\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x17\x00\x00\x00\x00\x78\x00\x3c\x3c\x00\x78\x1c\x00'\
|
||||
b'\x70\x1e\x00\xf0\x0f\x01\xe0\x07\x01\xc0\x03\x83\x80\x03\xc7\x80'\
|
||||
b'\x01\xef\x00\x00\xee\x00\x00\xfe\x00\x00\x7c\x00\x00\x38\x00\x00'\
|
||||
b'\x7c\x00\x00\xfe\x00\x01\xef\x00\x01\xc7\x00\x03\xc7\x80\x07\x83'\
|
||||
b'\xc0\x07\x01\xc0\x0e\x00\xe0\x1e\x00\xf0\x3c\x00\x78\x38\x00\x38'\
|
||||
b'\x78\x00\x3c\xf0\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00'\
|
||||
b'\x00\x00\x00\xf0\x00\x1e\x70\x00\x1c\x38\x00\x38\x3c\x00\x78\x1c'\
|
||||
b'\x00\x70\x0e\x00\xe0\x0f\x01\xe0\x07\x01\xc0\x03\x83\x80\x03\xc7'\
|
||||
b'\x80\x01\xc7\x00\x00\xee\x00\x00\xfe\x00\x00\x7c\x00\x00\x38\x00'\
|
||||
b'\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00'\
|
||||
b'\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x00\x1f\xff'\
|
||||
b'\xf0\x1f\xff\xf0\x1f\xff\xf0\x00\x00\xf0\x00\x01\xe0\x00\x03\xc0'\
|
||||
b'\x00\x03\x80\x00\x07\x80\x00\x0f\x00\x00\x1e\x00\x00\x1c\x00\x00'\
|
||||
b'\x38\x00\x00\x78\x00\x00\xf0\x00\x01\xe0\x00\x01\xc0\x00\x03\xc0'\
|
||||
b'\x00\x07\x80\x00\x0f\x00\x00\x0e\x00\x00\x1c\x00\x00\x3c\x00\x00'\
|
||||
b'\x78\x00\x00\x7f\xff\xf8\x7f\xff\xf8\x7f\xff\xf8\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0a\x00\x00\x00\x3f\x80\x3f\x80\x3f\x80\x38\x00'\
|
||||
b'\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00'\
|
||||
b'\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00'\
|
||||
b'\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00'\
|
||||
b'\x38\x00\x38\x00\x3f\x80\x3f\x80\x3f\x80\x00\x00\x0a\x00\x00\x00'\
|
||||
b'\xe0\x00\xe0\x00\x70\x00\x70\x00\x70\x00\x70\x00\x38\x00\x38\x00'\
|
||||
b'\x38\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x0e\x00\x0e\x00\x0e\x00'\
|
||||
b'\x0e\x00\x07\x00\x07\x00\x07\x00\x07\x80\x03\x80\x03\x80\x03\x80'\
|
||||
b'\x01\xc0\x01\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0a\x00\x00\x00\x7f\x00\x7f\x00\x7f\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x7f\x00\x7f\x00\x7f\x00\x00\x00\x11\x00\x00\x00'\
|
||||
b'\x00\x01\xc0\x00\x03\xe0\x00\x03\xe0\x00\x07\x70\x00\x07\x70\x00'\
|
||||
b'\x06\x30\x00\x0e\x38\x00\x0e\x38\x00\x1c\x1c\x00\x1c\x1c\x00\x38'\
|
||||
b'\x0e\x00\x38\x0e\x00\x38\x0e\x00\x70\x07\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf8\xff\xff\xf8'\
|
||||
b'\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0c\x00\x00\x00\x78\x00\x3c\x00\x1c\x00\x0c\x00\x06\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x01\xfc\x00\x07\xff\x00\x0f\xff\x80\x1e\x07\xc0'\
|
||||
b'\x3c\x01\xc0\x38\x01\xc0\x00\x01\xc0\x00\x07\xc0\x01\xff\xc0\x0f'\
|
||||
b'\xff\xc0\x1f\xf9\xc0\x1e\x01\xc0\x38\x01\xc0\x38\x03\xc0\x38\x07'\
|
||||
b'\xc0\x3c\x0f\xc0\x1f\xff\xc0\x0f\xfd\xc0\x07\xf0\xe0\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x38\x00\x00\x38\x00\x00'\
|
||||
b'\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38'\
|
||||
b'\xf8\x00\x3b\xfe\x00\x3f\xff\x00\x3f\x0f\x80\x3e\x07\x80\x3c\x03'\
|
||||
b'\x80\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x01\xc0\x3c\x03\x80\x3c\x07\x80\x3f\x0f\x00\x3f'\
|
||||
b'\xff\x00\x3b\xfe\x00\x38\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x00\x07\xfc\x00'\
|
||||
b'\x0f\xfe\x00\x1e\x0f\x00\x3c\x07\x80\x38\x03\x80\x70\x00\x00\x70'\
|
||||
b'\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x00\x00\x70\x03'\
|
||||
b'\x80\x38\x03\x80\x3c\x07\x00\x3e\x0f\x00\x1f\xfe\x00\x0f\xfc\x00'\
|
||||
b'\x03\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00'\
|
||||
b'\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00'\
|
||||
b'\x01\xc0\x00\x01\xc0\x01\xf1\xc0\x07\xfd\xc0\x0f\xff\xc0\x1f\x0f'\
|
||||
b'\xc0\x1c\x07\xc0\x1c\x03\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x1c\x03\xc0\x1e'\
|
||||
b'\x07\xc0\x0f\x0f\xc0\x0f\xff\xc0\x07\xfd\xc0\x01\xf1\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x01\xf8\x00\x07\xfe\x00\x0f\xff\x00\x0f\x0f\x80\x1c\x03\x80\x18'\
|
||||
b'\x01\x80\x38\x01\xc0\x3f\xff\xc0\x3f\xff\xc0\x3f\xff\xc0\x38\x00'\
|
||||
b'\x00\x38\x00\x00\x38\x00\x00\x1c\x01\xc0\x1e\x03\x80\x1f\x07\x80'\
|
||||
b'\x0f\xff\x00\x07\xfe\x00\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0b\x00\x00\x00\x07\xe0\x0f\xe0\x1f\xe0\x1e\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\xff\xc0\xff\xc0\xff\xc0\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x01\xf1\xc0\x07\xfd\xc0\x0f\xff\xc0\x0f\x0f\xc0\x1e'\
|
||||
b'\x07\xc0\x1c\x03\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01'\
|
||||
b'\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x1c\x03\xc0\x1e\x07\xc0'\
|
||||
b'\x0f\x0f\xc0\x0f\xff\xc0\x07\xfd\xc0\x01\xf9\xc0\x00\x01\xc0\x38'\
|
||||
b'\x01\xc0\x3c\x03\x80\x3e\x07\x80\x1f\xff\x00\x0f\xfe\x00\x03\xf8'\
|
||||
b'\x00\x00\x00\x00\x13\x00\x00\x00\x00\x38\x00\x00\x38\x00\x00\x38'\
|
||||
b'\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\xf8'\
|
||||
b'\x00\x3b\xfe\x00\x3f\xff\x00\x3f\x0f\x80\x3c\x07\x80\x3c\x03\x80'\
|
||||
b'\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38'\
|
||||
b'\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03'\
|
||||
b'\x80\x38\x03\x80\x38\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07'\
|
||||
b'\x00\x00\x38\x38\x38\x00\x00\x00\x00\x38\x38\x38\x38\x38\x38\x38'\
|
||||
b'\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0b\x00\x00\x00\x07\x00\x07\x00\x07\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x00\x0f\x00\x7e\x00\x7e\x00\xfc\x00\x00\x00\x13\x00\x00\x00'\
|
||||
b'\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00\x1c\x00\x00'\
|
||||
b'\x1c\x00\x00\x1c\x00\x00\x1c\x03\xc0\x1c\x07\x80\x1c\x0f\x00\x1c'\
|
||||
b'\x1e\x00\x1c\x7c\x00\x1c\xf8\x00\x1d\xe0\x00\x1f\xc0\x00\x1f\xe0'\
|
||||
b'\x00\x1f\xf0\x00\x1e\x78\x00\x1c\x78\x00\x1c\x3c\x00\x1c\x1e\x00'\
|
||||
b'\x1c\x0f\x00\x1c\x0f\x00\x1c\x07\x80\x1c\x03\xc0\x1c\x01\xe0\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x38\x38\x38\x38\x38\x38'\
|
||||
b'\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38'\
|
||||
b'\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x7c'\
|
||||
b'\x0f\x80\x1d\xfe\x3f\xc0\x1d\xff\x7f\xe0\x1f\x87\xe0\xf0\x1e\x07'\
|
||||
b'\xc0\x70\x1e\x03\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x1c\x03'\
|
||||
b'\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x1c\x03'\
|
||||
b'\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x1c\x03'\
|
||||
b'\x80\x70\x1c\x03\x80\x70\x1c\x03\x80\x70\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x38\xf8\x00\x3b\xfe\x00\x3f\xff\x00\x3f\x0f\x80'\
|
||||
b'\x3c\x07\x80\x3c\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38'\
|
||||
b'\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03'\
|
||||
b'\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'\
|
||||
b'\xf8\x00\x07\xfe\x00\x0f\xff\x00\x1f\x0f\x80\x1e\x07\x80\x1c\x03'\
|
||||
b'\x80\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x01\xc0\x1c\x03\x80\x1e\x07\x80\x1f\x0f\x80\x0f'\
|
||||
b'\xff\x00\x07\xfe\x00\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\xf8\x00\x3b\xfe\x00'\
|
||||
b'\x3b\xff\x00\x3f\x0f\x80\x3e\x07\x80\x3c\x03\x80\x38\x01\xc0\x38'\
|
||||
b'\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01'\
|
||||
b'\xc0\x3c\x03\x80\x3c\x07\x80\x3f\x0f\x00\x3f\xff\x00\x3b\xfc\x00'\
|
||||
b'\x38\xf8\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38\x00\x00\x38'\
|
||||
b'\x00\x00\x38\x00\x00\x38\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x01\xf1\xc0\x07\xfd\xc0\x0f\xfd\xc0\x1f\x0f'\
|
||||
b'\xc0\x1e\x07\xc0\x1c\x03\xc0\x38\x03\xc0\x38\x01\xc0\x38\x01\xc0'\
|
||||
b'\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x38\x01\xc0\x1c\x03\xc0\x1e'\
|
||||
b'\x07\xc0\x0f\x0f\xc0\x0f\xff\xc0\x03\xfd\xc0\x01\xf1\xc0\x00\x01'\
|
||||
b'\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0\x00\x01\xc0'\
|
||||
b'\x00\x01\xc0\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x39\xf0\x3b\xf0\x3f\xe0\x3e\x00'\
|
||||
b'\x3c\x00\x3c\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00'\
|
||||
b'\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\xf0\x00\x1f\xfc\x00\x3f\xfe'\
|
||||
b'\x00\x78\x0f\x00\x70\x07\x00\x70\x00\x00\x78\x00\x00\x3f\x00\x00'\
|
||||
b'\x3f\xf0\x00\x0f\xfe\x00\x01\xff\x00\x00\x1f\x80\x00\x07\x80\x70'\
|
||||
b'\x03\x80\x78\x03\x80\x3c\x0f\x00\x3f\xff\x00\x0f\xfe\x00\x03\xf8'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\xff\xc0\xff\xc0\xff'\
|
||||
b'\xc0\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1f\xc0\x0f\xc0\x07'\
|
||||
b'\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x03\x80\x38\x03'\
|
||||
b'\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80'\
|
||||
b'\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38\x03\x80\x38'\
|
||||
b'\x03\x80\x38\x07\x80\x3c\x07\x80\x3e\x1f\x80\x1f\xfb\x80\x0f\xf3'\
|
||||
b'\x80\x03\xe3\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xe0\x03\x80\x70\x07\x00\x70\x07\x00\x70'\
|
||||
b'\x07\x00\x38\x0e\x00\x38\x0e\x00\x3c\x1e\x00\x1c\x1c\x00\x1c\x1c'\
|
||||
b'\x00\x0e\x38\x00\x0e\x38\x00\x0e\x38\x00\x07\x70\x00\x07\x70\x00'\
|
||||
b'\x07\x70\x00\x03\xe0\x00\x03\xe0\x00\x01\xc0\x00\x01\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x0e\x01\xc0\x70\x0e\x01'\
|
||||
b'\xc0\x70\x1f\x01\xc0\x38\x1f\x03\x80\x38\x1b\x03\x80\x38\x1b\x07'\
|
||||
b'\x80\x1c\x3b\x87\x00\x1c\x39\x87\x00\x0e\x31\x8e\x00\x0e\x31\x8e'\
|
||||
b'\x00\x0e\x31\x8e\x00\x07\x71\xdc\x00\x07\x60\xdc\x00\x07\x60\xdc'\
|
||||
b'\x00\x03\x60\xd8\x00\x03\xe0\xf8\x00\x03\xc0\x70\x00\x01\xc0\x70'\
|
||||
b'\x00\x01\xc0\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xf0\x07\x70\x0e\x38\x1e\x3c\x1c\x1c'\
|
||||
b'\x38\x0e\x78\x0f\x70\x07\xe0\x03\xe0\x03\xc0\x03\xc0\x07\xe0\x0f'\
|
||||
b'\xf0\x0e\x70\x1e\x38\x3c\x3c\x38\x1c\x70\x0e\xf0\x0f\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\xe0\x03\x80\x70\x07\x80\x70\x07\x00'\
|
||||
b'\x78\x07\x00\x38\x0f\x00\x38\x0e\x00\x3c\x0e\x00\x1c\x1c\x00\x1c'\
|
||||
b'\x1c\x00\x0e\x3c\x00\x0e\x38\x00\x0f\x38\x00\x07\x78\x00\x07\x70'\
|
||||
b'\x00\x07\xf0\x00\x03\xe0\x00\x03\xe0\x00\x01\xe0\x00\x01\xc0\x00'\
|
||||
b'\x01\xc0\x00\x03\xc0\x00\x03\x80\x00\x07\x80\x00\x3f\x00\x00\x3e'\
|
||||
b'\x00\x00\x3c\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x7f\xff\x00\x7f\xff\x00\x7f\xff\x00\x00\x1e\x00\x00\x3c'\
|
||||
b'\x00\x00\x78\x00\x00\x70\x00\x00\xf0\x00\x01\xe0\x00\x03\xc0\x00'\
|
||||
b'\x07\x80\x00\x0f\x00\x00\x1e\x00\x00\x3c\x00\x00\x78\x00\x00\x70'\
|
||||
b'\x00\x00\xff\xff\x00\xff\xff\x00\xff\xff\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0c\x00\x00\x00\x00\xf0\x03\xf0\x03\xf0\x07\x80\x07'\
|
||||
b'\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07'\
|
||||
b'\x00\x0e\x00\x1e\x00\x7c\x00\x70\x00\x7c\x00\x1e\x00\x0e\x00\x07'\
|
||||
b'\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07\x00\x07'\
|
||||
b'\x00\x07\x80\x03\xf0\x03\xf0\x00\xf0\x00\x00\x09\x00\x00\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c\x00\x1c'\
|
||||
b'\x00\x1c\x00\x0c\x00\x00\x00\xf0\x00\xfc\x00\xfc\x00\x1e\x00\x0e'\
|
||||
b'\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e'\
|
||||
b'\x00\x07\x00\x07\x80\x03\xe0\x00\xe0\x03\xe0\x07\x80\x0f\x00\x0e'\
|
||||
b'\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e\x00\x0e'\
|
||||
b'\x00\x1e\x00\xfc\x00\xfc\x00\xf0\x00\x00\x00\x15\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x80'\
|
||||
b'\x00\x1f\xf0\x10\x3f\xfc\x70\x38\x7f\xf0\x20\x1f\xe0\x00\x07\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x6b\x00\xb3\x00\xfb\x00\x43\x01\xae\x01\x19\x02\xa7\x02'\
|
||||
b'\x12\x03\x37\x03\x7f\x03\xc7\x03\x0f\x04\x7a\x04\xc2\x04\x0a\x05'\
|
||||
b'\x52\x05\x9a\x05\x05\x06\x70\x06\xdb\x06\x46\x07\xb1\x07\x1c\x08'\
|
||||
b'\x87\x08\xf2\x08\x5d\x09\xc8\x09\x10\x0a\x58\x0a\xc3\x0a\x2e\x0b'\
|
||||
b'\x99\x0b\x04\x0c\xb5\x0c\x20\x0d\x8b\x0d\x19\x0e\xa7\x0e\x12\x0f'\
|
||||
b'\x7d\x0f\x0b\x10\x99\x10\xe1\x10\x4c\x11\xb7\x11\x22\x12\xb0\x12'\
|
||||
b'\x3e\x13\xcc\x13\x37\x14\xc5\x14\x53\x15\xbe\x15\x29\x16\xb7\x16'\
|
||||
b'\x22\x17\xd3\x17\x3e\x18\xa9\x18\x14\x19\x5c\x19\xa4\x19\xec\x19'\
|
||||
b'\x57\x1a\xc2\x1a\x0a\x1b\x75\x1b\xe0\x1b\x4b\x1c\xb6\x1c\x21\x1d'\
|
||||
b'\x69\x1d\xd4\x1d\x3f\x1e\x64\x1e\xac\x1e\x17\x1f\x3c\x1f\xca\x1f'\
|
||||
b'\x35\x20\xa0\x20\x0b\x21\x76\x21\xbe\x21\x29\x22\x71\x22\xdc\x22'\
|
||||
b'\x47\x23\xd5\x23\x1d\x24\x88\x24\xf3\x24\x3b\x25\x83\x25\xcb\x25'\
|
||||
b'\x36\x26'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
_mvi = memoryview(_index)
|
||||
ifb = lambda l : l[0] | (l[1] << 8)
|
||||
|
||||
def get_ch(ch):
|
||||
oc = ord(ch)
|
||||
ioff = 2 * (oc - 32 + 1) if oc >= 32 and oc <= 126 else 0
|
||||
doff = ifb(_mvi[ioff : ])
|
||||
width = ifb(_mvfont[doff : ])
|
||||
|
||||
next_offs = doff + 2 + ((width - 1)//8 + 1) * 35
|
||||
return _mvfont[doff + 2:next_offs], 35, width
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
# Code generated by font_to_py.py.
|
||||
# Font: Arial.ttf Char set: 0123456789:
|
||||
# Cmd: ./font_to_py.py Arial.ttf 50 arial_50.py -x -c 0123456789:
|
||||
version = '0.33'
|
||||
|
||||
def height():
|
||||
return 50
|
||||
|
||||
def baseline():
|
||||
return 49
|
||||
|
||||
def max_width():
|
||||
return 37
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 48
|
||||
|
||||
def max_ch():
|
||||
return 63
|
||||
|
||||
_font =\
|
||||
b'\x25\x00\x00\x03\xfe\x00\x00\x00\x1f\xff\xc0\x00\x00\x7f\xff\xf0'\
|
||||
b'\x00\x00\xff\xff\xf8\x00\x01\xff\xff\xfc\x00\x03\xff\xff\xfe\x00'\
|
||||
b'\x07\xfe\x03\xff\x00\x07\xf8\x00\xff\x80\x0f\xf0\x00\x7f\x80\x0f'\
|
||||
b'\xe0\x00\x3f\x80\x0f\xc0\x00\x1f\xc0\x1f\xc0\x00\x1f\xc0\x1f\xc0'\
|
||||
b'\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x03\x80\x00\x0f\xc0\x00\x00\x00'\
|
||||
b'\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x1f\x80\x00\x00\x00\x3f'\
|
||||
b'\x80\x00\x00\x00\x7f\x00\x00\x00\x00\xff\x00\x00\x00\x01\xfe\x00'\
|
||||
b'\x00\x00\x03\xfc\x00\x00\x00\x07\xf8\x00\x00\x00\x0f\xf0\x00\x00'\
|
||||
b'\x00\x1f\xe0\x00\x00\x00\x3f\xc0\x00\x00\x00\x7f\x80\x00\x00\x00'\
|
||||
b'\x7f\x00\x00\x00\x00\xfe\x00\x00\x00\x00\xfc\x00\x00\x00\x01\xfc'\
|
||||
b'\x00\x00\x00\x01\xfc\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf8\x00'\
|
||||
b'\x00\x00\x01\xf8\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf8\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf8\x00\x00\x00\x01'\
|
||||
b'\xf8\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf8'\
|
||||
b'\x00\x00\x00\x01\xf8\x00\x00\x00\x00\x00\x00\x00\x25\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x03\xfe\x00\x00\x00\x0f\xff\x80\x00\x00\x3f\xff'\
|
||||
b'\xe0\x00\x00\x7f\xff\xf0\x00\x00\xff\xff\xf8\x00\x01\xff\xff\xfc'\
|
||||
b'\x00\x03\xfe\x07\xfc\x00\x03\xfc\x01\xfe\x00\x07\xf0\x00\xfe\x00'\
|
||||
b'\x07\xf0\x00\x7f\x00\x07\xe0\x00\x3f\x00\x0f\xe0\x00\x3f\x00\x0f'\
|
||||
b'\xc0\x00\x1f\x80\x0f\xc0\x00\x1f\x80\x0f\xc0\x00\x1f\x80\x0f\xc0'\
|
||||
b'\x00\x1f\x80\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00'\
|
||||
b'\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f'\
|
||||
b'\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0'\
|
||||
b'\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f'\
|
||||
b'\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80'\
|
||||
b'\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x0f\xc0\x00\x1f\x80\x0f\xc0\x00'\
|
||||
b'\x1f\x80\x0f\xc0\x00\x1f\x80\x0f\xc0\x00\x1f\x80\x0f\xe0\x00\x3f'\
|
||||
b'\x80\x07\xe0\x00\x3f\x00\x07\xf0\x00\x7f\x00\x07\xf8\x00\xff\x00'\
|
||||
b'\x03\xfc\x01\xfe\x00\x03\xff\x07\xfe\x00\x01\xff\xff\xfc\x00\x00'\
|
||||
b'\xff\xff\xf8\x00\x00\x7f\xff\xf0\x00\x00\x3f\xff\xe0\x00\x00\x0f'\
|
||||
b'\xff\x80\x00\x00\x03\xfe\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x07\x80\x00\x00\x00\x0f\x80\x00\x00\x00\x0f\x80\x00\x00\x00'\
|
||||
b'\x1f\x80\x00\x00\x00\x3f\x80\x00\x00\x00\x7f\x80\x00\x00\x00\xff'\
|
||||
b'\x80\x00\x00\x03\xff\x80\x00\x00\x07\xff\x80\x00\x00\x0f\xff\x80'\
|
||||
b'\x00\x00\x3f\xff\x80\x00\x00\xff\xdf\x80\x00\x01\xff\x9f\x80\x00'\
|
||||
b'\x01\xfe\x1f\x80\x00\x01\xfc\x1f\x80\x00\x01\xf0\x1f\x80\x00\x01'\
|
||||
b'\xc0\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00'\
|
||||
b'\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f'\
|
||||
b'\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80'\
|
||||
b'\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00'\
|
||||
b'\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00'\
|
||||
b'\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00'\
|
||||
b'\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f'\
|
||||
b'\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80'\
|
||||
b'\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00'\
|
||||
b'\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00\x03\xfe\x00\x00'\
|
||||
b'\x00\x1f\xff\xc0\x00\x00\x7f\xff\xe0\x00\x01\xff\xff\xf8\x00\x03'\
|
||||
b'\xff\xff\xfc\x00\x03\xff\xff\xfc\x00\x07\xfe\x07\xfe\x00\x0f\xf0'\
|
||||
b'\x00\xff\x00\x0f\xe0\x00\x7f\x00\x0f\xc0\x00\x3f\x00\x1f\xc0\x00'\
|
||||
b'\x3f\x80\x1f\x80\x00\x1f\x80\x1f\x80\x00\x1f\x80\x03\x80\x00\x1f'\
|
||||
b'\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80'\
|
||||
b'\x00\x00\x00\x3f\x00\x00\x00\x00\x3f\x00\x00\x00\x00\x7f\x00\x00'\
|
||||
b'\x00\x00\xfe\x00\x00\x00\x01\xfe\x00\x00\x00\x03\xfc\x00\x00\x00'\
|
||||
b'\x07\xf8\x00\x00\x00\x0f\xf0\x00\x00\x00\x1f\xe0\x00\x00\x00\x3f'\
|
||||
b'\xe0\x00\x00\x00\x7f\xc0\x00\x00\x00\xff\x80\x00\x00\x01\xfe\x00'\
|
||||
b'\x00\x00\x03\xfc\x00\x00\x00\x07\xf8\x00\x00\x00\x1f\xf0\x00\x00'\
|
||||
b'\x00\x3f\xe0\x00\x00\x00\x7f\xc0\x00\x00\x00\xff\x80\x00\x00\x01'\
|
||||
b'\xfe\x00\x00\x00\x03\xfc\x00\x00\x00\x07\xf8\x00\x00\x00\x07\xf0'\
|
||||
b'\x00\x00\x00\x0f\xe0\x00\x00\x00\x0f\xe0\x00\x00\x00\x1f\xff\xff'\
|
||||
b'\xff\x80\x1f\xff\xff\xff\x80\x3f\xff\xff\xff\x80\x3f\xff\xff\xff'\
|
||||
b'\x80\x3f\xff\xff\xff\x80\x3f\xff\xff\xff\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x25\x00\x00\x00\x00\x00\x00\x00\x07\xfc\x00\x00\x00\x1f\xff\x80'\
|
||||
b'\x00\x00\x7f\xff\xe0\x00\x00\xff\xff\xf0\x00\x01\xff\xff\xf8\x00'\
|
||||
b'\x03\xff\xff\xfc\x00\x07\xfc\x07\xfe\x00\x0f\xf0\x01\xfe\x00\x0f'\
|
||||
b'\xe0\x00\xfe\x00\x0f\xc0\x00\x7f\x00\x1f\xc0\x00\x3f\x00\x1f\x80'\
|
||||
b'\x00\x3f\x00\x03\x80\x00\x3f\x00\x00\x00\x00\x3f\x00\x00\x00\x00'\
|
||||
b'\x3f\x00\x00\x00\x00\x7e\x00\x00\x00\x00\xfe\x00\x00\x00\x01\xfc'\
|
||||
b'\x00\x00\x00\x0f\xf8\x00\x00\x01\xff\xf0\x00\x00\x01\xff\xe0\x00'\
|
||||
b'\x00\x01\xff\xe0\x00\x00\x01\xff\xf8\x00\x00\x01\xff\xfc\x00\x00'\
|
||||
b'\x01\x8f\xfe\x00\x00\x00\x01\xff\x00\x00\x00\x00\x7f\x00\x00\x00'\
|
||||
b'\x00\x3f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\xc0\x00\x00\x00'\
|
||||
b'\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f'\
|
||||
b'\xc0\x00\x00\x00\x0f\xc0\x03\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0'\
|
||||
b'\x1f\xc0\x00\x1f\x80\x1f\xc0\x00\x1f\x80\x0f\xe0\x00\x3f\x80\x0f'\
|
||||
b'\xf0\x00\x7f\x00\x07\xf8\x00\xff\x00\x07\xfe\x03\xfe\x00\x03\xff'\
|
||||
b'\xff\xfc\x00\x01\xff\xff\xf8\x00\x00\xff\xff\xf0\x00\x00\x7f\xff'\
|
||||
b'\xe0\x00\x00\x1f\xff\x80\x00\x00\x03\xfc\x00\x00\x25\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x00\x00\x00\x03'\
|
||||
b'\xf0\x00\x00\x00\x07\xf0\x00\x00\x00\x0f\xf0\x00\x00\x00\x0f\xf0'\
|
||||
b'\x00\x00\x00\x1f\xf0\x00\x00\x00\x3f\xf0\x00\x00\x00\x7f\xf0\x00'\
|
||||
b'\x00\x00\x7f\xf0\x00\x00\x00\xff\xf0\x00\x00\x01\xff\xf0\x00\x00'\
|
||||
b'\x01\xff\xf0\x00\x00\x03\xfb\xf0\x00\x00\x07\xf3\xf0\x00\x00\x0f'\
|
||||
b'\xf3\xf0\x00\x00\x0f\xe3\xf0\x00\x00\x1f\xc3\xf0\x00\x00\x3f\x83'\
|
||||
b'\xf0\x00\x00\x7f\x83\xf0\x00\x00\x7f\x03\xf0\x00\x00\xfe\x03\xf0'\
|
||||
b'\x00\x01\xfc\x03\xf0\x00\x03\xfc\x03\xf0\x00\x03\xf8\x03\xf0\x00'\
|
||||
b'\x07\xf0\x03\xf0\x00\x0f\xf0\x03\xf0\x00\x0f\xe0\x03\xf0\x00\x1f'\
|
||||
b'\xc0\x03\xf0\x00\x3f\x80\x03\xf0\x00\x7f\x80\x03\xf0\x00\x7f\xff'\
|
||||
b'\xff\xff\xc0\x7f\xff\xff\xff\xc0\x7f\xff\xff\xff\xc0\x7f\xff\xff'\
|
||||
b'\xff\xc0\x7f\xff\xff\xff\xc0\x7f\xff\xff\xff\xc0\x00\x00\x03\xf0'\
|
||||
b'\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00'\
|
||||
b'\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00'\
|
||||
b'\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00'\
|
||||
b'\x03\xf0\x00\x00\x00\x00\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x7f\xff\xff\x00\x00\x7f\xff\xff\x00\x00\xff'\
|
||||
b'\xff\xff\x00\x00\xff\xff\xff\x00\x00\xff\xff\xff\x00\x00\xff\xff'\
|
||||
b'\xff\x00\x00\xfc\x00\x00\x00\x01\xfc\x00\x00\x00\x01\xf8\x00\x00'\
|
||||
b'\x00\x01\xf8\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf8\x00\x00\x00'\
|
||||
b'\x03\xf8\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00\x03'\
|
||||
b'\xf0\x7f\x00\x00\x03\xf3\xff\xc0\x00\x07\xf7\xff\xf0\x00\x07\xff'\
|
||||
b'\xff\xf8\x00\x07\xff\xff\xfc\x00\x07\xff\xff\xfe\x00\x07\xfe\x03'\
|
||||
b'\xff\x00\x0f\xf8\x00\xff\x00\x0f\xf0\x00\x7f\x80\x0f\xe0\x00\x3f'\
|
||||
b'\x80\x01\xc0\x00\x1f\x80\x00\x00\x00\x1f\xc0\x00\x00\x00\x0f\xc0'\
|
||||
b'\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00'\
|
||||
b'\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00'\
|
||||
b'\x00\x0f\xc0\x1f\x80\x00\x1f\x80\x1f\x80\x00\x1f\x80\x1f\xc0\x00'\
|
||||
b'\x1f\x80\x0f\xc0\x00\x3f\x00\x0f\xe0\x00\x7f\x00\x07\xf0\x00\xfe'\
|
||||
b'\x00\x07\xfc\x03\xfe\x00\x03\xff\xff\xfc\x00\x01\xff\xff\xf8\x00'\
|
||||
b'\x00\xff\xff\xf0\x00\x00\x7f\xff\xe0\x00\x00\x1f\xff\x80\x00\x00'\
|
||||
b'\x07\xfc\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00\x01\xfe\x00\x00'\
|
||||
b'\x00\x0f\xff\xc0\x00\x00\x3f\xff\xf0\x00\x00\x7f\xff\xf8\x00\x00'\
|
||||
b'\xff\xff\xfc\x00\x01\xff\xff\xfe\x00\x03\xff\x03\xfe\x00\x03\xf8'\
|
||||
b'\x00\xff\x00\x07\xf0\x00\x7f\x00\x07\xf0\x00\x3f\x00\x0f\xe0\x00'\
|
||||
b'\x3f\x80\x0f\xc0\x00\x1f\x80\x0f\xc0\x00\x00\x00\x1f\x80\x00\x00'\
|
||||
b'\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00'\
|
||||
b'\x1f\x00\xff\x00\x00\x3f\x07\xff\xc0\x00\x3f\x0f\xff\xf0\x00\x3f'\
|
||||
b'\x3f\xff\xf8\x00\x3f\x7f\xff\xfc\x00\x3f\x7f\xff\xfe\x00\x3f\xfe'\
|
||||
b'\x03\xff\x00\x3f\xf0\x00\xff\x00\x3f\xe0\x00\x7f\x80\x3f\xc0\x00'\
|
||||
b'\x3f\x80\x3f\x80\x00\x1f\x80\x3f\x80\x00\x1f\xc0\x3f\x00\x00\x0f'\
|
||||
b'\xc0\x3f\x00\x00\x0f\xc0\x3f\x00\x00\x0f\xc0\x3f\x00\x00\x0f\xc0'\
|
||||
b'\x1f\x00\x00\x0f\xc0\x1f\x00\x00\x0f\xc0\x1f\x00\x00\x0f\xc0\x1f'\
|
||||
b'\x80\x00\x1f\xc0\x1f\x80\x00\x1f\x80\x0f\xc0\x00\x1f\x80\x0f\xc0'\
|
||||
b'\x00\x3f\x80\x07\xe0\x00\x7f\x00\x07\xf8\x00\xff\x00\x03\xfe\x03'\
|
||||
b'\xfe\x00\x01\xff\xff\xfc\x00\x01\xff\xff\xfc\x00\x00\x7f\xff\xf8'\
|
||||
b'\x00\x00\x3f\xff\xe0\x00\x00\x0f\xff\xc0\x00\x00\x01\xfe\x00\x00'\
|
||||
b'\x25\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xff\xff\xff'\
|
||||
b'\xc0\x1f\xff\xff\xff\xc0\x1f\xff\xff\xff\xc0\x1f\xff\xff\xff\xc0'\
|
||||
b'\x1f\xff\xff\xff\xc0\x1f\xff\xff\xff\x80\x00\x00\x00\x0f\x80\x00'\
|
||||
b'\x00\x00\x1f\x00\x00\x00\x00\x3e\x00\x00\x00\x00\x7c\x00\x00\x00'\
|
||||
b'\x00\xfc\x00\x00\x00\x01\xf8\x00\x00\x00\x01\xf0\x00\x00\x00\x03'\
|
||||
b'\xf0\x00\x00\x00\x07\xe0\x00\x00\x00\x07\xc0\x00\x00\x00\x0f\xc0'\
|
||||
b'\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x3f\x00\x00'\
|
||||
b'\x00\x00\x3f\x00\x00\x00\x00\x7e\x00\x00\x00\x00\x7e\x00\x00\x00'\
|
||||
b'\x00\xfc\x00\x00\x00\x00\xfc\x00\x00\x00\x01\xf8\x00\x00\x00\x01'\
|
||||
b'\xf8\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0\x00\x00\x00\x03\xf0'\
|
||||
b'\x00\x00\x00\x07\xe0\x00\x00\x00\x07\xe0\x00\x00\x00\x07\xe0\x00'\
|
||||
b'\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00\x00\x0f\xc0\x00\x00'\
|
||||
b'\x00\x0f\xc0\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00'\
|
||||
b'\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x3f'\
|
||||
b'\x00\x00\x00\x00\x3f\x00\x00\x00\x00\x3f\x00\x00\x00\x00\x3f\x00'\
|
||||
b'\x00\x00\x00\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x25\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x03\xfe\x00\x00\x00\x1f\xff\x80\x00\x00\x3f\xff'\
|
||||
b'\xe0\x00\x00\x7f\xff\xf0\x00\x00\xff\xff\xf8\x00\x01\xff\xff\xfc'\
|
||||
b'\x00\x03\xfe\x03\xfe\x00\x03\xf8\x00\xfe\x00\x03\xf0\x00\x7e\x00'\
|
||||
b'\x07\xf0\x00\x7f\x00\x07\xe0\x00\x3f\x00\x07\xe0\x00\x3f\x00\x07'\
|
||||
b'\xe0\x00\x3f\x00\x07\xe0\x00\x3f\x00\x07\xe0\x00\x3f\x00\x07\xf0'\
|
||||
b'\x00\x7f\x00\x03\xf0\x00\x7e\x00\x03\xf8\x00\xfe\x00\x01\xfe\x03'\
|
||||
b'\xfc\x00\x00\xff\xff\xf8\x00\x00\x7f\xff\xf0\x00\x00\x1f\xff\xc0'\
|
||||
b'\x00\x00\x3f\xff\xe0\x00\x00\xff\xff\xf8\x00\x01\xff\xff\xfc\x00'\
|
||||
b'\x03\xfe\x03\xfe\x00\x07\xf8\x00\xff\x00\x07\xe0\x00\x7f\x00\x0f'\
|
||||
b'\xe0\x00\x3f\x80\x0f\xc0\x00\x1f\x80\x1f\xc0\x00\x1f\xc0\x1f\x80'\
|
||||
b'\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00'\
|
||||
b'\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\xc0\x00\x1f'\
|
||||
b'\xc0\x0f\xc0\x00\x1f\x80\x0f\xc0\x00\x3f\x80\x0f\xe0\x00\x3f\x80'\
|
||||
b'\x07\xf8\x00\xff\x00\x07\xfe\x03\xff\x00\x03\xff\xff\xfe\x00\x01'\
|
||||
b'\xff\xff\xfc\x00\x00\xff\xff\xf8\x00\x00\x7f\xff\xf0\x00\x00\x1f'\
|
||||
b'\xff\xc0\x00\x00\x03\xfe\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x03\xfc\x00\x00\x00\x1f\xff\x00\x00\x00\x7f\xff\xc0\x00\x00\xff'\
|
||||
b'\xff\xf0\x00\x01\xff\xff\xf8\x00\x03\xff\xff\xfc\x00\x03\xfe\x03'\
|
||||
b'\xfc\x00\x07\xf8\x00\xfe\x00\x0f\xf0\x00\x7e\x00\x0f\xe0\x00\x3f'\
|
||||
b'\x00\x0f\xe0\x00\x1f\x00\x1f\xc0\x00\x1f\x80\x1f\xc0\x00\x0f\x80'\
|
||||
b'\x1f\x80\x00\x0f\x80\x1f\x80\x00\x0f\x80\x1f\x80\x00\x0f\xc0\x1f'\
|
||||
b'\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80\x00\x0f\xc0\x1f\x80'\
|
||||
b'\x00\x0f\xc0\x1f\xc0\x00\x1f\xc0\x0f\xc0\x00\x1f\xc0\x0f\xe0\x00'\
|
||||
b'\x3f\xc0\x0f\xf0\x00\x7f\xc0\x07\xf8\x00\xff\xc0\x07\xfe\x03\xff'\
|
||||
b'\xc0\x03\xff\xff\xff\xc0\x01\xff\xff\xef\xc0\x00\xff\xff\xcf\xc0'\
|
||||
b'\x00\x7f\xff\x0f\xc0\x00\x1f\xfe\x0f\xc0\x00\x07\xf0\x0f\xc0\x00'\
|
||||
b'\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00\x00\x1f\x80\x00\x00'\
|
||||
b'\x00\x1f\x80\x00\x00\x00\x3f\x00\x0f\xc0\x00\x3f\x00\x0f\xc0\x00'\
|
||||
b'\x3f\x00\x0f\xe0\x00\x7e\x00\x07\xe0\x00\xfe\x00\x07\xf0\x01\xfc'\
|
||||
b'\x00\x03\xfc\x07\xfc\x00\x03\xff\xff\xf8\x00\x01\xff\xff\xf0\x00'\
|
||||
b'\x00\xff\xff\xe0\x00\x00\x7f\xff\xc0\x00\x00\x1f\xff\x00\x00\x00'\
|
||||
b'\x07\xf8\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x03\xf0\x00\x03\xf0\x00\x03\xf0\x00\x03\xf0\x00\x03\xf0\x00\x03'\
|
||||
b'\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x03\xf0\x00\x03\xf0\x00\x03\xf0\x00'\
|
||||
b'\x03\xf0\x00\x03\xf0\x00\x03\xf0\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\xfc\x00\xf8\x01\xf4\x02\xf0\x03\xec\x04\xe8\x05\xe4\x06'\
|
||||
b'\xe0\x07\xdc\x08\xd8\x09\xd4\x0a\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x6c\x0b'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
_mvi = memoryview(_index)
|
||||
ifb = lambda l : l[0] | (l[1] << 8)
|
||||
|
||||
def get_ch(ch):
|
||||
oc = ord(ch)
|
||||
ioff = 2 * (oc - 48 + 1) if oc >= 48 and oc <= 63 else 0
|
||||
doff = ifb(_mvi[ioff : ])
|
||||
width = ifb(_mvfont[doff : ])
|
||||
|
||||
next_offs = doff + 2 + ((width - 1)//8 + 1) * 50
|
||||
return _mvfont[doff + 2:next_offs], 50, width
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
# Code generated by font-to-py.py.
|
||||
# Font: Courier Prime.ttf
|
||||
version = '0.2'
|
||||
|
||||
def height():
|
||||
return 20
|
||||
|
||||
def max_width():
|
||||
return 14
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return True
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 126
|
||||
|
||||
_font =\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x7c\x00\xfe\x00\xc7\x00\xc3\x00\x03\x00'\
|
||||
b'\x07\x00\x1e\x00\x18\x00\x18\x00\x18\x00\x3c\x00\x3c\x00\x18\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x60\x00\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x00\x00\x60\x00\xf0\x00'\
|
||||
b'\xf0\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\xe6\x00\xe6\x00\x66\x00\x66\x00\x66\x00\x66\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x03\x30\x02\x20'\
|
||||
b'\x02\x20\x06\x60\x3f\xf8\x3f\xf8\x0c\xc0\x08\x80\x7f\xf0\xff\xf0'\
|
||||
b'\x19\x80\x11\x00\x33\x00\x33\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x0c\x00\x0c\x00\x3d\x80\x7f\x80\xcd\x80\xcc\x80'\
|
||||
b'\xec\x00\x7f\x00\x0f\x80\x0c\xc0\xcc\xc0\xcd\xc0\xff\x80\xcf\x00'\
|
||||
b'\x0c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x38\x00\xfe\x18\xc6\x30\xc6\x60\xfe\xc0\x39\x80\x03\x00'\
|
||||
b'\x06\x70\x1d\xfc\x39\x8c\x71\x8c\x61\xfc\x00\x70\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x1e\x00\x3f\x00'\
|
||||
b'\x63\x00\x63\x00\x60\x00\x30\x00\x31\xc0\x49\xc0\xc7\x00\xc3\x00'\
|
||||
b'\xe3\x00\x7f\xc0\x39\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x04\x00\x0e\x00'\
|
||||
b'\x18\x00\x30\x00\x30\x00\x60\x00\x60\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\x60\x00\x60\x00\x30\x00\x38\x00\x1c\x00'\
|
||||
b'\x0e\x00\x04\x00\x0e\x00\x40\x00\xe0\x00\x30\x00\x18\x00\x18\x00'\
|
||||
b'\x0c\x00\x0c\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00'\
|
||||
b'\x0c\x00\x0c\x00\x18\x00\x38\x00\x70\x00\xe0\x00\x80\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x0c\x00\x0c\x00\x0c\x00\xed\xc0\x7f\x80\x0c\x00'\
|
||||
b'\x1e\x00\x33\x00\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\xff\xc0\xff\xc0\x0c\x00\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x00\x70\x00'\
|
||||
b'\x60\x00\x60\x00\xc0\x00\xc0\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xc0\xff\xc0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00'\
|
||||
b'\xf0\x00\xf0\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\xc0\x01\x80\x01\x80\x03\x00\x03\x00\x02\x00\x06\x00'\
|
||||
b'\x04\x00\x0c\x00\x0c\x00\x18\x00\x18\x00\x30\x00\x30\x00\x20\x00'\
|
||||
b'\x60\x00\x40\x00\xc0\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x1e\x00\x3f\x00\x61\x80\xe1\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xe1\xc0\x61\x80\x3f\x00\x1e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x0c\x00\x7c\x00\xec\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\xff\xc0\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x3e\x00\xff\x00\xc3\x80\xc1\x80\x01\x80\x01\x00'\
|
||||
b'\x02\x00\x04\x00\x08\x00\x11\x80\x21\x80\xff\x80\xff\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x3e\x00'\
|
||||
b'\x7f\x00\x61\x80\x61\x80\x01\x80\x1f\x00\x1f\x00\x03\x80\x01\x80'\
|
||||
b'\x01\x80\xc3\x80\xff\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\x03\x00\x07\x00\x0b\x00\x1b\x00'\
|
||||
b'\x13\x00\x23\x00\x63\x00\xff\xc0\xff\xe0\x03\x00\x03\x00\x0f\xc0'\
|
||||
b'\x0f\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x7f\x80\x7f\x80\x60\x00\x60\x00\x7e\x00\x7f\x00\x63\x80'\
|
||||
b'\x01\x80\x01\x80\x01\x80\xc3\x80\xff\x00\x3c\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x07\x80\x1f\x80'\
|
||||
b'\x3c\x00\x70\x00\x60\x00\xcf\x00\xff\x80\xe1\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\x61\xc0\x7f\x80\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\xff\x80\xff\x80\xc1\x80\xc1\x00\x03\x00'\
|
||||
b'\x02\x00\x06\x00\x06\x00\x0c\x00\x0c\x00\x08\x00\x18\x00\x10\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x1e\x00\x3f\x00\x61\x80\x61\x80\x73\x80\x3f\x00\x7f\x00\xe3\x80'\
|
||||
b'\xc1\x80\xc1\x80\xe3\x80\x7f\x00\x3e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x3e\x00\x7f\x80\xe1\x80'\
|
||||
b'\xc0\xc0\xc0\xc0\xe1\xc0\x7f\xc0\x3c\xc0\x01\x80\x03\x80\x0f\x00'\
|
||||
b'\x7e\x00\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\xf0\x00\xf0\x00'\
|
||||
b'\x60\x00\x00\x00\x00\x00\x60\x00\xf0\x00\xf0\x00\x60\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x30\x00\x78\x00\x78\x00\x30\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x78\x00\x70\x00\x60\x00\x60\x00\xc0\x00\xc0\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x60\x01\xe0\x07\x80'\
|
||||
b'\x1e\x00\x78\x00\xe0\x00\x78\x00\x0e\x00\x03\x80\x00\xe0\x00\x40'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xc0\xff\xc0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\xff\xc0\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x80\x00'\
|
||||
b'\xe0\x00\x38\x00\x0e\x00\x03\xc0\x00\xc0\x03\x80\x0e\x00\x38\x00'\
|
||||
b'\xe0\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x7c\x00\xfe\x00\xc7\x00\xc3\x00\x03\x00'\
|
||||
b'\x07\x00\x1e\x00\x18\x00\x18\x00\x18\x00\x3c\x00\x3c\x00\x18\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0f\x80\x1f\xc0\x38\xe0\x66\xf0\x6f\xb0\xcd\x30\xd9\x30'\
|
||||
b'\xd9\x30\xdb\x70\xdf\xe0\x6c\xc0\x70\x00\x3f\xc0\x0f\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x3f\x00\x3f\x00\x07\x80'\
|
||||
b'\x0c\x80\x0c\x80\x18\xc0\x18\x40\x3f\xe0\x3f\xe0\x30\x60\x60\x30'\
|
||||
b'\xf8\xf8\xf8\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\xff\x00\xff\xc0\x30\xc0\x30\xc0\x30\xc0\x3f\x80'\
|
||||
b'\x3f\xc0\x30\xe0\x30\x60\x30\x60\x30\xe0\xff\xc0\xff\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x1f\x60'\
|
||||
b'\x3f\xe0\x70\xe0\x60\x60\xc0\x60\xc0\x40\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\x60\x00\x70\x60\x3f\xe0\x1f\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\xff\x00\xff\x80\x31\xc0\x30\xe0'\
|
||||
b'\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\xe0\x31\xc0\xff\x80'\
|
||||
b'\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\xff\xe0\xff\xe0\x30\x60\x33\x60\x33\x00\x3f\x00\x3f\x00'\
|
||||
b'\x33\x00\x33\x00\x30\x60\x30\x60\xff\xe0\xff\xe0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xff\xe0\xff\xe0'\
|
||||
b'\x30\x60\x33\x60\x33\x00\x3f\x00\x3f\x00\x33\x00\x33\x00\x30\x00'\
|
||||
b'\x30\x00\xfe\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x1e\xc0\x3f\xc0\x71\xc0\x60\xc0\xc0\xc0'\
|
||||
b'\xc0\x00\xc0\x00\xc7\xf0\xc7\xf0\x60\xc0\x70\xc0\x3f\xc0\x1f\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\xfd\xf8\xfd\xf8\x30\x60\x30\x60\x30\x60\x3f\xe0\x3f\xe0\x30\x60'\
|
||||
b'\x30\x60\x30\x60\x30\x60\xfd\xf8\xfd\xf8\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xff\xc0\xff\xc0\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\xff\xc0\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x3f\xf8\x3f\xf8\x01\x80\x01\x80\x01\x80\x01\x80'\
|
||||
b'\x81\x80\xc1\x80\xc1\x80\xc1\x80\xc3\x80\x7f\x00\x3e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xfc\xf0'\
|
||||
b'\xfc\xf0\x30\x40\x31\x80\x33\x00\x34\x00\x3f\x00\x31\x80\x30\x80'\
|
||||
b'\x30\xc0\x30\x40\xfc\x70\xfc\x30\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\x7f\x00\xff\x00\x18\x00\x18\x00'\
|
||||
b'\x18\x00\x18\x00\x18\x00\x18\x30\x18\x30\x18\x30\x18\x30\x7f\xf0'\
|
||||
b'\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\xf0\xf0\xf0\xf0\x70\xe0\x79\xe0\x69\x60\x69\x60\x6f\x60'\
|
||||
b'\x66\x60\x66\x60\x66\x60\x60\x60\xf9\xf0\xf9\xf0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xf0\xf8\xf8\xf8'\
|
||||
b'\x3c\x30\x34\x30\x32\x30\x32\x30\x31\x30\x31\x30\x30\xb0\x30\x70'\
|
||||
b'\x30\x70\x7c\x30\x7c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x1f\x80\x3f\xc0\x70\xe0\x60\x60\xc0\x30'\
|
||||
b'\xc0\x30\xc0\x30\xc0\x30\xc0\x30\x60\x60\x70\xe0\x3f\xc0\x1f\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x7f\xc0\xff\xe0\x18\x70\x18\x30\x18\x30\x18\x70\x1f\xe0\x1f\xc0'\
|
||||
b'\x18\x00\x18\x00\x18\x00\x7f\x00\xff\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x1f\x80\x3f\xc0\x70\xe0'\
|
||||
b'\x60\x60\xc0\x30\xc0\x30\xc0\x30\xc0\x30\xc0\x30\x60\x60\x70\xe0'\
|
||||
b'\x3f\xc0\x0f\x80\x18\x20\x3f\xe0\x3f\xc0\x20\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\xff\x80\xff\xc0\x30\xe0\x30\x60\x30\xe0\x3f\xc0'\
|
||||
b'\x3f\x00\x31\x80\x30\xc0\x30\xc0\x30\x60\xfc\x78\xfc\x38\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x3c\xc0'\
|
||||
b'\x7f\xc0\xe1\xc0\xc0\xc0\xc0\x00\x70\x00\x1f\x00\x01\x80\x00\xc0'\
|
||||
b'\xc0\xc0\xe1\xc0\xff\x80\xdf\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\xff\xc0\xff\xc0\xcc\xc0\xcc\xc0'\
|
||||
b'\xcc\xc0\xcc\xc0\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x7f\x80'\
|
||||
b'\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\xfc\xfc\xfc\xfc\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x38\x70\x1f\xe0\x0f\xc0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xfc\x7c\xfc\x7c'\
|
||||
b'\x30\x30\x30\x30\x10\x20\x18\x60\x18\x40\x0c\xc0\x0c\xc0\x04\x80'\
|
||||
b'\x07\x80\x07\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\xf8\x7c\xf8\x7c\x60\x18\x63\x18\x23\x10'\
|
||||
b'\x23\x90\x37\x90\x37\xb0\x34\xb0\x3c\xf0\x1c\xe0\x18\x60\x18\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\xf9\xf0\xf9\xf0\x30\xc0\x19\x80\x1f\x80\x0f\x00\x06\x00\x0f\x00'\
|
||||
b'\x19\x80\x30\xc0\x60\x60\xf9\xf0\xf9\xf0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\xf9\xf0\xf9\xf0\x30\xc0'\
|
||||
b'\x30\xc0\x19\x80\x0f\x00\x0f\x00\x06\x00\x06\x00\x06\x00\x06\x00'\
|
||||
b'\x3f\xc0\x3f\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\xff\xc0\xff\xc0\xc1\x80\xc3\x00\x02\x00\x04\x00'\
|
||||
b'\x0c\x00\x18\x00\x10\xc0\x20\xc0\x40\xc0\xff\xc0\xff\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xfc\x00\xfc\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xfc\x00\xfc\x00'\
|
||||
b'\x00\x00\x0e\x00\xc0\x00\x40\x00\x60\x00\x20\x00\x30\x00\x30\x00'\
|
||||
b'\x18\x00\x18\x00\x0c\x00\x0c\x00\x04\x00\x06\x00\x02\x00\x03\x00'\
|
||||
b'\x03\x00\x01\x80\x01\x80\x00\xc0\x00\x00\x00\x00\x0e\x00\xfc\x00'\
|
||||
b'\xfc\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\xfc\x00\xfc\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x18\x00\x18\x00'\
|
||||
b'\x3c\x00\x24\x00\x66\x00\xc6\x00\xc3\x00\x83\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xff\xfc\xff\xfc\x00\x00\x00\x00\x00\x00\x0e\x00\xe0\x00\xf8\x00'\
|
||||
b'\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3e\x00\xff\x00\xc1\x80\x3f\x80\x7f\x80\xc1\x80\xc1\x80\xc3\x80'\
|
||||
b'\xff\x80\x7c\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\xf0\x00\xf0\x00\x30\x00\x30\x00\x30\x00\x37\xc0\x3f\xe0\x38\x60'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x38\x60\xff\xe0\xf3\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x1f\x60\x7f\xe0\x70\xe0\xc0\x60\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\x70\x60\x7f\xc0\x1f\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x03\xc0\x03\xc0\x00\xc0\x00\xc0\x00\xc0\x3e\xc0'\
|
||||
b'\x7f\xc0\x61\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x61\xc0\x7f\xf0'\
|
||||
b'\x3c\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x7f\x80\x60\xc0\xff\xc0'\
|
||||
b'\xff\xc0\xc0\x00\xc0\x00\x60\xc0\x7f\xc0\x1f\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x0f\x80\x1f\xc0\x38\x40\x30\x00'\
|
||||
b'\x30\x00\xff\x80\xff\x80\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00'\
|
||||
b'\x30\x00\xff\x80\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x78\x7f\xf8'\
|
||||
b'\x60\xe0\xc0\x60\xc0\x60\xc0\x60\xc0\x60\x60\xe0\x7f\xe0\x1e\x60'\
|
||||
b'\x00\x60\x20\xe0\x3f\xc0\x1f\x80\x00\x00\x0e\x00\xf0\x00\xf0\x00'\
|
||||
b'\x30\x00\x30\x00\x30\x00\x37\xc0\x3f\xe0\x3c\x60\x38\x60\x30\x60'\
|
||||
b'\x30\x60\x30\x60\x30\x60\xfd\xf8\xfd\xf8\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x0c\x00\x0c\x00\x0c\x00\x00\x00\x00\x00'\
|
||||
b'\x7c\x00\x7c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\xff\xc0\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x03\x00\x03\x00\x03\x00\x00\x00\x00\x00\x7f\x00\x7f\x00\x03\x00'\
|
||||
b'\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00'\
|
||||
b'\xc3\x00\xfe\x00\x3c\x00\x00\x00\x0e\x00\xf0\x00\xf0\x00\x30\x00'\
|
||||
b'\x30\x00\x30\x00\x33\xe0\x33\xe0\x31\x80\x33\x00\x34\x00\x3a\x00'\
|
||||
b'\x31\x80\x30\xc0\xfd\xf0\xfd\xf0\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x7c\x00\x7c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\xff\xc0'\
|
||||
b'\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x70\xff\xf8\x3b\x98\x33\x18'\
|
||||
b'\x33\x18\x33\x18\x33\x18\x33\x18\xfb\x9c\xfb\x9c\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\xf3\xc0\xf7\xe0\x38\x60\x38\x60\x30\x60\x30\x60\x30\x60'\
|
||||
b'\x30\x60\xfd\xf8\xfd\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x80\x3f\xc0'\
|
||||
b'\x70\xe0\xc0\x30\xc0\x30\xc0\x30\xc0\x30\x70\xe0\x3f\xc0\x1f\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xf7\xc0\xff\xe0\x38\x60\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x38\x60\x3f\xe0\x37\xc0\x30\x00\x30\x00\xfc\x00'\
|
||||
b'\xfc\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3e\xf0\x7f\xf0\x61\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x61\xc0'\
|
||||
b'\x7f\xc0\x3c\xc0\x00\xc0\x00\xc0\x03\xf0\x03\xf0\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xc0\xf7\xe0\x3e\x40'\
|
||||
b'\x38\x00\x30\x00\x30\x00\x30\x00\x30\x00\xff\x00\xff\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x7d\x80\xff\x80\xc1\x80\xc0\x80\x7c\x00\x03\x80'\
|
||||
b'\xc0\xc0\xe1\xc0\xff\xc0\xdf\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x30\x00\x30\x00\x30\x00\x30\x00\xff\x80'\
|
||||
b'\xff\x80\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\xc0\x1f\xc0'\
|
||||
b'\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xe0\xf1\xe0\x30\x60\x30\x60'\
|
||||
b'\x30\x60\x30\x60\x30\xe0\x30\xe0\x3f\xf8\x1e\x78\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\xf8\xf0\xf9\xf0\x20\x60\x30\xc0\x10\xc0\x18\x80\x09\x80'\
|
||||
b'\x0d\x00\x0f\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x3c\xf8\x3c'\
|
||||
b'\x63\x18\x63\x18\x27\x90\x37\xb0\x34\xb0\x1c\xe0\x1c\xe0\x18\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xf9\xf0\xf9\xf0\x30\xc0\x19\x80\x0f\x00'\
|
||||
b'\x0f\x00\x19\x80\x30\xc0\xf9\xf0\xf9\xf0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xf8\xf0\xf9\xf0\x30\x60\x30\xc0\x18\xc0\x19\x80\x0d\x80\x07\x00'\
|
||||
b'\x07\x00\x06\x00\x0c\x00\x1c\x00\x78\x00\x70\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xc0\xff\x80\xc1\x00'\
|
||||
b'\xc2\x00\x04\x00\x18\x00\x30\xc0\x60\xc0\xff\xc0\xff\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x06\x00\x0e\x00\x18\x00'\
|
||||
b'\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x38\x00\xf0\x00\xf0\x00'\
|
||||
b'\x38\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x1e\x00\x0e\x00'\
|
||||
b'\x00\x00\x0e\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x0e\x00\xc0\x00'\
|
||||
b'\xe0\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x38\x00'\
|
||||
b'\x1e\x00\x1e\x00\x38\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00'\
|
||||
b'\xf0\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x78\x40\xff\xc0\x87\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x2a\x00\x54\x00\x7e\x00\xa8\x00\xd2\x00\xfc\x00\x26\x01'\
|
||||
b'\x50\x01\x7a\x01\xa4\x01\xce\x01\xf8\x01\x22\x02\x4c\x02\x76\x02'\
|
||||
b'\xa0\x02\xca\x02\xf4\x02\x1e\x03\x48\x03\x72\x03\x9c\x03\xc6\x03'\
|
||||
b'\xf0\x03\x1a\x04\x44\x04\x6e\x04\x98\x04\xc2\x04\xec\x04\x16\x05'\
|
||||
b'\x40\x05\x6a\x05\x94\x05\xbe\x05\xe8\x05\x12\x06\x3c\x06\x66\x06'\
|
||||
b'\x90\x06\xba\x06\xe4\x06\x0e\x07\x38\x07\x62\x07\x8c\x07\xb6\x07'\
|
||||
b'\xe0\x07\x0a\x08\x34\x08\x5e\x08\x88\x08\xb2\x08\xdc\x08\x06\x09'\
|
||||
b'\x30\x09\x5a\x09\x84\x09\xae\x09\xd8\x09\x02\x0a\x2c\x0a\x56\x0a'\
|
||||
b'\x80\x0a\xaa\x0a\xd4\x0a\xfe\x0a\x28\x0b\x52\x0b\x7c\x0b\xa6\x0b'\
|
||||
b'\xd0\x0b\xfa\x0b\x24\x0c\x4e\x0c\x78\x0c\xa2\x0c\xcc\x0c\xf6\x0c'\
|
||||
b'\x20\x0d\x4a\x0d\x74\x0d\x9e\x0d\xc8\x0d\xf2\x0d\x1c\x0e\x46\x0e'\
|
||||
b'\x70\x0e\x9a\x0e\xc4\x0e\xee\x0e\x18\x0f\x42\x0f\x6c\x0f\x96\x0f'\
|
||||
b'\xc0\x0f'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
|
||||
def _chr_addr(ordch):
|
||||
offset = 2 * (ordch - 32)
|
||||
return int.from_bytes(_index[offset:offset + 2], 'little')
|
||||
|
||||
def get_ch(ch):
|
||||
ordch = ord(ch)
|
||||
ordch = ordch + 1 if ordch >= 32 and ordch <= 126 else 32
|
||||
offset = _chr_addr(ordch)
|
||||
width = int.from_bytes(_font[offset:offset + 2], 'little')
|
||||
next_offs = _chr_addr(ordch +1)
|
||||
return _mvfont[offset + 2:next_offs], 20, width
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
# Code generated by font_to_py.py.
|
||||
# Font: FreeSans.ttf Char set: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~£¬°Ωαβγδθλμπωϕ
|
||||
# Cmd: ./font_to_py.py -xk extended FreeSans.ttf 17 font10.py
|
||||
version = '0.33'
|
||||
|
||||
def height():
|
||||
return 17
|
||||
|
||||
def baseline():
|
||||
return 13
|
||||
|
||||
def max_width():
|
||||
return 17
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 981
|
||||
|
||||
_font =\
|
||||
b'\x09\x00\x1e\x00\x63\x80\x61\x80\x01\x80\x01\x80\x03\x00\x06\x00'\
|
||||
b'\x04\x00\x0c\x00\x0c\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x06\x00\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x20\x00\x30\x00\x00\x00\x00\x06\x00\x00\x78\x78\x78'\
|
||||
b'\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x00\x00\x19\x00\x19\x00\x13\x00\x7f\x80\x12\x00\x32\x00\x32'\
|
||||
b'\x00\xff\x80\x26\x00\x24\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x09\x00\x08\x00\x1e\x00\x2b\x00\x69\x80\x69\x80\x68\x00\x68'\
|
||||
b'\x00\x1e\x00\x0b\x80\x09\x80\x69\x80\x6b\x00\x3e\x00\x08\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x3c\x10\x66\x20\x66\x40\x66'\
|
||||
b'\x40\x64\x80\x18\x80\x01\x3c\x02\x66\x02\x66\x04\x66\x04\x66\x08'\
|
||||
b'\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x0f\x00\x19'\
|
||||
b'\x80\x19\x80\x19\x80\x0f\x00\x0c\x00\x3a\x60\x73\x60\x61\xc0\x60'\
|
||||
b'\xc0\x71\xc0\x1e\x20\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00'\
|
||||
b'\x60\x60\x60\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x06\x00\x08\x10\x10\x30\x20\x60\x60\x60\x60\x60\x60\x20\x30\x10'\
|
||||
b'\x18\x08\x00\x06\x00\x40\x60\x20\x30\x10\x18\x18\x18\x18\x18\x18'\
|
||||
b'\x10\x30\x20\x60\x40\x00\x07\x00\x10\x54\x38\x28\x28\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x0c\x00\x0c\x00\x3f\x00\x0c'\
|
||||
b'\x00\x0c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x20\x20\x40\x00'\
|
||||
b'\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x60\x00\x00\x00\x00\x05\x00\x08\x08\x10\x10\x10\x20\x20\x20'\
|
||||
b'\x40\x40\x40\x80\x80\x00\x00\x00\x00\x09\x00\x00\x00\x1e\x00\x33'\
|
||||
b'\x00\x21\x00\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x21'\
|
||||
b'\x00\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x04\x00\x0c\x00\x3c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c'\
|
||||
b'\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x09\x00\x00\x00\x1e\x00\x33\x00\x61\x80\x61\x80\x01\x80\x03'\
|
||||
b'\x00\x06\x00\x1c\x00\x30\x00\x20\x00\x60\x00\x7f\x80\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x09\x00\x00\x00\x3e\x00\x73\x80\x61\x80\x01'\
|
||||
b'\x80\x01\x00\x0e\x00\x03\x80\x01\x80\x01\x80\x61\x80\x73\x00\x1e'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x03\x00\x03'\
|
||||
b'\x00\x07\x00\x0b\x00\x0b\x00\x13\x00\x23\x00\x23\x00\x3f\x80\x03'\
|
||||
b'\x00\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x3f\x00\x20\x00\x20\x00\x40\x00\x5e\x00\x73\x00\x01\x80\x01'\
|
||||
b'\x80\x01\x80\x61\x80\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x09\x00\x00\x00\x1e\x00\x33\x00\x21\x80\x60\x00\x60\x00\x7e'\
|
||||
b'\x00\x73\x00\x61\x80\x61\x80\x61\x80\x33\x00\x1e\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x09\x00\x00\x00\xff\x00\x03\x00\x02\x00\x06'\
|
||||
b'\x00\x04\x00\x0c\x00\x08\x00\x18\x00\x18\x00\x10\x00\x30\x00\x30'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x1e\x00\x33'\
|
||||
b'\x00\x61\x80\x61\x80\x33\x00\x1e\x00\x33\x00\x61\x80\x61\x80\x61'\
|
||||
b'\x80\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x1e\x00\x33\x00\x61\x80\x61\x80\x61\x80\x33\x80\x1d\x80\x01'\
|
||||
b'\x80\x01\x80\x61\x00\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x04\x00\x00\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x60'\
|
||||
b'\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x60\x20\x20\x40\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x01\x80\x07\x00\x1c\x00\x60\x00\x70\x00\x1c\x00\x03'\
|
||||
b'\x80\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\x80\x00\x00\x00'\
|
||||
b'\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x38\x00\x0e'\
|
||||
b'\x00\x01\x80\x03\x80\x0e\x00\x70\x00\x40\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x09\x00\x1e\x00\x63\x80\x61\x80\x01\x80\x01\x80\x03'\
|
||||
b'\x00\x06\x00\x04\x00\x0c\x00\x0c\x00\x00\x00\x00\x00\x0c\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x11\x00\x03\xf0\x00\x06\x1c\x00\x18'\
|
||||
b'\x06\x00\x10\x03\x00\x31\xdb\x80\x26\x39\x80\x66\x31\x80\x6c\x31'\
|
||||
b'\x80\x6c\x31\x80\x6c\x23\x00\x6e\x67\x00\x37\xbc\x00\x18\x00\x00'\
|
||||
b'\x0c\x00\x00\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x06\x00'\
|
||||
b'\x0e\x00\x0b\x00\x1b\x00\x1b\x00\x11\x80\x31\x80\x31\x80\x3f\xc0'\
|
||||
b'\x60\xc0\x60\x40\x40\x60\xc0\x60\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0b\x00\x7f\x00\x61\xc0\x60\xc0\x60\xc0\x60\xc0\x61\x80\x7f\x00'\
|
||||
b'\x60\xc0\x60\x60\x60\x60\x60\x60\x60\xc0\x7f\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0c\x00\x0f\xc0\x18\x60\x30\x30\x20\x30\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x20\x30\x30\x30\x18\x60\x0f\xc0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x7f\x80\x60\xc0\x60\x60'\
|
||||
b'\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x60'\
|
||||
b'\x60\xc0\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x7f\x80'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x7f\x80\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x7f\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0a\x00\x7f\x80\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x7f\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0d\x00\x07\xe0\x18\x30\x30\x18\x30\x00\x60\x00'\
|
||||
b'\x60\x00\x60\xf8\x60\x18\x60\x18\x30\x18\x30\x38\x18\x78\x07\x88'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x7f\xe0\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00\x09'\
|
||||
b'\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x63\x00\x63\x00\x62\x00\x3c\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x60\x60\x60\xc0\x61\x80\x63\x00\x66\x00\x6c'\
|
||||
b'\x00\x7e\x00\x73\x00\x63\x00\x61\x80\x60\xc0\x60\xc0\x60\x60\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x60\x00\x60\x00\x60\x00\x60'\
|
||||
b'\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60'\
|
||||
b'\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x70\x1c\x70'\
|
||||
b'\x1c\x78\x3c\x78\x3c\x68\x2c\x6c\x6c\x6c\x6c\x64\x4c\x66\xcc\x66'\
|
||||
b'\xcc\x62\x8c\x63\x8c\x63\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x70\x30\x70\x30\x78\x30\x68\x30\x6c\x30\x66\x30\x62\x30\x63'\
|
||||
b'\x30\x61\xb0\x61\xb0\x60\xf0\x60\x70\x60\x70\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0d\x00\x0f\xc0\x18\x60\x30\x30\x70\x30\x60\x18\x60'\
|
||||
b'\x18\x60\x18\x60\x18\x60\x18\x70\x30\x30\x30\x18\x60\x0f\xc0\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x7f\x80\x60\xc0\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\xc0\x7f\x80\x60\x00\x60\x00\x60\x00\x60\x00\x60'\
|
||||
b'\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x0f\xc0\x18'\
|
||||
b'\x60\x30\x30\x70\x30\x60\x18\x60\x18\x60\x18\x60\x18\x60\x18\x70'\
|
||||
b'\xb0\x30\xf0\x18\x60\x0f\xf0\x00\x10\x00\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x7f\x80\x60\xe0\x60\x60\x60\x60\x60\x60\x60\xc0\x7f\x80\x60'\
|
||||
b'\xe0\x60\x60\x60\x60\x60\x60\x60\x60\x60\x70\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x1f\x80\x30\xc0\x60\x60\x60\x00\x60\x00\x30'\
|
||||
b'\x00\x1f\x00\x03\xc0\x00\xe0\x60\x60\x60\x60\x30\xc0\x1f\x80\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x3f\xc0\x06\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x30\xc0\x1f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x0b'\
|
||||
b'\x00\xc0\x60\x40\x40\x60\xc0\x60\xc0\x20\x80\x31\x80\x31\x80\x11'\
|
||||
b'\x00\x1b\x00\x0b\x00\x0a\x00\x0e\x00\x06\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x10\x00\xc1\x83\xc1\x82\x42\x86\x62\xc6\x62\xc6\x62'\
|
||||
b'\x44\x24\x44\x24\x6c\x34\x2c\x3c\x28\x18\x38\x18\x38\x18\x18\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x60\x40\x20\xc0\x31\x80\x19'\
|
||||
b'\x00\x1b\x00\x0e\x00\x06\x00\x0e\x00\x1b\x00\x11\x80\x31\x80\x60'\
|
||||
b'\xc0\x40\x60\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x40\x60\x60'\
|
||||
b'\x60\x30\xc0\x30\xc0\x19\x80\x0d\x00\x0f\x00\x06\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x06\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a'\
|
||||
b'\x00\x7f\xc0\x00\xc0\x01\x80\x03\x00\x03\x00\x06\x00\x0c\x00\x0c'\
|
||||
b'\x00\x18\x00\x30\x00\x30\x00\x60\x00\x7f\xc0\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x05\x00\x70\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x70\x05\x00\x80\x80\x40\x40\x40\x20\x20\x20'\
|
||||
b'\x10\x10\x10\x08\x08\x00\x00\x00\x00\x05\x00\xe0\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\xe0\x08\x00\x00\x18'\
|
||||
b'\x18\x3c\x24\x24\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xc0\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x04\x00\xc0\x40\x20\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3e\x00\x63\x00\x03\x00\x03\x00\x3f\x00\x63\x00\x63\x00\x67\x00'\
|
||||
b'\x3b\x80\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x6f\x00\x71\x80\x60\x80\xe0\x80\xe0\x80\xe0\x80'\
|
||||
b'\xe0\x80\xf1\x80\x6f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x33\x00\x61\x80\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x61\x80\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0a\x00\x01\x80\x01\x80\x01\x80\x01\x80\x1d\x80\x33\x80'\
|
||||
b'\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x33\x80\x1d\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x1e\x00\x33\x00\x61\x80\x61\x80\x7f\x80\x60\x00\x61\x80\x33\x00'\
|
||||
b'\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18\x30\x30\x30'\
|
||||
b'\x78\x30\x30\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00\x09\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x1d\x80\x33\x80\x61\x80\x61\x80\x61'\
|
||||
b'\x80\x61\x80\x61\x80\x33\x80\x1d\x80\x01\x80\x01\x80\x63\x00\x3e'\
|
||||
b'\x00\x09\x00\x60\x00\x60\x00\x60\x00\x60\x00\x6f\x00\x71\x80\x61'\
|
||||
b'\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x04\x00\x60\x00\x00\x00\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x00\x00\x00\x00\x04\x00\x30\x00\x00\x00\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\xe0\x09\x00\x60\x00\x60'\
|
||||
b'\x00\x60\x00\x60\x00\x63\x00\x66\x00\x6c\x00\x7c\x00\x74\x00\x66'\
|
||||
b'\x00\x63\x00\x63\x00\x61\x80\x00\x00\x00\x00\x00\x00\x00\x00\x04'\
|
||||
b'\x00\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6e\xf0\x73\x98'\
|
||||
b'\x63\x18\x63\x18\x63\x18\x63\x18\x63\x18\x63\x18\x63\x18\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x6f\x00\x71\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80'\
|
||||
b'\x61\x80\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x1e\x00\x33\x00\x61\x80\x61\x80\x61\x80\x61\x80'\
|
||||
b'\x61\x80\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x6f\x00\x71\x80\x60\x80\xe0\x80'\
|
||||
b'\xe0\x80\xe0\x80\xe0\x80\xf1\x80\x6f\x00\x60\x00\x60\x00\x60\x00'\
|
||||
b'\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x80\x33\x80'\
|
||||
b'\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x33\x80\x1d\x80\x01\x80'\
|
||||
b'\x01\x80\x01\x80\x00\x00\x06\x00\x00\x00\x00\x00\x6c\x70\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x3e'\
|
||||
b'\x63\x60\x60\x38\x07\x63\x63\x3e\x00\x00\x00\x00\x05\x00\x00\x00'\
|
||||
b'\x30\x30\x78\x30\x30\x30\x30\x30\x30\x30\x38\x00\x00\x00\x00\x09'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x61\x80\x61\x80\x61\x80\x61'\
|
||||
b'\x80\x61\x80\x61\x80\x61\x80\x63\x80\x3d\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x08\x00\x00\x00\x00\x00\xc3\x43\x62\x66\x26\x34\x3c'\
|
||||
b'\x18\x18\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xc6\x30\x46\x30\x47\x20\x6f\x20\x69\x60\x29\x60\x29\xc0\x39\xc0'\
|
||||
b'\x10\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00'\
|
||||
b'\x42\x66\x34\x18\x18\x1c\x24\x66\x43\x00\x00\x00\x00\x08\x00\x00'\
|
||||
b'\x00\x00\x00\xc3\x42\x42\x66\x24\x24\x3c\x18\x18\x18\x10\x30\x60'\
|
||||
b'\x08\x00\x00\x00\x00\x00\x7f\x06\x04\x0c\x18\x30\x20\x60\x7f\x00'\
|
||||
b'\x00\x00\x00\x06\x00\x18\x30\x30\x30\x30\x30\x30\x70\x60\x70\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x18\x04\x00\x30\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x00\x06\x00\x60\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x38\x18\x38\x30\x30\x30\x30\x30\x30\x60\x09\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31\x00\x4f\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x09\x00\x1f\x00\x31\x80\x61\x80\x60\x00\x60\x00\x30\x00\xfc\x00'\
|
||||
b'\x18\x00\x18\x00\x18\x00\x30\x00\x7c\x80\x47\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x3f\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0e\x00\x11\x00'\
|
||||
b'\x11\x00\x11\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x0f\xc0'\
|
||||
b'\x18\x60\x30\x30\x30\x18\x60\x18\x60\x18\x60\x18\x60\x18\x60\x18'\
|
||||
b'\x30\x30\x10\x60\x08\xc0\x7c\xf8\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x80\x33\x80\x61\x80'\
|
||||
b'\x61\x80\x61\x80\x61\x80\x61\x80\x33\x80\x1f\xc0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x09\x00\x3e\x00\x23\x00\x63\x00\x63\x00\x63\x00'\
|
||||
b'\x66\x00\x6c\x00\x63\x00\x61\x80\x61\x80\x61\x80\x73\x00\x7e\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\xc1\x80\x61\x80\x21\x00\x33\x00\x32\x00\x1e\x00\x1e\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x00\x00\x09\x00\x3f\x00'\
|
||||
b'\x30\x00\x1c\x00\x0e\x00\x1f\x00\x33\x00\x61\x80\x61\x80\x61\x80'\
|
||||
b'\x61\x80\x61\x80\x33\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x09\x00\x1e\x00\x33\x00\x21\x00\x61\x80\x61\x80\x61\x80\x7f\x80'\
|
||||
b'\x61\x80\x61\x80\x61\x80\x61\x00\x33\x00\x1e\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x09\x00\x60\x00\x10\x00\x18\x00\x18\x00\x18\x00'\
|
||||
b'\x1c\x00\x34\x00\x34\x00\x26\x00\x62\x00\x62\x00\x43\x00\xc1\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80\x61\x80'\
|
||||
b'\x73\x80\x7f\x80\x60\x00\x60\x00\x60\x00\x00\x00\x0a\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x7f\xc0\x31\x80\x31\x80\x31\x80\x31\x80'\
|
||||
b'\x31\x80\x31\x80\x31\x80\x31\xc0\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x60\x30\x30\x20\x10'\
|
||||
b'\x63\x10\xe3\x10\xe3\x10\xe3\x10\xb3\x30\x1c\xe0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0c\x00\x00\x00\x06\x00\x06\x00\x06\x00\x1f\x80'\
|
||||
b'\x36\x60\x66\x30\x66\x30\x66\x30\x66\x30\x66\x30\x36\x60\x1f\xc0'\
|
||||
b'\x06\x00\x06\x00\x06\x00\x00\x00'
|
||||
|
||||
_sparse =\
|
||||
b'\x20\x00\x24\x00\x21\x00\x37\x00\x22\x00\x4a\x00\x23\x00\x5d\x00'\
|
||||
b'\x24\x00\x81\x00\x25\x00\xa5\x00\x26\x00\xc9\x00\x27\x00\xed\x00'\
|
||||
b'\x28\x00\x00\x01\x29\x00\x13\x01\x2a\x00\x26\x01\x2b\x00\x39\x01'\
|
||||
b'\x2c\x00\x5d\x01\x2d\x00\x70\x01\x2e\x00\x83\x01\x2f\x00\x96\x01'\
|
||||
b'\x30\x00\xa9\x01\x31\x00\xcd\x01\x32\x00\xf1\x01\x33\x00\x15\x02'\
|
||||
b'\x34\x00\x39\x02\x35\x00\x5d\x02\x36\x00\x81\x02\x37\x00\xa5\x02'\
|
||||
b'\x38\x00\xc9\x02\x39\x00\xed\x02\x3a\x00\x11\x03\x3b\x00\x24\x03'\
|
||||
b'\x3c\x00\x37\x03\x3d\x00\x5b\x03\x3e\x00\x7f\x03\x3f\x00\xa3\x03'\
|
||||
b'\x40\x00\xc7\x03\x41\x00\xfc\x03\x42\x00\x20\x04\x43\x00\x44\x04'\
|
||||
b'\x44\x00\x68\x04\x45\x00\x8c\x04\x46\x00\xb0\x04\x47\x00\xd4\x04'\
|
||||
b'\x48\x00\xf8\x04\x49\x00\x1c\x05\x4a\x00\x2f\x05\x4b\x00\x53\x05'\
|
||||
b'\x4c\x00\x77\x05\x4d\x00\x9b\x05\x4e\x00\xbf\x05\x4f\x00\xe3\x05'\
|
||||
b'\x50\x00\x07\x06\x51\x00\x2b\x06\x52\x00\x4f\x06\x53\x00\x73\x06'\
|
||||
b'\x54\x00\x97\x06\x55\x00\xbb\x06\x56\x00\xdf\x06\x57\x00\x03\x07'\
|
||||
b'\x58\x00\x27\x07\x59\x00\x4b\x07\x5a\x00\x6f\x07\x5b\x00\x93\x07'\
|
||||
b'\x5c\x00\xa6\x07\x5d\x00\xb9\x07\x5e\x00\xcc\x07\x5f\x00\xdf\x07'\
|
||||
b'\x60\x00\x03\x08\x61\x00\x16\x08\x62\x00\x3a\x08\x63\x00\x5e\x08'\
|
||||
b'\x64\x00\x82\x08\x65\x00\xa6\x08\x66\x00\xca\x08\x67\x00\xdd\x08'\
|
||||
b'\x68\x00\x01\x09\x69\x00\x25\x09\x6a\x00\x38\x09\x6b\x00\x4b\x09'\
|
||||
b'\x6c\x00\x6f\x09\x6d\x00\x82\x09\x6e\x00\xa6\x09\x6f\x00\xca\x09'\
|
||||
b'\x70\x00\xee\x09\x71\x00\x12\x0a\x72\x00\x36\x0a\x73\x00\x49\x0a'\
|
||||
b'\x74\x00\x5c\x0a\x75\x00\x6f\x0a\x76\x00\x93\x0a\x77\x00\xa6\x0a'\
|
||||
b'\x78\x00\xca\x0a\x79\x00\xdd\x0a\x7a\x00\xf0\x0a\x7b\x00\x03\x0b'\
|
||||
b'\x7c\x00\x16\x0b\x7d\x00\x29\x0b\x7e\x00\x3c\x0b\xa3\x00\x60\x0b'\
|
||||
b'\xac\x00\x84\x0b\xb0\x00\xa8\x0b\xa9\x03\xcc\x0b\xb1\x03\xf0\x0b'\
|
||||
b'\xb2\x03\x14\x0c\xb3\x03\x38\x0c\xb4\x03\x5c\x0c\xb8\x03\x80\x0c'\
|
||||
b'\xbb\x03\xa4\x0c\xbc\x03\xc8\x0c\xc0\x03\xec\x0c\xc9\x03\x10\x0d'\
|
||||
b'\xd5\x03\x34\x0d'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
_mvsp = memoryview(_sparse)
|
||||
ifb = lambda l : l[0] | (l[1] << 8)
|
||||
|
||||
def bs(lst, val):
|
||||
while True:
|
||||
m = (len(lst) & ~ 7) >> 1
|
||||
v = ifb(lst[m:])
|
||||
if v == val:
|
||||
return ifb(lst[m + 2:])
|
||||
if not m:
|
||||
return 0
|
||||
lst = lst[m:] if v < val else lst[:m]
|
||||
|
||||
def get_ch(ch):
|
||||
doff = bs(_mvsp, ord(ch))
|
||||
width = ifb(_mvfont[doff : ])
|
||||
|
||||
next_offs = doff + 2 + ((width - 1)//8 + 1) * 17
|
||||
return _mvfont[doff + 2:next_offs], 17, width
|
||||
|
|
@ -0,0 +1,395 @@
|
|||
# Code generated by font_to_py.py.
|
||||
# Font: FreeSans.ttf Char set: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~£¬°Ωαβγδθλμπωϕ
|
||||
# Cmd: ./font_to_py.py -x -k extended FreeSans.ttf 23 font14.py
|
||||
version = '0.33'
|
||||
|
||||
def height():
|
||||
return 23
|
||||
|
||||
def baseline():
|
||||
return 18
|
||||
|
||||
def max_width():
|
||||
return 23
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 981
|
||||
|
||||
_font =\
|
||||
b'\x0d\x00\x00\x00\x0f\xc0\x1f\xe0\x38\x70\x30\x30\x30\x30\x00\x30'\
|
||||
b'\x00\x70\x00\x60\x01\xc0\x01\x80\x03\x00\x03\x00\x03\x00\x00\x00'\
|
||||
b'\x00\x00\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x18\x18\x18\x18'\
|
||||
b'\x18\x18\x18\x18\x18\x18\x18\x18\x18\x00\x00\x18\x18\x00\x00\x00'\
|
||||
b'\x00\x00\x08\x00\x00\x00\x66\x66\x66\x66\x44\x44\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00'\
|
||||
b'\x00\x04\x60\x04\x60\x0c\x60\x0c\x40\x7f\xf8\x7f\xf8\x08\xc0\x18'\
|
||||
b'\xc0\x18\xc0\x18\x80\xff\xf0\xff\xf0\x31\x80\x31\x80\x31\x00\x33'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x02\x00\x0f'\
|
||||
b'\x80\x3f\xe0\x32\x60\x62\x30\x62\x30\x62\x00\x62\x00\x3a\x00\x3f'\
|
||||
b'\x00\x0f\xe0\x02\xf0\x02\x30\x62\x30\x62\x30\x72\x70\x3f\xe0\x0f'\
|
||||
b'\x80\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x02\x00\x1e\x02\x00\x3f\x04\x00\x73\x8c\x00\x61'\
|
||||
b'\x88\x00\x73\x98\x00\x3f\x10\x00\x1e\x20\x00\x00\x23\xc0\x00\x47'\
|
||||
b'\xe0\x00\xce\x70\x00\x8c\x30\x01\x8c\x30\x01\x0e\x70\x02\x07\xe0'\
|
||||
b'\x02\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0f\x00\x00\x00\x00\x00\x07\x80\x0f\xc0\x1c\xe0\x18\x60'\
|
||||
b'\x18\x60\x0c\xc0\x0f\x80\x0f\x00\x1b\x98\x31\xd8\x60\xf8\x60\x70'\
|
||||
b'\x60\x30\x70\xf8\x3f\xd8\x1f\x0c\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x05\x00\x00\x00\x60\x60\x60\x60\x40\x40\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x02\x04'\
|
||||
b'\x0c\x08\x18\x18\x10\x30\x30\x30\x30\x30\x30\x30\x30\x18\x18\x18'\
|
||||
b'\x0c\x0c\x04\x02\x08\x00\x00\x40\x20\x30\x10\x18\x18\x08\x0c\x0c'\
|
||||
b'\x0c\x0c\x0c\x0c\x0c\x0c\x18\x18\x18\x30\x30\x20\x40\x09\x00\x00'\
|
||||
b'\x00\x08\x00\x08\x00\x6b\x00\x3e\x00\x1c\x00\x36\x00\x24\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x03\x00\x3f\xf0\x3f\xf0\x03\x00\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30'\
|
||||
b'\x30\x10\x10\x20\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x7c\x7c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x30\x30\x00\x00\x00\x00\x00\x06\x00\x00\x04\x0c\x08\x08\x18'\
|
||||
b'\x10\x10\x10\x30\x20\x20\x20\x60\x40\x40\xc0\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x0f\x80\x1f\xc0\x38\xe0\x30\x60\x60'\
|
||||
b'\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x60\x30\x30'\
|
||||
b'\x60\x38\xe0\x1f\xc0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x01\x00\x03\x00\x07\x00\x1f\x00\x1f'\
|
||||
b'\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x0f\x80\x3f\xe0\x30\x70\x60\x30\x60'\
|
||||
b'\x30\x00\x30\x00\x30\x00\xe0\x01\xc0\x07\x80\x0e\x00\x18\x00\x10'\
|
||||
b'\x00\x20\x00\x3f\xf0\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x0f\xc0\x3f\xe0\x30\x70\x60\x30\x60'\
|
||||
b'\x30\x00\x70\x07\xe0\x07\xe0\x00\x70\x00\x30\x00\x30\x60\x30\x60'\
|
||||
b'\x30\x30\x60\x3f\xe0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x00\xc0\x00\xc0\x01\xc0\x03\xc0\x06'\
|
||||
b'\xc0\x04\xc0\x0c\xc0\x18\xc0\x10\xc0\x20\xc0\x3f\xf0\x3f\xf0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x3f\xe0\x3f\xe0\x30\x00\x30\x00\x30'\
|
||||
b'\x00\x37\x80\x3f\xe0\x70\xe0\x00\x70\x00\x30\x00\x30\x00\x30\x60'\
|
||||
b'\x30\x70\xe0\x3f\xc0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x07\x80\x1f\xe0\x38\x60\x30\x70\x20'\
|
||||
b'\x00\x60\x00\x67\x80\x7f\xe0\x70\x60\x60\x30\x60\x30\x60\x30\x20'\
|
||||
b'\x30\x38\x60\x1f\xe0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x7f\xe0\x7f\xe0\x00\x40\x00\xc0\x00'\
|
||||
b'\x80\x01\x80\x03\x00\x03\x00\x06\x00\x06\x00\x04\x00\x0c\x00\x0c'\
|
||||
b'\x00\x08\x00\x18\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x0f\x80\x1f\xc0\x38\xe0\x30\x60\x30'\
|
||||
b'\x60\x38\xe0\x1f\xc0\x1f\xc0\x38\xe0\x60\x30\x60\x30\x60\x30\x60'\
|
||||
b'\x30\x30\x60\x1f\xc0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x00\x00\x0f\x00\x3f\xc0\x30\xc0\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x30\xe0\x3f\xe0\x1f\x60\x00\x60\x00\x60\x60'\
|
||||
b'\xc0\x31\xc0\x3f\x80\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x06\x00\x00\x00\x00\x00\x00\x00\x30\x30\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x30\x30\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00\x30\x30\x10\x10'\
|
||||
b'\x20\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x10\x00\xf0\x03\xc0\x0f\x00\x78\x00\x60\x00\x3c'\
|
||||
b'\x00\x0f\x00\x03\xe0\x00\x70\x00\x10\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x7f\xf0\x00\x00\x00\x00\x7f'\
|
||||
b'\xf0\x7f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x60\x00\x78\x00\x1e\x00\x07\xc0\x00\xf0\x00\x30\x00'\
|
||||
b'\xf0\x07\x80\x1e\x00\x78\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0d\x00\x00\x00\x0f\xc0\x1f\xe0\x38\x70\x30\x30\x30'\
|
||||
b'\x30\x00\x30\x00\x70\x00\x60\x01\xc0\x01\x80\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x00\x00\x00\x00\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x17\x00\x00\x00\x00\x00\x7f\x00\x03\xff\xc0\x07\x81'\
|
||||
b'\xe0\x0e\x00\x70\x1c\x38\x38\x38\xfd\x98\x30\xc7\x8c\x31\x83\x0c'\
|
||||
b'\x63\x83\x0c\x63\x03\x0c\x63\x02\x0c\x63\x06\x18\x63\x06\x18\x73'\
|
||||
b'\x8e\x30\x31\xff\xf0\x38\xe3\xc0\x1c\x00\x00\x0f\x00\x00\x03\xff'\
|
||||
b'\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x03\x80'\
|
||||
b'\x03\xc0\x07\xc0\x06\xc0\x06\xe0\x0e\x60\x0c\x60\x0c\x70\x18\x30'\
|
||||
b'\x18\x30\x1f\xf8\x3f\xf8\x30\x18\x30\x1c\x70\x0c\x60\x0c\x60\x0e'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x3f\xe0'\
|
||||
b'\x3f\xf0\x30\x38\x30\x18\x30\x18\x30\x18\x30\x30\x3f\xe0\x3f\xf0'\
|
||||
b'\x30\x18\x30\x0c\x30\x0c\x30\x0c\x30\x0c\x30\x18\x3f\xf8\x3f\xf0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x03\xf0'\
|
||||
b'\x0f\xf8\x1c\x1c\x38\x0e\x30\x06\x60\x00\x60\x00\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x06\x30\x06\x38\x0c\x1c\x1c\x0f\xf8\x03\xe0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x3f\xe0'\
|
||||
b'\x3f\xf8\x30\x38\x30\x0c\x30\x0c\x30\x06\x30\x06\x30\x06\x30\x06'\
|
||||
b'\x30\x06\x30\x06\x30\x06\x30\x0c\x30\x0c\x30\x38\x3f\xf0\x3f\xe0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x3f\xf8'\
|
||||
b'\x3f\xf8\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x3f\xf8\x3f\xf8'\
|
||||
b'\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x3f\xfc\x3f\xfc'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x3f\xf8'\
|
||||
b'\x3f\xf8\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x3f\xf0\x3f\xf0'\
|
||||
b'\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x03'\
|
||||
b'\xf0\x00\x0f\xfc\x00\x1c\x0e\x00\x38\x07\x00\x30\x03\x00\x70\x00'\
|
||||
b'\x00\x60\x00\x00\x60\x00\x00\x60\x3f\x00\x60\x3f\x00\x60\x03\x00'\
|
||||
b'\x70\x03\x00\x30\x03\x00\x38\x07\x00\x1c\x1f\x00\x0f\xfb\x00\x03'\
|
||||
b'\xe1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x11\x00\x00\x00\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30'\
|
||||
b'\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x3f\xfe\x00\x3f\xfe'\
|
||||
b'\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00'\
|
||||
b'\x30\x06\x00\x30\x06\x00\x30\x06\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00'\
|
||||
b'\x00\x0c\x00\x00\x00\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x60\xc0\x60'\
|
||||
b'\xc0\x71\xc0\x3f\x80\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0f\x00\x00\x00\x30\x0e\x30\x1c\x30\x38\x30\x70\x30\xe0\x31'\
|
||||
b'\xc0\x33\x80\x37\x80\x3f\x80\x3c\xc0\x38\xe0\x30\x60\x30\x30\x30'\
|
||||
b'\x38\x30\x18\x30\x0c\x30\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x0d\x00\x00\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30'\
|
||||
b'\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30'\
|
||||
b'\x00\x30\x00\x3f\xf0\x3f\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x13\x00\x00\x00\x00\x38\x01\xc0\x38\x01\xc0\x3c\x03\xc0\x3c'\
|
||||
b'\x03\xc0\x36\x02\xc0\x36\x06\xc0\x36\x06\xc0\x33\x04\xc0\x33\x0c'\
|
||||
b'\xc0\x33\x0c\xc0\x31\x98\xc0\x31\x98\xc0\x31\x98\xc0\x30\xf0\xc0'\
|
||||
b'\x30\xf0\xc0\x30\xf0\xc0\x30\x60\xc0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x38\x06\x00'\
|
||||
b'\x38\x06\x00\x3c\x06\x00\x3c\x06\x00\x36\x06\x00\x37\x06\x00\x33'\
|
||||
b'\x06\x00\x31\x86\x00\x31\xc6\x00\x30\xc6\x00\x30\x66\x00\x30\x66'\
|
||||
b'\x00\x30\x36\x00\x30\x3e\x00\x30\x1e\x00\x30\x0e\x00\x30\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12'\
|
||||
b'\x00\x00\x00\x00\x03\xf0\x00\x0f\xfc\x00\x1c\x0e\x00\x38\x07\x00'\
|
||||
b'\x30\x03\x00\x70\x03\x80\x60\x01\x80\x60\x01\x80\x60\x01\x80\x60'\
|
||||
b'\x01\x80\x60\x01\x80\x70\x03\x80\x30\x03\x00\x38\x07\x00\x1c\x0e'\
|
||||
b'\x00\x0f\xfc\x00\x03\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x3f\xe0\x3f\xf8\x30\x18'\
|
||||
b'\x30\x0c\x30\x0c\x30\x0c\x30\x0c\x30\x1c\x3f\xf8\x3f\xf0\x30\x00'\
|
||||
b'\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x03\xf0\x00\x0f\xfc'\
|
||||
b'\x00\x1c\x0e\x00\x38\x07\x00\x30\x03\x00\x70\x03\x80\x60\x01\x80'\
|
||||
b'\x60\x01\x80\x60\x01\x80\x60\x01\x80\x60\x01\x80\x70\x03\x80\x30'\
|
||||
b'\x13\x00\x38\x1f\x00\x1c\x1e\x00\x0f\xff\x00\x03\xf3\x00\x00\x01'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00'\
|
||||
b'\x00\x3f\xf0\x3f\xf8\x30\x1c\x30\x0c\x30\x0c\x30\x0c\x30\x0c\x30'\
|
||||
b'\x18\x3f\xf0\x3f\xf8\x30\x1c\x30\x0c\x30\x0c\x30\x0c\x30\x0c\x30'\
|
||||
b'\x0c\x30\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00'\
|
||||
b'\x00\x07\xe0\x1f\xf8\x18\x38\x30\x0c\x30\x0c\x30\x00\x38\x00\x1f'\
|
||||
b'\x00\x0f\xf0\x00\xf8\x00\x1c\x00\x0c\x60\x0c\x60\x0c\x38\x18\x1f'\
|
||||
b'\xf8\x07\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00'\
|
||||
b'\x00\x7f\xf8\x7f\xf8\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03'\
|
||||
b'\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00'\
|
||||
b'\x00\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06'\
|
||||
b'\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00\x30\x06\x00'\
|
||||
b'\x30\x06\x00\x30\x06\x00\x30\x06\x00\x38\x0e\x00\x1c\x1c\x00\x0f'\
|
||||
b'\xf8\x00\x07\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0f\x00\x00\x00\x60\x0c\x60\x0c\x60\x1c\x30\x18'\
|
||||
b'\x30\x18\x38\x38\x18\x30\x18\x30\x1c\x70\x0c\x60\x0c\x60\x0e\xe0'\
|
||||
b'\x06\xc0\x06\xc0\x07\xc0\x03\x80\x03\x80\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x16\x00\x00\x00\x00\xe0\x70\x18\x60\x70\x38\x60'\
|
||||
b'\x78\x38\x60\x78\x30\x70\xd8\x30\x30\xd8\x30\x30\xcc\x70\x30\xcc'\
|
||||
b'\x60\x39\x8c\x60\x19\x86\x60\x19\x86\xe0\x1b\x86\xc0\x1f\x06\xc0'\
|
||||
b'\x0f\x03\xc0\x0f\x03\xc0\x0e\x03\x80\x0e\x03\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x70'\
|
||||
b'\x0c\x30\x18\x38\x38\x1c\x30\x0c\x60\x0e\xe0\x06\xc0\x03\x80\x03'\
|
||||
b'\x80\x07\xc0\x06\xc0\x0e\x60\x1c\x70\x18\x30\x38\x18\x70\x1c\x60'\
|
||||
b'\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x60'\
|
||||
b'\x0e\x70\x0c\x38\x1c\x18\x18\x1c\x38\x0c\x30\x06\x60\x07\xe0\x03'\
|
||||
b'\xc0\x03\xc0\x01\x80\x01\x80\x01\x80\x01\x80\x01\x80\x01\x80\x01'\
|
||||
b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x7f'\
|
||||
b'\xf8\x7f\xf8\x00\x38\x00\x30\x00\x70\x00\xe0\x01\xc0\x01\x80\x03'\
|
||||
b'\x00\x07\x00\x0e\x00\x1c\x00\x18\x00\x38\x00\x70\x00\x7f\xf8\x7f'\
|
||||
b'\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x78\x78'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x78\x78\x06\x00\x00\x80\xc0\x40\x40\x60\x20\x20\x20\x30'\
|
||||
b'\x10\x10\x10\x18\x08\x08\x0c\x04\x00\x00\x00\x00\x00\x06\x00\x00'\
|
||||
b'\x78\x78\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18'\
|
||||
b'\x18\x18\x18\x18\x78\x78\x0b\x00\x00\x00\x00\x00\x0c\x00\x0e\x00'\
|
||||
b'\x0a\x00\x1b\x00\x13\x00\x31\x00\x31\x80\x20\x80\x60\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xff\xf8\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x06\x00\x00\x30\x18\x0c\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x80\x3f'\
|
||||
b'\xc0\x60\xe0\x00\x60\x00\x60\x0f\xe0\x3e\x60\x60\x60\x60\x60\x61'\
|
||||
b'\xe0\x3f\x70\x1e\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d'\
|
||||
b'\x00\x00\x00\x60\x00\x60\x00\x60\x00\x60\x00\x60\x00\x67\x80\x7f'\
|
||||
b'\xe0\x78\xe0\x70\x70\x60\x30\x60\x30\x60\x30\x60\x30\x70\x70\x78'\
|
||||
b'\xe0\x6f\xc0\x67\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x80\x1f'\
|
||||
b'\xc0\x30\xe0\x70\x60\x60\x00\x60\x00\x60\x00\x60\x00\x70\x60\x30'\
|
||||
b'\xe0\x3f\xc0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d'\
|
||||
b'\x00\x00\x00\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x0f\x30\x1f'\
|
||||
b'\xf0\x38\xf0\x70\x70\x60\x30\x60\x30\x60\x30\x60\x30\x70\x70\x38'\
|
||||
b'\xf0\x1f\xb0\x0f\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x80\x1f'\
|
||||
b'\xc0\x38\x60\x70\x30\x60\x30\x7f\xf0\x7f\xf0\x60\x00\x60\x30\x30'\
|
||||
b'\x60\x1f\xe0\x0f\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06'\
|
||||
b'\x00\x00\x18\x38\x30\x30\x30\x78\x78\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0f\x60\x3f\xe0\x30\xe0\x70\xe0\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x70\xe0\x30\xe0\x3f\x60\x0e\x60\x00\x60'\
|
||||
b'\x00\xe0\x60\xc0\x3f\xc0\x1f\x00\x0c\x00\x00\x00\x60\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x67\x80\x6f\xe0\x78\xe0\x70\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x30\x30\x00\x00\x00'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00'\
|
||||
b'\x00\x06\x00\x00\x30\x30\x00\x00\x00\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\xf0\xe0\x0c\x00\x00\x00\x60\x00'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x60\xc0\x61\x80\x63\x00\x66\x00'\
|
||||
b'\x6e\x00\x7e\x00\x77\x00\x63\x00\x61\x80\x61\xc0\x60\xc0\x60\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x00\x00'\
|
||||
b'\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x67\x1f\x00\x6f\xbf\x80\x71\xe3\x80'\
|
||||
b'\x60\xc1\x80\x60\xc1\x80\x60\xc1\x80\x60\xc1\x80\x60\xc1\x80\x60'\
|
||||
b'\xc1\x80\x60\xc1\x80\x60\xc1\x80\x60\xc1\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x67\x80\x6f\xe0\x78\xe0\x70\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x80\x1f\xc0\x38\xe0\x70\x70'\
|
||||
b'\x60\x30\x60\x30\x60\x30\x60\x30\x70\x70\x38\xe0\x1f\xc0\x0f\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x67\x80\x6f\xc0\x78\xe0\x70\x70'\
|
||||
b'\x60\x30\x60\x30\x60\x30\x60\x30\x70\x70\x78\xe0\x7f\xc0\x67\x80'\
|
||||
b'\x60\x00\x60\x00\x60\x00\x60\x00\x00\x00\x0d\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x30\x1f\xf0\x38\xf0\x70\x70'\
|
||||
b'\x60\x30\x60\x30\x60\x30\x60\x30\x70\x70\x38\xf0\x3f\xf0\x0f\x30'\
|
||||
b'\x00\x30\x00\x30\x00\x30\x00\x30\x00\x00\x08\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x66\x6e\x78\x60\x60\x60\x60\x60\x60\x60\x60\x60\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x1f\x80\x3f\xe0\x70\x60\x60\x00\x70\x00\x3f\x00\x0f\xc0\x00'\
|
||||
b'\xe0\x60\x60\x70\xe0\x3f\xc0\x1f\x80\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x06\x00\x00\x00\x00\x00\x30\x30\x78\x78\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x38\x38\x00\x00\x00\x00\x00\x0c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\xe0\x71\xe0\x7f\x60'\
|
||||
b'\x1e\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x60\x60\xe0\x60\xc0'\
|
||||
b'\x70\xc0\x31\x80\x31\x80\x19\x80\x1b\x00\x1b\x00\x0f\x00\x0e\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xc1\xc3\x00\x61\xc3\x00\x63\xc3\x00\x63\xc6\x00\x33\x66\x00\x33'\
|
||||
b'\x66\x00\x32\x66\x00\x36\x6c\x00\x1e\x3c\x00\x1e\x3c\x00\x1c\x38'\
|
||||
b'\x00\x0c\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x60\xc0\x71\xc0\x31\x80\x1b\x00\x0e\x00\x0e\x00\x0e\x00\x1b'\
|
||||
b'\x00\x1b\x00\x31\x80\x60\xc0\x60\xc0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\xc0\xe0\x60\xc0\x60\xc0\x61\x80\x31\x80\x31\x80\x33\x00\x1b'\
|
||||
b'\x00\x1b\x00\x1e\x00\x0e\x00\x0e\x00\x0c\x00\x0c\x00\x18\x00\x78'\
|
||||
b'\x00\x70\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x7f\xc0\x7f\xc0\x01\xc0\x01\x80\x03\x00\x06\x00\x0c\x00\x18'\
|
||||
b'\x00\x30\x00\x60\x00\x7f\xc0\x7f\xc0\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x08\x00\x00\x0c\x1c\x18\x18\x18\x18\x18\x18\x18\x18'\
|
||||
b'\x70\x70\x18\x18\x18\x18\x18\x18\x18\x18\x1c\x0c\x06\x00\x00\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x08\x00\x00\x30\x38\x18\x18\x18\x18\x18\x18'\
|
||||
b'\x18\x18\x0e\x0e\x18\x18\x18\x18\x18\x18\x18\x18\x38\x30\x0c\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00'\
|
||||
b'\x7c\x00\x4e\x40\x07\xc0\x01\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00'\
|
||||
b'\x00\x00\x0f\xc0\x1f\xe0\x38\x60\x60\x30\x60\x30\x60\x00\x70\x00'\
|
||||
b'\x38\x00\xff\x00\xff\x00\x1c\x00\x0c\x00\x0c\x00\x18\x00\x2f\x10'\
|
||||
b'\x7f\xf0\x61\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x3f\xf8\x3f\xf8\x00\x18\x00\x18\x00\x18\x00\x18\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\x00\x00\x07\x00\x0f\x80\x18\xc0\x10\x40\x18\xc0\x0f\x80'\
|
||||
b'\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00'\
|
||||
b'\x00\x00\x00\x03\xe0\x00\x0f\xf8\x00\x1c\x1c\x00\x38\x0e\x00\x30'\
|
||||
b'\x06\x00\x60\x03\x00\x60\x03\x00\x60\x03\x00\x60\x03\x00\x60\x03'\
|
||||
b'\x00\x60\x03\x00\x30\x06\x00\x30\x0e\x00\x18\x0c\x00\x0c\x38\x00'\
|
||||
b'\x7e\x3f\x00\x7e\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x0f\x60\x3f\xe0\x30\xe0\x60\xe0\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\xe0\x30\xe0\x3f\xf0\x0f\x70\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x1f\x80\x3f\xc0\x70\xe0\x60'\
|
||||
b'\x60\x60\x60\x60\xc0\x63\x80\x63\xc0\x60\x60\x60\x30\x60\x30\x60'\
|
||||
b'\x30\x60\x30\x60\x30\x70\x60\x7f\xe0\x6f\x80\x60\x00\x60\x00\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\xe0\x60\xe0\x60\x70\xc0\x30\xc0\x30\xc0\x39\x80\x19'\
|
||||
b'\x80\x1b\x80\x0f\x00\x0f\x00\x06\x00\x06\x00\x06\x00\x06\x00\x06'\
|
||||
b'\x00\x06\x00\x06\x00\x0d\x00\x00\x00\x3f\xe0\x3f\xe0\x18\x00\x0e'\
|
||||
b'\x00\x03\x00\x0f\x80\x3f\xc0\x38\xe0\x70\x70\x60\x30\x60\x30\x60'\
|
||||
b'\x30\x60\x30\x70\x70\x30\xe0\x3f\xc0\x0f\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x0f\x00\x1f\x80\x30\xc0\x30'\
|
||||
b'\xc0\x60\x60\x60\x60\x60\x60\x7f\xe0\x7f\xe0\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x30\xc0\x30\xc0\x1f\x80\x0f\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x70\x00\x78\x00\x0c\x00\x0c'\
|
||||
b'\x00\x06\x00\x06\x00\x0e\x00\x0f\x00\x1b\x00\x19\x00\x19\x80\x31'\
|
||||
b'\x80\x30\xc0\x30\xc0\x60\xc0\x60\x70\xe0\x70\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x70\xe0\x7f\xe0\x6f\x60\x60\x00\x60\x00\x60'\
|
||||
b'\x00\x60\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x7f\xf8\x7f\xf8\x30\x30\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x30\x30\x30\x30\x30\x3c\x30\x1c\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x0c\x00\x30\x0e\x00\x30'\
|
||||
b'\x06\x00\x61\x87\x00\x61\x83\x00\x61\x83\x00\x61\x83\x00\x61\x83'\
|
||||
b'\x00\x61\x83\x00\x33\xc6\x00\x3f\x7e\x00\x1e\x38\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00'\
|
||||
b'\x00\x00\x01\x80\x01\x80\x01\x80\x01\x80\x0f\xf0\x1f\xf8\x39\x9c'\
|
||||
b'\x71\x8e\x61\x86\x61\x86\x61\x86\x61\x86\x71\x8e\x39\x9c\x1f\xf8'\
|
||||
b'\x0f\xf0\x01\x80\x01\x80\x01\x80\x01\x80\x00\x00'
|
||||
|
||||
_sparse =\
|
||||
b'\x20\x00\x30\x00\x21\x00\x49\x00\x22\x00\x62\x00\x23\x00\x7b\x00'\
|
||||
b'\x24\x00\xab\x00\x25\x00\xdb\x00\x26\x00\x22\x01\x27\x00\x52\x01'\
|
||||
b'\x28\x00\x6b\x01\x29\x00\x84\x01\x2a\x00\x9d\x01\x2b\x00\xcd\x01'\
|
||||
b'\x2c\x00\xfd\x01\x2d\x00\x16\x02\x2e\x00\x2f\x02\x2f\x00\x48\x02'\
|
||||
b'\x30\x00\x61\x02\x31\x00\x91\x02\x32\x00\xc1\x02\x33\x00\xf1\x02'\
|
||||
b'\x34\x00\x21\x03\x35\x00\x51\x03\x36\x00\x81\x03\x37\x00\xb1\x03'\
|
||||
b'\x38\x00\xe1\x03\x39\x00\x11\x04\x3a\x00\x41\x04\x3b\x00\x5a\x04'\
|
||||
b'\x3c\x00\x73\x04\x3d\x00\xa3\x04\x3e\x00\xd3\x04\x3f\x00\x03\x05'\
|
||||
b'\x40\x00\x33\x05\x41\x00\x7a\x05\x42\x00\xaa\x05\x43\x00\xda\x05'\
|
||||
b'\x44\x00\x0a\x06\x45\x00\x3a\x06\x46\x00\x6a\x06\x47\x00\x9a\x06'\
|
||||
b'\x48\x00\xe1\x06\x49\x00\x28\x07\x4a\x00\x41\x07\x4b\x00\x71\x07'\
|
||||
b'\x4c\x00\xa1\x07\x4d\x00\xd1\x07\x4e\x00\x18\x08\x4f\x00\x5f\x08'\
|
||||
b'\x50\x00\xa6\x08\x51\x00\xd6\x08\x52\x00\x1d\x09\x53\x00\x4d\x09'\
|
||||
b'\x54\x00\x7d\x09\x55\x00\xad\x09\x56\x00\xf4\x09\x57\x00\x24\x0a'\
|
||||
b'\x58\x00\x6b\x0a\x59\x00\x9b\x0a\x5a\x00\xcb\x0a\x5b\x00\xfb\x0a'\
|
||||
b'\x5c\x00\x14\x0b\x5d\x00\x2d\x0b\x5e\x00\x46\x0b\x5f\x00\x76\x0b'\
|
||||
b'\x60\x00\xa6\x0b\x61\x00\xbf\x0b\x62\x00\xef\x0b\x63\x00\x1f\x0c'\
|
||||
b'\x64\x00\x4f\x0c\x65\x00\x7f\x0c\x66\x00\xaf\x0c\x67\x00\xc8\x0c'\
|
||||
b'\x68\x00\xf8\x0c\x69\x00\x28\x0d\x6a\x00\x41\x0d\x6b\x00\x5a\x0d'\
|
||||
b'\x6c\x00\x8a\x0d\x6d\x00\xa3\x0d\x6e\x00\xea\x0d\x6f\x00\x1a\x0e'\
|
||||
b'\x70\x00\x4a\x0e\x71\x00\x7a\x0e\x72\x00\xaa\x0e\x73\x00\xc3\x0e'\
|
||||
b'\x74\x00\xf3\x0e\x75\x00\x0c\x0f\x76\x00\x3c\x0f\x77\x00\x6c\x0f'\
|
||||
b'\x78\x00\xb3\x0f\x79\x00\xe3\x0f\x7a\x00\x13\x10\x7b\x00\x43\x10'\
|
||||
b'\x7c\x00\x5c\x10\x7d\x00\x75\x10\x7e\x00\x8e\x10\xa3\x00\xbe\x10'\
|
||||
b'\xac\x00\xee\x10\xb0\x00\x1e\x11\xa9\x03\x4e\x11\xb1\x03\x95\x11'\
|
||||
b'\xb2\x03\xc5\x11\xb3\x03\xf5\x11\xb4\x03\x25\x12\xb8\x03\x55\x12'\
|
||||
b'\xbb\x03\x85\x12\xbc\x03\xb5\x12\xc0\x03\xe5\x12\xc9\x03\x15\x13'\
|
||||
b'\xd5\x03\x5c\x13'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
_mvsp = memoryview(_sparse)
|
||||
ifb = lambda l : l[0] | (l[1] << 8)
|
||||
|
||||
def bs(lst, val):
|
||||
while True:
|
||||
m = (len(lst) & ~ 7) >> 1
|
||||
v = ifb(lst[m:])
|
||||
if v == val:
|
||||
return ifb(lst[m + 2:])
|
||||
if not m:
|
||||
return 0
|
||||
lst = lst[m:] if v < val else lst[:m]
|
||||
|
||||
def get_ch(ch):
|
||||
doff = bs(_mvsp, ord(ch))
|
||||
width = ifb(_mvfont[doff : ])
|
||||
|
||||
next_offs = doff + 2 + ((width - 1)//8 + 1) * 23
|
||||
return _mvfont[doff + 2:next_offs], 23, width
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
# Code generated by font-to-py.py.
|
||||
# Font: FreeSans.ttf
|
||||
version = '0.2'
|
||||
|
||||
def height():
|
||||
return 14
|
||||
|
||||
def max_width():
|
||||
return 14
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 126
|
||||
|
||||
_font =\
|
||||
b'\x08\x00\x00\x78\x8c\x84\x04\x18\x30\x20\x20\x00\x20\x00\x00\x00'\
|
||||
b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x05\x00\x00\x80\x80\x80\x80\x80\x80\x80\x80\x00\x80\x00\x00\x00'\
|
||||
b'\x05\x00\x00\xa0\xa0\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x08\x00\x00\x00\x12\x14\x7f\x24\x24\xfe\x28\x48\x48\x00\x00\x00'\
|
||||
b'\x08\x00\x20\x78\xac\xa4\xa0\xa0\x78\x2c\xa4\xac\x78\x20\x00\x00'\
|
||||
b'\x0c\x00\x00\x00\x70\x80\x89\x00\x89\x00\x8a\x00\x72\x00\x04\xe0'\
|
||||
b'\x05\x10\x09\x10\x09\x10\x10\xe0\x00\x00\x00\x00\x00\x00\x09\x00'\
|
||||
b'\x00\x00\x30\x00\x48\x00\x48\x00\x78\x00\x20\x00\x52\x00\x9e\x00'\
|
||||
b'\x8c\x00\x8e\x00\x73\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x80'\
|
||||
b'\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x20'\
|
||||
b'\x40\x40\x80\x80\x80\x80\x80\x80\x80\x40\x40\x20\x05\x00\x00\x80'\
|
||||
b'\x40\x40\x20\x20\x20\x20\x20\x20\x20\x40\x40\x80\x05\x00\x00\x20'\
|
||||
b'\xf8\x20\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x20\x20\xf8\x20\x20\x20\x00\x00\x00\x04\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x80\x80\x80\x00\x05\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x04\x00\x00\x10'\
|
||||
b'\x10\x20\x20\x20\x40\x40\x40\x80\x80\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\x48\x84\x84\x84\x84\x84\x84\x48\x78\x00\x00\x00\x08\x00\x00\x20'\
|
||||
b'\x60\xe0\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\xcc\x84\x04\x0c\x18\x60\x40\x80\xfc\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\xc4\x84\x04\x38\x04\x04\x84\xcc\x78\x00\x00\x00\x08\x00\x00\x08'\
|
||||
b'\x18\x38\x28\x48\x88\xfc\x08\x08\x08\x00\x00\x00\x08\x00\x00\x7c'\
|
||||
b'\x80\x80\xb8\xcc\x04\x04\x04\x88\x78\x00\x00\x00\x08\x00\x00\x38'\
|
||||
b'\x48\x84\x80\xf8\xcc\x84\x84\x4c\x78\x00\x00\x00\x08\x00\x00\xfc'\
|
||||
b'\x0c\x08\x10\x10\x20\x20\x20\x40\x40\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\x84\x84\x84\x78\xcc\x84\x84\xcc\x78\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\xc8\x84\x84\xcc\x74\x04\x04\x88\x70\x00\x00\x00\x04\x00\x00\x00'\
|
||||
b'\x00\x80\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x04\x00\x00\x00'\
|
||||
b'\x00\x00\x80\x00\x00\x00\x00\x00\x80\x80\x80\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x1c\x70\x80\x60\x1c\x04\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\xfc\x00\xfc\x00\x00\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x00\x00\xe0\x38\x06\x1c\x60\x80\x00\x00\x00\x08\x00\x00\x78'\
|
||||
b'\x8c\x84\x04\x18\x30\x20\x20\x00\x20\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x07\xc0\x18\x60\x20\x10\x43\x48\x84\xc8\x88\xc8\x88\x88\x89\x90'\
|
||||
b'\xc6\xe0\x60\x00\x30\x00\x0f\xc0\x00\x00\x09\x00\x00\x00\x0c\x00'\
|
||||
b'\x1c\x00\x14\x00\x16\x00\x32\x00\x22\x00\x7f\x00\x41\x00\x41\x80'\
|
||||
b'\xc1\x80\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\xfc\x00\x82\x00'\
|
||||
b'\x82\x00\x82\x00\xfc\x00\x86\x00\x82\x00\x82\x00\x86\x00\xfc\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x3c\x00\x42\x00\x41\x00'\
|
||||
b'\x80\x00\x80\x00\x80\x00\x81\x00\xc1\x00\x62\x00\x3c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0a\x00\x00\x00\xfc\x00\x82\x00\x83\x00\x81\x00'\
|
||||
b'\x81\x00\x81\x00\x81\x00\x83\x00\x82\x00\xfc\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x09\x00\x00\x00\xfe\x00\x80\x00\x80\x00\x80\x00\xfc\x00'\
|
||||
b'\x80\x00\x80\x00\x80\x00\x80\x00\xfe\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x08\x00\x00\xfc\x80\x80\x80\xfc\x80\x80\x80\x80\x80\x00\x00\x00'\
|
||||
b'\x0b\x00\x00\x00\x1e\x00\x61\x00\x40\x80\x80\x00\x80\x00\x87\x80'\
|
||||
b'\x80\x80\xc0\x80\x61\x80\x3e\x80\x00\x00\x00\x00\x00\x00\x0a\x00'\
|
||||
b'\x00\x00\x81\x00\x81\x00\x81\x00\x81\x00\xff\x00\x81\x00\x81\x00'\
|
||||
b'\x81\x00\x81\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x80'\
|
||||
b'\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00\x00\x00\x07\x00\x00\x04'\
|
||||
b'\x04\x04\x04\x04\x04\x04\x84\x84\x78\x00\x00\x00\x09\x00\x00\x00'\
|
||||
b'\x82\x00\x84\x00\x88\x00\x90\x00\xb0\x00\xd8\x00\x88\x00\x84\x00'\
|
||||
b'\x86\x00\x82\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x80\x80\x80'\
|
||||
b'\x80\x80\x80\x80\x80\x80\xfc\x00\x00\x00\x0c\x00\x00\x00\xc1\x80'\
|
||||
b'\xc1\x80\xc1\x80\xa2\x80\xa2\x80\xa2\x80\x94\x80\x94\x80\x94\x80'\
|
||||
b'\x88\x80\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\xc1\x00\xc1\x00'\
|
||||
b'\xe1\x00\xb1\x00\x91\x00\x89\x00\x8d\x00\x87\x00\x83\x00\x83\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x3e\x00\x63\x00\xc1\x00'\
|
||||
b'\x80\x80\x80\x80\x80\x80\x80\x80\xc1\x00\x63\x00\x3e\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x09\x00\x00\x00\xfc\x00\x86\x00\x82\x00\x82\x00'\
|
||||
b'\x86\x00\xfc\x00\x80\x00\x80\x00\x80\x00\x80\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0b\x00\x00\x00\x3e\x00\x63\x00\xc1\x00\x80\x80\x80\x80'\
|
||||
b'\x80\x80\x80\x80\xc5\x80\x63\x00\x3f\x00\x00\x80\x00\x00\x00\x00'\
|
||||
b'\x0a\x00\x00\x00\xfc\x00\x82\x00\x82\x00\x82\x00\x82\x00\xfc\x00'\
|
||||
b'\x82\x00\x82\x00\x82\x00\x83\x00\x00\x00\x00\x00\x00\x00\x09\x00'\
|
||||
b'\x00\x00\x7c\x00\xc6\x00\x82\x00\xc0\x00\x78\x00\x0e\x00\x02\x00'\
|
||||
b'\x82\x00\xc6\x00\x7c\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00'\
|
||||
b'\xfe\x00\x10\x00\x10\x00\x10\x00\x10\x00\x10\x00\x10\x00\x10\x00'\
|
||||
b'\x10\x00\x10\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x81\x00'\
|
||||
b'\x81\x00\x81\x00\x81\x00\x81\x00\x81\x00\x81\x00\x81\x00\xc3\x00'\
|
||||
b'\x3c\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\xc1\x80\x41\x00'\
|
||||
b'\x41\x00\x63\x00\x22\x00\x32\x00\x16\x00\x14\x00\x1c\x00\x08\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\xc2\x18\x45\x18\x45\x10'\
|
||||
b'\x65\x10\x65\xb0\x28\xa0\x28\xa0\x38\xa0\x38\xe0\x10\x40\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x09\x00\x00\x00\x41\x00\x63\x00\x32\x00\x14\x00'\
|
||||
b'\x0c\x00\x1c\x00\x16\x00\x22\x00\x63\x00\x41\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x09\x00\x00\x00\xc1\x80\x63\x00\x22\x00\x36\x00\x14\x00'\
|
||||
b'\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x09\x00\x00\x00\x7f\x00\x03\x00\x06\x00\x04\x00\x0c\x00\x18\x00'\
|
||||
b'\x30\x00\x20\x00\x40\x00\xff\x00\x00\x00\x00\x00\x00\x00\x04\x00'\
|
||||
b'\x00\xc0\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\xc0\x04\x00'\
|
||||
b'\x00\x80\x80\x40\x40\x40\x20\x20\x20\x10\x10\x00\x00\x00\x04\x00'\
|
||||
b'\x00\xc0\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\xc0\x07\x00'\
|
||||
b'\x00\x20\x60\x50\x90\x88\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x04\x00'\
|
||||
b'\x00\x40\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00'\
|
||||
b'\x00\x00\x00\x78\x84\x04\x04\x7c\x84\x8c\x76\x00\x00\x00\x08\x00'\
|
||||
b'\x00\x80\x80\xb8\xcc\x84\x84\x84\x84\xc8\xb8\x00\x00\x00\x07\x00'\
|
||||
b'\x00\x00\x00\x78\x44\x80\x80\x80\x80\x44\x78\x00\x00\x00\x08\x00'\
|
||||
b'\x00\x02\x02\x3a\x46\x82\x82\x82\x82\x46\x3a\x00\x00\x00\x07\x00'\
|
||||
b'\x00\x00\x00\x3c\x44\x82\xfe\x80\x80\x46\x3c\x00\x00\x00\x04\x00'\
|
||||
b'\x00\x60\x40\xe0\x40\x40\x40\x40\x40\x40\x40\x00\x00\x00\x08\x00'\
|
||||
b'\x00\x00\x00\x3a\x46\x82\x82\x82\x82\x46\x7a\x02\x84\x7c\x08\x00'\
|
||||
b'\x00\x80\x80\xb0\xc8\x88\x88\x88\x88\x88\x88\x00\x00\x00\x03\x00'\
|
||||
b'\x00\x80\x00\x80\x80\x80\x80\x80\x80\x80\x80\x00\x00\x00\x03\x00'\
|
||||
b'\x00\x40\x00\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\xc0\x07\x00'\
|
||||
b'\x00\x80\x80\x88\x90\xa0\xe0\x90\x98\x88\x8c\x00\x00\x00\x03\x00'\
|
||||
b'\x00\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00\x00\x00\x0b\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xb7\x00\xcc\x80\x88\x80\x88\x80\x88\x80'\
|
||||
b'\x88\x80\x88\x80\x88\x80\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\xb8\xc4\x84\x84\x84\x84\x84\x84\x00\x00\x00\x07\x00\x00\x00'\
|
||||
b'\x00\x38\x44\x82\x82\x82\x82\x44\x38\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\xb8\xc8\x84\x84\x84\x84\xc8\xb8\x80\x80\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x3a\x46\x82\x82\x82\x82\x46\x7a\x02\x02\x00\x05\x00\x00\x00'\
|
||||
b'\x00\xa0\xc0\x80\x80\x80\x80\x80\x80\x00\x00\x00\x07\x00\x00\x00'\
|
||||
b'\x00\x70\x88\x80\xc0\x70\x08\x88\x70\x00\x00\x00\x04\x00\x00\x00'\
|
||||
b'\x40\xe0\x40\x40\x40\x40\x40\x40\x60\x00\x00\x00\x08\x00\x00\x00'\
|
||||
b'\x00\x84\x84\x84\x84\x84\x84\x8c\x74\x00\x00\x00\x07\x00\x00\x00'\
|
||||
b'\x00\xc6\x44\x44\x6c\x28\x28\x38\x10\x00\x00\x00\x0a\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x8c\x40\xcc\xc0\x4c\x80\x5c\x80\x52\x80\x73\x80'\
|
||||
b'\x33\x00\x33\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x44'\
|
||||
b'\x68\x28\x30\x30\x28\x4c\xc4\x00\x00\x00\x07\x00\x00\x00\x00\xc6'\
|
||||
b'\x44\x44\x6c\x28\x28\x30\x10\x10\x20\x60\x07\x00\x00\x00\x00\x7c'\
|
||||
b'\x0c\x08\x10\x30\x60\x40\xfc\x00\x00\x00\x05\x00\x00\x60\x40\x40'\
|
||||
b'\x40\x40\x40\x80\x40\x40\x40\x40\x40\x60\x04\x00\x00\x80\x80\x80'\
|
||||
b'\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x05\x00\x00\xc0\x40\x40'\
|
||||
b'\x40\x40\x40\x20\x40\x40\x40\x40\x40\xc0\x07\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x62\x9e\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x10\x00\x20\x00\x30\x00\x40\x00\x50\x00\x60\x00\x7e\x00'\
|
||||
b'\x9c\x00\xac\x00\xbc\x00\xcc\x00\xdc\x00\xec\x00\xfc\x00\x0c\x01'\
|
||||
b'\x1c\x01\x2c\x01\x3c\x01\x4c\x01\x5c\x01\x6c\x01\x7c\x01\x8c\x01'\
|
||||
b'\x9c\x01\xac\x01\xbc\x01\xcc\x01\xdc\x01\xec\x01\xfc\x01\x0c\x02'\
|
||||
b'\x1c\x02\x2c\x02\x4a\x02\x68\x02\x86\x02\xa4\x02\xc2\x02\xe0\x02'\
|
||||
b'\xf0\x02\x0e\x03\x2c\x03\x3c\x03\x4c\x03\x6a\x03\x7a\x03\x98\x03'\
|
||||
b'\xb6\x03\xd4\x03\xf2\x03\x10\x04\x2e\x04\x4c\x04\x6a\x04\x88\x04'\
|
||||
b'\xa6\x04\xc4\x04\xe2\x04\x00\x05\x1e\x05\x2e\x05\x3e\x05\x4e\x05'\
|
||||
b'\x5e\x05\x6e\x05\x7e\x05\x8e\x05\x9e\x05\xae\x05\xbe\x05\xce\x05'\
|
||||
b'\xde\x05\xee\x05\xfe\x05\x0e\x06\x1e\x06\x2e\x06\x3e\x06\x5c\x06'\
|
||||
b'\x6c\x06\x7c\x06\x8c\x06\x9c\x06\xac\x06\xbc\x06\xcc\x06\xdc\x06'\
|
||||
b'\xec\x06\x0a\x07\x1a\x07\x2a\x07\x3a\x07\x4a\x07\x5a\x07\x6a\x07'\
|
||||
b'\x7a\x07'
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
|
||||
def _chr_addr(ordch):
|
||||
offset = 2 * (ordch - 32)
|
||||
return int.from_bytes(_index[offset:offset + 2], 'little')
|
||||
|
||||
def get_ch(ch):
|
||||
ordch = ord(ch)
|
||||
ordch = ordch + 1 if ordch >= 32 and ordch <= 126 else 32
|
||||
offset = _chr_addr(ordch)
|
||||
width = int.from_bytes(_font[offset:offset + 2], 'little')
|
||||
next_offs = _chr_addr(ordch +1)
|
||||
return _mvfont[offset + 2:next_offs], 14, width
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
# Code generated by font-to-py.py.
|
||||
# Font: FreeSans.ttf
|
||||
version = '0.25'
|
||||
|
||||
def height():
|
||||
return 20
|
||||
|
||||
def max_width():
|
||||
return 20
|
||||
|
||||
def hmap():
|
||||
return True
|
||||
|
||||
def reverse():
|
||||
return False
|
||||
|
||||
def monospaced():
|
||||
return False
|
||||
|
||||
def min_ch():
|
||||
return 32
|
||||
|
||||
def max_ch():
|
||||
return 126
|
||||
|
||||
_font =\
|
||||
b'\x0b\x00\x00\x00\x3c\x00\x7e\x00\xc7\x00\xc3\x00\x03\x00\x03\x00'\
|
||||
b'\x06\x00\x0c\x00\x08\x00\x18\x00\x18\x00\x00\x00\x00\x00\x18\x00'\
|
||||
b'\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x07\x00\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00'\
|
||||
b'\xc0\xc0\x00\x00\x00\x00\x07\x00\x00\x00\xd8\xd8\xd8\xd8\x90\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x0c\xc0\x08\x80\x08\x80\x7f\xe0\x7f\xe0\x19\x80\x11\x00'\
|
||||
b'\x11\x00\xff\xc0\xff\xc0\x33\x00\x33\x00\x22\x00\x22\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0b\x00\x08\x00\x3e\x00\x7f\x80\xe9\xc0'\
|
||||
b'\xc8\xc0\xc8\xc0\xc8\x00\xe8\x00\x7c\x00\x1f\x80\x09\xc0\x08\xc0'\
|
||||
b'\xc8\xc0\xe9\xc0\x7f\x80\x3e\x00\x08\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x12\x00\x00\x00\x00\x00\x00\x00\x38\x10\x00\x7c\x10\x00\xc6\x20'\
|
||||
b'\x00\xc6\x20\x00\xc6\x40\x00\x7c\xc0\x00\x38\x80\x00\x01\x1e\x00'\
|
||||
b'\x01\x3f\x00\x02\x73\x80\x02\x61\x80\x04\x73\x80\x04\x3f\x00\x08'\
|
||||
b'\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00'\
|
||||
b'\x00\x00\x00\x00\x0e\x00\x1f\x00\x31\x80\x31\x80\x31\x80\x1f\x00'\
|
||||
b'\x1c\x00\x76\x60\xe3\x60\xc1\xc0\xc0\xc0\xe1\xc0\x7f\x60\x3e\x30'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\xc0\xc0\xc0\xc0'\
|
||||
b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00'\
|
||||
b'\x00\x10\x10\x20\x20\x60\x40\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x40\x60'\
|
||||
b'\x20\x30\x10\x18\x07\x00\x00\x40\x40\x20\x20\x30\x10\x18\x18\x18'\
|
||||
b'\x18\x18\x18\x18\x10\x30\x20\x60\x40\xc0\x08\x00\x00\x20\x20\xf8'\
|
||||
b'\x20\x50\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x18\x00\x18\x00\x18\x00\xff\x00\xff\x00\x18\x00\x18\x00\x18\x00'\
|
||||
b'\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xc0\x40\x40\x80\x00'\
|
||||
b'\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xf8\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xc0\xc0\x00\x00\x00\x00\x06\x00\x00\x04'\
|
||||
b'\x0c\x08\x08\x18\x10\x10\x30\x20\x20\x60\x40\x40\xc0\x80\x00\x00'\
|
||||
b'\x00\x00\x0b\x00\x00\x00\x00\x00\x3e\x00\x7f\x00\x63\x00\xe3\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xe3\x80\x63\x00'\
|
||||
b'\x7f\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x10\x00\x30\x00\xf0\x00\xf0\x00\x30\x00\x30\x00\x30\x00'\
|
||||
b'\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x3e\x00\x7f\x00'\
|
||||
b'\xe3\x80\xc1\x80\x01\x80\x01\x80\x03\x00\x0e\x00\x1c\x00\x30\x00'\
|
||||
b'\x60\x00\xc0\x00\xff\x80\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0b\x00\x00\x00\x00\x00\x3e\x00\x7f\x00\xe3\x80\xc1\x80\x01\x80'\
|
||||
b'\x0f\x00\x0f\x00\x03\x80\x01\x80\x01\x80\xc1\x80\xe3\x80\x7f\x00'\
|
||||
b'\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00'\
|
||||
b'\x06\x00\x06\x00\x0e\x00\x1e\x00\x16\x00\x26\x00\x46\x00\x46\x00'\
|
||||
b'\x86\x00\xff\x00\xff\x00\x06\x00\x06\x00\x06\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x7f\x00\x7f\x00\x60\x00'\
|
||||
b'\x60\x00\xde\x00\xff\x00\xe3\x80\x01\x80\x01\x80\x01\x80\x01\x80'\
|
||||
b'\xc3\x00\x7f\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00'\
|
||||
b'\x00\x00\x00\x00\x1e\x00\x3f\x00\x63\x00\x61\x80\xc0\x00\xde\x00'\
|
||||
b'\xff\x00\xe3\x80\xc1\x80\xc1\x80\xc1\x80\x63\x80\x7f\x00\x3e\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\xff\x80'\
|
||||
b'\xff\x80\x01\x00\x03\x00\x02\x00\x06\x00\x04\x00\x0c\x00\x08\x00'\
|
||||
b'\x18\x00\x18\x00\x10\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0b\x00\x00\x00\x00\x00\x1c\x00\x3e\x00\x63\x00\x63\x00'\
|
||||
b'\x63\x00\x3e\x00\x3e\x00\x63\x00\xc1\x80\xc1\x80\xc1\x80\x63\x00'\
|
||||
b'\x7f\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x3e\x00\x7f\x00\xe3\x00\xc1\x80\xc1\x80\xc1\x80\xe3\x80'\
|
||||
b'\x7f\x80\x3d\x80\x01\x80\x03\x00\xe3\x00\x7e\x00\x3c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\xc0\xc0\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xc0\xc0\x00\x00\x00\x00\x05\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\xc0\xc0\x00\x00\x00\x00\x00\x00\xc0\xc0\x40\x40'\
|
||||
b'\x80\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x40\x01\xc0\x07\x00\x3c\x00\xe0\x00\xe0\x00\x78\x00\x0f\x00'\
|
||||
b'\x03\xc0\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xc0'\
|
||||
b'\xff\xc0\x00\x00\x00\x00\xff\xc0\xff\xc0\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\xe0\x00\x78\x00\x0e\x00\x03\xc0\x01\xc0'\
|
||||
b'\x07\x00\x3c\x00\xf0\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0b\x00\x00\x00\x3c\x00\x7e\x00\xc7\x00\xc3\x00\x03\x00\x03\x00'\
|
||||
b'\x06\x00\x0c\x00\x08\x00\x18\x00\x18\x00\x00\x00\x00\x00\x18\x00'\
|
||||
b'\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x03'\
|
||||
b'\xf0\x00\x0f\xfc\x00\x1e\x0f\x00\x38\x03\x80\x71\xe1\x80\x63\xe9'\
|
||||
b'\xc0\x67\x18\xc0\xce\x18\xc0\xcc\x18\xc0\xcc\x10\xc0\xcc\x31\x80'\
|
||||
b'\xce\x73\x80\x67\xff\x00\x63\x9e\x00\x30\x00\x00\x3c\x00\x00\x0f'\
|
||||
b'\xf8\x00\x03\xf0\x00\x00\x00\x00\x0d\x00\x00\x00\x07\x00\x07\x00'\
|
||||
b'\x07\x80\x0d\x80\x0d\x80\x08\xc0\x18\xc0\x18\xc0\x10\x60\x3f\xe0'\
|
||||
b'\x3f\xe0\x30\x30\x60\x30\x60\x38\xc0\x18\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0d\x00\x00\x00\xff\x00\xff\x80\xc1\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc1\xc0\xff\x00\xff\x80\xc0\xc0\xc0\x60\xc0\x60\xc0\x60\xc0\xe0'\
|
||||
b'\xff\xc0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x0f\x80\x3f\xe0\x70\x60\x60\x30\xe0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xe0\x30\x60\x70\x70\x60\x3f\xe0\x0f\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\xff\x00\xff\x80\xc1\xc0'\
|
||||
b'\xc0\xc0\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60'\
|
||||
b'\xc0\xc0\xc1\xc0\xff\x80\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0d\x00\x00\x00\xff\xc0\xff\xc0\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xff\x80\xff\x80\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xff\xc0'\
|
||||
b'\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\xff\x80'\
|
||||
b'\xff\x80\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xff\x00\xff\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0f\x00\x00\x00\x0f\xc0\x3f\xf0\x38\x30\x60\x18'\
|
||||
b'\x60\x00\xc0\x00\xc0\x00\xc1\xf8\xc1\xf8\xc0\x18\xe0\x18\x60\x38'\
|
||||
b'\x78\x78\x3f\xd8\x0f\x88\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00'\
|
||||
b'\x00\x00\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xff\xe0'\
|
||||
b'\xff\xe0\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x0b\x00'\
|
||||
b'\x00\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00'\
|
||||
b'\x03\x00\x03\x00\x03\x00\xc3\x00\xc3\x00\xe7\x00\x7e\x00\x3c\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\xc0\x60\xc0\xc0'\
|
||||
b'\xc1\x80\xc3\x00\xc6\x00\xcc\x00\xdc\x00\xf6\x00\xe6\x00\xc3\x00'\
|
||||
b'\xc1\x80\xc1\x80\xc0\xc0\xc0\x60\xc0\x60\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0b\x00\x00\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xff\x80\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00'\
|
||||
b'\x00\xe0\x1c\x00\xe0\x1c\x00\xf0\x3c\x00\xf0\x3c\x00\xd0\x2c\x00'\
|
||||
b'\xd8\x6c\x00\xd8\x6c\x00\xc8\x4c\x00\xcc\xcc\x00\xcc\xcc\x00\xc4'\
|
||||
b'\x8c\x00\xc6\x8c\x00\xc7\x8c\x00\xc3\x0c\x00\xc3\x0c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\xe0\x60'\
|
||||
b'\xe0\x60\xf0\x60\xf0\x60\xd8\x60\xd8\x60\xcc\x60\xc4\x60\xc6\x60'\
|
||||
b'\xc2\x60\xc3\x60\xc1\xe0\xc1\xe0\xc0\xe0\xc0\xe0\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x10\x00\x00\x00\x0f\xc0\x1f\xe0\x38\x70\x60\x18'\
|
||||
b'\x60\x1c\xc0\x0c\xc0\x0c\xc0\x0c\xc0\x0c\xc0\x0c\x60\x1c\x60\x18'\
|
||||
b'\x38\x70\x1f\xe0\x0f\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00'\
|
||||
b'\x00\x00\xff\x00\xff\x80\xc1\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc1\xc0'\
|
||||
b'\xff\x80\xff\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x0f\xc0\x1f\xe0'\
|
||||
b'\x38\x70\x60\x18\x60\x1c\xc0\x0c\xc0\x0c\xc0\x0c\xc0\x0c\xc0\x0c'\
|
||||
b'\x60\x18\x60\xd8\x38\x70\x1f\xf8\x0f\x98\x00\x08\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0e\x00\x00\x00\xff\x80\xff\xc0\xc0\xe0\xc0\x60\xc0\x60'\
|
||||
b'\xc0\x60\xc0\xc0\xff\x80\xff\xc0\xc0\xe0\xc0\x60\xc0\x60\xc0\x60'\
|
||||
b'\xc0\x60\xc0\x70\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00'\
|
||||
b'\x1f\x80\x7f\xe0\xe0\x70\xc0\x30\xc0\x00\xe0\x00\x78\x00\x3f\x80'\
|
||||
b'\x03\xe0\x00\x70\xc0\x30\xc0\x30\x70\x60\x7f\xe0\x1f\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\xff\xc0\xff\xc0\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x0c\x00'\
|
||||
b'\x0c\x00\x0c\x00\x0c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60'\
|
||||
b'\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\xc0\x60\x60\xc0\x7f\xc0'\
|
||||
b'\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\xc0\x30'\
|
||||
b'\x60\x30\x60\x30\x20\x20\x30\x60\x30\x60\x10\x40\x18\xc0\x18\xc0'\
|
||||
b'\x08\x80\x0d\x80\x0d\x80\x07\x00\x07\x00\x07\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x13\x00\x00\x00\x00\xc0\xc0\xc0\x60\xe0\xc0\x60'\
|
||||
b'\xe0\xc0\x61\xe0\xc0\x61\xb1\x80\x31\xb1\x80\x31\xb1\x80\x33\x11'\
|
||||
b'\x80\x33\x19\x00\x13\x1b\x00\x1f\x1b\x00\x1e\x0b\x00\x1e\x0e\x00'\
|
||||
b'\x0e\x0e\x00\x0c\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0d\x00\x00\x00\x60\x30\x30\x70\x30\x60\x18\xc0\x0c\xc0'\
|
||||
b'\x0d\x80\x07\x00\x07\x00\x07\x00\x0d\x80\x18\xc0\x18\xe0\x30\x60'\
|
||||
b'\x70\x30\x60\x38\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00'\
|
||||
b'\x60\x18\x70\x38\x30\x30\x18\x60\x18\x60\x0c\xc0\x0f\xc0\x07\x80'\
|
||||
b'\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\xff\xe0\xff\xe0\x00\xc0'\
|
||||
b'\x01\x80\x03\x80\x03\x00\x06\x00\x0c\x00\x1c\x00\x38\x00\x30\x00'\
|
||||
b'\x60\x00\xc0\x00\xff\xe0\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x06\x00\x00\xe0\xe0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xe0\xe0\x06\x00\x00\x80\xc0\x40\x40\x60\x20\x20'\
|
||||
b'\x30\x10\x10\x18\x08\x08\x0c\x04\x00\x00\x00\x00\x06\x00\x00\xe0'\
|
||||
b'\xe0\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\xe0\xe0\x09\x00\x00\x00\x00\x00\x18\x00\x38\x00\x28\x00\x2c\x00'\
|
||||
b'\x64\x00\x46\x00\xc2\x00\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xf0'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x05\x00\x00\xc0\x60\x30\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x3e\x00\xff\x80\xc1\x80\x01\x80'\
|
||||
b'\x01\x80\x3f\x80\xf1\x80\xc1\x80\xc3\x80\xff\xc0\x78\xc0\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc0\x00\xdf\x00\xff\x80\xe1\x80\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xe1\x80\xff\x80\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x7f\x00'\
|
||||
b'\x61\x80\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc1\x80\x63\x80\x7f\x00'\
|
||||
b'\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x01\x80'\
|
||||
b'\x01\x80\x01\x80\x01\x80\x3d\x80\x7f\x80\x63\x80\xc1\x80\xc1\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\x63\x80\x7f\x80\x3d\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3e\x00\x7f\x00\x63\x00\xc1\x80\xff\x80\xff\x80\xc0\x00\xc0\x00'\
|
||||
b'\x63\x80\x7f\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00'\
|
||||
b'\x00\x30\x70\x60\x60\xf0\xf0\x60\x60\x60\x60\x60\x60\x60\x60\x60'\
|
||||
b'\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x3d\x80\x7f\x80\x63\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\x63\x80\x7f\x80\x3d\x80\x01\x80\xc3\x80\x7f\x00\x3e\x00\x0b\x00'\
|
||||
b'\x00\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xdf\x00\xdf\x80\xe3\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\xc0\xc0\x00\x00\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x05\x00'\
|
||||
b'\x00\x30\x30\x00\x00\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30'\
|
||||
b'\x30\x30\xf0\xe0\x0a\x00\x00\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00'\
|
||||
b'\xc3\x00\xc6\x00\xcc\x00\xd8\x00\xf8\x00\xec\x00\xce\x00\xc6\x00'\
|
||||
b'\xc3\x00\xc3\x00\xc1\x80\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00'\
|
||||
b'\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xde\x78\xfe\xfc\xe3\x8c\xc3\x0c\xc3\x0c\xc3\x0c\xc3\x0c\xc3\x0c'\
|
||||
b'\xc3\x0c\xc3\x0c\xc3\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x00\xdf\x80\xe3\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x3e\x00\x7f\x00\x63\x00\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\xc1\x80\xc1\x80\x63\x00\x7f\x00\x3e\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\x00'\
|
||||
b'\xff\x80\xe1\x80\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xe1\x80'\
|
||||
b'\xff\x80\xde\x00\xc0\x00\xc0\x00\xc0\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x3d\x80\x7f\x80\x63\x80\xc1\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\xc1\x80\x63\x80\x7f\x80\x3d\x80\x01\x80'\
|
||||
b'\x01\x80\x01\x80\x00\x00\x07\x00\x00\x00\x00\x00\x00\xd8\xf8\xe0'\
|
||||
b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x0a\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x00\x7f\x00\xc3\x00\xc0\x00'\
|
||||
b'\xf0\x00\x7e\x00\x0f\x00\x03\x00\xc3\x00\xfe\x00\x7c\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x60\x60\xf0\xf0\x60'\
|
||||
b'\x60\x60\x60\x60\x60\x60\x70\x70\x00\x00\x00\x00\x0b\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x80\xc1\x80\xc1\x80\xc1\x80'\
|
||||
b'\xc1\x80\xc1\x80\xc1\x80\xc1\x80\xe3\x80\xfd\x80\x79\x80\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\xc0\xc0\x61\x80\x61\x80\x61\x00\x23\x00\x33\x00\x32\x00'\
|
||||
b'\x16\x00\x1e\x00\x1c\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\x0c\xc3\x8c'\
|
||||
b'\x63\x8c\x67\x88\x66\x98\x24\xd8\x34\xd0\x3c\xd0\x3c\x70\x18\x70'\
|
||||
b'\x18\x60\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x61\x80\x63\x00\x33\x00\x1e\x00\x1c\x00'\
|
||||
b'\x0c\x00\x1c\x00\x16\x00\x33\x00\x63\x00\x41\x80\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\xc0\x80\x41\x80\x61\x80\x61\x00\x23\x00\x33\x00\x32\x00\x16\x00'\
|
||||
b'\x1c\x00\x1c\x00\x0c\x00\x08\x00\x18\x00\x78\x00\x70\x00\x0a\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xff\x00\x06\x00'\
|
||||
b'\x06\x00\x0c\x00\x18\x00\x30\x00\x60\x00\xc0\x00\xff\x00\xff\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x18\x38\x30\x30\x30'\
|
||||
b'\x30\x30\x30\x70\xc0\x70\x30\x30\x30\x30\x30\x30\x38\x18\x05\x00'\
|
||||
b'\x00\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0'\
|
||||
b'\xc0\xc0\xc0\xc0\x07\x00\x00\xc0\xe0\x60\x60\x60\x60\x60\x60\x70'\
|
||||
b'\x18\x70\x60\x60\x60\x60\x60\x60\xe0\xc0\x0a\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\xf1\x00\x9f\x00'\
|
||||
b'\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
|
||||
b'\x00\x00\x00\x00'
|
||||
|
||||
_index =\
|
||||
b'\x00\x00\x2a\x00\x2a\x00\x40\x00\x40\x00\x56\x00\x56\x00\x6c\x00'\
|
||||
b'\x6c\x00\x96\x00\x96\x00\xc0\x00\xc0\x00\xfe\x00\xfe\x00\x28\x01'\
|
||||
b'\x28\x01\x3e\x01\x3e\x01\x54\x01\x54\x01\x6a\x01\x6a\x01\x80\x01'\
|
||||
b'\x80\x01\xaa\x01\xaa\x01\xc0\x01\xc0\x01\xd6\x01\xd6\x01\xec\x01'\
|
||||
b'\xec\x01\x02\x02\x02\x02\x2c\x02\x2c\x02\x56\x02\x56\x02\x80\x02'\
|
||||
b'\x80\x02\xaa\x02\xaa\x02\xd4\x02\xd4\x02\xfe\x02\xfe\x02\x28\x03'\
|
||||
b'\x28\x03\x52\x03\x52\x03\x7c\x03\x7c\x03\xa6\x03\xa6\x03\xbc\x03'\
|
||||
b'\xbc\x03\xd2\x03\xd2\x03\xfc\x03\xfc\x03\x26\x04\x26\x04\x50\x04'\
|
||||
b'\x50\x04\x7a\x04\x7a\x04\xb8\x04\xb8\x04\xe2\x04\xe2\x04\x0c\x05'\
|
||||
b'\x0c\x05\x36\x05\x36\x05\x60\x05\x60\x05\x8a\x05\x8a\x05\xb4\x05'\
|
||||
b'\xb4\x05\xde\x05\xde\x05\x08\x06\x08\x06\x1e\x06\x1e\x06\x48\x06'\
|
||||
b'\x48\x06\x72\x06\x72\x06\x9c\x06\x9c\x06\xda\x06\xda\x06\x04\x07'\
|
||||
b'\x04\x07\x2e\x07\x2e\x07\x58\x07\x58\x07\x82\x07\x82\x07\xac\x07'\
|
||||
b'\xac\x07\xd6\x07\xd6\x07\x00\x08\x00\x08\x2a\x08\x2a\x08\x54\x08'\
|
||||
b'\x54\x08\x92\x08\x92\x08\xbc\x08\xbc\x08\xe6\x08\xe6\x08\x10\x09'\
|
||||
b'\x10\x09\x26\x09\x26\x09\x3c\x09\x3c\x09\x52\x09\x52\x09\x7c\x09'\
|
||||
b'\x7c\x09\xa6\x09\xa6\x09\xbc\x09\xbc\x09\xe6\x09\xe6\x09\x10\x0a'\
|
||||
b'\x10\x0a\x3a\x0a\x3a\x0a\x64\x0a\x64\x0a\x8e\x0a\x8e\x0a\xa4\x0a'\
|
||||
b'\xa4\x0a\xce\x0a\xce\x0a\xf8\x0a\xf8\x0a\x0e\x0b\x0e\x0b\x24\x0b'\
|
||||
b'\x24\x0b\x4e\x0b\x4e\x0b\x64\x0b\x64\x0b\x8e\x0b\x8e\x0b\xb8\x0b'\
|
||||
b'\xb8\x0b\xe2\x0b\xe2\x0b\x0c\x0c\x0c\x0c\x36\x0c\x36\x0c\x4c\x0c'\
|
||||
b'\x4c\x0c\x76\x0c\x76\x0c\x8c\x0c\x8c\x0c\xb6\x0c\xb6\x0c\xe0\x0c'\
|
||||
b'\xe0\x0c\x0a\x0d\x0a\x0d\x34\x0d\x34\x0d\x5e\x0d\x5e\x0d\x88\x0d'\
|
||||
b'\x88\x0d\x9e\x0d\x9e\x0d\xb4\x0d\xb4\x0d\xca\x0d\xca\x0d\xf4\x0d'\
|
||||
|
||||
_mvfont = memoryview(_font)
|
||||
|
||||
def get_ch(ch):
|
||||
ordch = ord(ch)
|
||||
ordch = ordch + 1 if ordch >= 32 and ordch <= 126 else 32
|
||||
idx_offs = 4 * (ordch - 32)
|
||||
offset = int.from_bytes(_index[idx_offs : idx_offs + 2], 'little')
|
||||
next_offs = int.from_bytes(_index[idx_offs + 2 : idx_offs + 4], 'little')
|
||||
width = int.from_bytes(_font[offset:offset + 2], 'little')
|
||||
return _mvfont[offset + 2:next_offs], 20, width
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# __init__.py Common functions for uasyncio primitives
|
||||
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
try:
|
||||
import uasyncio as asyncio
|
||||
except ImportError:
|
||||
import asyncio
|
||||
|
||||
|
||||
async def _g():
|
||||
pass
|
||||
type_coro = type(_g())
|
||||
|
||||
# If a callback is passed, run it and return.
|
||||
# If a coro is passed initiate it and return.
|
||||
# coros are passed by name i.e. not using function call syntax.
|
||||
def launch(func, tup_args):
|
||||
res = func(*tup_args)
|
||||
if isinstance(res, type_coro):
|
||||
res = asyncio.create_task(res)
|
||||
return res
|
||||
|
||||
def set_global_exception():
|
||||
def _handle_exception(loop, context):
|
||||
import sys
|
||||
sys.print_exception(context["exception"])
|
||||
sys.exit()
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.set_exception_handler(_handle_exception)
|
|
@ -0,0 +1,71 @@
|
|||
# delay_ms.py Now uses ThreadSafeFlag and has extra .wait() API
|
||||
# Usage:
|
||||
# from primitives.delay_ms import Delay_ms
|
||||
|
||||
# Copyright (c) 2018-2021 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
import uasyncio as asyncio
|
||||
from utime import ticks_add, ticks_diff, ticks_ms
|
||||
from . import launch
|
||||
|
||||
class Delay_ms:
|
||||
|
||||
class DummyTimer: # Stand-in for the timer class. Can be cancelled.
|
||||
def cancel(self):
|
||||
pass
|
||||
_fake = DummyTimer()
|
||||
|
||||
def __init__(self, func=None, args=(), duration=1000):
|
||||
self._func = func
|
||||
self._args = args
|
||||
self._durn = duration # Default duration
|
||||
self._retn = None # Return value of launched callable
|
||||
self._tend = None # Stop time (absolute ms).
|
||||
self._busy = False
|
||||
self._trig = asyncio.ThreadSafeFlag()
|
||||
self._tout = asyncio.Event() # Timeout event
|
||||
self.wait = self._tout.wait # Allow: await wait_ms.wait()
|
||||
self._ttask = self._fake # Timer task
|
||||
asyncio.create_task(self._run())
|
||||
|
||||
async def _run(self):
|
||||
while True:
|
||||
await self._trig.wait() # Await a trigger
|
||||
self._ttask.cancel() # Cancel and replace
|
||||
await asyncio.sleep_ms(0)
|
||||
dt = max(ticks_diff(self._tend, ticks_ms()), 0) # Beware already elapsed.
|
||||
self._ttask = asyncio.create_task(self._timer(dt))
|
||||
|
||||
async def _timer(self, dt):
|
||||
await asyncio.sleep_ms(dt)
|
||||
self._tout.set() # Only gets here if not cancelled.
|
||||
self._tout.clear()
|
||||
self._busy = False
|
||||
if self._func is not None:
|
||||
self._retn = launch(self._func, self._args)
|
||||
|
||||
# API
|
||||
# trigger may be called from hard ISR.
|
||||
def trigger(self, duration=0): # Update absolute end time, 0-> ctor default
|
||||
self._tend = ticks_add(ticks_ms(), duration if duration > 0 else self._durn)
|
||||
self._retn = None # Default in case cancelled.
|
||||
self._busy = True
|
||||
self._trig.set()
|
||||
|
||||
def stop(self):
|
||||
self._ttask.cancel()
|
||||
self._ttask = self._fake
|
||||
self._busy = False
|
||||
|
||||
def __call__(self): # Current running status
|
||||
return self._busy
|
||||
|
||||
running = __call__
|
||||
|
||||
def rvalue(self):
|
||||
return self._retn
|
||||
|
||||
def callback(self, func=None, args=()):
|
||||
self._func = func
|
||||
self._args = args
|
|
@ -0,0 +1,107 @@
|
|||
# pushbutton.py
|
||||
|
||||
# Copyright (c) 2018-2021 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
import uasyncio as asyncio
|
||||
import utime as time
|
||||
from . import launch
|
||||
from gui.primitives.delay_ms import Delay_ms
|
||||
|
||||
|
||||
# An alternative Pushbutton solution with lower RAM use is available here
|
||||
# https://github.com/kevinkk525/pysmartnode/blob/dev/pysmartnode/utils/abutton.py
|
||||
class Pushbutton:
|
||||
debounce_ms = 50
|
||||
long_press_ms = 1000
|
||||
double_click_ms = 400
|
||||
def __init__(self, pin, suppress=False, sense=None):
|
||||
self.pin = pin # Initialise for input
|
||||
self._supp = suppress
|
||||
self._dblpend = False # Doubleclick waiting for 2nd click
|
||||
self._dblran = False # Doubleclick executed user function
|
||||
self._tf = False
|
||||
self._ff = False
|
||||
self._df = False
|
||||
self._ld = False # Delay_ms instance for long press
|
||||
self._dd = False # Ditto for doubleclick
|
||||
self.sense = pin.value() if sense is None else sense # Convert from electrical to logical value
|
||||
self.state = self.rawstate() # Initial state
|
||||
asyncio.create_task(self.buttoncheck()) # Thread runs forever
|
||||
|
||||
def press_func(self, func=False, args=()):
|
||||
self._tf = func
|
||||
self._ta = args
|
||||
|
||||
def release_func(self, func=False, args=()):
|
||||
self._ff = func
|
||||
self._fa = args
|
||||
|
||||
def double_func(self, func=False, args=()):
|
||||
self._df = func
|
||||
self._da = args
|
||||
if func: # If double timer already in place, leave it
|
||||
if not self._dd:
|
||||
self._dd = Delay_ms(self._ddto)
|
||||
else:
|
||||
self._dd = False # Clearing down double func
|
||||
|
||||
def long_func(self, func=False, args=()):
|
||||
if func:
|
||||
if self._ld:
|
||||
self._ld.callback(func, args)
|
||||
else:
|
||||
self._ld = Delay_ms(func, args)
|
||||
else:
|
||||
self._ld = False
|
||||
|
||||
# Current non-debounced logical button state: True == pressed
|
||||
def rawstate(self):
|
||||
return bool(self.pin.value() ^ self.sense)
|
||||
|
||||
# Current debounced state of button (True == pressed)
|
||||
def __call__(self):
|
||||
return self.state
|
||||
|
||||
def _ddto(self): # Doubleclick timeout: no doubleclick occurred
|
||||
self._dblpend = False
|
||||
if self._supp and not self.state:
|
||||
if not self._ld or (self._ld and not self._ld()):
|
||||
launch(self._ff, self._fa)
|
||||
|
||||
async def buttoncheck(self):
|
||||
while True:
|
||||
state = self.rawstate()
|
||||
# State has changed: act on it now.
|
||||
if state != self.state:
|
||||
self.state = state
|
||||
if state: # Button pressed: launch pressed func
|
||||
if self._tf:
|
||||
launch(self._tf, self._ta)
|
||||
if self._ld: # There's a long func: start long press delay
|
||||
self._ld.trigger(Pushbutton.long_press_ms)
|
||||
if self._df:
|
||||
if self._dd(): # Second click: timer running
|
||||
self._dd.stop()
|
||||
self._dblpend = False
|
||||
self._dblran = True # Prevent suppressed launch on release
|
||||
launch(self._df, self._da)
|
||||
else:
|
||||
# First click: start doubleclick timer
|
||||
self._dd.trigger(Pushbutton.double_click_ms)
|
||||
self._dblpend = True # Prevent suppressed launch on release
|
||||
else: # Button release. Is there a release func?
|
||||
if self._ff:
|
||||
if self._supp:
|
||||
d = self._ld
|
||||
# If long delay exists, is running and doubleclick status is OK
|
||||
if not self._dblpend and not self._dblran:
|
||||
if (d and d()) or not d:
|
||||
launch(self._ff, self._fa)
|
||||
else:
|
||||
launch(self._ff, self._fa)
|
||||
if self._ld:
|
||||
self._ld.stop() # Avoid interpreting a second click as a long push
|
||||
self._dblran = False
|
||||
# Ignore state changes until switch has settled
|
||||
await asyncio.sleep_ms(Pushbutton.debounce_ms)
|
|
@ -0,0 +1,42 @@
|
|||
# switch.py
|
||||
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
import uasyncio as asyncio
|
||||
import utime as time
|
||||
from . import launch
|
||||
|
||||
class Switch:
|
||||
debounce_ms = 50
|
||||
def __init__(self, pin):
|
||||
self.pin = pin # Should be initialised for input with pullup
|
||||
self._open_func = False
|
||||
self._close_func = False
|
||||
self.switchstate = self.pin.value() # Get initial state
|
||||
asyncio.create_task(self.switchcheck()) # Thread runs forever
|
||||
|
||||
def open_func(self, func, args=()):
|
||||
self._open_func = func
|
||||
self._open_args = args
|
||||
|
||||
def close_func(self, func, args=()):
|
||||
self._close_func = func
|
||||
self._close_args = args
|
||||
|
||||
# Return current state of switch (0 = pressed)
|
||||
def __call__(self):
|
||||
return self.switchstate
|
||||
|
||||
async def switchcheck(self):
|
||||
while True:
|
||||
state = self.pin.value()
|
||||
if state != self.switchstate:
|
||||
# State has changed: act on it now.
|
||||
self.switchstate = state
|
||||
if state == 0 and self._close_func:
|
||||
launch(self._close_func, self._close_args)
|
||||
elif state == 1 and self._open_func:
|
||||
launch(self._open_func, self._open_args)
|
||||
# Ignore further state changes until switch has settled
|
||||
await asyncio.sleep_ms(Switch.debounce_ms)
|
|
@ -0,0 +1,218 @@
|
|||
# buttons.py Extension to ugui providing pushbutton classes
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
import uasyncio as asyncio
|
||||
from gui.core.ugui import Screen, Widget, display
|
||||
from gui.primitives.delay_ms import Delay_ms
|
||||
from gui.core.colors import *
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
|
||||
class Button(Widget):
|
||||
lit_time = 1000
|
||||
long_press_time = 1000
|
||||
def __init__(self, writer, row, col, *, shape=RECTANGLE, height=20, width=50,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, textcolor=None, litcolor=None, text='',
|
||||
callback=dolittle, args=[], onrelease=False, lp_callback=dolittle, lp_args=[]):
|
||||
sl = writer.stringlen(text)
|
||||
if shape == CIRCLE: # Only height need be specified
|
||||
width = max(sl, height)
|
||||
height = width
|
||||
else:
|
||||
width = max(sl, width)
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False, True)
|
||||
self.shape = shape
|
||||
self.radius = height // 2
|
||||
self.fill = bgcolor is not None # Draw background if color specified
|
||||
self.litcolor = litcolor
|
||||
self.textcolor = self.fgcolor if textcolor is None else textcolor
|
||||
self.orig_fgcolor = self.fgcolor
|
||||
self.orig_bgcolor = self.bgcolor
|
||||
self.text = text
|
||||
self.callback = callback
|
||||
self.callback_args = args
|
||||
self.onrelease = onrelease
|
||||
self.lp_callback = lp_callback
|
||||
self.lp_args = lp_args
|
||||
if self.litcolor is not None:
|
||||
self.delay = Delay_ms(self.shownormal)
|
||||
self.litcolor = litcolor if self.fgcolor is not None else None
|
||||
|
||||
def show(self):
|
||||
if self.screen is not Screen.current_screen:
|
||||
return
|
||||
x = self.col
|
||||
y = self.row
|
||||
w = self.width
|
||||
h = self.height
|
||||
if not self.visible: # erase the button
|
||||
display.usegrey(False)
|
||||
display.fill_rect(x, y, w, h, BGCOLOR)
|
||||
return
|
||||
super().show() # Blank rectangle containing button
|
||||
if self.shape == CIRCLE: # Button coords are of top left corner of bounding box
|
||||
x += self.radius
|
||||
y += self.radius
|
||||
if self.fill:
|
||||
display.fillcircle(x, y, self.radius, self.bgcolor)
|
||||
display.circle(x, y, self.radius, self.fgcolor)
|
||||
if len(self.text):
|
||||
display.print_centred(self.writer, x, y, self.text, self.textcolor, self.bgcolor)
|
||||
else:
|
||||
xc = x + w // 2
|
||||
yc = y + h // 2
|
||||
if self.shape == RECTANGLE: # rectangle
|
||||
if self.fill:
|
||||
display.fill_rect(x, y, w, h, self.bgcolor)
|
||||
display.rect(x, y, w, h, self.fgcolor)
|
||||
if len(self.text):
|
||||
display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor)
|
||||
elif self.shape == CLIPPED_RECT: # clipped rectangle
|
||||
if self.fill:
|
||||
display.fill_clip_rect(x, y, w, h, self.bgcolor)
|
||||
display.clip_rect(x, y, w, h, self.fgcolor)
|
||||
if len(self.text):
|
||||
display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor)
|
||||
|
||||
async def shownormal(self):
|
||||
# Handle case where screen changed while timer was active: delay repaint
|
||||
# until screen is current. Pathological app behaviour where another
|
||||
# control caused a screen change while timer running.
|
||||
while self.screen is not Screen.current_screen:
|
||||
await asyncio.sleep_ms(500)
|
||||
self.bgcolor = self.orig_bgcolor
|
||||
self.draw = True # Redisplay
|
||||
|
||||
def do_sel(self): # Select was pushed
|
||||
if not self.onrelease:
|
||||
self.callback(self, *self.callback_args) # CB takes self as 1st arg.
|
||||
if self.litcolor is not None and self.has_focus(): # CB may have changed focus
|
||||
self.bgcolor = self.litcolor
|
||||
self.draw = True # Redisplay
|
||||
self.delay.trigger(Button.lit_time)
|
||||
|
||||
def unsel(self): # Select was released
|
||||
if self.onrelease:
|
||||
self.callback(self, *self.callback_args) # Callback not a bound method so pass self
|
||||
|
||||
def longsel(self): # Select was long pressed
|
||||
self.lp_callback(self, *self.lp_args)
|
||||
|
||||
# Preferred way to close a screen or dialog. Produces an X button at the top RHS.
|
||||
# Note that if the bottom screen is closed, the application terminates.
|
||||
class CloseButton(Button):
|
||||
def __init__(self, writer, width=0, callback=dolittle, args=(), bgcolor=RED):
|
||||
scr = Screen.current_screen
|
||||
wd = max(writer.stringlen('X') + 6, width)
|
||||
self.user_cb = callback
|
||||
self.user_args = args
|
||||
super().__init__(writer, *scr.locn(4, scr.width - wd - 4),
|
||||
width = wd, height = wd, bgcolor = bgcolor,
|
||||
callback = self.cb, text = 'X')
|
||||
|
||||
def cb(self, _):
|
||||
self.user_cb(self, *self.user_args)
|
||||
Screen.back()
|
||||
|
||||
# Group of buttons, typically at same location, where pressing one shows
|
||||
# the next e.g. start/stop toggle or sequential select from short list
|
||||
class ButtonList:
|
||||
def __init__(self, callback=dolittle):
|
||||
self.user_callback = callback
|
||||
self.lstbuttons = []
|
||||
self.current = None # No current button
|
||||
self._greyed_out = False
|
||||
|
||||
def add_button(self, *args, **kwargs):
|
||||
button = Button(*args, **kwargs)
|
||||
self.lstbuttons.append(button)
|
||||
active = self.current is None # 1st button added is active
|
||||
button.visible = active
|
||||
button.callback = self._callback
|
||||
if active:
|
||||
self.current = button
|
||||
return button
|
||||
|
||||
def value(self, button=None, new_cb=False):
|
||||
if button is not None and button is not self.current:
|
||||
old = self.current
|
||||
new = button
|
||||
self.current = new
|
||||
old.visible = False
|
||||
new.visible = True
|
||||
new.draw = True # Redisplay without changing currency
|
||||
# Args for user callback: button instance followed by any specified.
|
||||
# Normal behaviour is to run cb of old button: this mimics a button press.
|
||||
# Optionally programmatic value changes can run the cb of new button.
|
||||
if new_cb: # Forced value change, callback is that of new button
|
||||
self.user_callback(new, *new.callback_args)
|
||||
else: # A button was pressed
|
||||
# Callback context is button just pressed, not the new one
|
||||
self.user_callback(old, *old.callback_args)
|
||||
return self.current
|
||||
|
||||
def greyed_out(self, val=None):
|
||||
if val is not None and self._greyed_out != val:
|
||||
self._greyed_out = val
|
||||
for button in self.lstbuttons:
|
||||
button.greyed_out(val)
|
||||
self.current.draw = True
|
||||
return self._greyed_out
|
||||
|
||||
def _callback(self, button, *_):
|
||||
old = button
|
||||
old_index = self.lstbuttons.index(button)
|
||||
new = self.lstbuttons[(old_index + 1) % len(self.lstbuttons)]
|
||||
self.current = new
|
||||
old.visible = False
|
||||
new.visible = True
|
||||
Screen.select(new) # Move currency and redisplay
|
||||
# Callback context is button just pressed, not the new one
|
||||
self.user_callback(old, *old.callback_args)
|
||||
|
||||
|
||||
# Group of buttons at different locations, where pressing one shows
|
||||
# only current button highlighted and oes callback from current one
|
||||
class RadioButtons:
|
||||
def __init__(self, highlight, callback=dolittle, selected=0):
|
||||
self.user_callback = callback
|
||||
self.lstbuttons = []
|
||||
self.current = None # No current button
|
||||
self.highlight = highlight
|
||||
self.selected = selected
|
||||
self._greyed_out = False
|
||||
|
||||
def add_button(self, *args, **kwargs):
|
||||
button = Button(*args, **kwargs)
|
||||
self.lstbuttons.append(button)
|
||||
button.callback = self._callback
|
||||
active = len(self.lstbuttons) == self.selected + 1
|
||||
button.bgcolor = self.highlight if active else button.orig_bgcolor
|
||||
if active:
|
||||
self.current = button
|
||||
return button
|
||||
|
||||
def value(self, button=None):
|
||||
if button is not None and button is not self.current:
|
||||
self._callback(button, *button.callback_args)
|
||||
return self.current
|
||||
|
||||
def greyed_out(self, val=None):
|
||||
if val is not None and self._greyed_out != val:
|
||||
self._greyed_out = val
|
||||
for button in self.lstbuttons:
|
||||
button.greyed_out(val)
|
||||
return self._greyed_out
|
||||
|
||||
def _callback(self, button, *args):
|
||||
for but in self.lstbuttons:
|
||||
if but is button:
|
||||
but.bgcolor = self.highlight
|
||||
self.current = button
|
||||
else:
|
||||
but.bgcolor = but.orig_bgcolor
|
||||
but.draw = True
|
||||
self.user_callback(button, *args) # user gets button with args they specified
|
|
@ -0,0 +1,36 @@
|
|||
# checkbox.py Extension to ugui providing the Checkbox class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2019-2021 Peter Hinch
|
||||
|
||||
from gui.core.ugui import Widget, display
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
class Checkbox(Widget):
|
||||
def __init__(self, writer, row, col, *, height=30, fillcolor=None,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False,
|
||||
callback=dolittle, args=[], value=False, active=True):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor, value, active)
|
||||
super()._set_callbacks(callback, args)
|
||||
self.fillcolor = fillcolor
|
||||
|
||||
def show(self):
|
||||
if super().show():
|
||||
x = self.col
|
||||
y = self.row
|
||||
ht = self.height
|
||||
x1 = x + ht - 1
|
||||
y1 = y + ht - 1
|
||||
if self._value:
|
||||
if self.fillcolor is not None:
|
||||
display.fill_rect(x, y, ht, ht, self.fillcolor)
|
||||
else:
|
||||
display.fill_rect(x, y, ht, ht, self.bgcolor)
|
||||
display.rect(x, y, ht, ht, self.fgcolor)
|
||||
if self.fillcolor is None and self._value:
|
||||
display.line(x, y, x1, y1, self.fgcolor)
|
||||
display.line(x, y1, x1, y, self.fgcolor)
|
||||
|
||||
def do_sel(self): # Select was pushed
|
||||
self.value(not self._value) # Upddate and refresh
|
|
@ -0,0 +1,104 @@
|
|||
# dial.py Dial and Pointer classes for micro-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
import cmath
|
||||
from gui.core.ugui import Widget, display
|
||||
from gui.widgets.label import Label
|
||||
|
||||
# Line defined by polar coords; origin and line are complex
|
||||
def polar(display, origin, line, color):
|
||||
xs, ys = origin.real, origin.imag
|
||||
theta = cmath.polar(line)[1]
|
||||
display.line(round(xs), round(ys), round(xs + line.real), round(ys - line.imag), color)
|
||||
|
||||
def conj(v): # complex conjugate
|
||||
return v.real - v.imag * 1j
|
||||
|
||||
# Draw an arrow; origin and vec are complex, scalar lc defines length of chevron.
|
||||
# cw and ccw are unit vectors of +-3pi/4 radians for chevrons (precompiled)
|
||||
def arrow(display, origin, vec, lc, color, ccw=cmath.exp(3j * cmath.pi/4), cw=cmath.exp(-3j * cmath.pi/4)):
|
||||
length, theta = cmath.polar(vec)
|
||||
uv = cmath.rect(1, theta) # Unit rotation vector
|
||||
start = -vec
|
||||
if length > 3 * lc: # If line is long
|
||||
ds = cmath.rect(lc, theta)
|
||||
start += ds # shorten to allow for length of tail chevrons
|
||||
chev = lc + 0j
|
||||
polar(display, origin, vec, color) # Origin to tip
|
||||
polar(display, origin, start, color) # Origin to tail
|
||||
polar(display, origin + conj(vec), chev*ccw*uv, color) # Tip chevron
|
||||
polar(display, origin + conj(vec), chev*cw*uv, color)
|
||||
if length > lc: # Confusing appearance of very short vectors with tail chevron
|
||||
polar(display, origin + conj(start), chev*ccw*uv, color) # Tail chevron
|
||||
polar(display, origin + conj(start), chev*cw*uv, color)
|
||||
|
||||
|
||||
class Pointer():
|
||||
def __init__(self, dial):
|
||||
self.dial = dial
|
||||
dial.vectors.add(self)
|
||||
self.val = 0 + 0j
|
||||
self.color = None
|
||||
|
||||
def value(self, v=None, color=None):
|
||||
self.color = color
|
||||
if v is not None:
|
||||
if isinstance(v, complex):
|
||||
l = cmath.polar(v)[0]
|
||||
if l > 1:
|
||||
self.val = v/l
|
||||
else:
|
||||
self.val = v
|
||||
else:
|
||||
raise ValueError('Pointer value must be complex.')
|
||||
self.dial.draw = True
|
||||
return self.val
|
||||
|
||||
class Dial(Widget):
|
||||
CLOCK = 0
|
||||
COMPASS = 1
|
||||
def __init__(self, writer, row, col, *, height=50,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, ticks=4,
|
||||
label=None, style=0, pip=None):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor)
|
||||
self.style = style
|
||||
self.pip = self.fgcolor if pip is None else pip
|
||||
if label is not None:
|
||||
self.label = Label(writer, row + height + 3, col, label)
|
||||
radius = int(height / 2)
|
||||
self.radius = radius
|
||||
self.ticks = ticks
|
||||
self.xorigin = col + radius
|
||||
self.yorigin = row + radius
|
||||
self.vectors = set()
|
||||
|
||||
def show(self):
|
||||
if super().show():
|
||||
# cache bound variables
|
||||
ticks = self.ticks
|
||||
radius = self.radius
|
||||
xo = self.xorigin
|
||||
yo = self.yorigin
|
||||
# vectors (complex)
|
||||
vor = xo + 1j * yo
|
||||
vtstart = 0.9 * radius + 0j # start of tick
|
||||
vtick = 0.1 * radius + 0j # tick
|
||||
vrot = cmath.exp(2j * cmath.pi/ticks) # unit rotation
|
||||
for _ in range(ticks):
|
||||
polar(display, vor + conj(vtstart), vtick, self.fgcolor)
|
||||
vtick *= vrot
|
||||
vtstart *= vrot
|
||||
display.circle(xo, yo, radius, self.fgcolor)
|
||||
vshort = 1000 # Length of shortest vector
|
||||
for v in self.vectors:
|
||||
color = self.fgcolor if v.color is None else v.color
|
||||
val = v.value() * radius # val is complex
|
||||
vshort = min(vshort, cmath.polar(val)[0])
|
||||
if self.style == Dial.CLOCK:
|
||||
polar(display, vor, val, color)
|
||||
else:
|
||||
arrow(display, vor, val, 5, color)
|
||||
if isinstance(self.pip, int) and vshort > 5:
|
||||
display.fillcircle(xo, yo, 2, self.pip)
|
|
@ -0,0 +1,52 @@
|
|||
# dialog.py Extension to ugui providing the DialogBox class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from gui.core.ugui import display, Window, Screen
|
||||
from gui.core.colors import *
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.buttons import Button, CloseButton
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
class DialogBox(Window):
|
||||
def __init__(self, writer, row=20, col=20, *, elements, label=None,
|
||||
bgcolor=DARKGREEN, buttonwidth=25, closebutton=True, callback=dolittle, args=[]):
|
||||
|
||||
def back(button, text): # Callback for normal buttons
|
||||
Window.value(text)
|
||||
callback(Window, *args)
|
||||
Screen.back()
|
||||
|
||||
def backbutton(button, text):
|
||||
Window.value(text)
|
||||
callback(Window, *args)
|
||||
|
||||
height = 80
|
||||
spacing = 10
|
||||
buttonwidth = max(max(writer.stringlen(e[0]) for e in elements) + 4, buttonwidth)
|
||||
buttonheight = max(writer.height, 15)
|
||||
nelements = len(elements)
|
||||
width = spacing + (buttonwidth + spacing) * nelements
|
||||
if label is not None:
|
||||
width = max(width, writer.stringlen(label) + 2 * spacing)
|
||||
super().__init__(row, col, height, width, bgcolor = bgcolor)
|
||||
|
||||
col = spacing # Coordinates relative to window
|
||||
row = self.height - buttonheight - 10
|
||||
gap = 0
|
||||
if nelements > 1:
|
||||
gap = ((width - 2 * spacing) - nelements * buttonwidth) // (nelements - 1)
|
||||
if label is not None:
|
||||
r, c = self.locn(10, col)
|
||||
Label(writer, r, c, label, bgcolor = bgcolor)
|
||||
for text, color in elements:
|
||||
Button(writer, *self.locn(row, col), height = buttonheight, width = buttonwidth,
|
||||
textcolor = BLACK, bgcolor = color,
|
||||
text = text, shape = RECTANGLE,
|
||||
callback = back, args = (text,))
|
||||
col += buttonwidth + gap
|
||||
|
||||
if closebutton:
|
||||
CloseButton(writer, callback = backbutton, args = ('Close',))
|
|
@ -0,0 +1,92 @@
|
|||
# dropdown.py Extension to ugui providing the Dropdown class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from gui.core.ugui import Widget, display, Window, Screen
|
||||
from gui.core.colors import *
|
||||
|
||||
from gui.widgets.listbox import Listbox
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
# Next and Prev close the listbox without updating the Dropdown. This is
|
||||
# handled by Screen .move bound method
|
||||
class _ListDialog(Window):
|
||||
|
||||
def __init__(self, writer, row, col, dropdown, textwidth):
|
||||
dd = dropdown
|
||||
elements = dd.elements
|
||||
# Need to determine Window dimensions from size of Listbox, which
|
||||
# depends on number and length of elements.
|
||||
entry_height, lb_height, textwidth = Listbox.dimensions(writer, elements)
|
||||
lb_width = textwidth + 2
|
||||
# Calculate Window dimensions
|
||||
ap_height = lb_height + 6 # Allow for listbox border
|
||||
ap_width = lb_width + 6
|
||||
super().__init__(row, col, ap_height, ap_width)
|
||||
self.listbox = Listbox(writer, row + 3, col + 3, elements = elements, width = lb_width,
|
||||
fgcolor = dd.fgcolor, bgcolor = dd.bgcolor, bdcolor=False,
|
||||
fontcolor = WHITE, select_color = dd.select_color,
|
||||
value = dd.value(), callback = self.callback)
|
||||
self.dropdown = dd
|
||||
|
||||
def callback(self, obj_listbox):
|
||||
Screen.back()
|
||||
self.dropdown.value(obj_listbox.value()) # Update it
|
||||
|
||||
|
||||
class Dropdown(Widget):
|
||||
def __init__(self, writer, row, col, *, elements, width=None, value=0,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, fontcolor=None, select_color=DARKBLUE,
|
||||
callback=dolittle, args=[]):
|
||||
|
||||
self.entry_height = writer.height + 2 # Allow a pixel above and below text
|
||||
height = self.entry_height
|
||||
if width is None: # Allow for square at end for arrow
|
||||
self.textwidth = max(writer.stringlen(s) for s in elements)
|
||||
width = self.textwidth + 2 + height
|
||||
else:
|
||||
self.textwidth = width
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, value, True)
|
||||
super()._set_callbacks(callback, args)
|
||||
self.select_color = select_color
|
||||
self.fontcolor = self.fgcolor if fontcolor is None else fontcolor
|
||||
self.elements = elements
|
||||
|
||||
def show(self):
|
||||
if super().show():
|
||||
x, y = self.col, self.row
|
||||
self._draw(x, y)
|
||||
if self._value is not None:
|
||||
display.print_left(self.writer, x, y + 1, self.elements[self._value], self.fontcolor)
|
||||
|
||||
def textvalue(self, text=None): # if no arg return current text
|
||||
if text is None:
|
||||
return self.elements[self._value]
|
||||
else: # set value by text
|
||||
try:
|
||||
v = self.elements.index(text)
|
||||
except ValueError:
|
||||
v = None
|
||||
else:
|
||||
if v != self._value:
|
||||
self.value(v)
|
||||
return v
|
||||
|
||||
def _draw(self, x, y):
|
||||
self.draw_border()
|
||||
display.vline(x + self.width - self.height, y, self.height, self.fgcolor)
|
||||
xcentre = x + self.width - self.height // 2 # Centre of triangle
|
||||
ycentre = y + self.height // 2
|
||||
halflength = (self.height - 8) // 2
|
||||
length = halflength * 2
|
||||
if length > 0:
|
||||
display.hline(xcentre - halflength, ycentre - halflength, length, self.fgcolor)
|
||||
display.line(xcentre - halflength, ycentre - halflength, xcentre, ycentre + halflength, self.fgcolor)
|
||||
display.line(xcentre + halflength, ycentre - halflength, xcentre, ycentre + halflength, self.fgcolor)
|
||||
|
||||
def do_sel(self): # Select was pushed
|
||||
if len(self.elements) > 1:
|
||||
args = (self.writer, self.row - 2, self.col - 2, self, self.textwidth)
|
||||
Screen.change(_ListDialog, args = args)
|
|
@ -0,0 +1,259 @@
|
|||
# graph.py Graph plotting widgets for micro-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from hardware_setup import ssd, display # Create a display instance
|
||||
from gui.core.ugui import Widget
|
||||
from cmath import rect, pi
|
||||
from micropython import const
|
||||
from array import array
|
||||
|
||||
type_gen = type((lambda: (yield))())
|
||||
|
||||
# Line clipping outcode bits
|
||||
_TOP = const(1)
|
||||
_BOTTOM = const(2)
|
||||
_LEFT = const(4)
|
||||
_RIGHT = const(8)
|
||||
# Bounding box for line clipping
|
||||
_XMAX = const(1)
|
||||
_XMIN = const(-1)
|
||||
_YMAX = const(1)
|
||||
_YMIN = const(-1)
|
||||
|
||||
|
||||
class Curve():
|
||||
@staticmethod
|
||||
def _outcode(x, y):
|
||||
oc = _TOP if y > 1 else 0
|
||||
oc |= _BOTTOM if y < -1 else 0
|
||||
oc |= _RIGHT if x > 1 else 0
|
||||
oc |= _LEFT if x < -1 else 0
|
||||
return oc
|
||||
|
||||
def __init__(self, graph, color, populate=None, origin=(0, 0), excursion=(1, 1)):
|
||||
if not isinstance(self, PolarCurve): # Check not done in subclass
|
||||
if isinstance(graph, PolarGraph) or not isinstance(graph, CartesianGraph):
|
||||
raise ValueError('Curve must use a CartesianGraph instance.')
|
||||
self.graph = graph
|
||||
self.origin = origin
|
||||
self.excursion = excursion
|
||||
self.color = color if color is not None else graph.fgcolor
|
||||
self.lastpoint = None
|
||||
self.newpoint = None
|
||||
if populate is not None and self._valid(populate):
|
||||
for x, y in populate:
|
||||
self.point(x, y)
|
||||
|
||||
def _valid(self, populate):
|
||||
if not isinstance(populate, type_gen):
|
||||
raise ValueError('populate must be a generator.')
|
||||
return True
|
||||
|
||||
def point(self, x=None, y=None):
|
||||
if x is None or y is None:
|
||||
self.newpoint = None
|
||||
self.lastpoint = None
|
||||
return
|
||||
|
||||
self.newpoint = self._scale(x, y) # In-range points scaled to +-1 bounding box
|
||||
if self.lastpoint is None: # Nothing to plot. Save for next line.
|
||||
self.lastpoint = self.newpoint
|
||||
return
|
||||
|
||||
res = self._clip(*(self.lastpoint + self.newpoint)) # Clip to +-1 box
|
||||
if res is not None: # Ignore lines which don't intersect
|
||||
self.graph.line(res[0:2], res[2:], self.color)
|
||||
self.lastpoint = self.newpoint # Scaled but not clipped
|
||||
|
||||
# Cohen–Sutherland line clipping algorithm
|
||||
# If self.newpoint and self.lastpoint are valid clip them so that both lie
|
||||
# in +-1 range. If both are outside the box return None.
|
||||
def _clip(self, x0, y0, x1, y1):
|
||||
oc1 = self._outcode(x0, y0)
|
||||
oc2 = self._outcode(x1, y1)
|
||||
while True:
|
||||
if not oc1 | oc2: # OK to plot
|
||||
return x0, y0, x1, y1
|
||||
if oc1 & oc2: # Nothing to do
|
||||
return
|
||||
oc = oc1 if oc1 else oc2
|
||||
if oc & _TOP:
|
||||
x = x0 + (_YMAX - y0)*(x1 - x0)/(y1 - y0)
|
||||
y = _YMAX
|
||||
elif oc & _BOTTOM:
|
||||
x = x0 + (_YMIN - y0)*(x1 - x0)/(y1 - y0)
|
||||
y = _YMIN
|
||||
elif oc & _RIGHT:
|
||||
y = y0 + (_XMAX - x0)*(y1 - y0)/(x1 - x0)
|
||||
x = _XMAX
|
||||
elif oc & _LEFT:
|
||||
y = y0 + (_XMIN - x0)*(y1 - y0)/(x1 - x0)
|
||||
x = _XMIN
|
||||
if oc is oc1:
|
||||
x0, y0 = x, y
|
||||
oc1 = self._outcode(x0, y0)
|
||||
else:
|
||||
x1, y1 = x, y
|
||||
oc2 = self._outcode(x1, y1)
|
||||
|
||||
def _scale(self, x, y): # Scale to +-1.0
|
||||
x0, y0 = self.origin
|
||||
xr, yr = self.excursion
|
||||
xs = (x - x0) / xr
|
||||
ys = (y - y0) / yr
|
||||
return xs, ys
|
||||
|
||||
class PolarCurve(Curve): # Points are complex
|
||||
def __init__(self, graph, color, populate=None):
|
||||
if not isinstance(graph, PolarGraph):
|
||||
raise ValueError('PolarCurve must use a PolarGraph instance.')
|
||||
super().__init__(graph, color)
|
||||
if populate is not None and self._valid(populate):
|
||||
for z in populate:
|
||||
self.point(z)
|
||||
|
||||
def point(self, z=None):
|
||||
if z is None:
|
||||
self.newpoint = None
|
||||
self.lastpoint = None
|
||||
return
|
||||
|
||||
self.newpoint = self._scale(z.real, z.imag) # In-range points scaled to +-1 bounding box
|
||||
if self.lastpoint is None: # Nothing to plot. Save for next line.
|
||||
self.lastpoint = self.newpoint
|
||||
return
|
||||
|
||||
res = self._clip(*(self.lastpoint + self.newpoint)) # Clip to +-1 box
|
||||
if res is not None: # At least part of line was in box
|
||||
start = res[0] + 1j*res[1]
|
||||
end = res[2] + 1j*res[3]
|
||||
self.graph.cline(start, end, self.color)
|
||||
self.lastpoint = self.newpoint # Scaled but not clipped
|
||||
|
||||
|
||||
class TSequence(Curve):
|
||||
def __init__(self, graph, color, size, yorigin=0, yexc=1):
|
||||
super().__init__(graph, color, origin=(0, yorigin), excursion=(1, yexc))
|
||||
self.data = array('f', (0 for _ in range(size)))
|
||||
self.cur = 0
|
||||
self.size = size
|
||||
self.count = 0
|
||||
|
||||
def add(self, v):
|
||||
p = self.cur
|
||||
size = self.size
|
||||
self.data[self.cur] = v
|
||||
self.cur += 1
|
||||
self.cur %= size
|
||||
if self.count < size:
|
||||
self.count += 1
|
||||
x = 0
|
||||
dx = 1/size
|
||||
for _ in range(self.count):
|
||||
self.point(x, self.data[p])
|
||||
x -= dx
|
||||
p -= 1
|
||||
p %= size
|
||||
self.point()
|
||||
|
||||
|
||||
class Graph(Widget):
|
||||
def __init__(self, writer, row, col, height, width, fgcolor, bgcolor, bdcolor, gridcolor):
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
self.x0 = col
|
||||
self.x1 = col + width
|
||||
self.y0 = row
|
||||
self.y1 = row + height
|
||||
if gridcolor is None:
|
||||
gridcolor = self.fgcolor
|
||||
self.gridcolor = gridcolor
|
||||
|
||||
def clear(self):
|
||||
self.draw = True # Clear working area
|
||||
|
||||
def show(self):
|
||||
return super().show() # Draw or erase border
|
||||
|
||||
class CartesianGraph(Graph):
|
||||
def __init__(self, writer, row, col, *, height=90, width = 120, fgcolor=None, bgcolor=None, bdcolor=None,
|
||||
gridcolor=None, xdivs=10, ydivs=10, xorigin=5, yorigin=5):
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, gridcolor)
|
||||
self.xdivs = xdivs
|
||||
self.ydivs = ydivs
|
||||
self.x_axis_len = max(xorigin, xdivs - xorigin) * width / xdivs # Max distance from origin in pixels
|
||||
self.y_axis_len = max(yorigin, ydivs - yorigin) * height / ydivs
|
||||
self.xp_origin = self.x0 + xorigin * width / xdivs # Origin in pixels
|
||||
self.yp_origin = self.y0 + (ydivs - yorigin) * height / ydivs
|
||||
self.xorigin = xorigin
|
||||
self.yorigin = yorigin
|
||||
self.draw = True
|
||||
|
||||
def show(self):
|
||||
if super().show(): # Clear working area
|
||||
x0 = self.x0
|
||||
x1 = self.x1
|
||||
y0 = self.y0
|
||||
y1 = self.y1
|
||||
if self.ydivs > 0:
|
||||
dy = self.height / (self.ydivs) # Y grid line
|
||||
for line in range(self.ydivs + 1):
|
||||
color = self.fgcolor if line == self.yorigin else self.gridcolor
|
||||
ypos = round(self.y1 - dy * line)
|
||||
ssd.hline(x0, ypos, x1 - x0, color)
|
||||
if self.xdivs > 0:
|
||||
width = x1 - x0
|
||||
dx = width / (self.xdivs) # X grid line
|
||||
for line in range(self.xdivs + 1):
|
||||
color = self.fgcolor if line == self.xorigin else self.gridcolor
|
||||
xpos = round(x0 + dx * line)
|
||||
ssd.vline(xpos, y0, y1 - y0, color)
|
||||
|
||||
# Called by Curve
|
||||
def line(self, start, end, color): # start and end relative to origin and scaled -1 .. 0 .. +1
|
||||
xs = round(self.xp_origin + start[0] * self.x_axis_len)
|
||||
ys = round(self.yp_origin - start[1] * self.y_axis_len)
|
||||
xe = round(self.xp_origin + end[0] * self.x_axis_len)
|
||||
ye = round(self.yp_origin - end[1] * self.y_axis_len)
|
||||
ssd.line(xs, ys, xe, ye, color)
|
||||
|
||||
class PolarGraph(Graph):
|
||||
def __init__(self, writer, row, col, *, height=90, fgcolor=None, bgcolor=None, bdcolor=None,
|
||||
gridcolor=None, adivs=3, rdivs=4):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor, gridcolor)
|
||||
self.adivs = adivs * 2 # No. of divisions of Pi radians
|
||||
self.rdivs = rdivs
|
||||
self.radius = round(height / 2) # Unit: pixels
|
||||
self.xp_origin = self.x0 + self.radius # Origin in pixels
|
||||
self.yp_origin = self.y0 + self.radius
|
||||
self.draw = True
|
||||
|
||||
def show(self):
|
||||
if super().show(): # Clear working area
|
||||
display.usegrey(False)
|
||||
x0 = self.x0
|
||||
y0 = self.y0
|
||||
radius = self.radius
|
||||
adivs = self.adivs
|
||||
rdivs = self.rdivs
|
||||
diam = 2 * radius
|
||||
if rdivs > 0:
|
||||
for r in range(1, rdivs + 1):
|
||||
display.circle(self.xp_origin, self.yp_origin, round(radius * r / rdivs), self.gridcolor)
|
||||
if adivs > 0:
|
||||
v = complex(1)
|
||||
m = rect(1, pi / adivs)
|
||||
for _ in range(adivs):
|
||||
self.cline(-v, v, self.gridcolor)
|
||||
v *= m
|
||||
ssd.vline(x0 + radius, y0, diam, self.fgcolor)
|
||||
ssd.hline(x0, y0 + radius, diam, self.fgcolor)
|
||||
|
||||
def cline(self, start, end, color): # start and end are complex, 0 <= magnitude <= 1
|
||||
height = self.radius # Unit: pixels
|
||||
xs = round(self.xp_origin + start.real * height)
|
||||
ys = round(self.yp_origin - start.imag * height)
|
||||
xe = round(self.xp_origin + end.real * height)
|
||||
ye = round(self.yp_origin - end.imag * height)
|
||||
ssd.line(xs, ys, xe, ye, color)
|
|
@ -0,0 +1,60 @@
|
|||
# knob.py Extension to microgui providing a control knob (rotary potentiometer) widget
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from gui.core.ugui import LinearIO, display
|
||||
import math
|
||||
|
||||
TWOPI = 2 * math.pi
|
||||
# Null function
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
# *********** CONTROL KNOB CLASS ***********
|
||||
|
||||
class Knob(LinearIO):
|
||||
def __init__(self, writer, row, col, *, height=70, arc=TWOPI, ticks=9, value=0.0,
|
||||
fgcolor=None, bgcolor=None, color=None, bdcolor=None,
|
||||
callback=dolittle, args=[], active=True):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor, value, active)
|
||||
super()._set_callbacks(callback, args)
|
||||
radius = height / 2
|
||||
self.arc = min(max(arc, 0), TWOPI) # Usable angle of control
|
||||
self.radius = radius
|
||||
self.xorigin = col + radius
|
||||
self.yorigin = row + radius
|
||||
self.ticklen = 0.1 * radius
|
||||
self.pointerlen = radius - self.ticklen - 5
|
||||
self.ticks = max(ticks, 2) # start and end of travel
|
||||
self.color = color
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
if active: # Run callback (e.g. to set dynamic colors)
|
||||
self.callback(self, *self.args)
|
||||
|
||||
def show(self):
|
||||
if super().show(False): # Honour bgcolor
|
||||
arc = self.arc
|
||||
ticks = self.ticks
|
||||
radius = self.radius
|
||||
ticklen = self.ticklen
|
||||
for tick in range(ticks):
|
||||
theta = (tick / (ticks - 1)) * arc - arc / 2
|
||||
x_start = int(self.xorigin + radius * math.sin(theta))
|
||||
y_start = int(self.yorigin - radius * math.cos(theta))
|
||||
x_end = int(self.xorigin + (radius - ticklen) * math.sin(theta))
|
||||
y_end = int(self.yorigin - (radius - ticklen) * math.cos(theta))
|
||||
display.line(x_start, y_start, x_end, y_end, self.fgcolor)
|
||||
if self.color is not None:
|
||||
display.fillcircle(self.xorigin, self.yorigin, radius - ticklen, self.color)
|
||||
display.circle(self.xorigin, self.yorigin, radius - ticklen, self.fgcolor)
|
||||
display.circle(self.xorigin, self.yorigin, radius - ticklen - 3, self.fgcolor)
|
||||
|
||||
self._drawpointer(self._value, self.fgcolor) # draw new
|
||||
|
||||
def _drawpointer(self, value, color):
|
||||
arc = self.arc
|
||||
length = self.pointerlen
|
||||
angle = value * arc - arc / 2
|
||||
x_end = int(self.xorigin + length * math.sin(angle))
|
||||
y_end = int(self.yorigin - length * math.cos(angle))
|
||||
display.line(int(self.xorigin), int(self.yorigin), x_end, y_end, color)
|
|
@ -0,0 +1,38 @@
|
|||
# label.py Extension to micro-gui providing the Label class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
from gui.core.ugui import Widget, display
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.colors import *
|
||||
|
||||
# text: str display string int save width
|
||||
class Label(Widget):
|
||||
def __init__(self, writer, row, col, text, invert=False, fgcolor=None, bgcolor=BLACK, bdcolor=False):
|
||||
# Determine width of object
|
||||
if isinstance(text, int):
|
||||
width = text
|
||||
text = None
|
||||
else:
|
||||
width = writer.stringlen(text)
|
||||
height = writer.height
|
||||
self.invert = invert
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor)
|
||||
if text is not None:
|
||||
self.value(text, invert)
|
||||
|
||||
def value(self, text=None, invert=False, fgcolor=None, bgcolor=None, bdcolor=None):
|
||||
txt = super().value(text) # Sets .draw ensuring refresh
|
||||
# Redraw even if no text supplied: colors may have changed.
|
||||
self.invert = invert
|
||||
self.fgcolor = self.def_fgcolor if fgcolor is None else fgcolor
|
||||
self.bgcolor = self.def_bgcolor if bgcolor is None else bgcolor
|
||||
if bdcolor is False:
|
||||
self.def_bdcolor = False
|
||||
self.bdcolor = self.def_bdcolor if bdcolor is None else bdcolor
|
||||
return txt
|
||||
|
||||
def show(self):
|
||||
if super().show(): # Draw or erase border
|
||||
if isinstance(txt := super().value(), str):
|
||||
display.print_left(self.writer, self.col, self.row, txt, self.fgcolor, self.bgcolor, self.invert)
|
|
@ -0,0 +1,27 @@
|
|||
# led.py Extension to ugui providing the LED class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from gui.core.ugui import Widget, display
|
||||
from gui.core.colors import *
|
||||
|
||||
|
||||
class LED(Widget):
|
||||
def __init__(self, writer, row, col, *, height=30, fgcolor=None, bgcolor=None, bdcolor=False, color=RED):
|
||||
super().__init__(writer, row, col, height, height, fgcolor, bgcolor, bdcolor, False)
|
||||
self._value = False
|
||||
self._color = color
|
||||
self.radius = self.height // 2
|
||||
self.x = col + self.radius
|
||||
self.y = row + self.radius
|
||||
|
||||
def show(self):
|
||||
if super().show(): # Draw or erase border
|
||||
color = self._color if self._value else BLACK
|
||||
display.fillcircle(int(self.x), int(self.y), int(self.radius), color)
|
||||
display.circle(int(self.x), int(self.y), int(self.radius), self.fgcolor)
|
||||
|
||||
def color(self, color):
|
||||
self._color = color
|
||||
self.draw = True
|
|
@ -0,0 +1,106 @@
|
|||
# listbox.py Extension to ugui providing the Listbox class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
from micropython import const
|
||||
from gui.core.ugui import Widget, display
|
||||
from gui.core.colors import *
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
# Behaviour has issues compared to touch displays because movement between
|
||||
# entries is sequential. This can affect the choice in when the callback runs.
|
||||
# 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):
|
||||
@staticmethod
|
||||
def dimensions(writer, elements):
|
||||
entry_height = writer.height + 2 # Allow a pixel above and below text
|
||||
le = len(elements)
|
||||
height = entry_height * le + 2
|
||||
textwidth = max(writer.stringlen(s) for s in elements) + 4
|
||||
return entry_height, height, textwidth
|
||||
|
||||
def __init__(self, writer, row, col, *, elements, width=None, value=0,
|
||||
fgcolor=None, bgcolor=None, bdcolor=False, fontcolor=None, select_color=DARKBLUE,
|
||||
callback=dolittle, args=[], also=0):
|
||||
|
||||
self.entry_height, height, textwidth = self.dimensions(writer, elements)
|
||||
self.also = also
|
||||
if width is None:
|
||||
width = textwidth
|
||||
if not isinstance(value, int) or value >= len(elements):
|
||||
value = 0
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, value, True)
|
||||
self.cb = callback
|
||||
self.cb_args = args
|
||||
self.select_color = select_color
|
||||
self.fontcolor = fontcolor
|
||||
fail = False
|
||||
try:
|
||||
self.elements = [s for s in elements if type(s) is str]
|
||||
except:
|
||||
fail = True
|
||||
else:
|
||||
fail = len(self.elements) == 0
|
||||
if fail:
|
||||
raise ValueError('elements must be a list or tuple of one or more strings')
|
||||
self._value = value # No callback until user selects
|
||||
self.ev = value
|
||||
|
||||
def show(self):
|
||||
if not super().show(False): # Clear to self.bgcolor
|
||||
return
|
||||
|
||||
length = len(self.elements)
|
||||
x = self.col
|
||||
y = self.row
|
||||
for n in range(length):
|
||||
if n == self._value:
|
||||
display.fill_rect(x, y + 1, self.width, self.entry_height - 1, self.select_color)
|
||||
display.print_left(self.writer, x + 2, y + 1, self.elements[n], self.fgcolor, self.select_color)
|
||||
else:
|
||||
display.print_left(self.writer, x + 2, y + 1, self.elements[n], self.fgcolor, self.bgcolor)
|
||||
y += self.entry_height
|
||||
|
||||
def textvalue(self, text=None): # if no arg return current text
|
||||
if text is None:
|
||||
return self.elements[self._value]
|
||||
else: # set value by text
|
||||
try:
|
||||
v = self.elements.index(text)
|
||||
except ValueError:
|
||||
v = None
|
||||
else:
|
||||
if v != self._value:
|
||||
self.value(v)
|
||||
return v
|
||||
|
||||
def do_up(self, _):
|
||||
if v := self._value:
|
||||
self.value(v - 1)
|
||||
if (self.also & ON_MOVE): # Treat as if select pressed
|
||||
self.do_sel()
|
||||
|
||||
def do_down(self, _):
|
||||
if (v := self._value) < len(self.elements) - 1:
|
||||
self.value(v + 1)
|
||||
if (self.also & ON_MOVE):
|
||||
self.do_sel()
|
||||
|
||||
# Callback runs if select is pressed. Also (if ON_LEAVE) if user changes
|
||||
# list currency and then moves off the control. Otherwise if we have a
|
||||
# callback that refreshes another control, that second control does not
|
||||
# track currency.
|
||||
def do_sel(self): # Select was pushed
|
||||
self.ev = self._value
|
||||
self.cb(self, *self.cb_args)
|
||||
|
||||
def enter(self):
|
||||
self.ev = self._value # Value change detection
|
||||
|
||||
def leave(self):
|
||||
if (self.also & ON_LEAVE) and self._value != self.ev:
|
||||
self.do_sel()
|
|
@ -0,0 +1,64 @@
|
|||
# meter.py Extension to ugui providing a linear "meter" widget.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2019 Peter Hinch
|
||||
|
||||
from gui.core.ugui import Widget, display
|
||||
from gui.widgets.label import Label
|
||||
from gui.core.colors import *
|
||||
|
||||
# Null function
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
class Meter(Widget):
|
||||
BAR = 1
|
||||
LINE = 0
|
||||
def __init__(self, writer, row, col, *, height=50, width=10,
|
||||
fgcolor=None, bgcolor=BLACK, ptcolor=None, bdcolor=None,
|
||||
divisions=5, label=None, style=0, legends=None, value=0):
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor) # TODO Consider active
|
||||
self.divisions = divisions
|
||||
if label is not None:
|
||||
Label(writer, row + height + 3, col, label)
|
||||
self.style = style
|
||||
self.ptcolor = ptcolor if ptcolor is not None else self.fgcolor
|
||||
if legends is not None: # Legends
|
||||
x = col + width + 4
|
||||
y = row + height
|
||||
dy = 0 if len(legends) <= 1 else height / (len(legends) -1)
|
||||
yl = y - writer.height / 2 # Start at bottom
|
||||
for legend in legends:
|
||||
Label(writer, int(yl), x, legend)
|
||||
yl -= dy
|
||||
self.value(value)
|
||||
|
||||
def value(self, n=None, color=None):
|
||||
if n is None:
|
||||
return super().value()
|
||||
n = super().value(min(1, max(0, n)))
|
||||
if color is not None:
|
||||
self.ptcolor = color
|
||||
return n
|
||||
|
||||
def show(self):
|
||||
if super().show(): # Draw or erase border
|
||||
val = super().value()
|
||||
wri = self.writer
|
||||
width = self.width
|
||||
height = self.height
|
||||
x0 = self.col
|
||||
x1 = self.col + width
|
||||
y0 = self.row
|
||||
y1 = self.row + height
|
||||
if self.divisions > 0:
|
||||
dy = height / (self.divisions) # Tick marks
|
||||
for tick in range(self.divisions + 1):
|
||||
ypos = int(y0 + dy * tick)
|
||||
display.hline(x0 + 2, ypos, x1 - x0 - 4, self.fgcolor)
|
||||
|
||||
y = int(y1 - val * height) # y position of slider
|
||||
if self.style == self.LINE:
|
||||
display.hline(x0, y, width, self.ptcolor) # Draw pointer
|
||||
else:
|
||||
w = width / 2
|
||||
display.fill_rect(int(x0 + w - 2), y, 4, y1 - y, self.ptcolor)
|
|
@ -0,0 +1,132 @@
|
|||
# scale.py Extension to micro-gui providing the Scale class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# Usage:
|
||||
# from gui.widgets.scale import Scale
|
||||
|
||||
from gui.core.ugui import LinearIO, display
|
||||
from hardware_setup import ssd # Display driver for Writer
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.colors import BLACK
|
||||
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
class Scale(LinearIO):
|
||||
def __init__(self, writer, row, col, *,
|
||||
ticks=200, legendcb=None, tickcb=None,
|
||||
height=0, width=100, bdcolor=None, fgcolor=None, bgcolor=None,
|
||||
callback=dolittle, args=[],
|
||||
pointercolor=None, fontcolor=None, value=0.0, active=False):
|
||||
if ticks % 2:
|
||||
raise ValueError('ticks arg must be divisible by 2')
|
||||
self.ticks = ticks
|
||||
self.tickcb = tickcb
|
||||
def lcb(f):
|
||||
return '{:3.1f}'.format(f)
|
||||
self.legendcb = legendcb if legendcb is not None else lcb
|
||||
bgcolor = BLACK if bgcolor is None else bgcolor
|
||||
text_ht = writer.font.height()
|
||||
ctrl_ht = 12 # Minimum height for ticks
|
||||
# Add 2 pixel internal border to give a little more space
|
||||
min_ht = text_ht + 6 # Ht of text, borders and gap between text and ticks
|
||||
if height < min_ht + ctrl_ht:
|
||||
height = min_ht + ctrl_ht # min workable height
|
||||
else:
|
||||
ctrl_ht = height - min_ht # adjust ticks for greater height
|
||||
width &= 0xfffe # Make divisible by 2: avoid 1 pixel pointer offset
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, self._to_int(value), active)
|
||||
if active:
|
||||
super()._set_callbacks(callback, args)
|
||||
self.minval = -1.0 # By default scales run from -1.0 to +1.0
|
||||
self.fontcolor = fontcolor if fontcolor is not None else self.fgcolor
|
||||
self.x0 = col + 2
|
||||
self.x1 = col + self.width - 2
|
||||
self.y0 = row + 2
|
||||
self.y1 = row + self.height - 2
|
||||
self.ptrcolor = pointercolor if pointercolor is not None else self.fgcolor
|
||||
# Define tick dimensions
|
||||
ytop = self.y0 + text_ht + 2 # Top of scale graphic (2 pixel gap)
|
||||
ycl = ytop + (self.y1 - ytop) // 2 # Centre line
|
||||
self.sdl = round(ctrl_ht * 1 / 3) # Length of small tick.
|
||||
self.sdy0 = ycl - self.sdl // 2
|
||||
self.mdl = round(ctrl_ht * 2 / 3) # Medium tick
|
||||
self.mdy0 = ycl - self.mdl // 2
|
||||
self.ldl = ctrl_ht # Large tick
|
||||
self.ldy0 = ycl - self.ldl // 2
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
if active: # Run callback (e.g. to set dynamic colors)
|
||||
self.callback(self, *self.args)
|
||||
|
||||
def show(self):
|
||||
wri = self.writer
|
||||
x0: int = self.x0 # Internal rectangle occupied by scale and text
|
||||
x1: int = self.x1
|
||||
y0: int = self.y0
|
||||
y1: int = self.y1
|
||||
if super().show():
|
||||
# Scale is drawn using ints. Each division is 10 units.
|
||||
val: int = self._value # 0..ticks*10
|
||||
# iv increments for each tick. Its value modulo N determines tick length
|
||||
iv: int # val / 10 at a tick position
|
||||
d: int # val % 10: offset relative to a tick position
|
||||
fx: int # X offset of current tick in value units
|
||||
if val >= 100: # Whole LHS of scale will be drawn
|
||||
iv, d = divmod(val - 100, 10) # Initial value
|
||||
fx = 10 - d
|
||||
iv += 1
|
||||
else: # Scale will scroll right
|
||||
iv = 0
|
||||
fx = 100 - val
|
||||
|
||||
# Window shows 20 divisions, each of which corresponds to 10 units of value.
|
||||
# So pixels per unit value == win_width/200
|
||||
win_width: int = x1 - x0
|
||||
ticks: int = self.ticks # Total # of ticks visible and hidden
|
||||
while True:
|
||||
x: int = x0 + (fx * win_width) // 200 # Current X position
|
||||
ys: int # Start Y position for tick
|
||||
yl: int # tick length
|
||||
if x > x1 or iv > ticks: # Out of space or data (scroll left)
|
||||
break
|
||||
if not iv % 10:
|
||||
txt = self.legendcb(self._fvalue(iv * 10))
|
||||
tlen = wri.stringlen(txt)
|
||||
Writer.set_textpos(ssd, y0, min(x, x1 - tlen))
|
||||
wri.setcolor(self.fontcolor, self.bgcolor)
|
||||
wri.printstring(txt)
|
||||
wri.setcolor()
|
||||
ys = self.ldy0 # Large tick
|
||||
yl = self.ldl
|
||||
elif not iv % 5:
|
||||
ys = self.mdy0
|
||||
yl = self.mdl
|
||||
else:
|
||||
ys = self.sdy0
|
||||
yl = self.sdl
|
||||
if self.tickcb is None:
|
||||
color = self.fgcolor
|
||||
else:
|
||||
color = self.tickcb(self._fvalue(iv * 10), self.fgcolor)
|
||||
display.vline(x, ys, yl, color) # Draw tick
|
||||
fx += 10
|
||||
iv += 1
|
||||
|
||||
display.vline(x0 + (x1 - x0) // 2, y0, y1 - y0, self.ptrcolor) # Draw pointer
|
||||
|
||||
def _to_int(self, v):
|
||||
return round((v + 1.0) * self.ticks * 5) # 0..self.ticks*10
|
||||
|
||||
def _fvalue(self, v=None):
|
||||
return v / (5 * self.ticks) - 1.0
|
||||
|
||||
def value(self, val=None): # User method to get or set value
|
||||
if val is not None:
|
||||
val = min(max(val, - 1.0), 1.0)
|
||||
v = self._to_int(val)
|
||||
if v != self._value:
|
||||
self._value = v
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
self.callback(self, *self.args)
|
||||
return self._fvalue(self._value)
|
|
@ -0,0 +1,157 @@
|
|||
# scale_log.py Extension to micro-gui providing the ScaleLog class
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# A logarithmic Scale which responds to user input
|
||||
# Usage:
|
||||
# from gui.widgets.scale_log import ScaleLog
|
||||
|
||||
|
||||
import uasyncio as asyncio
|
||||
from time import ticks_ms, ticks_diff
|
||||
from math import log10
|
||||
|
||||
from gui.core.ugui import LinearIO, display
|
||||
from hardware_setup import ssd # Display driver for Writer
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.colors import BLACK
|
||||
|
||||
# Null function
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
|
||||
# Start value is 1.0. User applies scaling to value and ticks callback.
|
||||
class ScaleLog(LinearIO):
|
||||
def __init__(self, writer, row, col, *,
|
||||
decades=5, height=0, width=160,
|
||||
bdcolor=None, fgcolor=None, bgcolor=None,
|
||||
pointercolor=None, fontcolor=None,
|
||||
legendcb=None, tickcb=None,
|
||||
callback=dolittle, args=[],
|
||||
value=1.0, delta=0.01, active=False):
|
||||
# For correct text rendering inside control must explicitly set bgcolor
|
||||
bgcolor = BLACK if bgcolor is None else bgcolor
|
||||
if decades < 3:
|
||||
raise ValueError('decades must be >= 3')
|
||||
self.mval = 10**decades # Max value
|
||||
self.tickcb = tickcb
|
||||
self.delta = delta # Min multiplier = 1 + delta
|
||||
def lcb(f):
|
||||
return '{:<1.0f}'.format(f)
|
||||
self.legendcb = legendcb if legendcb is not None else lcb
|
||||
text_ht = writer.height
|
||||
ctrl_ht = 12 # Minimum height for ticks
|
||||
min_ht = text_ht + 8 # Ht of text and gap between text and ticks
|
||||
if height < min_ht + ctrl_ht:
|
||||
height = min_ht + ctrl_ht # min workable height
|
||||
else:
|
||||
ctrl_ht = height - min_ht # adjust ticks for greater height
|
||||
width &= 0xfffe # Make divisible by 2: avoid 1 pixel pointer offset
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, self._constrain(value), active)
|
||||
if active:
|
||||
super()._set_callbacks(callback, args)
|
||||
self.fontcolor = fontcolor if fontcolor is not None else self.fgcolor
|
||||
|
||||
self.x0 = col + 2
|
||||
self.x1 = col + self.width - 2
|
||||
self.y0 = row + 2
|
||||
self.y1 = row + self.height - 2
|
||||
self.ptrcolor = pointercolor if pointercolor is not None else self.fgcolor
|
||||
# Define tick dimensions
|
||||
ytop = self.y0 + text_ht + 2 # Top of scale graphic (2 pixel gap)
|
||||
ycl = ytop + (self.y1 - ytop) // 2 # Centre line
|
||||
self.sdl = round(ctrl_ht * 1 / 3) # Length of small tick.
|
||||
self.sdy0 = ycl - self.sdl // 2
|
||||
self.mdl = round(ctrl_ht * 2 / 3) # Medium tick
|
||||
self.mdy0 = ycl - self.mdl // 2
|
||||
self.ldl = ctrl_ht # Large tick
|
||||
self.ldy0 = ycl - self.ldl // 2
|
||||
self.dw = (self.x1 - self.x0) // 2 # Pixel width of a decade
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
if active: # Run callback (e.g. to set dynamic colors)
|
||||
self.callback(self, *self.args)
|
||||
|
||||
# Pre calculated log10(x) for x in range(1, 10)
|
||||
def show(self, logs=(0.0, 0.3010, 0.4771, 0.6021, 0.6990, 0.7782, 0.8451, 0.9031, 0.9542)):
|
||||
#start = ticks_ms()
|
||||
x0: int = self.x0 # Internal rectangle occupied by scale and text
|
||||
x1: int = self.x1
|
||||
y0: int = self.y0
|
||||
y1: int = self.y1
|
||||
xc: int = x0 + (x1 - x0) // 2 # x location of pointer
|
||||
dw: int = self.dw # Width of a decade in pixels
|
||||
wri = self.writer
|
||||
if super().show():
|
||||
vc = self._value # Current value, corresponds to centre of display
|
||||
d = int(log10(vc)) - 1 # 10**d is start of a decade guaranteed to be outside display
|
||||
vs = max(10 ** d, 1.0) # vs: start value of current decade
|
||||
while True: # For each decade until we run out of space
|
||||
done = True # Assume completion
|
||||
xs: float = xc - dw * log10(vc / vs) # x location of start of scale
|
||||
tick: int
|
||||
q: float
|
||||
# log10 ~38us on Pi Pico
|
||||
for tick, q in enumerate(logs):
|
||||
vt: float = vs * (1 + tick) # Value of current tick
|
||||
x: int = round(xs + q * dw) # x location of current tick
|
||||
if x >= x1:
|
||||
break # All visible ticks drawn
|
||||
elif x > x0: # Tick is visible
|
||||
if not tick:
|
||||
txt = self.legendcb(vt)
|
||||
tlen = wri.stringlen(txt)
|
||||
Writer.set_textpos(ssd, y0, min(x, x1 - tlen))
|
||||
wri.setcolor(self.fontcolor, self.bgcolor)
|
||||
wri.printstring(txt)
|
||||
ys = self.ldy0 # Large tick
|
||||
yl = self.ldl
|
||||
elif tick == 4:
|
||||
ys = self.mdy0
|
||||
yl = self.mdl
|
||||
else:
|
||||
ys = self.sdy0
|
||||
yl = self.sdl
|
||||
if self.tickcb is None:
|
||||
color = self.fgcolor
|
||||
else:
|
||||
color = self.tickcb(vt, self.fgcolor)
|
||||
display.vline(x, ys, yl, color) # Draw tick
|
||||
if (not tick) and (vt > 0.999 * self.mval):
|
||||
break # Drawn last tick at end of data
|
||||
else:
|
||||
vs *= 10 # More to do. Next decade.
|
||||
done = False
|
||||
if done:
|
||||
break
|
||||
|
||||
display.vline(xc, y0, y1 - y0, self.ptrcolor) # Draw pointer
|
||||
#print(ticks_diff(ticks_ms(), start)) 75-95ms on Pyboard D depending on calbacks
|
||||
|
||||
def _constrain(self, v):
|
||||
return min(max(v, 1.0), self.mval)
|
||||
|
||||
def value(self, val=None): # User method to get or set value
|
||||
if val is not None:
|
||||
v = self._constrain(val)
|
||||
if self._value is None or v != self._value:
|
||||
self._value = v
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
self.callback(self, *self.args)
|
||||
return self._value
|
||||
|
||||
|
||||
async def btnhan(self, button, up):
|
||||
up = up == 1
|
||||
delta = self.delta
|
||||
maxdelta = 0.64
|
||||
smul= (1 + delta) if up else (1 / (1 + delta))
|
||||
self.value(self.value() * smul)
|
||||
t = ticks_ms()
|
||||
while not button():
|
||||
await asyncio.sleep_ms(0) # Quit fast on button release
|
||||
if ticks_diff(ticks_ms(), t) > 500: # Button was held down
|
||||
delta = min(maxdelta, delta * 2)
|
||||
smul = (1 + delta) if up else (1 / (1 + delta))
|
||||
self.value(self.value() * smul)
|
||||
t = ticks_ms()
|
|
@ -0,0 +1,161 @@
|
|||
# sliders.py Extension to ugui providing linear "potentiometer" widgets.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
from micropython import const
|
||||
from gui.core.ugui import LinearIO, display # Class and instance
|
||||
from gui.widgets.label import Label
|
||||
|
||||
# Null function
|
||||
dolittle = lambda *_ : None
|
||||
|
||||
# *********** SLIDER CLASSES ***********
|
||||
# A slider's text items lie outside its bounding box (area sensitive to touch)
|
||||
|
||||
_SLIDE_DEPTH = const(6) # Must be divisible by 2
|
||||
_TICK_VISIBLE = const(3) # No. of tick pixels visible either side of slider
|
||||
_HALF_SLOT_WIDTH = const(2) # Width of slot /2
|
||||
|
||||
# Slider ontrols have been rewritten to avoid the need for reading back framebuffer
|
||||
# contents as this is unreliable on RA8875.
|
||||
class Slider(LinearIO):
|
||||
def __init__(self, writer, row, col, *,
|
||||
height=100, width=20, divisions=10, legends=None,
|
||||
fgcolor=None, bgcolor=None, fontcolor=None, bdcolor=None, slotcolor=None,
|
||||
callback=dolittle, args=[], value=0.0, active=True):
|
||||
width &= 0xfe # ensure divisible by 2
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, value, active)
|
||||
if active:
|
||||
super()._set_callbacks(callback, args)
|
||||
self.divisions = divisions
|
||||
self.legends = legends
|
||||
self.fontcolor = self.fgcolor if fontcolor is None else fontcolor
|
||||
self.slotcolor = self.bgcolor if slotcolor is None else slotcolor
|
||||
# Define slider
|
||||
self.slide_x0 = col + _TICK_VISIBLE # Draw slider shorter than ticks
|
||||
self.slide_w = width - 2 * _TICK_VISIBLE
|
||||
# y coord of top left hand corner of slide when value == 0
|
||||
self.slide_y0 = row + height - _SLIDE_DEPTH - 1
|
||||
# Slot coordinates
|
||||
centre = col + width // 2
|
||||
self.slot_x0 = centre - _HALF_SLOT_WIDTH
|
||||
self.slot_y0 = row + _SLIDE_DEPTH // 2
|
||||
self.slot_h = height - _SLIDE_DEPTH - 1
|
||||
# Prevent Label objects being added to display list when already there.
|
||||
self.drawn = False
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
if active: # Run callback (e.g. to set dynamic colors)
|
||||
self.callback(self, *self.args)
|
||||
|
||||
def show(self):
|
||||
# Blank slot, ticks and slider
|
||||
if super().show(False): # Honour bgcolor
|
||||
x = self.col
|
||||
y = self.slot_y0
|
||||
# Length of travel of slider
|
||||
slot_len = self.slot_h # Dimensions of slot
|
||||
slot_w = 2 * _HALF_SLOT_WIDTH
|
||||
if self.divisions > 0:
|
||||
dy = slot_len / (self.divisions) # Tick marks
|
||||
xs = x + 1
|
||||
xe = x + self.width -1
|
||||
for tick in range(self.divisions + 1):
|
||||
ypos = int(y + dy * tick)
|
||||
display.line(xs, ypos, xe, ypos, self.fgcolor)
|
||||
# Blank and redraw slot
|
||||
display.fill_rect(self.slot_x0, self.slot_y0, slot_w, slot_len, self.slotcolor)
|
||||
display.rect(self.slot_x0, self.slot_y0, slot_w, slot_len, self.fgcolor)
|
||||
|
||||
# Legends: if redrawing, they are already on the Screen's display list
|
||||
if self.legends is not None and not self.drawn:
|
||||
if len(self.legends) <= 1:
|
||||
dy = 0
|
||||
else:
|
||||
dy = slot_len / (len(self.legends) -1)
|
||||
yl = y + slot_len # Start at bottom
|
||||
wri = self.writer
|
||||
fhdelta = wri.height / 2
|
||||
for legend in self.legends:
|
||||
Label(wri, int(yl - fhdelta), x + self.width + 4, legend, fgcolor = self.fontcolor)
|
||||
yl -= dy
|
||||
|
||||
slide_y = round(self.slide_y0 - self._value * slot_len)
|
||||
display.fill_rect(self.slide_x0, slide_y, self.slide_w, _SLIDE_DEPTH, self.fgcolor)
|
||||
self.drawn = True
|
||||
|
||||
def color(self, color):
|
||||
if color != self.fgcolor:
|
||||
self.fgcolor = color
|
||||
self.draw = True
|
||||
|
||||
|
||||
class HorizSlider(LinearIO):
|
||||
def __init__(self, writer, row, col, *,
|
||||
height=20, width=100, divisions=10, legends=None,
|
||||
fgcolor=None, bgcolor=None, fontcolor=None, bdcolor=None,
|
||||
slotcolor=None,
|
||||
callback=dolittle, args=[], value=0.0, active=True):
|
||||
height &= 0xfe # ensure divisible by 2
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, value, active)
|
||||
if active:
|
||||
super()._set_callbacks(callback, args)
|
||||
self.divisions = divisions
|
||||
self.legends = legends
|
||||
self.fontcolor = self.fgcolor if fontcolor is None else fontcolor
|
||||
self.slotcolor = self.bgcolor if slotcolor is None else slotcolor
|
||||
|
||||
# Define slider
|
||||
self.slide_y0 = row + _TICK_VISIBLE # Draw slider shorter than ticks
|
||||
self.slide_h = height - 2 * _TICK_VISIBLE
|
||||
|
||||
# Slot coordinates
|
||||
self.slot_x0 = col + _SLIDE_DEPTH // 2
|
||||
self.slot_w = width - _SLIDE_DEPTH - 1
|
||||
centre = row + height // 2
|
||||
self.slot_y0 = centre - _HALF_SLOT_WIDTH
|
||||
# Prevent Label objects being added to display list when already there.
|
||||
self.drawn = False
|
||||
self.draw = True # Ensure a redraw on next refresh
|
||||
if active: # Run callback (e.g. to set dynamic colors)
|
||||
self.callback(self, *self.args)
|
||||
|
||||
def show(self):
|
||||
# Blank slot, ticks and slider
|
||||
if super().show(False): # Honour bgcolor
|
||||
x = self.slot_x0
|
||||
y = self.row
|
||||
slot_len = self.slot_w # Slot dimensions
|
||||
slot_h = 2 * _HALF_SLOT_WIDTH
|
||||
if self.divisions > 0:
|
||||
dx = slot_len / (self.divisions) # Tick marks
|
||||
ys = y + 1
|
||||
ye = y + self.height - 1
|
||||
for tick in range(self.divisions + 1):
|
||||
xpos = int(x + dx * tick)
|
||||
display.line(xpos, ys, xpos, ye, self.fgcolor)
|
||||
# Blank and redraw slot
|
||||
display.fill_rect(self.slot_x0, self.slot_y0, slot_len, slot_h, self.slotcolor)
|
||||
display.rect(self.slot_x0, self.slot_y0, slot_len, slot_h, self.fgcolor)
|
||||
|
||||
# Legends: if redrawing, they are already on the Screen's display list
|
||||
if self.legends is not None and not self.drawn:
|
||||
if len(self.legends) <= 1:
|
||||
dx = 0
|
||||
else:
|
||||
dx = slot_len / (len(self.legends) -1)
|
||||
xl = x
|
||||
wri = self.writer
|
||||
for legend in self.legends:
|
||||
offset = wri.stringlen(legend) / 2
|
||||
Label(wri, y - wri.height - 4, int(xl - offset), legend, fgcolor = self.fontcolor)
|
||||
xl += dx
|
||||
|
||||
self.slide_x = round(self.col + self._value * slot_len)
|
||||
display.fill_rect(self.slide_x, self.slide_y0, _SLIDE_DEPTH, self.slide_h, self.fgcolor)
|
||||
self.drawn = True
|
||||
|
||||
def color(self, color):
|
||||
if color != self.fgcolor:
|
||||
self.fgcolor = color
|
||||
self.draw = True
|
|
@ -0,0 +1,140 @@
|
|||
# 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.ugui import LinearIO
|
||||
from hardware_setup import ssd # Display driver for Writer
|
||||
from gui.core.writer import Writer
|
||||
|
||||
from time import ticks_diff, ticks_ms
|
||||
import uasyncio as asyncio
|
||||
|
||||
# Reason for no tab support in nano-gui/private/reason_for_no_tabs
|
||||
|
||||
class Textbox(LinearIO):
|
||||
def __init__(self, writer, row, col, width, nlines, *, bdcolor=None, fgcolor=None,
|
||||
bgcolor=None, clip=True, active=False):
|
||||
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, 0, active)
|
||||
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
|
||||
|
||||
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(ssd, row, col)
|
||||
wri.printstring(line)
|
||||
row += ht
|
||||
col = left
|
||||
wri.setcolor() # Restore defaults
|
||||
|
||||
def show(self):
|
||||
if 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.draw = True # Cause a refresh
|
||||
return True
|
||||
return False
|
||||
|
||||
def value(self):
|
||||
return len(self.lines)
|
||||
|
||||
def clear(self):
|
||||
self.lines = []
|
||||
self.draw = True # Cause a refresh
|
||||
|
||||
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.draw = True # Cause a refresh
|
||||
|
||||
async def btnhan(self, button, up):
|
||||
self.scroll(-up)
|
||||
t = ticks_ms()
|
||||
d = 1
|
||||
while not button():
|
||||
await asyncio.sleep_ms(0) # Quit fast on button release
|
||||
if ticks_diff(ticks_ms(), t) > 500: # Button was held down
|
||||
d = min(16, d * 2)
|
||||
self.scroll(-up * d)
|
||||
t = ticks_ms()
|
|
@ -0,0 +1,120 @@
|
|||
# vectors.py Extension to ugui providing vector display
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# VectorDial class is display-only: no practical way to perform
|
||||
# input on multiple vectors
|
||||
|
||||
from micropython import const
|
||||
from gui.core.ugui import Screen, Widget, display
|
||||
from gui.widgets.label import Label
|
||||
from gui.core.colors import *
|
||||
import cmath
|
||||
|
||||
conj = lambda v : v.real - v.imag * 1j # Complex conjugate
|
||||
|
||||
# Draw a vector in complex coordinates. Origin and end are complex.
|
||||
# End is relative to origin.
|
||||
def pline(origin, vec, color):
|
||||
xs, ys = origin.real, origin.imag
|
||||
display.line(round(xs), round(ys), round(xs + vec.real), round(ys - vec.imag), color)
|
||||
|
||||
# Draw an arrow; origin and vec are complex, scalar lc defines length of chevron.
|
||||
# cw and ccw are unit vectors of +-3pi/4 radians for chevrons.
|
||||
def arrow(origin, vec, lc, color):
|
||||
ccw = cmath.exp(3j * cmath.pi/4) # Unit vectors
|
||||
cw = cmath.exp(-3j * cmath.pi/4)
|
||||
length, theta = cmath.polar(vec)
|
||||
uv = cmath.rect(1, theta) # Unit rotation vector
|
||||
start = -vec
|
||||
if length > 3 * lc: # If line is long
|
||||
ds = cmath.rect(lc, theta)
|
||||
start += ds # shorten to allow for length of tail chevrons
|
||||
chev = lc + 0j
|
||||
pline(origin, vec, color) # Origin to tip
|
||||
pline(origin, start, color) # Origin to tail
|
||||
pline(origin + conj(vec), chev*ccw*uv, color) # Tip chevron
|
||||
pline(origin + conj(vec), chev*cw*uv, color)
|
||||
if length > lc: # Confusing appearance of very short vectors with tail chevron
|
||||
pline(origin + conj(start), chev*ccw*uv, color) # Tail chevron
|
||||
pline(origin + conj(start), chev*cw*uv, color)
|
||||
|
||||
# Vector display
|
||||
class Pointer:
|
||||
def __init__(self, dial):
|
||||
dial.vectors.add(self)
|
||||
self.dial = dial
|
||||
self.color = WHITE
|
||||
self.val = 0j
|
||||
|
||||
def value(self, v=None, color=None):
|
||||
if color is not None:
|
||||
self.color = color
|
||||
if v is not None:
|
||||
if isinstance(v, complex):
|
||||
l = cmath.polar(v)[0]
|
||||
newval = v / l if l > 1 else v # Max length = 1.0
|
||||
else:
|
||||
raise ValueError('Pointer value must be complex.')
|
||||
if v != self.val and self.dial.screen is Screen.current_screen:
|
||||
self.show(newval)
|
||||
self.val = newval
|
||||
return self.val
|
||||
|
||||
def show(self, newval=None):
|
||||
v = self.val if newval is None else newval
|
||||
dial = self.dial
|
||||
color = self.color
|
||||
vor = dial.vor # Dial's origin as a vector
|
||||
r = dial.radius * (1 - dial.TICKLEN)
|
||||
if dial.arrow:
|
||||
arrow(vor, r * v, 5, color)
|
||||
else:
|
||||
pline(vor, r * v, color)
|
||||
self.dial.draw = True # Mark dial as dirty
|
||||
|
||||
|
||||
class VectorDial(Widget):
|
||||
TICKLEN = 0.1
|
||||
def __init__(self, writer, row, col, *,
|
||||
height=100, fgcolor=None, bgcolor=None, bdcolor=None,
|
||||
ticks=4, arrow=False, pip=None):
|
||||
super().__init__(writer, row, col, height, height,
|
||||
fgcolor, bgcolor, bdcolor, 0, False) # Display only
|
||||
self.arrow = arrow
|
||||
self.pip = self.fgcolor if pip is None else pip
|
||||
radius = height / 2
|
||||
self.radius = radius
|
||||
self.ticks = ticks
|
||||
self.xorigin = col + radius
|
||||
self.yorigin = row + radius
|
||||
self.vor = self.xorigin + 1j * self.yorigin # Origin as a vector
|
||||
self.vectors = set()
|
||||
self.draw = True
|
||||
|
||||
def show(self):
|
||||
if super().show():
|
||||
# cache bound variables
|
||||
ticks = self.ticks
|
||||
radius = self.radius
|
||||
xo = self.xorigin
|
||||
yo = self.yorigin
|
||||
vor = self.vor
|
||||
vtstart = (1 - self.TICKLEN) * radius + 0j # start of tick
|
||||
vtick = self.TICKLEN * radius + 0j # tick
|
||||
vrot = cmath.exp(2j * cmath.pi/ticks) # unit rotation
|
||||
for _ in range(ticks):
|
||||
pline(vor + conj(vtstart), vtick, self.fgcolor)
|
||||
vtick *= vrot
|
||||
vtstart *= vrot
|
||||
display.circle(xo, yo, radius, self.fgcolor)
|
||||
|
||||
vshort = 1000 # Length of shortest vector
|
||||
for v in self.vectors:
|
||||
val = v.value() * radius # val is complex
|
||||
vshort = min(vshort, cmath.polar(val)[0])
|
||||
v.show()
|
||||
if isinstance(self.pip, tuple) and vshort > 9:
|
||||
display.fillcircle(xo, yo, 3, self.pip)
|
||||
self.draw = False
|
|
@ -0,0 +1,55 @@
|
|||
# ili9341_pico.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# As written, supports:
|
||||
# ili9341 240x320 displays on Pi Pico
|
||||
# Edit the driver import for other displays.
|
||||
|
||||
# Demo of initialisation procedure designed to minimise risk of memory fail
|
||||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
# WIRING
|
||||
# Pico Display
|
||||
# GPIO Pin
|
||||
# 3v3 36 Vin
|
||||
# IO6 9 CLK Hardware SPI0
|
||||
# IO7 10 DATA (AKA SI MOSI)
|
||||
# IO8 11 DC
|
||||
# IO9 12 Rst
|
||||
# Gnd 13 Gnd
|
||||
# IO10 14 CS
|
||||
|
||||
# Pushbuttons are wired between the pin and Gnd
|
||||
# Pico pin Meaning
|
||||
# 16 Operate current control
|
||||
# 17 Decrease value of current control
|
||||
# 18 Select previous control
|
||||
# 19 Select next control
|
||||
# 20 Increase value of current control
|
||||
|
||||
from machine import Pin, SPI, freq
|
||||
import gc
|
||||
|
||||
from drivers.ili93xx.ili9341 import ILI9341 as SSD
|
||||
freq(250_000_000) # RP2 overclock
|
||||
# Create and export an SSD instance
|
||||
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
|
||||
prst = Pin(9, Pin.OUT, value=1)
|
||||
pcs = Pin(10, Pin.OUT, value=1)
|
||||
spi = SPI(0, baudrate=30_000_000)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, usd=True)
|
||||
|
||||
from gui.core.ugui import Display, setup
|
||||
# Create and export a Display instance
|
||||
# Define control buttons
|
||||
nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control
|
||||
sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current 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
|
||||
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
|
||||
display = Display(ssd, nxt, sel, prev, increase, decrease)
|
||||
setup(display)
|
|
@ -0,0 +1,55 @@
|
|||
# ili9341_pico.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# As written, supports:
|
||||
# ili9341 240x320 displays on Pi Pico
|
||||
# Edit the driver import for other displays.
|
||||
|
||||
# Demo of initialisation procedure designed to minimise risk of memory fail
|
||||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
# WIRING
|
||||
# Pico Display
|
||||
# GPIO Pin
|
||||
# 3v3 36 Vin
|
||||
# IO6 9 CLK Hardware SPI0
|
||||
# IO7 10 DATA (AKA SI MOSI)
|
||||
# IO8 11 DC
|
||||
# IO9 12 Rst
|
||||
# Gnd 13 Gnd
|
||||
# IO10 14 CS
|
||||
|
||||
# Pushbuttons are wired between the pin and Gnd
|
||||
# Pico pin Meaning
|
||||
# 16 Operate current control
|
||||
# 17 Decrease value of current control
|
||||
# 18 Select previous control
|
||||
# 19 Select next control
|
||||
# 20 Increase value of current control
|
||||
|
||||
from machine import Pin, SPI, freq
|
||||
import gc
|
||||
|
||||
from drivers.ili93xx.ili9341 import ILI9341 as SSD
|
||||
freq(250_000_000) # RP2 overclock
|
||||
# Create and export an SSD instance
|
||||
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
|
||||
prst = Pin(9, Pin.OUT, value=1)
|
||||
pcs = Pin(10, Pin.OUT, value=1)
|
||||
spi = SPI(0, baudrate=30_000_000)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, usd=True)
|
||||
|
||||
from gui.core.ugui import Display, setup
|
||||
# Create and export a Display instance
|
||||
# Define control buttons
|
||||
nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control
|
||||
sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current 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
|
||||
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
|
||||
display = Display(ssd, nxt, sel, prev, increase, decrease)
|
||||
setup(display)
|
|
@ -0,0 +1,123 @@
|
|||
# color_setup.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch, Ihor Nehrutsa
|
||||
|
||||
# Supports:
|
||||
# TTGO T-Display 1.14" 135*240(Pixel) based on ST7789V
|
||||
# http://www.lilygo.cn/claprod_view.aspx?TypeId=62&Id=1274
|
||||
# http://www.lilygo.cn/prod_view.aspx?TypeId=50044&Id=1126
|
||||
# https://github.com/Xinyuan-LilyGO/TTGO-T-Display
|
||||
# https://github.com/Xinyuan-LilyGO/TTGO-T-Display/blob/master/image/pinmap.jpg
|
||||
# https://github.com/Xinyuan-LilyGO/TTGO-T-Display/blob/master/schematic/ESP32-TFT(6-26).pdf
|
||||
|
||||
# WIRING (TTGO T-Display pin numbers and names).
|
||||
# Pinout of TFT Driver
|
||||
# ST7789 ESP32
|
||||
# TFT_MISO N/A
|
||||
TFT_MOSI = 19 # (SDA on schematic pdf) SPI interface output/input pin.
|
||||
TFT_SCLK = 18 # This pin is used to be serial interface clock.
|
||||
TFT_CS = 5 # Chip selection pin, low enable, high disable.
|
||||
TFT_DC = 16 # Display data/command selection pin in 4-line serial interface.
|
||||
TFT_RST = 23 # This signal will reset the device,Signal is active low.
|
||||
TFT_BL = 4 # (LEDK on schematic pdf) Display backlight control pin
|
||||
|
||||
ADC_IN = 34 # Measuring battery or USB voltage, see comment below
|
||||
ADC_EN = 14 # (PWR_EN on schematic pdf) is the ADC detection enable port
|
||||
|
||||
BUTTON1 = 35 # right of the USB connector
|
||||
BUTTON2 = 0 # left of the USB connector
|
||||
|
||||
# ESP32 pins, free for use in user applications
|
||||
#I2C_SDA = 21 # hardware ID 0
|
||||
#I2C_SCL = 22
|
||||
|
||||
#UART2TXD = 17
|
||||
|
||||
#GPIO2 = 2
|
||||
#GPIO15 = 15
|
||||
#GPIO13 = 13
|
||||
#GPIO12 = 12
|
||||
|
||||
#GPIO37 = 37
|
||||
#GPIO38 = 38
|
||||
#UART1TXD = 4
|
||||
#UART1RXD = 5
|
||||
#GPIO18 = 18
|
||||
#GPIO19 = 19
|
||||
#GPIO17 = 17
|
||||
|
||||
#DAC1 = 25
|
||||
#DAC2 = 26
|
||||
|
||||
# Input only pins
|
||||
#GPIO36 = 36 # input only
|
||||
#GPIO39 = 39 # input only
|
||||
|
||||
# Demo of initialisation procedure designed to minimise risk of memory fail
|
||||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
from machine import Pin, SPI, ADC, freq
|
||||
import gc
|
||||
|
||||
from drivers.st7789.st7789_4bit import *
|
||||
SSD = ST7789
|
||||
|
||||
pdc = Pin(TFT_DC, Pin.OUT, value=0) # Arbitrary pins
|
||||
pcs = Pin(TFT_CS, Pin.OUT, value=1)
|
||||
prst = Pin(TFT_RST, Pin.OUT, value=1)
|
||||
pbl = Pin(TFT_BL, Pin.OUT, value=1)
|
||||
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
# Conservative low baudrate. Can go to 62.5MHz.
|
||||
spi = SPI(1, 30_000_000, sck=Pin(TFT_SCLK), mosi=Pin(TFT_MOSI))
|
||||
freq(160_000_000)
|
||||
|
||||
''' TTGO
|
||||
v +----------------+
|
||||
40 | | |
|
||||
^ | +------+ | pin 36
|
||||
| | | | |
|
||||
| | | | |
|
||||
240 | | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
v | +------+ |
|
||||
40 | | | Reset button
|
||||
^ +----------------+
|
||||
>----<------>----<
|
||||
52 135 xx
|
||||
BUTTON2 BUTTON1
|
||||
'''
|
||||
# Right way up landscape: defined as top left adjacent to pin 36
|
||||
ssd = SSD(spi, height=135, width=240, dc=pdc, cs=pcs, rst=prst, disp_mode=LANDSCAPE, display=TDISPLAY)
|
||||
# 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)
|
||||
|
||||
from gui.core.ugui import Display, setup
|
||||
# Create and export a Display instance
|
||||
# Define control buttons
|
||||
nxt = Pin(36, Pin.IN, Pin.PULL_UP) # Move to next control
|
||||
sel = Pin(37, Pin.IN, Pin.PULL_UP) # Operate current control
|
||||
prev = Pin(38, Pin.IN, Pin.PULL_UP) # Move to previous control
|
||||
increase = Pin(39, Pin.IN, Pin.PULL_UP) # Increase control's value
|
||||
decrease = Pin(32, Pin.IN, Pin.PULL_UP) # Decrease control's value
|
||||
display = Display(ssd, nxt, sel, prev, increase, decrease)
|
||||
setup(display)
|
||||
|
||||
# optional
|
||||
# b1 = Pin(BUTTON1, Pin.IN)
|
||||
# b2 = Pin(BUTTON2, Pin.IN)
|
||||
# adc_en = Pin(ADC_EN, Pin.OUT, value=1)
|
||||
# adc_in = ADC(Pin(ADC_IN))
|
||||
# adc_en.value(0)
|
||||
'''
|
||||
Set ADC_EN to "1" and read voltage in BAT_ADC,
|
||||
if this voltage more than 4.3 V device have powered from USB.
|
||||
If less then 4.3 V - device have power from battery.
|
||||
To save battery you can set ADC_EN to "0" and in this case the USB converter
|
||||
will be power off and do not use your battery.
|
||||
When you need to measure battery voltage first set ADC_EN to "1",
|
||||
measure voltage and then set ADC_EN back to "0" for save battery.
|
||||
'''
|
Ładowanie…
Reference in New Issue