docs: Introduce the Application Writer's Guide.
This commit is contained in:
parent
bb8e95cdd4
commit
a2fd52ef2b
3
Makefile
3
Makefile
|
@ -72,8 +72,7 @@ docs:
|
||||||
|
|
||||||
|
|
||||||
sim:
|
sim:
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
||||||
PYTHONPATH=$(PWD)/wasp/boards/simulator:$(PWD)/wasp \
|
|
||||||
python3 -i wasp/main.py
|
python3 -i wasp/main.py
|
||||||
|
|
||||||
.PHONY: bootloader reloader docs micropython
|
.PHONY: bootloader reloader docs micropython
|
||||||
|
|
4
TODO.md
4
TODO.md
|
@ -64,10 +64,10 @@ applications.
|
||||||
* [X] Stopwatch app
|
* [X] Stopwatch app
|
||||||
* [X] Settings app
|
* [X] Settings app
|
||||||
* [X] PC-hosted simulation platform
|
* [X] PC-hosted simulation platform
|
||||||
* [o] Documentation
|
* [O] Documentation
|
||||||
- [X] Sphinx framework and integration with github.io
|
- [X] Sphinx framework and integration with github.io
|
||||||
- [X] Document bootloader protocols
|
- [X] Document bootloader protocols
|
||||||
- [ ] Application writer's guide
|
- [X] Application writer's guide
|
||||||
- [ ] Write full docstring documentation for all WASP components
|
- [ ] Write full docstring documentation for all WASP components
|
||||||
* [X] Application Launcher
|
* [X] Application Launcher
|
||||||
* [X] Debug notifications
|
* [X] Debug notifications
|
||||||
|
|
350
docs/appguide.rst
Normal file
350
docs/appguide.rst
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
Application Writer's Guide
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
WASP, the Watch Application System in Python, has one pervasive goal that
|
||||||
|
influences almost everything about it, from its name to its development
|
||||||
|
roadmap: make writing applications easy (and fun).
|
||||||
|
|
||||||
|
Applications that can be loaded, changed, adapted and remixed by the user
|
||||||
|
are what **really** distinguishes a smart watch from a "feature watch"[#]_.
|
||||||
|
In other words if we want a watch built around a tiny microcontroller to be
|
||||||
|
sufficiently "smart" then it has to be all about the applications.
|
||||||
|
|
||||||
|
This guide will help you get started writing applications for WASP. Have fun!
|
||||||
|
|
||||||
|
.. [#] The fixed function mobile phones that existed before iOS and Android
|
||||||
|
took over the industry were retrospectively renamed "feature phones" to
|
||||||
|
distinguish them from newer devices. Many of them were superficially similar
|
||||||
|
to early Android devices but is was the application ecosystem that really
|
||||||
|
made smart phones smart.
|
||||||
|
|
||||||
|
Hello World for WASP
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Let's start by examining a simple "Hello, World!" application for WASP.
|
||||||
|
|
||||||
|
.. literalinclude:: hello.py
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
There are a couple of points of interest:
|
||||||
|
|
||||||
|
1. Applications have a :py:data:`~.TemplateApp.NAME`, which is shown in the
|
||||||
|
launcher. Most applications also provide an :py:data:`~.TemplateApp.ICON`
|
||||||
|
but a default is displayed if this is omitted.
|
||||||
|
2. This example uses :py:meth:`~.TemplateApp.__init__` to initialize
|
||||||
|
the state of the application, this ensure the state remains "sticky"
|
||||||
|
when the application is activated and deactivated.
|
||||||
|
3. :py:meth:`~.TemplateApp.foreground` is the only mandatory application entry
|
||||||
|
point and is responsible for redrawing the screen. This application does
|
||||||
|
not implement :py:meth:`~.TemplateApp.background` because there is nothing
|
||||||
|
for us to do!
|
||||||
|
4. The use of :py:meth:`~.TemplateApp._draw` is optional. We could just do
|
||||||
|
the work in :py:meth:`~.TemplateApp.foreground` but this application follows
|
||||||
|
a common WASP idiom that is normally used to pattern to distinguish a full
|
||||||
|
refresh of the screen from an fast update (a redraw).
|
||||||
|
|
||||||
|
Application life-cycle
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Applications in WASP are triggered by and do all their processing
|
||||||
|
from calls their entry points. The entry points can be coarsely categorized
|
||||||
|
event notifications, timer callbacks (the application tick) and
|
||||||
|
system notifications.
|
||||||
|
|
||||||
|
System notifications control the application life-cycle and the entry point
|
||||||
|
calls, together with the implicit application states are shown below.
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
|
||||||
|
digraph lifecycle {
|
||||||
|
START -> BACKGROUND [ label=" __init__() " ];
|
||||||
|
BACKGROUND -> START [ label=" __del__() " ];
|
||||||
|
BACKGROUND -> ACTIVE [ label=" foreground() " ];
|
||||||
|
ACTIVE -> BACKGROUND [ label=" background() " ];
|
||||||
|
ACTIVE -> GO_TO_CLOCK [ label=" sleep() -> False " ];
|
||||||
|
GO_TO_CLOCK -> BACKGROUND [ label=" background() " ];
|
||||||
|
ACTIVE -> SLEEPING [ label=" sleep() -> True " ];
|
||||||
|
SLEEPING -> ACTIVE [ label=" wake() " ];
|
||||||
|
|
||||||
|
START [ shape=box ];
|
||||||
|
BACKGROUND [ shape=box, style=rounded ]
|
||||||
|
ACTIVE [ shape=box, style=rounded ]
|
||||||
|
SLEEPING [ shape=box, style=rounded ]
|
||||||
|
GO_TO_CLOCK [ label="GOTO ClockApp" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
When an application is initialized is enters the ``BACKGROUND`` state. A
|
||||||
|
backgrounded application will not execute but it should nevertheless
|
||||||
|
maintain its user visible state whilst in the background. To conserve
|
||||||
|
memory WASP does not permit two applications to run simultaneously but
|
||||||
|
because each application preserves its state when in the background it will
|
||||||
|
appear to the user as though all applications are running all the time.
|
||||||
|
|
||||||
|
For example, a stopwatch application should record the time that it was started
|
||||||
|
and remember that start time, regardless of it's state, until either the
|
||||||
|
stopwatch is stopped of the application is destroyed.
|
||||||
|
|
||||||
|
A backgrounded application can enter the ``ACTIVE`` state via a call to
|
||||||
|
:py:meth:`~.TemplateApp.foreground`. When it is active the application owns the
|
||||||
|
screen and should draw and maintain its UI.
|
||||||
|
|
||||||
|
If the system manager want to put an active application to sleep then it will
|
||||||
|
call :py:meth:`~.TemplateApp.sleep`. If the application returns True then the
|
||||||
|
application will stop running (e.g. receive no events and no application tick)
|
||||||
|
but instead must wait to receive a notification via
|
||||||
|
:py:meth:`~.TemplateApp.wake` telling the application that the device
|
||||||
|
is waking up and that it may update the screen if needed.
|
||||||
|
|
||||||
|
If an application does not support sleeping then it can simply not implement
|
||||||
|
:py:meth:`~.TemplateApp.sleep` (or :py:meth:`~.TemplateApp.wake`) although it
|
||||||
|
can also return False from :py:meth:`~.TemplateApp.sleep` if this is preferred.
|
||||||
|
In this case the system manager will automatically return to the default
|
||||||
|
application, typically the main clock face.
|
||||||
|
|
||||||
|
Note: *Most applications do not need to support sleep() since it is often
|
||||||
|
a better user experience for the watch to return to the default application
|
||||||
|
when they complete an interaction.*
|
||||||
|
|
||||||
|
API primer
|
||||||
|
----------
|
||||||
|
|
||||||
|
This API primer introduces some of the most important and frequently used
|
||||||
|
interfaces for WASP. For more comprehensive coverage see the
|
||||||
|
:ref:`WASP Reference Manual` which contains extensive API documentation
|
||||||
|
covering the entire of WASP, including its drivers.
|
||||||
|
|
||||||
|
System management
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The system management API does provide a number of low-level calls that
|
||||||
|
can register new applications and navigate between them. However most
|
||||||
|
applications need not use these. Instead most applications use a small
|
||||||
|
set of methods. In particular almost all applictions need to call a couple of
|
||||||
|
methods from :py:meth:`~.TemplateApp.foreground` in order to register
|
||||||
|
for notifications:
|
||||||
|
|
||||||
|
* :py:meth:`~.Manager.request_event` - register for UI events such as button
|
||||||
|
presses and touch screen activity.
|
||||||
|
* :py:meth:`~.Manager.request_tick` - register to receive an application tick
|
||||||
|
and specify the tick frequency.
|
||||||
|
|
||||||
|
Additionally if your application is a game or a similar program that should
|
||||||
|
not allow the watch to go to sleep then it should arrange to call
|
||||||
|
:py:meth:`~.Manager.keep_awake` from the application's
|
||||||
|
:py:meth:`~.TemplateApp.tick` method.
|
||||||
|
|
||||||
|
Drawing
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Most applications using the drawing toolbox, :py:data:`wasp.watch.drawable`,
|
||||||
|
in order to handle the display. Applications are permitted to directly access
|
||||||
|
:py:data:`wasp.watch.display` if they require direct pixel access or want to
|
||||||
|
exploit specific features of the display hardware (inverse video, partial
|
||||||
|
display, etc) but for simple applications then the following simple drawing
|
||||||
|
functions are sufficient.
|
||||||
|
|
||||||
|
* :py:meth:`~.Draw565.blit` - blit an image to the display at specified (x, y)
|
||||||
|
coordinates, image type is detected automatically
|
||||||
|
* :py:meth:`~.Draw565.fill` - fill a rectangle, without arguments the default
|
||||||
|
is a black rectangle covering the entire screen which is useful to clear
|
||||||
|
the screen prior to an update
|
||||||
|
* :py:meth:`~.Draw565.string` - render a string, optionally centring it
|
||||||
|
automatically
|
||||||
|
* :py:meth:`~.Draw565.wrap` - automatically determine where to break a string
|
||||||
|
so it can be rendered to a specified width
|
||||||
|
|
||||||
|
Most applications run some variant of the following code from their
|
||||||
|
:py:meth:`~.TemplateApp.foreground` or :py:meth:`~.TemplateApp._draw` methods
|
||||||
|
in order to clear the display ready for a redraw.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
draw = wasp.watch.drawable
|
||||||
|
draw.fill()
|
||||||
|
# now use draw to render the rest of the screen
|
||||||
|
|
||||||
|
Some applications customize the above code slightly if they require a custom
|
||||||
|
background colour and it may even be omitted entirely if the application
|
||||||
|
explicitly draws every pixel on the display.
|
||||||
|
|
||||||
|
Finally, WASP provides a small number of widgets that allow common fragments of
|
||||||
|
logic and redrawing code to be shared between applications:
|
||||||
|
|
||||||
|
* :py:class:`.BatteryMeter`
|
||||||
|
* :py:class:`.ScrollingIndicator`
|
||||||
|
|
||||||
|
MicroPython
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Many of the features of WASP are inherited directly from MicroPython_. It is
|
||||||
|
useful to have a basic understanding of MicroPython and, in particular, put
|
||||||
|
in a little time learning the best ways to copy with running
|
||||||
|
`MicroPython on microcontrollers`__.
|
||||||
|
|
||||||
|
.. _MicroPython: https://micropython.org/
|
||||||
|
__ http://docs.micropython.org/en/latest/reference/constrained.html
|
||||||
|
|
||||||
|
|
||||||
|
How to run your application
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Testing on the simulator
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
WASP provides a simulator that can be used to test applications before
|
||||||
|
downloading them to the device. The simulator is useful for ensuring the
|
||||||
|
code is syntactically correct and that there are not major runtime problems
|
||||||
|
(e.g. missing symbols).
|
||||||
|
|
||||||
|
Note: *The simulator does not model the RAM or code size limits of the
|
||||||
|
real device. It may still be necessary to tune the application for minimal
|
||||||
|
footprint after testing on the simulator.*
|
||||||
|
|
||||||
|
Firstly launch the simulator:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
sh$ make sim
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \\
|
||||||
|
python3 -i wasp/main.py
|
||||||
|
MOTOR: set on
|
||||||
|
BACKLIGHT: 2
|
||||||
|
Watch is running, use Ctrl-C to stop
|
||||||
|
|
||||||
|
From the simulator console we can register the application with the following
|
||||||
|
code:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
^C
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
KeyboardInterrupt
|
||||||
|
>>> from myapp import MyApp
|
||||||
|
>>> wasp.system.register(MyApp())
|
||||||
|
>>> wasp.system.run()
|
||||||
|
Watch is running, use Ctrl-C to stop
|
||||||
|
|
||||||
|
When an application is registered it does not start automatically but it will
|
||||||
|
have been added to the launcher and you will be able to select in the simulator
|
||||||
|
by using the Arrow keys to bring up the launcher and then clicking on your
|
||||||
|
application.
|
||||||
|
|
||||||
|
The application can also be registered automatically when you load the
|
||||||
|
simulator if you add it to ``wasp/main.py``. Try adding lines 5 and 6 from
|
||||||
|
the above example into this file (between ``import wasp`` and
|
||||||
|
``wasp.system.run()``).
|
||||||
|
|
||||||
|
Testing on the device
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If we have an application under development when we can launch a quick test
|
||||||
|
that does not result in the application being permanently stored on the device.
|
||||||
|
Providing there is enough available RAM then this can lead to a very quick
|
||||||
|
edit-test cycles.
|
||||||
|
|
||||||
|
Try:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
sh$ tools/wasptool \\
|
||||||
|
--exec myapp.py \\
|
||||||
|
--eval "wasp.system.register(MyApp())"
|
||||||
|
Preparing to run myapp.py:
|
||||||
|
[##################################################] 100%
|
||||||
|
|
||||||
|
Like the simulator, when an application is registered it does not start
|
||||||
|
automatically but it will have been added to the launcher and can be launched
|
||||||
|
using the normal gestures to control the device.
|
||||||
|
|
||||||
|
Note: *If the progress bar jams at the same point each time then it is likely
|
||||||
|
your application is too large to be compiled on the target. You may have to
|
||||||
|
adopt the frozen module approach from the next section.*
|
||||||
|
|
||||||
|
Making it permanent
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To ensure you application survives a system reset (press the hardware
|
||||||
|
button for around five seconds until the splash screen is seen, wait
|
||||||
|
five seconds and then press again) then we must copy it to the device
|
||||||
|
and ensure it gets launched during system startup.
|
||||||
|
|
||||||
|
Note: *Applications stored in external FLASH have a greater RAM overhead
|
||||||
|
than applications that are frozen into the WASP binary. See next section
|
||||||
|
for additional details.*
|
||||||
|
|
||||||
|
To copy your application to the external FLASH try:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
sh$ ./tools/wasptool --upload myapp.py
|
||||||
|
Uploading myapp.py:
|
||||||
|
[##################################################] 100%
|
||||||
|
|
||||||
|
At this point your application is stored on the external FLASH but it will
|
||||||
|
not automatically be loaded. This requires you to update the ``main.py`` file
|
||||||
|
stored in the external FLASH. When WASP runs for the first time it
|
||||||
|
automatically generates this file (using ``wasp/main.py`` as a template)
|
||||||
|
and copies it to the external FLASH. After this point ``main.py`` is user
|
||||||
|
modifiable and can be used to tweak the configuration of the watch before
|
||||||
|
it starts running.
|
||||||
|
|
||||||
|
Edit ``wasp/main.py`` to add the following two lines between ``import wasp``
|
||||||
|
and the ``wasp.system.run()``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from myapp import MyApp
|
||||||
|
wasp.system.register(MyApp())
|
||||||
|
|
||||||
|
Having done that we can use ``wasptool`` to upload the modified file
|
||||||
|
to the watch:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
sh$ ./tools/wasptool --upload wasp/main.py
|
||||||
|
Uploading wasp/main.py:
|
||||||
|
[##################################################] 100%
|
||||||
|
|
||||||
|
Note: *If the new code on the watch throws an exception (including
|
||||||
|
an out-of-memory exception) then your watch will display a black
|
||||||
|
screen at startup. If that happens, and you don't know how to debug
|
||||||
|
the problem, then you can use wasptool to restore the original version
|
||||||
|
of main.py .*
|
||||||
|
|
||||||
|
Freezing your application into the WASP binary
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Freezing your application causes it to consume dramatically less RAM. That is
|
||||||
|
because the code is both pre-compiled (meaning we don't need any RAM budget to
|
||||||
|
run the compiler) **and** it can execute directly from the internal FLASH
|
||||||
|
memory.
|
||||||
|
|
||||||
|
Freezing your application simply requires you to modify the ``manifest.py``
|
||||||
|
file for your board (e.g. ``wasp/boards/pinetime/manifest.py``) to include
|
||||||
|
your application and then the whole binary must be re-compiled as normal.
|
||||||
|
|
||||||
|
After that you an use the same technique described in the previous
|
||||||
|
section to add an import and register for you application to ``main.py``
|
||||||
|
|
||||||
|
Note: *The micropython import path "prefers" frozen modules to those
|
||||||
|
found in the external filesystem. If your application is both frozen and
|
||||||
|
copied to external FLASH then the frozen version will be loaded.*
|
||||||
|
|
||||||
|
Application entry points
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Applications provide entry points for the system manager to use to notify
|
||||||
|
the application of a change in system state or an user interface event.
|
||||||
|
|
||||||
|
.. automodule:: apps.template
|
||||||
|
:members:
|
||||||
|
:private-members:
|
||||||
|
:special-members:
|
|
@ -30,6 +30,7 @@ author = 'Daniel Thompson'
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
|
'sphinx.ext.graphviz',
|
||||||
'recommonmark',
|
'recommonmark',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
1
docs/hello.py
Symbolic link
1
docs/hello.py
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../wasp/apps/hello.py
|
|
@ -11,6 +11,7 @@ Welcome to WASP-OS's documentation!
|
||||||
:caption: Contents:
|
:caption: Contents:
|
||||||
|
|
||||||
README
|
README
|
||||||
|
appguide
|
||||||
wasp
|
wasp
|
||||||
TODO
|
TODO
|
||||||
license
|
license
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
WASP Internals
|
.. _WASP Reference Manual:
|
||||||
==============
|
|
||||||
|
WASP Reference Manual
|
||||||
|
=====================
|
||||||
|
|
||||||
System management
|
System management
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -27,10 +29,6 @@ Applications
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
||||||
.. automodule:: apps.template
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
.. automodule:: apps.testapp
|
.. automodule:: apps.testapp
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
@ -79,7 +77,6 @@ Libraries
|
||||||
|
|
||||||
.. automodule:: fonts.sans24
|
.. automodule:: fonts.sans24
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
.. automodule:: logo
|
.. automodule:: logo
|
||||||
:members:
|
:members:
|
||||||
|
|
19
hello.py
Normal file
19
hello.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# SPDX-License-Identifier: MY-LICENSE
|
||||||
|
# Copyright (C) YEAR(S), AUTHOR
|
||||||
|
|
||||||
|
import wasp
|
||||||
|
|
||||||
|
class HelloApp():
|
||||||
|
"""A hello world application for wasp-os."""
|
||||||
|
NAME = "Hello"
|
||||||
|
|
||||||
|
def __init__(self, msg="Hello, world!"):
|
||||||
|
self.msg = msg
|
||||||
|
|
||||||
|
def foreground(self):
|
||||||
|
self._draw()
|
||||||
|
|
||||||
|
def _draw(self):
|
||||||
|
draw = wasp.watch.drawable
|
||||||
|
draw.fill()
|
||||||
|
draw.string(self.msg, 0, 108, width=240)
|
19
wasp/apps/hello.py
Normal file
19
wasp/apps/hello.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# SPDX-License-Identifier: MY-LICENSE
|
||||||
|
# Copyright (C) YEAR(S), AUTHOR
|
||||||
|
|
||||||
|
import wasp
|
||||||
|
|
||||||
|
class HelloApp():
|
||||||
|
"""A hello world application for wasp-os."""
|
||||||
|
NAME = "Hello"
|
||||||
|
|
||||||
|
def __init__(self, msg="Hello, world!"):
|
||||||
|
self.msg = msg
|
||||||
|
|
||||||
|
def foreground(self):
|
||||||
|
self._draw()
|
||||||
|
|
||||||
|
def _draw(self):
|
||||||
|
draw = wasp.watch.drawable
|
||||||
|
draw.fill()
|
||||||
|
draw.string(self.msg, 0, 108, width=240)
|
|
@ -1,13 +1,40 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# Copyright (C) 2020 Daniel Thompson
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
"""Template application implementing all application method calls.
|
"""The complete set of wasp-os application entry points are documented
|
||||||
|
below as part of a template application. Note that the template does
|
||||||
|
not rely on any specific parent class. This is because applications in
|
||||||
|
wasp-os can rely on *duck typing* making a class hierarchy pointless.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import icons
|
import icons
|
||||||
|
|
||||||
class TemplateApp():
|
class TemplateApp():
|
||||||
"""Template application ready to use as a basis for new applications.
|
"""Template application.
|
||||||
|
|
||||||
|
The template application includes every application entry point. It
|
||||||
|
is used as a reference guide and can also be used as a template for
|
||||||
|
creating new applications.
|
||||||
|
|
||||||
|
.. data:: NAME = 'Template'
|
||||||
|
|
||||||
|
Applications must provide a short ``NAME`` that is used by the
|
||||||
|
launcher to describe the application. Names that are longer than
|
||||||
|
8 characters are likely to be abridged by the launcher in order
|
||||||
|
to fit on the screen.
|
||||||
|
|
||||||
|
.. data:: ICON = RLE2DATA
|
||||||
|
|
||||||
|
Applications can optionally provide an icon for display by the
|
||||||
|
launcher. Applications that expect to be installed on the quick
|
||||||
|
ring will not be listed by the launcher and need not provide any
|
||||||
|
icon. When no icon is provided the system will use a default
|
||||||
|
icon.
|
||||||
|
|
||||||
|
The icon is an opportunity to differentiate your application from others
|
||||||
|
so supplying an icon is strongly recommended. The icon, when provided,
|
||||||
|
must not be larger than 96x64.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
NAME = 'Template'
|
NAME = 'Template'
|
||||||
ICON = icons.app
|
ICON = icons.app
|
||||||
|
|
Loading…
Reference in a new issue