diff options
author | Dominik Holland <dominik.holland@pelagicore.com> | 2017-08-29 16:11:15 +0200 |
---|---|---|
committer | Dominik Holland <dominik.holland@pelagicore.com> | 2017-09-15 12:49:01 +0000 |
commit | c99b4539534a09e0da836b5dd5057e8b770e9863 (patch) | |
tree | 1c97b0b6c3745b8a706310c1b0abd2ad272b4492 | |
parent | c453170eeba7f3e2685329928deea600c6fc4a35 (diff) |
Refactor the control_panel interface class
The class now works more like the QtIvi public API and uses one object
per zone accessible using the zoneAt property.
This also intruces two new special controls for Enums and Flags, which
makes the generate.py part a little bit easier and make the controls
work in both directions (backend values and update of user values).
Change-Id: Ib012265ef405d4a4e20ed43d611caa0163a40446
Reviewed-by: Mike Krus <mike.krus@kdab.com>
11 files changed, 143 insertions, 105 deletions
diff --git a/src/tools/ivigenerator/generate.py b/src/tools/ivigenerator/generate.py index 39d47b1..157be8b 100755 --- a/src/tools/ivigenerator/generate.py +++ b/src/tools/ivigenerator/generate.py @@ -364,8 +364,9 @@ def qml_control_properties(symbol, backend_object): return 'id: {0}; from:-100000; to: {1}; {2}'.format(prop_str, top, binding) values = domain_values(symbol) - if values is None and symbol.type.is_enum: - values = symbol.type.reference.members + if values is None and (symbol.type.is_enum or symbol.type.is_flag): + values_string = ' '.join('ListElement {{ key: "{0}"; value: {1}.{0} }}'.format(e, qml_type(symbol.interface)) for e in symbol.type.reference.members) + return 'id: {0}; textRole: "key"; {2} model: ListModel {{ {1} }}'.format(prop_str, values_string, binding) if values is not None: values_string = ','.join('"'+str(e)+'"' for e in values) return 'id: {0}; model: [ {1} ]; '.format(prop_str, values_string) @@ -400,24 +401,6 @@ def qml_meta_control_name(symbol): if values is not None: return "ComboBox" - -def qml_flag_control(symbol): - """ - Returns QML code for creation of group of check-boxes for - the flag property - """ - # First try to calculate control name based on the tags - result = qml_meta_control_name(symbol) - # If nothing is defined, calculate it based on its type - if result is None and symbol.type.reference.members: - # form a group of checkboxes - values = symbol.type.reference.members - result = "" - for value in values: - result+="Text{{ text:'{0}'}} CheckBox {{ id: flag{0}; }}\n".format(value) - return result - - def qml_type_control_name(symbol): """ Returns name of the QML control inferred based on the type of the symbol. @@ -429,9 +412,11 @@ def qml_type_control_name(symbol): return "CheckBox" elif t.is_enum: if t.reference.is_enum: - return "ComboBox" + return "EnumControl" elif t.reference.is_flag: - return qml_flag_control(symbol) + return "FlagControl" + elif t.is_flag: + return "FlagControl" return "TextField" @@ -454,8 +439,6 @@ def qml_control(symbol, backend_object): Returns QML code for the control (or group of controls) to represent the editing UI for the symbol. """ - if symbol.type.reference and symbol.type.reference.is_flag: - return qml_flag_control(symbol) if symbol.type.is_struct: return qml_struct_control(symbol) @@ -470,12 +453,12 @@ def qml_binding_property(symbol): control_name = qml_control_name(symbol) if control_name == "CheckBox": return "checked" - elif control_name == "Slider" or control_name == "SpinBox": + elif control_name == "Slider" or control_name == "SpinBox" or control_name == "FlagControl" or control_name == "EnumControl": return "value" elif control_name == "TextField": return "text" elif control_name == "ComboBox": - return "currentText" + return "currentIndex" def qml_struct_control(symbol): if symbol.type.is_struct and symbol.type.reference.fields: diff --git a/src/tools/ivigenerator/ivigenerator.pro b/src/tools/ivigenerator/ivigenerator.pro index ce5fda0..15edf97 100644 --- a/src/tools/ivigenerator/ivigenerator.pro +++ b/src/tools/ivigenerator/ivigenerator.pro @@ -53,6 +53,8 @@ templates_generation_validator.files += \ templates_generation_validator.path = $$[QT_HOST_BINS]/ivigenerator/templates_generation_validator templates_control_panel.files += \ + templates_control_panel/EnumControl.qml.tpl \ + templates_control_panel/FlagControl.qml.tpl \ templates_control_panel/generated_comment.cpp.tpl \ templates_control_panel/global.h.tpl \ templates_control_panel/interface.cpp.tpl \ diff --git a/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl b/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl index 2e56f6a..8516302 100644 --- a/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl +++ b/src/tools/ivigenerator/templates_backend_simulator/backend.cpp.tpl @@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE {% endfor %} { + {{module.module_name}}Module::registerTypes(); {% set zones = interface.tags.config_simulator.zones if interface.tags.config_simulator else {} %} {% for zone_name, zone_id in zones.items() %} ZoneBackend {{zone_name}}Zone; diff --git a/src/tools/ivigenerator/templates_control_panel.yaml b/src/tools/ivigenerator/templates_control_panel.yaml index e8297d8..3a7f6e3 100644 --- a/src/tools/ivigenerator/templates_control_panel.yaml +++ b/src/tools/ivigenerator/templates_control_panel.yaml @@ -14,6 +14,10 @@ generate_rules: template_file: "module.h.tpl" - dest_file: "{{module.module_name|lower}}module.cpp" template_file: "module.cpp.tpl" + - dest_file: "FlagControl.qml" + template_file: "FlagControl.qml.tpl" + - dest_file: "EnumControl.qml" + template_file: "EnumControl.qml.tpl" interface_rules: - dest_file: '{{interface}}.qml' template_file: 'interface.qml.tpl' diff --git a/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl b/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl new file mode 100644 index 0000000..9f517e6 --- /dev/null +++ b/src/tools/ivigenerator/templates_control_panel/EnumControl.qml.tpl @@ -0,0 +1,31 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +ComboBox { + id: root + + property var value: 0 + + FontMetrics { + font: root.font + id: _metrics + } + + Binding { + target: root + property: "value" + value: model.get(currentIndex).value + } + + onValueChanged: { + for(var i=0; i<model.count; i++) { + if (model.get(i).value == value) { + //Make the ComboBox as big as it's content + root.implicitWidth = _metrics.boundingRect(model.get(i).key).width + 100 + currentIndex = i; + return; + } + } + console.warn("Couldn't find the value in the EnumControl model: " + value); + } +} diff --git a/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl b/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl new file mode 100644 index 0000000..9e5abc6 --- /dev/null +++ b/src/tools/ivigenerator/templates_control_panel/FlagControl.qml.tpl @@ -0,0 +1,29 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 + +RowLayout { + id: root + property alias model: repeater.model + property int value + property string textRole + + spacing: 2 + + Repeater { + id: repeater + RowLayout { + Text { text: model[textRole] } + CheckBox { + id: checkBox + checked: root.value & model.value; + onClicked: { + if (checked) + root.value |= model.value + else + root.value &= ~model.value + } + } + } + } +} diff --git a/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl b/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl index 7cf85d2..3d00e84 100644 --- a/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl +++ b/src/tools/ivigenerator/templates_control_panel/interface.cpp.tpl @@ -44,7 +44,7 @@ #include "{{class|lower}}.h" #include <QQmlEngine> - +#include <QDebug> namespace { const QString INITIAL_MAIN_ZONE = "MainZone"; @@ -57,24 +57,27 @@ QT_BEGIN_NAMESPACE \inmodule {{module}} {{ utils.format_comments(interface.comment) }} */ -{{class}}::{{class}}(QObject *parent) +{{class}}::{{class}}(const QString &zone, QObject *parent) : QObject(parent) - , m_currentZoneBackend(createZoneBackend()) - , m_currentZone(INITIAL_MAIN_ZONE) + , m_currentZone(zone) { - m_zones << INITIAL_MAIN_ZONE; + if (!zone.isEmpty()) { + return; + } + + //Add ourself to the available zones to make it available to the UI and still keep the code clean + m_zoneHash.insert(INITIAL_MAIN_ZONE, this); + m_zoneMap.insert(INITIAL_MAIN_ZONE, QVariant::fromValue(this)); + {% set zones = interface.tags.config_simulator.zones if interface.tags.config_simulator else {} %} {% for zone_name, zone_id in zones.items() %} - m_zones << "{{zone_id}}"; + addZone("{{zone_id}}"); {% endfor %} } /*! \internal */ {{class}}::~{{class}}() { -{% if module.tags.config.disablePrivateIVI %} - delete m_helper; -{% endif %} } /*! \internal */ @@ -89,24 +92,24 @@ void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minor void {{class}}::addZone(const QString &newZone) { - bool exists = false; - for (int i = 0; i < m_zones.count(); ++i) { - if (m_zones.at(i).toString() == newZone) { - exists = true; - break; - } + if (!m_currentZone.isEmpty()) { + qWarning("Adding a new zone is only possible from the root zone."); + return; } - if (!exists) { - m_zones.append(newZone); - emit zonesChanged(); - } -} + if (m_zoneHash.contains(newZone)) + return; + {{class}} *zoneObject = new {{class}}(newZone, this); + m_zoneHash.insert(newZone, zoneObject); + m_zoneMap.insert(newZone, QVariant::fromValue(zoneObject)); -QVariantList {{class}}::zones() const + emit zonesChanged(); +} + +QStringList {{class}}::zones() const { - return m_zones; + return m_zoneMap.keys(); } @@ -115,27 +118,11 @@ QString {{class}}::currentZone() const return m_currentZone; } - -void {{class}}::setCurrentZone(const QString &zone) +QVariantMap {{class}}::zoneAt() const { - if (zone != m_currentZone) { -{% if interface_zoned %} - m_zoneMap[m_currentZone]=m_currentZoneBackend; - m_currentZone = zone; - if(m_zoneMap.contains(m_currentZone)) { - m_currentZoneBackend = m_zoneMap[m_currentZone]; - } else { - m_currentZoneBackend = createZoneBackend(); - } -{% endif %} - emit currentZoneChanged(); -{% for property in interface.properties %} - emit {{property}}Changed(m_currentZoneBackend.{{property}}); -{% endfor %} - } + return m_zoneMap; } - {% for property in interface.properties %} /*! @@ -147,13 +134,15 @@ void {{class}}::setCurrentZone(const QString &zone) */ {{property|return_type}} {{class}}::{{property|getter_name}}() const { - return m_currentZoneBackend.{{property}}; + return m_{{property}}; } void {{class}}::{{property|setter_name}}({{ property|parameter_type }}) { - m_currentZoneBackend.{{property}} = {{property}}; - emit {{property}}Changed({{property}}); + if (m_{{property}} == {{property}}) + return; + m_{{property}} = {{property}}; + emit {{property}}Changed({{property}}); } {% endfor %} @@ -170,14 +159,4 @@ void {{class}}::{{property|setter_name}}({{ property|parameter_type }}) {% endfor %} -{{class}}::ZoneBackend {{class}}::createZoneBackend() { - ZoneBackend zoneBackend; -{% for property in interface.properties %} - zoneBackend.{{property}} = {{property|default_value}}; -{% endfor %} - return zoneBackend; -} - QT_END_NAMESPACE - -#include "moc_{{class|lower}}.cpp" diff --git a/src/tools/ivigenerator/templates_control_panel/interface.h.tpl b/src/tools/ivigenerator/templates_control_panel/interface.h.tpl index 04e626d..365ae25 100644 --- a/src/tools/ivigenerator/templates_control_panel/interface.h.tpl +++ b/src/tools/ivigenerator/templates_control_panel/interface.h.tpl @@ -49,7 +49,7 @@ #include <QObject> #include <QHash> - +#include <QVariantMap> QT_BEGIN_NAMESPACE @@ -62,27 +62,28 @@ class {{exportsymbol}} {{class}} : public QObject { class {{exportsymbol}} {{class}} : public QObject { {% endif %} Q_OBJECT - Q_PROPERTY(QString currentZone READ currentZone WRITE setCurrentZone NOTIFY currentZoneChanged) - Q_PROPERTY(QVariantList zones READ zones NOTIFY zonesChanged) + Q_PROPERTY(QString currentZone READ currentZone NOTIFY currentZoneChanged) + Q_PROPERTY(QStringList zones READ zones NOTIFY zonesChanged) + Q_PROPERTY(QVariantMap zoneAt READ zoneAt NOTIFY zonesChanged) {% for property in interface.properties %} Q_PROPERTY({{property|return_type}} {{property}} READ {{property|getter_name}} WRITE {{property|setter_name}} NOTIFY {{property}}Changed) {% endfor %} Q_CLASSINFO("IviPropertyDomains", "{{ interface.properties|json_domain|replace("\"", "\\\"") }}") public: - explicit {{class}}(QObject *parent = nullptr); + explicit {{class}}(const QString &zone = QString(), QObject *parent = nullptr); ~{{class}}(); static void registerQmlTypes(const QString& uri, int majorVersion=1, int minorVersion=0, const QString& qmlName = ""); Q_INVOKABLE void addZone(const QString& newZone); QString currentZone() const; - QVariantList zones() const; + QStringList zones() const; + QVariantMap zoneAt() const; {% for property in interface.properties %} {{property|return_type}} {{property|getter_name}}() const; {% endfor %} public Q_SLOTS: - void setCurrentZone(const QString& zone); {% for operation in interface.operations %} {{operation|return_type}} {{operation}}({{operation.parameters|map('parameter_type')|join(', ')}}){% if operation.const %} const{% endif %}; {% endfor %} @@ -101,18 +102,15 @@ Q_SIGNALS: {% endfor %} private: - struct ZoneBackend { {% for property in interface.properties %} - {{ property|return_type }} {{ property }}; + {{ property|return_type }} m_{{ property }}; {% endfor %} - }; - ZoneBackend m_currentZoneBackend ; {% if interface_zoned %} - QHash<QString,ZoneBackend> m_zoneMap; + QHash<QString,{{class}}*> m_zoneHash; + QVariantMap m_zoneMap; {% endif %} - QVariantList m_zones; QString m_currentZone; - ZoneBackend createZoneBackend(); + //ZoneBackend createZoneBackend(); }; QT_END_NAMESPACE diff --git a/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl b/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl index 6d1f904..e835883 100644 --- a/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl +++ b/src/tools/ivigenerator/templates_control_panel/interface.qml.tpl @@ -53,16 +53,15 @@ Flickable { ScrollBar.vertical: ScrollBar {} contentHeight: layout.childrenRect.height - {{interface|qml_type}}Object { + {{interface|qml_type}} { id: {{backend_obj}} -{% for property in interface.properties %} - {{property}}: {{property|lowerfirst}}Control.{{property|qml_binding_property}} -{% endfor%} - } + property {{interface|qml_type}} currentZoneObject: {{backend_obj}}.zoneAt[comboZones.displayText] + ColumnLayout { id: layout + anchors.fill: parent {% if interface.tags.config.zoned %} RowLayout { Text { @@ -73,12 +72,7 @@ Flickable { id: comboZones editable: true model: {{backend_obj}}.zones - onCurrentIndexChanged: { - var newZone = comboZones.textAt(comboZones.currentIndex) - if (newZone !== "") { - {{backend_obj}}.currentZone = newZone - } - } + currentIndex: {{backend_obj}}.zones.indexOf("MainZone") } Button { text:"+" @@ -100,10 +94,25 @@ Flickable { {% for property in interface.properties %} RowLayout { height: 30 + Layout.fillWidth: true Text { text: "{{property|upperfirst}}: " } - {{property|qml_control(backend_obj)}} + + Connections { + target: {{property|lowerfirst}}Control + on{{property|qml_binding_property|upperfirst}}Changed: { + currentZoneObject.{{property}} = {{property|lowerfirst}}Control.{{property|qml_binding_property}} + } + } + + Binding { + target: {{property|lowerfirst}}Control + property: "{{property|qml_binding_property}}" + value: currentZoneObject.{{property}} + } + + {{property|qml_control('currentZoneObject')}} } {% endfor %} {% if interface.operations|count %} diff --git a/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl b/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl index 14fed35..006f67f 100644 --- a/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl +++ b/src/tools/ivigenerator/templates_control_panel/main.cpp.tpl @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) {% for interface in module.interfaces %} {{interface}}::registerQmlTypes(QLatin1String("QtIvi.ControlPanel"), 1, 0, - QLatin1String("{{interface|qml_type}}Object")); + QLatin1String("{{interface|qml_type}}")); {% endfor %} QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); diff --git a/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl b/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl index e95c473..2a6d015 100644 --- a/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl +++ b/src/tools/ivigenerator/templates_control_panel/qml.qrc.tpl @@ -40,6 +40,8 @@ <RCC> <qresource prefix="/"> <file>main.qml</file> + <file>EnumControl.qml</file> + <file>FlagControl.qml</file> {% for interface in module.interfaces %} <file>{{interface}}.qml</file> {% endfor %} |