-
Notifications
You must be signed in to change notification settings - Fork 153
Property Enum file format (*.pef)
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
#Comments You can use C++ comments in PEF file.
// this will comment till the end of line
/*
this will comment a block of text
*/
#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
{
// list of any:
attribute
slot
sub property
sub property set
}
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
...
}
#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.
#Sub property
Here is a schema of sub property declaration:
PropertyType PropertyName
{
// list of any:
attribute
slot
delegate
}
For example:
property_set Foo
{
Bool boolProp
{
description = "boolProp is a boolean property";
value = false;
}
}
#Slots Any property and property set has two signals:
- propertyWillChange - fired before property changing
- propertyDidChange - fired after property changing In PEF file you can define slots for these signals.
property_set Foo
{
Bool boolProp
{
slot propertyDidChange
{
if (reason & QtnPropertyChangeReasonValue)
cout << "boolProperty has changed";
}
}
Int intProp
{
slot propertyDidChange
{
if (reason & QtnPropertyChangeReasonValue)
cout << "intProperty has changed";
}
}
slot propertyDidChange
{
if (reason & QtnPropertyChangeReasonValue)
cout << "either boolProp or intProperty has changed";
}
}
Depending on where slot is defined it will be connected to different signals. In the example above the first two slots will be connected to the corresponding properties boolProp and intProp and the last slot will be connected to the Foo property set itself.
#Delegates
Properties can be displayed and edited in different ways in property view widget. So you can select particular delegate and its attributes to customize property appearance and edit facilities.
For example this property will be edited by combobox with four items (the default delegate uses editbox as editor)
QString StringFromListProperty
{
description = "QString property with list of accepted values (one, two, three, four).";
value = "two";
delegate List
{
items = QStringList() << "one" << "two" << "three" << "four";
}
}