Developing the Scene¶
As it is an important part of the Karabo GUI, we expect that the Scene will require new widgets/elements and other changes as time goes by. The following should be considered guidelines for accomplishing that in a way which doesn’t cause undue pain to existing users of the GUI.
Basic Architecture¶
The scene code is generally split into two parts: model and view. The model
code lives in karabo.common.scenemodel
and is responsible for the
representation of scene data and reading/writing those data to/from files. It
is built using the Traits library, which
you should familiarize yourself with if you plan to work on the scene. The view
code for the scene lives in karabogui.sceneview
. It is built using Qt and
makes use of the model objects.
Note
This separation of model and view has an important benefit: You don’t need a GUI to work with scenes. Having a well defined and independent data model means that power users can script the creation/modification of scene files.
Data Model¶
The job of karabo.common.scenemodel
is to describe the data of a scene.
GUI code does not belong here. For that, see The View below.
Scene File Versioning¶
Every scene file, starting with version 2, contains a krb:version
attribute
in the root SVG element which gives the version of the file. If the attribute
is missing, a file is assumed to be version 1.
The general philosophy of versioning in the scene file format is that old data must always be readable. If a file is then modified and saved, it will be written using the latest version of the file format. To accomplish this, the scene data model code will necessarily accumulate reader code over time, but will only ever know how to write out the current version of the file format.
The Scene File Format¶
Version 1 of the scene file format is described in detail here: Scene File Version 1. In general, the file format is SVG and individual elements in a scene file are recognized by their corresponding reader functions in the Karabo library.
Version 2 of the scene file format is basically the same as version 1, but some elements have minor changes which are incompatible with the old reader implementations. These changes should be in agreement with the guidelines enumerated below.
Version 3 (and later) does not yet exist at the time of this writing. The condition for it to exist would be if an existing element (or elements) need(s) a new reader. As soon as the format of any element changes enough that it can’t be handled cleanly by the current reader, then a new reader (for that element) and new file version is required.
Making Changes to the Scene File format¶
If you wish to add new data to the scene file format, or change the format of data which is already there, you should take note of the following:
- If adding a new element, create a class which inherits
BaseSceneObjectData
(a model class).- Create a reader function for the class. Register the reader with the
register_scene_reader
decorator. Make sure you passversion=<current version>
(where<current version>
is the value ofSCENE_FILE_VERSION
) to the decorator. Don’t passSCENE_FILE_VERSION
because this value will change over time and you want to pin your reader to a single version. - Create a writer function for the class. Register the writer with the
register_scene_writer
decorator. - Add unit tests which cover all the new code that you added. Try to cover edge cases that you can think of.
- Starting Karabo 2.10, the scene reader and writer functions would only
expect one parameter, which is the XML element (
element
). The reader and writer entrypoint function (read_func
/write_func
) is not passed anymore. The functionsread_element
andwrite_element
can be used if there is a need to handle children elements.
- Create a reader function for the class. Register the reader with the
- If lightly modifying an existing model class, you can make small changes to
the reader function
- Leave the
SCENE_FILE_VERSION
constant alone. - Make whatever changes are necessary to the model class.
- Update the other reader function(s) for the model if needed
- Update unit tests carefully.
- Leave the
- If modifying an existing model class in a way which requires a new reader
function:
- Increment the
SCENE_FILE_VERSION
constant first. - Make whatever changes are necessary to the model class.
- Create a new reader function and register it with a version equal to the
new value of
SCENE_FILE_VERSION
. Remember not to useSCENE_FILE_VERSION
here. Use its value. - Update the old reader function(s), but only if NOT doing so would cause
an exception when instantiating the model class.
- The overall aim is to construct the latest version of the model class from any version of the file data.
- Update unit tests carefully.
- Increment the
Note
Removing data from the file format is always safe. Old files which contain the data will continue to be readable, because the reader can simply ignore the data.
Note
Similarly, adding new widgets to the file format is also safe, as long as the
addition is orthogonal to existing data in the format. As of version 2.2(-ish)
the UnknownWidgetDataModel
catches new widgets which do not have a reader
registered.
Unit Tests¶
The scene model code, by virtue of being independent from the view code, has very extensive test coverage. You should strive to maintain this when making changes. It is intended as a defensive measure against introducing breaking changes to users. Unfortunately, it’s not automatic, and it requires a bit of discipline on the part of developers working on the scene.
This is very important. Good unit test coverage of the scene file model code is the main defense against user hostile bugs encountered when loading scenes.
The View¶
The job of the subpackage karabogui.sceneview
is to create a visual
representation of the data in scene model objects and give a way to
manipulate that data.
Adding a New Widget¶
If you haven’t added the data for your widget to the scene model yet, you should first do that before proceeding with the view portion. Once your new widget has a data model class associated with it, you can make it appear in the scene by doing the following:
- Create a
BaseBindingController
class (or classes) which will be shown in the scene. - Make sure your controller class has a
model
trait which is anInstance
of whatever your scene model class is. - Register your controller class with the
register_binding_controller
decorator. - Add unit tests for your controller class.
- Test in the GUI.
Note
A Developer’s Checklist is documented in Widget Developer Checklist
Note
If your new scene object does NOT need to interact with device properties
you should take a look at karabogui.sceneview.widget
. Adding things to
the scene view isn’t always dealing with properties.
Adding a New Shape¶
Creating a new shape karabogui.sceneview.shapes
is a bit easier, due to
the fact that shapes are not maintaining backwards compatibility with other
parts of the GUI code base. That said, you should still begin by creating a
data model class for your shape.
- Create a
BaseShape
class which will be shown in the scene - Import your shape and model classes in
karabogui.sceneview.builder
and add them to the_SHAPE_CLASSES
dictionary. - Test in the GUI