Until now, widgets were re-created during each iteration. For multiple,
reasons, using static widget objects is much easier, so instead of
creating new widgets continuously, modules now create the widgets during
instantiation and get the list of widgets passed as parameter whenever
an update occurs. During the update, they can still manipulate the
widget list by removing and adding elements as needed.
Advantages:
* Less memory fragmentation (fewer (de)allocations)
* Easier event management (widgets now have static IDs)
* Easier module code (widget contents can simply be the result of a
callback)
see #23
Add custom exceptions and add error handling to the engine's module
loading logic. I.e. when a non-existent module is loaded, an exception
is thrown now.
see #23
Add basic drawing of widgets. Each module instance returns a list of
widgets using the widgets() method which is then forwarded to the draw()
method of the configured output.
see #23
This is going to be a bit more comprehensive than anticipated. In order
to cleanly refactor the core and the engine, basically start from
scratch with the implementation.
Goals:
* Test coverage
* Maintain backwards compatibility with module interface as much as
possible (but still make modules easier to code)
* Simplicity
see #23
Hide alias concept for modules in the engine. That way, the individual
modules never get to know about whether a module has been aliased or
not.
see #23
Big oversight in my previous commits: Widgets need to be able to have
specific configurations (i.e. the path for different instances of the
"disk" module has to be different).
To account for that, it is now possible to assign an "alias" to a module
instance using ":" (for example: -m "disk:home"). This alias is then
used for the configuration parameter resolution automatically, for
example:
-m disk:home -p home.path=/home
As a consequence, parameter names in the module code are now relative to
the module, which means: shorter!