Skip to content

Property Enum file format (*.pef)

Alex Zhondin edited this page Feb 12, 2017 · 18 revisions

Defining property sets is a very similar with defining GUI elements. In most cases it's just hierarchy of objects with attributes. Now many GUI frameworks allow define GUI stuff using declarative language (like QML in Qt or XAML in .NET) in contrast of imperative C++ code.

So PEF format was introduced to help users to define properties in declarative way.

Let's consider the following example. Here is a simple property set with three sub properties.

    #include "Core/PropertyCore.h"
    ...
    auto textAttr = new QtnPropertySet(nullptr);
    textAttr.setName("TextAttributes");

    auto wrapping = new QtnPropertyBool(textAttr);
    wrapping->setName("WordWrap");
    wrapping->setDescription("Text word wrapping");
    wrapping->setValue(true);

    auto height = new QtnPropertyInt(textAttr);
    height->setName("Height");
    height->setDescription("Text height");
    height->setMaxValue(100);
    height->setMinValue(1);
    height->setStepValue(1);
    height->setValue(16);

    auto textColor = new QtnPropertyQColor(textAttr);
    textColor->setName("Color");
    textColor->setDescription("Foreground text color");
    textColor->setValue(QColor(0, 0, 0));

This code has a lot of redundancy and can be represented in more compact and elegant way using PEF (TextAttribues.pef):

#include "Core/PropertyCore.h"

property_set TextAttributes
{
    Bool WordWrap
    {
        description = "Text word wrapping";
        value = true;
    }
    Int Height
    {
        description = "Text height";
        value = 16;
        minValue = 1;
        maxValue = 100;
        stepValue = 1;
    }
    QColor Color
    {
        description = "Foreground text color";
        value = QColor(0, 0, 0);
    }
}

QtnPEG (Property/Enum Generator) executable converts *.pef file info C++ code. For example

QtnPEG.exe TextAttrubutes.pef 

will produce TextAttributes.pef.h and TextAttributes.pef.cpp files where QtnPropertySetTextAttributes class is declared and implemented.

PEF files consist of several parts. Each part is optional. #Includes To include some file in the generated *.h or *.cpp file you can use three include directives:

#include "foo.h"
or
#include_h "foo.h"

will include "foo.h" file into generated *.h file.

#include_cpp "foo.h"

will include "foo.h" into generated *.cpp file

#C++ code You can inject any C++ code into generated files using the following constructions:

code_h
{
    // this code goes into header file
    std::string foo();
}

code_cpp
{
    // this code goes into source file
    std::string foo()
    {
        return "Hello from foo"s;
    }
}

#Enum declaration Raw C++ enum is not suitable for properties because doesn't have string representation of the enum values. PEF file allows you to declare enum which will be converted into C++ class with raw C++ enum and string values associated with values.
The enum declaration below:

enum COLOR
{
    transparent(0, "transparent") hidden,
    red (1, "red"),
    blue (2, "blue"),
    green (3, "green")
}

will produce the following C++ code:

// header file code
class COLOR
{
public:
    enum Enum
    {
        transparent = 0,
        red = 1,
        blue = 2,
        green = 3
    };
    
    static const QtnEnumInfo& info();
    static const unsigned int values_count = 4;
};
// source file code
static QtnEnumInfo& create_COLOR_info()
{
    QVector<QtnEnumValueInfo> staticValues;
    staticValues.append(QtnEnumValueInfo(COLOR::transparent, "transparent", "transparent", QtnEnumValueStateHidden));
    staticValues.append(QtnEnumValueInfo(COLOR::red, "red", "red"));
    staticValues.append(QtnEnumValueInfo(COLOR::blue, "blue", "blue"));
    staticValues.append(QtnEnumValueInfo(COLOR::green, "green", "green"));
    
    static QtnEnumInfo enumInfo("COLOR", staticValues);
    return enumInfo;
}

const QtnEnumInfo& COLOR::info()
{
    static QtnEnumInfo& enumInfo = create_COLOR_info();
    return enumInfo;
}

Here you can get a raw C++ enum using COLOR::Enum and access to enum values attributes (strings and states) using COLOR::info()

    // some examples of using COLOR
    COLOR::Enum value = ...
    ...
    switch (value)
    {
        case COLOR::red:
            // process red
            break;
        case COLOR::blue:
            // process blue
            break;
        default:
            // process other colors
            break;
    }

    if (auto enumValueInfo = COLOR::info().findByValue(COLOR::green))
    {
        assert(enumValueInfo->name() == "green");
    }

    if (auto enumValueInfo = COLOR::info().findByName("green"))
    {
        assert(enumValueInfo->value() == COLOR::green);
    }

#Property sets The main intend of PEF files is to declare property sets. You can declare one or more property sets in a single PEF file.
Property set declaration consists of two big parts: header and body.

    property_set_header
    {
        property_set_body
    }

The header declares property set's name followed by property_set keyword:

    property_set Foo
    {
    }

This will produce C++ class for Foo property set:

    class QtnPropertySetFoo: public QtnPropertySet
    {
        Q_OBJECT
        ...
    }

In property set body you can define property set's attributes, sub properties, sub property sets and slots. #Attributes Attributes can be defined for property set, sub property or sub property set.
For example the code below:

    property_set Foo
    {
        description = tr("Detailed description");
        state = QtnPropertyStateInvisible;
    }

will generate the following C++ code:

    void QtnPropertySetFoo::init()
    {
        static QString Foo_name = tr("Foo");
        setName(Foo_name);

        setDescription(tr("Foo"));
        setState(QtnPropertyStateInvisible);
    }

So any line attrName = attrValue; will be converted into setAttrName(attrValue); call.