Skip to content
Snippets Groups Projects
scenes.rst 10.19 KiB

Device Scenes

Karabo provides a protocol for devices to share predefined scenes. These allows the author of a device to provide what they think are a good starting point. Moreover, these are easily accessible from the topology panel in the GUI:

images/default_scenes.png

A default scene can also be accessed by double-clicking on a device.

This section shows how to enable your device to have builtin scenes.

Implementing this functionality requires the creation of a scene in the scene editor, its conversion to a C++ ostringstream, and adding the requestScene slot to the device.

From Scene To Header File

Begin by drawing an adequate scene in the GUI's scene editor, and save it locally on your computer as SVG (right-click on scene -> Save to File).

SVG is XML-based, and thus can be easily edited. Convert the SVG to a header file scenes.hh with a function. Thus the original SVG:

<?xml version="1.0"?>
<svg:svg xmlns:krb="http://karabo.eu/scene" xmlns:svg="http://www.w3.org/2000/svg" height="768" width="1024" krb:version="2">
        <svg:g krb:class="BoxLayout" krb:direction="0" krb:height="33" krb:width="87" krb:x="30" krb:y="26">
        <svg:rect height="24" width="39" x="0" y="0" krb:background="transparent" krb:class="Label" krb:font="Sans,9,-1,5,50,0,0,0,0,0" krb:foreground="#000000" krb:frameWidth="0" krb:text="Start"/>
        <svg:rect height="23" width="46" x="0" y="0" krb:class="DisplayComponent" krb:keys="Generator.start" krb:requires_confirmation="false" krb:widget="DisplayCommand"/>
</svg:g>
<svg:g krb:class="BoxLayout" krb:direction="0" krb:height="33" krb:width="81" krb:x="35" krb:y="61">
        <svg:rect height="24" width="37" x="0" y="0" krb:background="transparent" krb:class="Label" krb:font="Sans,9,-1,5,50,0,0,0,0,0" krb:foreground="#000000" krb:frameWidth="0" krb:text="Stop"/>
        <svg:rect height="23" width="43" x="0" y="0" krb:class="DisplayComponent" krb:keys="Generator.stop" krb:requires_confirmation="false" krb:widget="DisplayCommand"/>
</svg:g>
<svg:g krb:class="BoxLayout" krb:direction="0" krb:height="33" krb:width="145" krb:x="150" krb:y="33">
        <svg:rect height="24" width="95" x="0" y="0" krb:background="transparent" krb:class="Label" krb:font="Sans,9,-1,5,50,0,0,0,0,0" krb:foreground="#000000" krb:frameWidth="0" krb:text="Float property"/>
        <svg:rect height="23" width="49" x="0" y="0" krb:class="DisplayComponent" krb:keys="Generator.floatProperty" krb:widget="DisplayLabel"/>
</svg:g>
<svg:g krb:class="BoxLayout" krb:direction="0" krb:height="329" krb:width="514" krb:x="36" krb:y="119">
        <svg:rect height="24" width="47" x="0" y="0" krb:background="transparent" krb:class="Label" krb:font="Sans,9,-1,5,50,0,0,0,0,0" krb:foreground="#000000" krb:frameWidth="0" krb:text="image"/>
        <svg:rect height="319" width="465" x="0" y="0" krb:class="DisplayComponent" krb:keys="Generator.output.schema.image" krb:show_axes="true" krb:show_color_bar="true" krb:show_tool_bar="true" krb:widget="WebcamImage"/>
</svg:g>
</svg:svg>

Becomes:

#include <sstream>

std::string getControls(const std::string& instanceId) {
    std::ostringstream ret;
    // SVG header
    ret << "<?xml version=\"1.0\"?>"
        << "<svg:svg xmlns:krb=\"http://karabo.eu/scene\" xmlns:svg=\"http://www.w3.org/2000/svg\" "
        << "height=\"119\" width=\"150\" krb:version=\"2\">"
    // Start button label
        << "<svg:g krb:class=\"BoxLayout\" krb:direction=\"0\" krb:height=\"33\" krb:width=\"87\" krb:x=\"30\" krb:y=\"26\">"
        << "<svg:rect height=\"24\" width=\"39\" x=\"0\" y=\"0\" krb:background=\"transparent\" krb:class=\"Label\" krb:font=\"Sans,9,-1,5,50,0,0,0,0,0\" "
        << "krb:foreground=\"#000000\" krb:frameWidth=\"0\" krb:text=\"Start\"/>"
    // Start button itself
        << "<svg:rect height=\"23\" width=\"46\" x=\"0\" y=\"0\" krb:class=\"DisplayComponent\" "
        << "krb:keys=\"" << instanceId << ".start\" krb:requires_confirmation=\"false\" krb:widget=\"DisplayCommand\"/></svg:g>"
    // Stop button label
        << "<svg:g krb:class=\"BoxLayout\" krb:direction=\"0\" krb:height=\"33\" krb:width=\"81\" krb:x=\"35\" krb:y=\"61\">"
        << "<svg:rect height=\"24\" width=\"37\" x=\"0\" y=\"0\" krb:background=\"transparent\" krb:class=\"Label\" krb:font=\"Sans,9,-1,5,50,0,0,0,0,0\" "
        << "krb:foreground=\"#000000\" krb:frameWidth=\"0\" krb:text=\"Stop\"/>"
    // Stop button itself
        << "<svg:rect height=\"23\" width=\"43\" x=\"0\" y=\"0\" krb:class=\"DisplayComponent\" "
        << "krb:keys=\"" << instanceId << ".stop\" krb:requires_confirmation=\"false\" krb:widget=\"DisplayCommand\"/></svg:g>"
    // SVG footer
        << "</svg:svg>";
    return ret.str();
}

Add this file to your project.

Providing The Scene From Your Device

Add a read-only VECTOR_STRING_ELEMENT property called availableScenes to your expected parameters, and register and implement the requestScene slot. This is a predefined slot, which allows various actors to understand the scene protocol.

The slot takes a Hash params and lets the device reply with a Hash containing the origin, its datatype (deviceScene), and the scene serialized as xml:

#include "scenes.hh"

using namespace karabo::util;

// Define the list of scenes
void MyDevice::expectedParameters(karabo::util::Schema& expected) {

   VECTOR_STRING_ELEMENT(expected).key("availableScenes")
       .setSepcialDisplayType(KARABO_SCHEMA_DISPLAY_TYPE_SCENES)
       .readOnly().initialValue(std::vector<std::string>{"controls"})
       .commit();
}

// Register in the constructor that we have this functionality
MyDevice::MyDevice(const karabo::util::Hash& config)
    : karabo::core::Device<>(config)
{
    KARABO_SLOT(requestScene, karabo::util::Hash);
}

// The function that provides the scene
void MyDevice::requestScene(const karabo::util::Hash& params) {
    Hash result("type", "deviceScene", "origin", this->getInstanceId());
    Hash& payload = result.bindReference<Hash>("payload");

    payload.set("success", true);
    payload.set("name", "controls");
    payload.set("data", getControls());

    this->reply(result);
}